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.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/fs/bcachefs/fs-ioctl.c b/fs/bcachefs/fs-ioctl.c
index 3dc8630ff9fe..3f90fad039da 100644
--- a/fs/bcachefs/fs-ioctl.c
+++ b/fs/bcachefs/fs-ioctl.c
@@ -476,6 +476,47 @@ err:
return ret;
}
+static long bch2_ioctl_subvolume_list(struct bch_fs *c, struct file *file,
+ struct bch_ioctl_subvolume_list __user *user_arg)
+{
+ struct bch_inode_info *inode = file_bch_inode(file);
+ struct bch_ioctl_subvolume_list arg;
+ DARRAY(u64) children = {};
+
+ int ret = copy_from_user_errcode(&arg, user_arg, sizeof(arg)) ?:
+ bch2_trans_run(c,
+ for_each_btree_key_upto(trans, iter, BTREE_ID_subvolume_children,
+ POS(inode->ei_subvol, 0),
+ POS(inode->ei_subvol, U64_MAX), 0, k, ({
+ darray_push(&children, k.k->p.offset);
+ }))) ?:
+ (children.nr > arg.buflen ? -ERANGE : 0) ?:
+ (arg.buflen = children.nr, 0) ?:
+ copy_to_user_errcode(user_arg, &arg, sizeof(arg)) ?:
+ copy_to_user_errcode(&user_arg->buf, children.data,
+ sizeof(children.data[0]) * children.nr);
+
+ darray_exit(&children);
+ return ret;
+}
+
+static long bch2_ioctl_subvolume_path(struct bch_fs *c, struct file *file,
+ struct bch_ioctl_subvolume_path __user *user_arg)
+{
+ struct bch_ioctl_subvolume_path arg;
+ darray_char path = {};
+
+ int ret = copy_from_user_errcode(&arg, user_arg, sizeof(arg)) ?:
+ bch2_subvol_to_path_checked(c, file->f_path.mnt, arg.subvolid, &path);
+ (path.nr > arg.buflen ? -ERANGE : 0) ?:
+ (arg.buflen = path.nr, 0) ?:
+ copy_to_user_errcode(user_arg, &arg, sizeof(arg)) ?:
+ copy_to_user_errcode(&user_arg->buf, path.data, path.nr);
+
+ darray_exit(&path);
+ return ret;
+}
+
long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
struct bch_inode_info *inode = file_bch_inode(file);
@@ -535,6 +576,14 @@ long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
}
+ case BCH_IOCTL_SUBVOLUME_LIST:
+ ret = bch2_ioctl_subvolume_list(c, file, (void __user *) arg);
+ break;
+
+ case BCH_IOCTL_SUBVOLUME_PATH:
+ ret = bch2_ioctl_subvolume_path(c, file, (void __user *) arg);
+ break;
+
default:
ret = bch2_fs_ioctl(c, cmd, (void __user *) arg);
break;