diff --git a/kmod/src/dir.c b/kmod/src/dir.c index 75420229..f380a5d8 100644 --- a/kmod/src/dir.c +++ b/kmod/src/dir.c @@ -31,6 +31,7 @@ #include "lock.h" #include "hash.h" #include "omap.h" +#include "forest.h" #include "counters.h" #include "scoutfs_trace.h" @@ -836,6 +837,7 @@ static int scoutfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, si->crtime = inode->i_mtime; inode_inc_iversion(dir); inode_inc_iversion(inode); + scoutfs_forest_inc_inode_count(sb); if (S_ISDIR(mode)) { inc_nlink(inode); @@ -1309,6 +1311,7 @@ static int scoutfs_symlink(struct inode *dir, struct dentry *dentry, si->crtime = inode->i_ctime; i_size_write(inode, name_len); inode_inc_iversion(inode); + scoutfs_forest_inc_inode_count(sb); scoutfs_update_inode_item(inode, inode_lock, &ind_locks); scoutfs_update_inode_item(dir, dir_lock, &ind_locks); @@ -1908,6 +1911,7 @@ static int scoutfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mod ihold(inode); /* need to update inode modifications in d_tmpfile */ d_tmpfile(dentry, inode); inode_inc_iversion(inode); + scoutfs_forest_inc_inode_count(sb); scoutfs_update_inode_item(inode, inode_lock, &ind_locks); scoutfs_update_inode_item(dir, dir_lock, &ind_locks); diff --git a/kmod/src/forest.c b/kmod/src/forest.c index 6890fbd7..1b4c9c4b 100644 --- a/kmod/src/forest.c +++ b/kmod/src/forest.c @@ -66,6 +66,8 @@ struct forest_info { struct workqueue_struct *workq; struct delayed_work log_merge_dwork; + + atomic64_t inode_count_delta; }; #define DECLARE_FOREST_INFO(sb, name) \ @@ -523,6 +525,62 @@ int scoutfs_forest_srch_add(struct super_block *sb, u64 hash, u64 ino, u64 id) return ret; } +void scoutfs_forest_inc_inode_count(struct super_block *sb) +{ + DECLARE_FOREST_INFO(sb, finf); + + atomic64_inc(&finf->inode_count_delta); +} + +void scoutfs_forest_dec_inode_count(struct super_block *sb) +{ + DECLARE_FOREST_INFO(sb, finf); + + atomic64_dec(&finf->inode_count_delta); +} + +/* + * Return the total inode count from the super block and all the + * log_btrees it references. This assumes it's working with a block + * reference hierarchy that should be fully consistent. If we see + * ESTALE we've hit persistent corruption. + */ +int scoutfs_forest_inode_count(struct super_block *sb, struct scoutfs_super_block *super, + u64 *inode_count) +{ + struct scoutfs_log_trees *lt; + SCOUTFS_BTREE_ITEM_REF(iref); + struct scoutfs_key key; + int ret; + + *inode_count = le64_to_cpu(super->inode_count); + + scoutfs_key_init_log_trees(&key, 0, 0); + for (;;) { + ret = scoutfs_btree_next(sb, &super->logs_root, &key, &iref); + if (ret == 0) { + if (iref.val_len == sizeof(*lt)) { + key = *iref.key; + scoutfs_key_inc(&key); + lt = iref.val; + *inode_count += le64_to_cpu(lt->inode_count_delta); + } else { + ret = -EIO; + } + scoutfs_btree_put_iref(&iref); + } + if (ret < 0) { + if (ret == -ENOENT) + ret = 0; + else if (ret == -ESTALE) + ret = -EIO; + break; + } + } + + return ret; +} + /* * This is called from transactions as a new transaction opens and is * serialized with all writers. @@ -551,6 +609,8 @@ void scoutfs_forest_init_btrees(struct super_block *sb, WARN_ON_ONCE(finf->srch_bl); /* commiting should have put the block */ finf->srch_bl = NULL; + atomic64_set(&finf->inode_count_delta, le64_to_cpu(lt->inode_count_delta)); + trace_scoutfs_forest_init_our_log(sb, le64_to_cpu(lt->rid), le64_to_cpu(lt->nr), le64_to_cpu(lt->item_root.ref.blkno), @@ -578,6 +638,8 @@ void scoutfs_forest_get_btrees(struct super_block *sb, scoutfs_block_put(sb, finf->srch_bl); finf->srch_bl = NULL; + lt->inode_count_delta = cpu_to_le64(atomic64_read(&finf->inode_count_delta)); + trace_scoutfs_forest_prepare_commit(sb, <->item_root.ref, <->bloom_ref); } diff --git a/kmod/src/forest.h b/kmod/src/forest.h index 8084731f..30564a11 100644 --- a/kmod/src/forest.h +++ b/kmod/src/forest.h @@ -33,6 +33,11 @@ int scoutfs_forest_insert_list(struct super_block *sb, struct scoutfs_btree_item_list *lst); int scoutfs_forest_srch_add(struct super_block *sb, u64 hash, u64 ino, u64 id); +void scoutfs_forest_inc_inode_count(struct super_block *sb); +void scoutfs_forest_dec_inode_count(struct super_block *sb); +int scoutfs_forest_inode_count(struct super_block *sb, struct scoutfs_super_block *super, + u64 *inode_count); + void scoutfs_forest_init_btrees(struct super_block *sb, struct scoutfs_alloc *alloc, struct scoutfs_block_writer *wri, diff --git a/kmod/src/format.h b/kmod/src/format.h index 3f20db33..825d7327 100644 --- a/kmod/src/format.h +++ b/kmod/src/format.h @@ -472,6 +472,7 @@ struct scoutfs_log_trees { struct scoutfs_srch_file srch_file; __le64 data_alloc_zone_blocks; __le64 data_alloc_zones[SCOUTFS_DATA_ALLOC_ZONE_LE64S]; + __le64 inode_count_delta; __le64 max_item_seq; __le64 finalize_seq; __le64 rid; @@ -795,6 +796,7 @@ struct scoutfs_super_block { __u8 uuid[SCOUTFS_UUID_BYTES]; __le64 seq; __le64 next_ino; + __le64 inode_count; __le64 total_meta_blocks; /* both static and dynamic */ __le64 total_data_blocks; struct scoutfs_quorum_config qconf; diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 6fb586f2..b4190dbf 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -34,6 +34,7 @@ #include "client.h" #include "cmp.h" #include "omap.h" +#include "forest.h" #include "btree.h" /* @@ -1578,6 +1579,8 @@ retry: goto out; ret = scoutfs_inode_orphan_delete(sb, ino, orph_lock); + if (ret == 0) + scoutfs_forest_dec_inode_count(sb); out: del_deleting_ino(inf, &del); if (release) diff --git a/kmod/src/server.c b/kmod/src/server.c index 2ca229a6..acb16cf4 100644 --- a/kmod/src/server.c +++ b/kmod/src/server.c @@ -938,6 +938,7 @@ static int finalize_and_start_log_merge(struct super_block *sb, struct scoutfs_l memset(<->item_root, 0, sizeof(lt->item_root)); memset(<->bloom_ref, 0, sizeof(lt->bloom_ref)); + lt->inode_count_delta = 0; lt->max_item_seq = 0; lt->finalize_seq = 0; le64_add_cpu(<->nr, 1); @@ -2010,6 +2011,9 @@ static int splice_log_merge_completions(struct super_block *sb, err_str = "deleting log trees item"; goto out; } + + le64_add_cpu(&super->inode_count, le64_to_cpu(lt.inode_count_delta)); + } init_log_merge_key(&key, SCOUTFS_LOG_MERGE_STATUS_ZONE, 0, 0); diff --git a/utils/src/mkfs.c b/utils/src/mkfs.c index cb8eb21e..b4d1f77e 100644 --- a/utils/src/mkfs.c +++ b/utils/src/mkfs.c @@ -216,6 +216,7 @@ static int do_mkfs(struct mkfs_args *args) super->fmt_vers = cpu_to_le64(args->fmt_vers); uuid_generate(super->uuid); super->next_ino = cpu_to_le64(round_up(SCOUTFS_ROOT_INO + 1, SCOUTFS_LOCK_INODE_GROUP_NR)); + super->inode_count = cpu_to_le64(1); super->seq = cpu_to_le64(1); super->total_meta_blocks = cpu_to_le64(last_meta + 1); super->total_data_blocks = cpu_to_le64(last_data + 1); diff --git a/utils/src/print.c b/utils/src/print.c index ba6195b8..8e5d4852 100644 --- a/utils/src/print.c +++ b/utils/src/print.c @@ -277,6 +277,7 @@ static int print_log_trees_item(struct scoutfs_key *key, u64 seq, u8 flags, void " data_avail: "ALCROOT_F"\n" " data_freed: "ALCROOT_F"\n" " srch_file: "SRF_FMT"\n" + " inode_count_delta: %lld\n" " max_item_seq: %llu\n" " finalize_seq: %llu\n" " rid: %016llx\n" @@ -294,6 +295,7 @@ static int print_log_trees_item(struct scoutfs_key *key, u64 seq, u8 flags, void ALCROOT_A(<->data_avail), ALCROOT_A(<->data_freed), SRF_A(<->srch_file), + le64_to_cpu(lt->inode_count_delta), le64_to_cpu(lt->max_item_seq), le64_to_cpu(lt->finalize_seq), le64_to_cpu(lt->rid), @@ -940,7 +942,7 @@ static void print_super_block(struct scoutfs_super_block *super, u64 blkno) printf(" flags: 0x%016llx\n", le64_to_cpu(super->flags)); /* XXX these are all in a crazy order */ - printf(" next_ino %llu seq %llu\n" + printf(" next_ino %llu inode_count %llu seq %llu\n" " total_meta_blocks %llu total_data_blocks %llu\n" " meta_alloc[0]: "ALCROOT_F"\n" " meta_alloc[1]: "ALCROOT_F"\n" @@ -956,6 +958,7 @@ static void print_super_block(struct scoutfs_super_block *super, u64 blkno) " mounted_clients: "BTR_FMT"\n" " srch_root: "BTR_FMT"\n", le64_to_cpu(super->next_ino), + le64_to_cpu(super->inode_count), le64_to_cpu(super->seq), le64_to_cpu(super->total_meta_blocks), le64_to_cpu(super->total_data_blocks),