diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2024-03-02 15:31:42 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2024-03-02 20:55:52 -0500 |
commit | a11fd8a0038e6d6ee9ada483883814989366345d (patch) | |
tree | f89971ebc51184729c5579f9f07cf7948aa20911 | |
parent | fe2b194e6c0ce8154c85ea34b3ed251d523d654f (diff) |
bcachefs: new subvol ioctlsbcachefs_subvol_ioctls
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/bcachefs_ioctl.h | 19 | ||||
-rw-r--r-- | fs/bcachefs/fs-common.c | 28 | ||||
-rw-r--r-- | fs/bcachefs/fs-ioctl.c | 49 |
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; |