summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/bcachefs/bcachefs_ioctl.h15
-rw-r--r--fs/bcachefs/chardev.c34
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: