From fb66372988d6ee160fe5ea7087e8c8e866bf8685 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Mon, 12 Oct 2020 10:46:16 -0700 Subject: [PATCH] scoutfs: add alloc foreach cb iterator Add an alloc call which reads all the persistent allocators and calls a callback for each. This is going to be used to calculate free blocks in clients for df, and in an ioctl to give a more detailed view of allocators. Signed-off-by: Zach Brown --- kmod/src/alloc.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++ kmod/src/alloc.h | 6 ++ kmod/src/format.h | 6 ++ 3 files changed, 149 insertions(+) diff --git a/kmod/src/alloc.c b/kmod/src/alloc.c index ca088c89..a7298e1e 100644 --- a/kmod/src/alloc.c +++ b/kmod/src/alloc.c @@ -1110,3 +1110,140 @@ bool scoutfs_alloc_meta_lo_thresh(struct super_block *sb, return lo; } + +/* + * Call the callers callback for every persistent allocator structure + * we can find. + */ +int scoutfs_alloc_foreach(struct super_block *sb, + scoutfs_alloc_foreach_cb_t cb, void *arg) +{ + struct scoutfs_btree_ref stale_refs[2] = {{0,}}; + struct scoutfs_btree_ref refs[2] = {{0,}}; + struct scoutfs_super_block *super = NULL; + struct scoutfs_srch_compact_input *scin; + struct scoutfs_log_trees_val ltv; + SCOUTFS_BTREE_ITEM_REF(iref); + struct scoutfs_key key; + int ret; + + super = kmalloc(sizeof(struct scoutfs_super_block), GFP_NOFS); + scin = kmalloc(sizeof(struct scoutfs_srch_compact_input), GFP_NOFS); + if (!super || !scin) { + ret = -ENOMEM; + goto out; + } + +retry: + ret = scoutfs_read_super(sb, super); + if (ret < 0) + goto out; + + refs[0] = super->logs_root.ref; + refs[1] = super->srch_root.ref; + + /* all the server allocators */ + ret = cb(sb, arg, SCOUTFS_ALLOC_OWNER_SERVER, 0, true, true, + le64_to_cpu(super->meta_alloc[0].total_len)) ?: + cb(sb, arg, SCOUTFS_ALLOC_OWNER_SERVER, 0, true, true, + le64_to_cpu(super->meta_alloc[1].total_len)) ?: + cb(sb, arg, SCOUTFS_ALLOC_OWNER_SERVER, 0, false, true, + le64_to_cpu(super->data_alloc.total_len)) ?: + cb(sb, arg, SCOUTFS_ALLOC_OWNER_SERVER, 1, true, true, + le64_to_cpu(super->server_meta_avail[0].total_nr)) ?: + cb(sb, arg, SCOUTFS_ALLOC_OWNER_SERVER, 1, true, true, + le64_to_cpu(super->server_meta_avail[1].total_nr)) ?: + cb(sb, arg, SCOUTFS_ALLOC_OWNER_SERVER, 1, true, false, + le64_to_cpu(super->server_meta_freed[0].total_nr)) ?: + cb(sb, arg, SCOUTFS_ALLOC_OWNER_SERVER, 1, true, false, + le64_to_cpu(super->server_meta_freed[1].total_nr)); + if (ret < 0) + goto out; + + /* mount fs transaction allocators */ + scoutfs_key_init_log_trees(&key, 0, 0); + for (;;) { + ret = scoutfs_btree_next(sb, &super->logs_root, &key, &iref); + if (ret == -ENOENT) + break; + if (ret < 0) + goto out; + + if (iref.val_len == sizeof(ltv)) { + key = *iref.key; + memcpy(<v, iref.val, sizeof(ltv)); + } else { + ret = -EIO; + } + scoutfs_btree_put_iref(&iref); + if (ret < 0) + goto out; + + ret = cb(sb, arg, SCOUTFS_ALLOC_OWNER_MOUNT, + le64_to_cpu(key.sklt_rid), true, true, + le64_to_cpu(ltv.meta_avail.total_nr)) ?: + cb(sb, arg, SCOUTFS_ALLOC_OWNER_MOUNT, + le64_to_cpu(key.sklt_rid), true, false, + le64_to_cpu(ltv.meta_freed.total_nr)) ?: + cb(sb, arg, SCOUTFS_ALLOC_OWNER_MOUNT, + le64_to_cpu(key.sklt_rid), false, true, + le64_to_cpu(ltv.data_avail.total_len)) ?: + cb(sb, arg, SCOUTFS_ALLOC_OWNER_MOUNT, + le64_to_cpu(key.sklt_rid), false, false, + le64_to_cpu(ltv.data_freed.total_len)); + if (ret < 0) + goto out; + + scoutfs_key_inc(&key); + } + + /* srch compaction allocators */ + memset(&key, 0, sizeof(key)); + key.sk_zone = SCOUTFS_SRCH_ZONE; + key.sk_type = SCOUTFS_SRCH_BUSY_TYPE; + + for (;;) { + /* _BUSY_ is last type, _next won't see other types */ + ret = scoutfs_btree_next(sb, &super->srch_root, &key, &iref); + if (ret == -ENOENT) + break; + if (ret == 0) { + if (iref.val_len == sizeof(scin)) { + key = *iref.key; + memcpy(scin, iref.val, iref.val_len); + } else { + ret = -EIO; + } + scoutfs_btree_put_iref(&iref); + } + if (ret < 0) + goto out; + + ret = cb(sb, arg, SCOUTFS_ALLOC_OWNER_SRCH, + le64_to_cpu(scin->id), true, true, + le64_to_cpu(scin->meta_avail.total_nr)) ?: + cb(sb, arg, SCOUTFS_ALLOC_OWNER_SRCH, + le64_to_cpu(scin->id), true, false, + le64_to_cpu(scin->meta_freed.total_nr)); + if (ret < 0) + goto out; + + scoutfs_key_inc(&key); + } + + ret = 0; +out: + if (ret == -ESTALE) { + if (memcmp(&stale_refs, &refs, sizeof(refs)) == 0) { + ret = -EIO; + } else { + BUILD_BUG_ON(sizeof(stale_refs) != sizeof(refs)); + memcpy(stale_refs, refs, sizeof(stale_refs)); + goto retry; + } + } + + kfree(super); + kfree(scin); + return ret; +} diff --git a/kmod/src/alloc.h b/kmod/src/alloc.h index 7b053756..d2cc1f58 100644 --- a/kmod/src/alloc.h +++ b/kmod/src/alloc.h @@ -122,4 +122,10 @@ int scoutfs_alloc_splice_list(struct super_block *sb, bool scoutfs_alloc_meta_lo_thresh(struct super_block *sb, struct scoutfs_alloc *alloc); +typedef int (*scoutfs_alloc_foreach_cb_t)(struct super_block *sb, void *arg, + int owner, u64 id, + bool meta, bool avail, u64 blocks); +int scoutfs_alloc_foreach(struct super_block *sb, + scoutfs_alloc_foreach_cb_t cb, void *arg); + #endif diff --git a/kmod/src/format.h b/kmod/src/format.h index 428c94e6..2bc0d010 100644 --- a/kmod/src/format.h +++ b/kmod/src/format.h @@ -297,6 +297,12 @@ struct scoutfs_alloc_root { struct scoutfs_btree_root root; }__packed; +/* types of allocators, exposed to alloc_detail ioctl */ +#define SCOUTFS_ALLOC_OWNER_NONE 0 +#define SCOUTFS_ALLOC_OWNER_SERVER 1 +#define SCOUTFS_ALLOC_OWNER_MOUNT 2 +#define SCOUTFS_ALLOC_OWNER_SRCH 3 + struct scoutfs_mounted_client_btree_val { __u8 flags; } __packed;