diff --git a/kmod/src/data.c b/kmod/src/data.c index bf56c45b..bae06b3c 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -603,9 +603,13 @@ out: * This is the low level extent item manipulation code. We hold and * release the transaction so the caller doesn't have to deal with * partial progress. + * + * If the inode is provided then we update its tracking of the online + * and offline blocks. If it's not provided then the inode is being + * destroyed and we don't have to keep it updated. */ -int scoutfs_data_truncate_items(struct super_block *sb, u64 ino, u64 iblock, - u64 last, bool offline, +int scoutfs_data_truncate_items(struct super_block *sb, struct inode *inode, + u64 ino, u64 iblock, u64 last, bool offline, struct scoutfs_lock *lock) { struct scoutfs_key_buf last_key; @@ -687,12 +691,17 @@ int scoutfs_data_truncate_items(struct super_block *sb, u64 ino, u64 iblock, break; map->blknos[i] = 0; + scoutfs_inode_add_online_blocks(inode, -1); } - if (offline && !test_bit(i, map->offline)) + if (offline && !test_bit(i, map->offline)) { set_bit(i, map->offline); - else if (!offline && test_bit(i, map->offline)) + scoutfs_inode_add_offline_blocks(inode, 1); + + } else if (!offline && test_bit(i, map->offline)) { clear_bit(i, map->offline); + scoutfs_inode_add_offline_blocks(inode, -1); + } modified = true; } @@ -905,7 +914,8 @@ out: * a new segment. Lots of concurrent allocations can interleave at * segment granularity. */ -static int find_alloc_block(struct super_block *sb, struct block_mapping *map, +static int find_alloc_block(struct super_block *sb, struct inode *inode, + struct block_mapping *map, struct scoutfs_key_buf *map_key, unsigned map_ind, bool map_exists, struct scoutfs_lock *data_lock) @@ -973,8 +983,10 @@ static int find_alloc_block(struct super_block *sb, struct block_mapping *map, goto out; /* update the mapping */ - clear_bit(map_ind, map->offline); + if (test_and_clear_bit(map_ind, map->offline)) + scoutfs_inode_add_offline_blocks(inode, -1); map->blknos[map_ind] = blkno; + scoutfs_inode_add_online_blocks(inode, 1); bytes = encode_mapping(map); scoutfs_kvec_init(val, map->encoded, bytes); @@ -1049,7 +1061,7 @@ static int scoutfs_get_block(struct inode *inode, sector_t iblock, * and try again if we've already done a bulk alloc in * our transaction. */ - ret = find_alloc_block(sb, map, &key, ind, exists, lock); + ret = find_alloc_block(sb, inode, map, &key, ind, exists, lock); if (ret) goto out; set_buffer_new(bh); diff --git a/kmod/src/data.h b/kmod/src/data.h index a305ad2e..e8157065 100644 --- a/kmod/src/data.h +++ b/kmod/src/data.h @@ -4,8 +4,8 @@ extern const struct address_space_operations scoutfs_file_aops; extern const struct file_operations scoutfs_file_fops; -int scoutfs_data_truncate_items(struct super_block *sb, u64 ino, u64 iblock, - u64 last, bool offline, +int scoutfs_data_truncate_items(struct super_block *sb, struct inode *inode, + u64 ino, u64 iblock, u64 last, bool offline, struct scoutfs_lock *lock); int scoutfs_data_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len); diff --git a/kmod/src/format.h b/kmod/src/format.h index 90d1d4c7..bb8d674a 100644 --- a/kmod/src/format.h +++ b/kmod/src/format.h @@ -449,6 +449,12 @@ struct scoutfs_timespec { * have changed. It is exposed via an ioctl and is then provided as an * argument to data functions to protect racing modification. * + * @online_blocks: The number of fixed 4k blocks currently allocated and + * storing data in the volume. + * + * @offline_blocks: The number of fixed 4k blocks that could be made + * online by staging. + * * XXX * - otime? * - compat flags? @@ -462,6 +468,8 @@ struct scoutfs_inode { __le64 meta_seq; __le64 data_seq; __le64 data_version; + __le64 online_blocks; + __le64 offline_blocks; __le64 next_readdir_pos; __le32 nlink; __le32 uid; diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 7207466e..2146ed9c 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -231,6 +231,8 @@ static void load_inode(struct inode *inode, struct scoutfs_inode *cinode) ci->meta_seq = le64_to_cpu(cinode->meta_seq); ci->data_seq = le64_to_cpu(cinode->data_seq); ci->data_version = le64_to_cpu(cinode->data_version); + ci->online_blocks = le64_to_cpu(cinode->online_blocks); + ci->offline_blocks = le64_to_cpu(cinode->offline_blocks); ci->next_readdir_pos = le64_to_cpu(cinode->next_readdir_pos); ci->flags = le32_to_cpu(cinode->flags); @@ -380,8 +382,9 @@ int scoutfs_complete_truncate(struct inode *inode, struct scoutfs_lock *lock) return 0; start = (i_size_read(inode) + SCOUTFS_BLOCK_SIZE - 1) >> SCOUTFS_BLOCK_SHIFT; - ret = scoutfs_data_truncate_items(inode->i_sb, scoutfs_ino(inode), - start, ~0ULL, false, lock); + ret = scoutfs_data_truncate_items(inode->i_sb, inode, + scoutfs_ino(inode), start, ~0ULL, + false, lock); err = clear_truncate_flag(inode, lock); return ret ? ret : err; @@ -493,6 +496,35 @@ void scoutfs_inode_inc_data_version(struct inode *inode) preempt_enable(); } +static void add_seq_value(struct scoutfs_inode_info *si, u64 *si_u64, u64 val) +{ + preempt_disable(); + write_seqcount_begin(&si->seqcount); + *si_u64 += val; + write_seqcount_end(&si->seqcount); + preempt_enable(); +} + +void scoutfs_inode_add_online_blocks(struct inode *inode, u64 val) +{ + struct scoutfs_inode_info *si; + + if (inode) { + si = SCOUTFS_I(inode); + add_seq_value(si, &SCOUTFS_I(inode)->online_blocks, val); + } +} + +void scoutfs_inode_add_offline_blocks(struct inode *inode, u64 val) +{ + struct scoutfs_inode_info *si; + + if (inode) { + si = SCOUTFS_I(inode); + add_seq_value(si, &SCOUTFS_I(inode)->offline_blocks, val); + } +} + static u64 read_seqcount_u64(struct inode *inode, u64 *val) { struct scoutfs_inode_info *si = SCOUTFS_I(inode); @@ -528,6 +560,19 @@ u64 scoutfs_inode_data_version(struct inode *inode) return read_seqcount_u64(inode, &si->data_version); } +u64 scoutfs_inode_online_blocks(struct inode *inode) +{ + struct scoutfs_inode_info *si = SCOUTFS_I(inode); + + return read_seqcount_u64(inode, &si->online_blocks); +} + +u64 scoutfs_inode_offline_blocks(struct inode *inode) +{ + struct scoutfs_inode_info *si = SCOUTFS_I(inode); + + return read_seqcount_u64(inode, &si->offline_blocks); +} static int scoutfs_iget_test(struct inode *inode, void *arg) { struct scoutfs_inode_info *ci = SCOUTFS_I(inode); @@ -612,6 +657,9 @@ static void store_inode(struct scoutfs_inode *cinode, struct inode *inode) cinode->meta_seq = cpu_to_le64(scoutfs_inode_meta_seq(inode)); cinode->data_seq = cpu_to_le64(scoutfs_inode_data_seq(inode)); cinode->data_version = cpu_to_le64(scoutfs_inode_data_version(inode)); + cinode->online_blocks = cpu_to_le64(scoutfs_inode_online_blocks(inode)); + cinode->offline_blocks = + cpu_to_le64(scoutfs_inode_offline_blocks(inode)); cinode->next_readdir_pos = cpu_to_le64(ci->next_readdir_pos); cinode->flags = cpu_to_le32(ci->flags); } @@ -1270,6 +1318,8 @@ struct inode *scoutfs_new_inode(struct super_block *sb, struct inode *dir, ci = SCOUTFS_I(inode); ci->ino = ino; ci->data_version = 0; + ci->online_blocks = 0; + ci->offline_blocks = 0; ci->next_readdir_pos = SCOUTFS_DIRENT_FIRST_POS; ci->have_item = false; atomic64_set(&ci->last_refreshed, lock->refresh_gen); diff --git a/kmod/src/inode.h b/kmod/src/inode.h index 532bb21a..0bc95a4c 100644 --- a/kmod/src/inode.h +++ b/kmod/src/inode.h @@ -21,6 +21,8 @@ struct scoutfs_inode_info { u64 meta_seq; u64 data_seq; u64 data_version; + u64 online_blocks; + u64 offline_blocks; u32 flags; /* @@ -97,9 +99,13 @@ struct inode *scoutfs_new_inode(struct super_block *sb, struct inode *dir, void scoutfs_inode_set_meta_seq(struct inode *inode); void scoutfs_inode_set_data_seq(struct inode *inode); void scoutfs_inode_inc_data_version(struct inode *inode); +void scoutfs_inode_add_online_blocks(struct inode *inode, u64 val); +void scoutfs_inode_add_offline_blocks(struct inode *inode, u64 val); u64 scoutfs_inode_meta_seq(struct inode *inode); u64 scoutfs_inode_data_seq(struct inode *inode); u64 scoutfs_inode_data_version(struct inode *inode); +u64 scoutfs_inode_online_blocks(struct inode *inode); +u64 scoutfs_inode_offline_blocks(struct inode *inode); int scoutfs_complete_truncate(struct inode *inode, struct scoutfs_lock *lock); int scoutfs_inode_refresh(struct inode *inode, struct scoutfs_lock *lock, diff --git a/kmod/src/ioctl.c b/kmod/src/ioctl.c index cb86dfa4..57faec81 100644 --- a/kmod/src/ioctl.c +++ b/kmod/src/ioctl.c @@ -378,7 +378,8 @@ static long scoutfs_ioc_release(struct file *file, unsigned long arg) end_inc = ((args.block + args.count) << SCOUTFS_BLOCK_SHIFT) - 1; truncate_inode_pages_range(&inode->i_data, start, end_inc); - ret = scoutfs_data_truncate_items(sb, scoutfs_ino(inode), args.block, + ret = scoutfs_data_truncate_items(sb, inode, scoutfs_ino(inode), + args.block, args.block + args.count - 1, true, lock); out: @@ -522,6 +523,8 @@ static long scoutfs_ioc_stat_more(struct file *file, unsigned long arg) stm.meta_seq = scoutfs_inode_meta_seq(inode); stm.data_seq = scoutfs_inode_data_seq(inode); stm.data_version = scoutfs_inode_data_version(inode); + stm.online_blocks = scoutfs_inode_online_blocks(inode); + stm.offline_blocks = scoutfs_inode_offline_blocks(inode); if (copy_to_user((void __user *)arg, &stm, stm.valid_bytes)) return -EFAULT; diff --git a/kmod/src/ioctl.h b/kmod/src/ioctl.h index 34917a34..33c94b95 100644 --- a/kmod/src/ioctl.h +++ b/kmod/src/ioctl.h @@ -178,6 +178,8 @@ struct scoutfs_ioctl_stat_more { __u64 meta_seq; __u64 data_seq; __u64 data_version; + __u64 online_blocks; + __u64 offline_blocks; } __packed; #define SCOUTFS_IOC_STAT_MORE _IOW(SCOUTFS_IOCTL_MAGIC, 7, \