diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bcachefs/bcachefs_ioctl.h | 15 | ||||
-rw-r--r-- | fs/bcachefs/chardev.c | 34 |
2 files changed, 49 insertions, 0 deletions
diff --git a/fs/bcachefs/bcachefs_ioctl.h b/fs/bcachefs/bcachefs_ioctl.h index 52594e925eb7..42e2cb5d7b4d 100644 --- a/fs/bcachefs/bcachefs_ioctl.h +++ b/fs/bcachefs/bcachefs_ioctl.h @@ -71,6 +71,7 @@ struct bch_ioctl_incremental { #define BCH_IOCTL_DISK_ONLINE _IOW(0xbc, 6, struct bch_ioctl_disk) #define BCH_IOCTL_DISK_OFFLINE _IOW(0xbc, 7, struct bch_ioctl_disk) #define BCH_IOCTL_DISK_SET_STATE _IOW(0xbc, 8, struct bch_ioctl_disk_set_state) +#define BCH_IOCTL_DISK_SET_STATE_v2 _IOW(0xbc, 22, struct bch_ioctl_disk_set_state_v2) #define BCH_IOCTL_DATA _IOW(0xbc, 10, struct bch_ioctl_data) #define BCH_IOCTL_FS_USAGE _IOWR(0xbc, 11, struct bch_ioctl_fs_usage) #define BCH_IOCTL_DEV_USAGE _IOWR(0xbc, 11, struct bch_ioctl_dev_usage) @@ -93,6 +94,12 @@ struct bch_ioctl_incremental { #define BCHFS_IOC_REINHERIT_ATTRS _IOR(0xbc, 64, const char __user *) +struct bch_ioctl_err_msg { + __u64 msg_ptr; + __u32 msg_len; + __u32 pad; +}; + /* * BCH_IOCTL_QUERY_UUID: get filesystem UUID * @@ -181,6 +188,14 @@ struct bch_ioctl_disk_set_state { __u64 dev; }; +struct bch_ioctl_disk_set_state_v2 { + __u32 flags; + __u8 new_state; + __u8 pad[3]; + __u64 dev; + struct bch_ioctl_err_msg err; +}; + #define BCH_DATA_OPS() \ x(scrub, 0) \ x(rereplicate, 1) \ diff --git a/fs/bcachefs/chardev.c b/fs/bcachefs/chardev.c index e6ed64dc11b7..3b8c1409bbf6 100644 --- a/fs/bcachefs/chardev.c +++ b/fs/bcachefs/chardev.c @@ -293,6 +293,38 @@ static long bch2_ioctl_disk_set_state(struct bch_fs *c, return ret; } +static long bch2_ioctl_disk_set_state_v2(struct bch_fs *c, + struct bch_ioctl_disk_set_state_v2 arg) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST| + BCH_FORCE_IF_METADATA_LOST| + BCH_FORCE_IF_DEGRADED| + BCH_BY_INDEX)) || + arg.pad[0] || arg.pad[1] || arg.pad[2] || + arg.new_state >= BCH_MEMBER_STATE_NR) + return -EINVAL; + + CLASS(bch2_device_lookup, ca)(c, arg.dev, arg.flags); + if (IS_ERR(ca)) + return PTR_ERR(ca); + + CLASS(printbuf, err)(); + int ret = bch2_dev_set_state(c, ca, arg.new_state, arg.flags, &err); + if (ret) { + if (err.pos > arg.err.msg_len) + return -ERANGE; + + prt_printf(&err, "\nerror=%s", bch2_err_str(ret)); + ret = copy_to_user_errcode((void __user *)(ulong)arg.err.msg_ptr, + err.buf, + err.pos) ?: ret; + } + return ret; +} + struct bch_data_ctx { struct thread_with_file thr; @@ -693,6 +725,8 @@ long bch2_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg) BCH_IOCTL(disk_offline, struct bch_ioctl_disk); case BCH_IOCTL_DISK_SET_STATE: BCH_IOCTL(disk_set_state, struct bch_ioctl_disk_set_state); + case BCH_IOCTL_DISK_SET_STATE_v2: + BCH_IOCTL(disk_set_state_v2, struct bch_ioctl_disk_set_state_v2); case BCH_IOCTL_DATA: BCH_IOCTL(data, struct bch_ioctl_data); case BCH_IOCTL_DISK_RESIZE: |