diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bcachefs/bcachefs_ioctl.h | 15 | ||||
-rw-r--r-- | fs/bcachefs/bkey_buf.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/buckets.c | 2 | ||||
-rw-r--r-- | fs/bcachefs/chardev.c | 37 | ||||
-rw-r--r-- | fs/bcachefs/darray.c | 1 | ||||
-rw-r--r-- | fs/bcachefs/error.c | 12 | ||||
-rw-r--r-- | fs/bcachefs/journal_reclaim.c | 2 | ||||
-rw-r--r-- | fs/bcachefs/opts.c | 2 | ||||
-rw-r--r-- | fs/bcachefs/replicas.c | 14 | ||||
-rw-r--r-- | fs/bcachefs/replicas.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/sb-members.c | 4 | ||||
-rw-r--r-- | fs/bcachefs/super-io.c | 4 | ||||
-rw-r--r-- | fs/bcachefs/super.c | 40 | ||||
-rw-r--r-- | fs/bcachefs/super.h | 9 |
14 files changed, 105 insertions, 41 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/bkey_buf.h b/fs/bcachefs/bkey_buf.h index 0d0c76b013be..0a1fc582f53a 100644 --- a/fs/bcachefs/bkey_buf.h +++ b/fs/bcachefs/bkey_buf.h @@ -2,6 +2,8 @@ #ifndef _BCACHEFS_BKEY_BUF_H #define _BCACHEFS_BKEY_BUF_H +#include <linux/mempool.h> + #include "bcachefs.h" #include "bkey.h" diff --git a/fs/bcachefs/buckets.c b/fs/bcachefs/buckets.c index 87a6f4dce296..280b169efb62 100644 --- a/fs/bcachefs/buckets.c +++ b/fs/bcachefs/buckets.c @@ -111,7 +111,7 @@ static int bch2_check_fix_ptr(struct btree_trans *trans, CLASS(printbuf, buf)(); int ret = 0; - CLASS(bch2_dev_tryget, ca)(c, p.ptr.dev); + CLASS(bch2_dev_tryget_noerror, ca)(c, p.ptr.dev); if (!ca) { if (fsck_err_on(p.ptr.dev != BCH_SB_MEMBER_INVALID, trans, ptr_to_invalid_device, diff --git a/fs/bcachefs/chardev.c b/fs/bcachefs/chardev.c index 467fc45e84fe..3b8c1409bbf6 100644 --- a/fs/bcachefs/chardev.c +++ b/fs/bcachefs/chardev.c @@ -287,11 +287,44 @@ static long bch2_ioctl_disk_set_state(struct bch_fs *c, if (IS_ERR(ca)) return PTR_ERR(ca); - int ret = bch2_dev_set_state(c, ca, arg.new_state, arg.flags); + CLASS(printbuf, err)(); + int ret = bch2_dev_set_state(c, ca, arg.new_state, arg.flags, &err); bch_err_msg(ca, ret, "setting device state"); 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; @@ -692,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: diff --git a/fs/bcachefs/darray.c b/fs/bcachefs/darray.c index c06c81e842e4..6940037bd19e 100644 --- a/fs/bcachefs/darray.c +++ b/fs/bcachefs/darray.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/log2.h> +#include <linux/rcupdate.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include "darray.h" diff --git a/fs/bcachefs/error.c b/fs/bcachefs/error.c index 32a286b3a74e..e33f3166c48a 100644 --- a/fs/bcachefs/error.c +++ b/fs/bcachefs/error.c @@ -141,14 +141,16 @@ void bch2_io_error_work(struct work_struct *work) if (ca->mi.state >= BCH_MEMBER_STATE_ro) return; - bool dev = !__bch2_dev_set_state(c, ca, BCH_MEMBER_STATE_ro, - BCH_FORCE_IF_DEGRADED); CLASS(printbuf, buf)(); __bch2_log_msg_start(ca->name, &buf); - prt_printf(&buf, "writes erroring for %u seconds, setting %s ro", - c->opts.write_error_timeout, - dev ? "device" : "filesystem"); + prt_printf(&buf, "writes erroring for %u seconds\n", + c->opts.write_error_timeout); + + bool dev = !__bch2_dev_set_state(c, ca, BCH_MEMBER_STATE_ro, + BCH_FORCE_IF_DEGRADED, &buf); + + prt_printf(&buf, "setting %s ro", dev ? "device" : "filesystem"); if (!dev) bch2_fs_emergency_read_only2(c, &buf); diff --git a/fs/bcachefs/journal_reclaim.c b/fs/bcachefs/journal_reclaim.c index 6400a63ed79b..bd1885607d3e 100644 --- a/fs/bcachefs/journal_reclaim.c +++ b/fs/bcachefs/journal_reclaim.c @@ -148,7 +148,7 @@ static struct journal_space __journal_space_available(struct journal *j, unsigne BUG_ON(nr_devs_want > ARRAY_SIZE(dev_space)); - ssize_t mem_limit = max_t(ssize_t, 0, + size_t mem_limit = max_t(ssize_t, 0, (totalram_pages() * PAGE_SIZE) / 4 - j->dirty_entry_bytes); for_each_member_device_rcu(c, ca, &c->rw_devs[BCH_DATA_journal]) { diff --git a/fs/bcachefs/opts.c b/fs/bcachefs/opts.c index 921f9049912d..c3ef35dc01e2 100644 --- a/fs/bcachefs/opts.c +++ b/fs/bcachefs/opts.c @@ -525,7 +525,7 @@ int bch2_opt_hook_pre_set(struct bch_fs *c, struct bch_dev *ca, enum bch_opt_id switch (id) { case Opt_state: if (ca) - return bch2_dev_set_state(c, ca, v, BCH_FORCE_IF_DEGRADED); + return bch2_dev_set_state(c, ca, v, BCH_FORCE_IF_DEGRADED, NULL); break; case Opt_compression: diff --git a/fs/bcachefs/replicas.c b/fs/bcachefs/replicas.c index 0784283ce78c..3ffd68d2608d 100644 --- a/fs/bcachefs/replicas.c +++ b/fs/bcachefs/replicas.c @@ -784,7 +784,7 @@ const struct bch_sb_field_ops bch_sb_field_ops_replicas_v0 = { /* Query replicas: */ bool bch2_have_enough_devs(struct bch_fs *c, struct bch_devs_mask devs, - unsigned flags, bool print) + unsigned flags, struct printbuf *err) { struct bch_replicas_entry_v1 *e; @@ -823,16 +823,14 @@ bool bch2_have_enough_devs(struct bch_fs *c, struct bch_devs_mask devs, : BCH_FORCE_IF_DATA_DEGRADED; if (dflags & ~flags) { - if (print) { - CLASS(printbuf, buf)(); - - bch2_replicas_entry_to_text(&buf, e); - bch_err(c, "insufficient devices online (%u) for replicas entry %s", - nr_online, buf.buf); + if (err) { + prt_printf(err, "insufficient devices online (%u) for replicas entry ", + nr_online); + bch2_replicas_entry_to_text(err, e); + prt_newline(err); } return false; } - } return true; diff --git a/fs/bcachefs/replicas.h b/fs/bcachefs/replicas.h index 5aba2c1ce133..15023a9b0b1e 100644 --- a/fs/bcachefs/replicas.h +++ b/fs/bcachefs/replicas.h @@ -44,7 +44,7 @@ static inline void bch2_replicas_entry_cached(struct bch_replicas_entry_v1 *e, } bool bch2_have_enough_devs(struct bch_fs *, struct bch_devs_mask, - unsigned, bool); + unsigned, struct printbuf *); unsigned bch2_sb_dev_has_data(struct bch_sb *, unsigned); unsigned bch2_dev_has_data(struct bch_fs *, struct bch_dev *); diff --git a/fs/bcachefs/sb-members.c b/fs/bcachefs/sb-members.c index e3c73d903898..d26a0ca4a59d 100644 --- a/fs/bcachefs/sb-members.c +++ b/fs/bcachefs/sb-members.c @@ -36,10 +36,12 @@ int bch2_dev_missing_bkey(struct bch_fs *c, struct bkey_s_c k, unsigned dev) void bch2_dev_missing_atomic(struct bch_fs *c, unsigned dev) { - if (dev != BCH_SB_MEMBER_INVALID) + if (dev != BCH_SB_MEMBER_INVALID) { bch2_fs_inconsistent(c, "pointer to %s device %u", test_bit(dev, c->devs_removed.d) ? "removed" : "nonexistent", dev); + dump_stack(); + } } void bch2_dev_bucket_missing(struct bch_dev *ca, u64 bucket) diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c index 5897380c4c08..61eeac671283 100644 --- a/fs/bcachefs/super-io.c +++ b/fs/bcachefs/super-io.c @@ -1189,13 +1189,13 @@ int bch2_write_super(struct bch_fs *c) nr_wrote = dev_mask_nr(&sb_written); can_mount_with_written = - bch2_have_enough_devs(c, sb_written, degraded_flags, false); + bch2_have_enough_devs(c, sb_written, degraded_flags, NULL); for (unsigned i = 0; i < ARRAY_SIZE(sb_written.d); i++) sb_written.d[i] = ~sb_written.d[i]; can_mount_without_written = - bch2_have_enough_devs(c, sb_written, degraded_flags, false); + bch2_have_enough_devs(c, sb_written, degraded_flags, NULL); /* * If we would be able to mount _without_ the devices we successfully diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c index ee3b30b1c2b5..4281a20f7856 100644 --- a/fs/bcachefs/super.c +++ b/fs/bcachefs/super.c @@ -1368,10 +1368,14 @@ static bool bch2_fs_may_start(struct bch_fs *c) return false; } break; - } + } } - return bch2_have_enough_devs(c, c->online_devs, flags, true); + CLASS(printbuf, err)(); + bool ret = bch2_have_enough_devs(c, c->online_devs, flags, &err); + if (!ret) + bch2_print_str(c, KERN_ERR, err.buf); + return ret; } int bch2_fs_start(struct bch_fs *c) @@ -1833,7 +1837,8 @@ static int bch2_dev_attach_bdev(struct bch_fs *c, struct bch_sb_handle *sb) * because we got an error or what have you? */ bool bch2_dev_state_allowed(struct bch_fs *c, struct bch_dev *ca, - enum bch_member_state new_state, int flags) + enum bch_member_state new_state, int flags, + struct printbuf *err) { struct bch_devs_mask new_online_devs; int nr_rw = 0, required; @@ -1870,7 +1875,7 @@ bool bch2_dev_state_allowed(struct bch_fs *c, struct bch_dev *ca, new_online_devs = c->online_devs; __clear_bit(ca->dev_idx, new_online_devs.d); - return bch2_have_enough_devs(c, new_online_devs, flags, false); + return bch2_have_enough_devs(c, new_online_devs, flags, err); default: BUG(); } @@ -1904,14 +1909,15 @@ static void __bch2_dev_read_write(struct bch_fs *c, struct bch_dev *ca) } int __bch2_dev_set_state(struct bch_fs *c, struct bch_dev *ca, - enum bch_member_state new_state, int flags) + enum bch_member_state new_state, int flags, + struct printbuf *err) { int ret = 0; if (ca->mi.state == new_state) return 0; - if (!bch2_dev_state_allowed(c, ca, new_state, flags)) + if (!bch2_dev_state_allowed(c, ca, new_state, flags, err)) return bch_err_throw(c, device_state_not_allowed); if (new_state != BCH_MEMBER_STATE_rw) @@ -1934,10 +1940,11 @@ int __bch2_dev_set_state(struct bch_fs *c, struct bch_dev *ca, } int bch2_dev_set_state(struct bch_fs *c, struct bch_dev *ca, - enum bch_member_state new_state, int flags) + enum bch_member_state new_state, int flags, + struct printbuf *err) { guard(rwsem_write)(&c->state_lock); - return __bch2_dev_set_state(c, ca, new_state, flags); + return __bch2_dev_set_state(c, ca, new_state, flags, err); } /* Device add/removal: */ @@ -1957,7 +1964,7 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags) */ bch2_dev_put(ca); - if (!bch2_dev_state_allowed(c, ca, BCH_MEMBER_STATE_failed, flags)) { + if (!bch2_dev_state_allowed(c, ca, BCH_MEMBER_STATE_failed, flags, NULL)) { bch_err(ca, "Cannot remove without losing data"); ret = bch_err_throw(c, device_state_not_allowed); goto err; @@ -2278,7 +2285,7 @@ int bch2_dev_offline(struct bch_fs *c, struct bch_dev *ca, int flags) return 0; } - if (!bch2_dev_state_allowed(c, ca, BCH_MEMBER_STATE_failed, flags)) { + if (!bch2_dev_state_allowed(c, ca, BCH_MEMBER_STATE_failed, flags, NULL)) { bch_err(ca, "Cannot offline required disk"); return bch_err_throw(c, device_state_not_allowed); } @@ -2455,10 +2462,14 @@ static void bch2_fs_bdev_mark_dead(struct block_device *bdev, bool surprise) struct bch_dev *ca = bdev_to_bch_dev(c, bdev); if (ca) { + CLASS(printbuf, buf)(); + __bch2_log_msg_start(ca->name, &buf); + prt_printf(&buf, "offline from block layer\n"); + bool dev = bch2_dev_state_allowed(c, ca, BCH_MEMBER_STATE_failed, - BCH_FORCE_IF_DEGRADED); - + BCH_FORCE_IF_DEGRADED, + &buf); if (!dev && sb) { if (!surprise) sync_filesystem(sb); @@ -2466,11 +2477,6 @@ static void bch2_fs_bdev_mark_dead(struct block_device *bdev, bool surprise) evict_inodes(sb); } - CLASS(printbuf, buf)(); - __bch2_log_msg_start(ca->name, &buf); - - prt_printf(&buf, "offline from block layer"); - if (dev) { __bch2_dev_offline(c, ca); } else { diff --git a/fs/bcachefs/super.h b/fs/bcachefs/super.h index e90bab9afe78..de2c4430b8f7 100644 --- a/fs/bcachefs/super.h +++ b/fs/bcachefs/super.h @@ -17,11 +17,14 @@ struct bch_fs *bch2_dev_to_fs(dev_t); struct bch_fs *bch2_uuid_to_fs(__uuid_t); bool bch2_dev_state_allowed(struct bch_fs *, struct bch_dev *, - enum bch_member_state, int); + enum bch_member_state, int, + struct printbuf *); int __bch2_dev_set_state(struct bch_fs *, struct bch_dev *, - enum bch_member_state, int); + enum bch_member_state, int, + struct printbuf *); int bch2_dev_set_state(struct bch_fs *, struct bch_dev *, - enum bch_member_state, int); + enum bch_member_state, int, + struct printbuf *); int bch2_dev_fail(struct bch_dev *, int); int bch2_dev_remove(struct bch_fs *, struct bch_dev *, int); |