summaryrefslogtreecommitdiff
path: root/fs/bcachefs/fs-ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/bcachefs/fs-ioctl.c')
-rw-r--r--fs/bcachefs/fs-ioctl.c91
1 files changed, 85 insertions, 6 deletions
diff --git a/fs/bcachefs/fs-ioctl.c b/fs/bcachefs/fs-ioctl.c
index 8b9d3c7d1f57..20b46126c066 100644
--- a/fs/bcachefs/fs-ioctl.c
+++ b/fs/bcachefs/fs-ioctl.c
@@ -199,8 +199,9 @@ static int bch2_ioc_goingdown(struct bch_fs *c, u32 __user *arg)
return ret;
}
-static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
- struct bch_ioctl_subvolume arg)
+static long __bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
+ struct bch_ioctl_subvolume_v2 arg,
+ struct printbuf *err)
{
struct inode *dir;
struct bch_inode_info *inode;
@@ -214,13 +215,17 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
unsigned create_flags = BCH_CREATE_SUBVOL;
if (arg.flags & ~(BCH_SUBVOL_SNAPSHOT_CREATE|
- BCH_SUBVOL_SNAPSHOT_RO))
+ BCH_SUBVOL_SNAPSHOT_RO)) {
+ prt_str(err, "invalid flasg");
return -EINVAL;
+ }
if (!(arg.flags & BCH_SUBVOL_SNAPSHOT_CREATE) &&
(arg.src_ptr ||
- (arg.flags & BCH_SUBVOL_SNAPSHOT_RO)))
+ (arg.flags & BCH_SUBVOL_SNAPSHOT_RO))) {
+ prt_str(err, "invalid flasg");
return -EINVAL;
+ }
if (arg.flags & BCH_SUBVOL_SNAPSHOT_CREATE)
create_flags |= BCH_CREATE_SNAPSHOT;
@@ -243,6 +248,7 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
if (src_path.dentry->d_sb->s_fs_info != c) {
path_put(&src_path);
+ prt_str(err, "src_path not on dst filesystem");
error = -EXDEV;
goto err1;
}
@@ -258,6 +264,7 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
goto err2;
if (dst_dentry->d_sb->s_fs_info != c) {
+ prt_str(err, "dst_path not on dst filesystem");
error = -EXDEV;
goto err3;
}
@@ -276,6 +283,7 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
s_user_ns = dir->i_sb->s_user_ns;
if (!kuid_has_mapping(s_user_ns, current_fsuid()) ||
!kgid_has_mapping(s_user_ns, current_fsgid())) {
+ prt_str(err, "current uid/gid not mapped into fs namespace");
error = -EOVERFLOW;
goto err3;
}
@@ -315,8 +323,35 @@ err1:
return error;
}
-static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
- struct bch_ioctl_subvolume arg)
+static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
+ struct bch_ioctl_subvolume arg)
+{
+ struct bch_ioctl_subvolume_v2 arg_v2 = {
+ .flags = arg.flags,
+ .dirfd = arg.dirfd,
+ .mode = arg.mode,
+ .dst_ptr = arg.dst_ptr,
+ .src_ptr = arg.src_ptr,
+ };
+
+ CLASS(printbuf, err)();
+ long ret = __bch2_ioctl_subvolume_create(c, filp, arg_v2, &err);
+ if (ret)
+ bch_err_msg(c, ret, "%s", err.buf);
+ return ret;
+}
+
+static long bch2_ioctl_subvolume_create_v2(struct bch_fs *c, struct file *filp,
+ struct bch_ioctl_subvolume_v2 arg)
+{
+ CLASS(printbuf, err)();
+ long ret = __bch2_ioctl_subvolume_create(c, filp, arg, &err);
+ return bch2_copy_ioctl_err_msg(&arg.err, &err, ret);
+}
+
+static long __bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
+ struct bch_ioctl_subvolume_v2 arg,
+ struct printbuf *err)
{
const char __user *name = (void __user *)(unsigned long)arg.dst_ptr;
struct path path;
@@ -350,6 +385,32 @@ err:
return ret;
}
+static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
+ struct bch_ioctl_subvolume arg)
+{
+ struct bch_ioctl_subvolume_v2 arg_v2 = {
+ .flags = arg.flags,
+ .dirfd = arg.dirfd,
+ .mode = arg.mode,
+ .dst_ptr = arg.dst_ptr,
+ .src_ptr = arg.src_ptr,
+ };
+
+ CLASS(printbuf, err)();
+ long ret = __bch2_ioctl_subvolume_destroy(c, filp, arg_v2, &err);
+ if (ret)
+ bch_err_msg(c, ret, "%s", err.buf);
+ return ret;
+}
+
+static long bch2_ioctl_subvolume_destroy_v2(struct bch_fs *c, struct file *filp,
+ struct bch_ioctl_subvolume_v2 arg)
+{
+ CLASS(printbuf, err)();
+ long ret = __bch2_ioctl_subvolume_destroy(c, filp, arg, &err);
+ return bch2_copy_ioctl_err_msg(&arg.err, &err, ret);
+}
+
long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
struct bch_inode_info *inode = file_bch_inode(file);
@@ -391,6 +452,15 @@ long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
}
+ case BCH_IOCTL_SUBVOLUME_CREATE_v2: {
+ struct bch_ioctl_subvolume_v2 i;
+
+ ret = copy_from_user(&i, (void __user *) arg, sizeof(i))
+ ? -EFAULT
+ : bch2_ioctl_subvolume_create_v2(c, file, i);
+ break;
+ }
+
case BCH_IOCTL_SUBVOLUME_DESTROY: {
struct bch_ioctl_subvolume i;
@@ -400,6 +470,15 @@ long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
}
+ case BCH_IOCTL_SUBVOLUME_DESTROY_v2: {
+ struct bch_ioctl_subvolume_v2 i;
+
+ ret = copy_from_user(&i, (void __user *) arg, sizeof(i))
+ ? -EFAULT
+ : bch2_ioctl_subvolume_destroy_v2(c, file, i);
+ break;
+ }
+
default:
ret = bch2_fs_ioctl(c, cmd, (void __user *) arg);
break;