summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2023-12-20 00:08:29 -0500
committerKent Overstreet <kent.overstreet@linux.dev>2023-12-23 23:40:46 -0500
commitbe12f5651d3f5c1d1f256ccb2a8731adbbd0d1d8 (patch)
tree4b34aadcc04725852869bb088d646ed124200231
parentd78d34661415d81357c229a8628ed1fc8a2c5ba4 (diff)
bcachefs: Initial support for zones
- On zoned devices, bucket size must match zone size - Factor out bch2_bucket_discard(), which now also issues a zone reset on zoned devices. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/Kconfig1
-rw-r--r--fs/bcachefs/Makefile3
-rw-r--r--fs/bcachefs/alloc_background.c6
-rw-r--r--fs/bcachefs/bcachefs.h1
-rw-r--r--fs/bcachefs/journal_reclaim.c9
-rw-r--r--fs/bcachefs/super-io.c1
-rw-r--r--fs/bcachefs/super.c19
-rw-r--r--fs/bcachefs/zone.c55
-rw-r--r--fs/bcachefs/zone.h17
9 files changed, 98 insertions, 14 deletions
diff --git a/fs/bcachefs/Kconfig b/fs/bcachefs/Kconfig
index 5cdfef3b551a..368132e927d6 100644
--- a/fs/bcachefs/Kconfig
+++ b/fs/bcachefs/Kconfig
@@ -24,6 +24,7 @@ config BCACHEFS_FS
select XXHASH
select SRCU
select SYMBOLIC_ERRNAME
+ select BLK_DEV_ZONED
help
The bcachefs filesystem - a modern, copy on write filesystem, with
support for multiple devices, compression, checksumming, etc.
diff --git a/fs/bcachefs/Makefile b/fs/bcachefs/Makefile
index ed550a40463e..f0a0a1f9ed11 100644
--- a/fs/bcachefs/Makefile
+++ b/fs/bcachefs/Makefile
@@ -85,6 +85,7 @@ bcachefs-y := \
two_state_shared_lock.o \
util.o \
varint.o \
- xattr.o
+ xattr.o \
+ zone.o
obj-$(CONFIG_MEAN_AND_VARIANCE_UNIT_TEST) += mean_and_variance_test.o
diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c
index 1a127b0a08b3..9d3666b94b0c 100644
--- a/fs/bcachefs/alloc_background.c
+++ b/fs/bcachefs/alloc_background.c
@@ -20,6 +20,7 @@
#include "recovery.h"
#include "trace.h"
#include "varint.h"
+#include "zone.h"
#include <linux/kthread.h>
#include <linux/math64.h>
@@ -1631,10 +1632,7 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
* thread that removes items from the need_discard tree
*/
bch2_trans_unlock(trans);
- blkdev_issue_discard(ca->disk_sb.bdev,
- k.k->p.offset * ca->mi.bucket_size,
- ca->mi.bucket_size,
- GFP_KERNEL);
+ bch2_bucket_discard(ca, k.k->p.offset);
*discard_pos_done = iter.pos;
ret = bch2_trans_relock_notrace(trans);
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h
index bf8d69fbfdb3..afa86dd7ff1a 100644
--- a/fs/bcachefs/bcachefs.h
+++ b/fs/bcachefs/bcachefs.h
@@ -553,6 +553,7 @@ struct bch_dev {
struct bch_sb_handle disk_sb;
struct bch_sb *sb_read_scratch;
int sb_write_error;
+ bool zoned;
dev_t dev;
atomic_t flush_seq;
diff --git a/fs/bcachefs/journal_reclaim.c b/fs/bcachefs/journal_reclaim.c
index 820d25e19e5f..330490d50ced 100644
--- a/fs/bcachefs/journal_reclaim.c
+++ b/fs/bcachefs/journal_reclaim.c
@@ -13,6 +13,7 @@
#include "replicas.h"
#include "sb-members.h"
#include "trace.h"
+#include "zone.h"
#include <linux/kthread.h>
#include <linux/sched/mm.h>
@@ -266,13 +267,7 @@ void bch2_journal_do_discards(struct journal *j)
struct journal_device *ja = &ca->journal;
while (should_discard_bucket(j, ja)) {
- if (!c->opts.nochanges &&
- ca->mi.discard &&
- bdev_max_discard_sectors(ca->disk_sb.bdev))
- blkdev_issue_discard(ca->disk_sb.bdev,
- bucket_to_sector(ca,
- ja->buckets[ja->discard_idx]),
- ca->mi.bucket_size, GFP_NOFS);
+ bch2_bucket_discard(ca, ja->buckets[ja->discard_idx]);
spin_lock(&j->lock);
ja->discard_idx = (ja->discard_idx + 1) % ja->nr;
diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c
index 134f2c2faf86..270863663595 100644
--- a/fs/bcachefs/super-io.c
+++ b/fs/bcachefs/super-io.c
@@ -19,6 +19,7 @@
#include "super.h"
#include "trace.h"
#include "vstructs.h"
+#include "zone.h"
#include <linux/backing-dev.h>
#include <linux/sort.h>
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
index 0f189c9d56b5..f27b93d0f56b 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -57,6 +57,7 @@
#include "super-io.h"
#include "sysfs.h"
#include "trace.h"
+#include "zone.h"
#include <linux/backing-dev.h>
#include <linux/blkdev.h>
@@ -1313,7 +1314,9 @@ err:
static int __bch2_dev_attach_bdev(struct bch_dev *ca, struct bch_sb_handle *sb)
{
- unsigned ret;
+ int ret;
+
+ BUG_ON(!percpu_ref_is_zero(&ca->io_ref));
if (bch2_dev_is_online(ca)) {
bch_err(ca, "already have device online in slot %u",
@@ -1327,7 +1330,19 @@ static int __bch2_dev_attach_bdev(struct bch_dev *ca, struct bch_sb_handle *sb)
return -BCH_ERR_device_size_too_small;
}
- BUG_ON(!percpu_ref_is_zero(&ca->io_ref));
+ ca->zoned = bdev_nr_zones(sb->bdev) != 0;
+ if (ca->zoned) {
+ struct blk_zone zone;
+
+ ret = bch2_zone_report(sb->bdev, 0, &zone);
+ if (ret)
+ return ret;
+
+ if (zone.len != ca->mi.bucket_size) {
+ bch_err(ca, "zone size doesn't match bucket size");
+ return -EINVAL;
+ }
+ }
ret = bch2_dev_journal_init(ca, sb->sb);
if (ret)
diff --git a/fs/bcachefs/zone.c b/fs/bcachefs/zone.c
new file mode 100644
index 000000000000..b6ad8c9daaea
--- /dev/null
+++ b/fs/bcachefs/zone.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "bcachefs.h"
+#include "buckets.h"
+#include "zone.h"
+
+#include <linux/blkdev.h>
+
+static int zone_report_cb(struct blk_zone *src, unsigned int idx, void *data)
+{
+ struct blk_zone *dst = data;
+
+ *dst = *src;
+ return 0;
+}
+
+int bch2_zone_report(struct block_device *bdev, sector_t sector, struct blk_zone *zone)
+{
+ int ret = blkdev_report_zones(bdev, sector, 1, zone_report_cb, zone);
+
+ if (ret)
+ pr_err("error getting zone %u: %i", 0, ret);
+ return ret;
+}
+
+void bch2_bucket_discard(struct bch_dev *ca, u64 b)
+{
+ struct bch_fs *c = ca->fs;
+
+ if (c->opts.nochanges)
+ return;
+
+ if (ca->mi.discard &&
+ bdev_max_discard_sectors(ca->disk_sb.bdev))
+ blkdev_issue_discard(ca->disk_sb.bdev,
+ bucket_to_sector(ca, b),
+ ca->mi.bucket_size, GFP_NOFS);
+
+ if (ca->zoned)
+ blkdev_zone_mgmt(ca->disk_sb.bdev, REQ_OP_ZONE_RESET,
+ bucket_to_sector(ca, b),
+ ca->mi.bucket_size, GFP_NOFS);
+}
+
+void bch2_bucket_finish(struct bch_dev *ca, u64 b)
+{
+ struct bch_fs *c = ca->fs;
+
+ if (c->opts.nochanges || !ca->zoned)
+ return;
+
+ blkdev_zone_mgmt(ca->disk_sb.bdev, REQ_OP_ZONE_FINISH,
+ bucket_to_sector(ca, b),
+ ca->mi.bucket_size, GFP_KERNEL);
+}
diff --git a/fs/bcachefs/zone.h b/fs/bcachefs/zone.h
new file mode 100644
index 000000000000..aa3653bdb59b
--- /dev/null
+++ b/fs/bcachefs/zone.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _BCACHEFS_ZONE_H
+#define _BCACHEFS_ZONE_H
+
+static inline bool blk_zone_writeable(struct blk_zone zone)
+{
+ return (zone.cond == BLK_ZONE_COND_EMPTY ||
+ zone.cond == BLK_ZONE_COND_IMP_OPEN ||
+ zone.cond == BLK_ZONE_COND_EXP_OPEN ||
+ zone.cond == BLK_ZONE_COND_CLOSED);
+}
+
+int bch2_zone_report(struct block_device *, sector_t, struct blk_zone *);
+void bch2_bucket_discard(struct bch_dev *, u64);
+void bch2_bucket_finish(struct bch_dev *, u64);
+
+#endif /* _BCACHEFS_ZONE_H */