summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2024-03-02 15:31:42 -0500
committerKent Overstreet <kent.overstreet@linux.dev>2024-03-02 20:55:52 -0500
commita11fd8a0038e6d6ee9ada483883814989366345d (patch)
treef89971ebc51184729c5579f9f07cf7948aa20911
parentfe2b194e6c0ce8154c85ea34b3ed251d523d654f (diff)
bcachefs: new subvol ioctlsbcachefs_subvol_ioctls
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/bcachefs_ioctl.h19
-rw-r--r--fs/bcachefs/fs-common.c28
-rw-r--r--fs/bcachefs/fs-ioctl.c49
3 files changed, 83 insertions, 13 deletions
diff --git a/fs/bcachefs/bcachefs_ioctl.h b/fs/bcachefs/bcachefs_ioctl.h
index 4b8fba754b1c..2d3a2f9ea123 100644
--- a/fs/bcachefs/bcachefs_ioctl.h
+++ b/fs/bcachefs/bcachefs_ioctl.h
@@ -85,6 +85,8 @@ struct bch_ioctl_incremental {
#define BCH_IOCTL_FSCK_OFFLINE _IOW(0xbc, 19, struct bch_ioctl_fsck_offline)
#define BCH_IOCTL_FSCK_ONLINE _IOW(0xbc, 20, struct bch_ioctl_fsck_online)
+#define BCH_IOCTL_SUBVOLUME_LIST _IOW(0xbc, 21, struct bch_ioctl_subvolume_list)
+#define BCH_IOCTL_SUBVOLUME_PATH _IOW(0xbc, 22, struct bch_ioctl_subvolume_path)
/* ioctl below act on a particular file, not the filesystem as a whole: */
@@ -409,4 +411,21 @@ struct bch_ioctl_fsck_online {
__u64 opts; /* string */
};
+/*
+ * BCH_IOCTL_SUBVOLUME_LIST: List child subvolumes of current subvolume
+ */
+struct bch_ioctl_subvolume_list {
+ __u64 buflen;
+ __u64 buf[];
+};
+
+/*
+ * BCH_IOCTL_SUBVOLUME_PATH: Get path to a given subvolid
+ */
+struct bch_ioctl_subvolume_path {
+ __u64 subvolid;
+ __u64 buflen;
+ __u8 buf[];
+};
+
#endif /* _BCACHEFS_IOCTL_H */
diff --git a/fs/bcachefs/fs-common.c b/fs/bcachefs/fs-common.c
index 7d1180036954..55ee914ddba0 100644
--- a/fs/bcachefs/fs-common.c
+++ b/fs/bcachefs/fs-common.c
@@ -557,9 +557,12 @@ static void memreverse(char *dst, const char *src, size_t len)
static void memreverse_inplace(char *p1, size_t len)
{
- char *p2 = p1 + len;
- while (p2 > p1)
- swap(*p1++, *--p2);
+ char *p2 = p1 + len;
+ while (p2 > p1) {
+ --p2;
+ swap(*p1, *p2);
+ p1++;
+ }
}
int bch2_inum_to_path_trans(struct btree_trans *trans, subvol_inum inum, darray_char *path)
@@ -570,9 +573,11 @@ int bch2_inum_to_path_trans(struct btree_trans *trans, subvol_inum inum, darray_
darray_init(path);
while (true) {
- ret = darray_push(path, '/');
- if (ret)
- goto err;
+ if (path->nr) {
+ ret = darray_push(path, '/');
+ if (ret)
+ goto err;
+ }
if (inum.subvol == BCACHEFS_ROOT_SUBVOL &&
inum.inum == BCACHEFS_ROOT_INO)
@@ -580,13 +585,10 @@ int bch2_inum_to_path_trans(struct btree_trans *trans, subvol_inum inum, darray_
struct bch_inode_unpacked inode_u;
ret = bch2_inode_find_by_inum_trans(trans, inum, &inode_u);
- if (ret)
- goto err;
-
- if (!inode_u.bi_dir) {
+ if (!ret && !inode_u.bi_dir)
ret = -BCH_ERR_ENOENT_no_backpointer;
+ if (ret)
goto err;
- }
u32 subvol = inode_u.bi_parent_subvol ?: inum.subvol;
u32 snapshot;
@@ -619,9 +621,9 @@ int bch2_inum_to_path_trans(struct btree_trans *trans, subvol_inum inum, darray_
ret = darray_push(path, '\0');
err:
+ bch2_trans_iter_exit(trans, &iter);
if (ret)
darray_exit(path);
- bch2_trans_iter_exit(trans, &iter);
return ret;
}
@@ -629,6 +631,6 @@ int bch2_subvol_to_path_trans(struct btree_trans *trans, u32 subvol, darray_char
{
struct bch_subvolume s;
- return bch2_subvolume_get(trans, subvol, true, 0, &s) ?:
+ return bch2_subvolume_get(trans, subvol, false, 0, &s) ?:
bch2_inum_to_path_trans(trans, (subvol_inum) { subvol, le64_to_cpu(s.inode) }, path);
}
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;