From dab0fd7d9a2aae70fcfb11e993e76d4150f5d5f2 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 12 Jun 2018 14:05:34 -0700 Subject: [PATCH] scoutfs: update inode item after releasing The release ioctl forgot to update the inode item after truncating online block mappings. This meant that the offline block count update was lost when the inode was evicted and re-read, leading to inconsistent offline block counts. Signed-off-by: Zach Brown --- kmod/src/count.h | 6 +++++- kmod/src/data.c | 34 ++++++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/kmod/src/count.h b/kmod/src/count.h index 95aed312..ae0c98ec 100644 --- a/kmod/src/count.h +++ b/kmod/src/count.h @@ -231,12 +231,16 @@ static inline const struct scoutfs_item_count SIC_WRITE_BEGIN(void) * - delete two existing free extents * - create a merged free extent */ -static inline const struct scoutfs_item_count SIC_TRUNC_EXTENT(void) +static inline const struct scoutfs_item_count +SIC_TRUNC_EXTENT(struct inode *inode) { struct scoutfs_item_count cnt = {0,}; unsigned int nr_file = 1 + 2 + 1; unsigned int nr_free = (2 + 1) * 2; + if (inode) + __count_dirty_inode(&cnt); + cnt.items += nr_file + nr_free; cnt.vals += nr_file * sizeof(struct scoutfs_file_extent); diff --git a/kmod/src/data.c b/kmod/src/data.c index 478746a6..83c3bee8 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -325,19 +325,22 @@ out: * left behind. Only blocks that have been allocated can be marked * offline. * - * 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. + * destroyed and isn't reachable, we don't need to update it. + * + * The caller is in charge of locking the inode and extents, but we may + * have to modify far more items than fit in a transaction so we're in + * charge of batching updates into transactions. If the inode is + * provided then we're responsible for updating its item as we go. */ 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_item_count cnt = SIC_TRUNC_EXTENT(inode); DECLARE_DATA_INFO(sb, datinf); + LIST_HEAD(ind_locks); s64 ret = 0; WARN_ON_ONCE(inode && !mutex_is_locked(&inode->i_mutex)); @@ -352,15 +355,30 @@ int scoutfs_data_truncate_items(struct super_block *sb, struct inode *inode, return -EINVAL; while (iblock <= last) { - ret = scoutfs_hold_trans(sb, SIC_TRUNC_EXTENT()); + if (inode) + ret = scoutfs_inode_index_lock_hold(inode, &ind_locks, + true, cnt); + else + ret = scoutfs_hold_trans(sb, cnt); if (ret) break; + if (inode) + ret = scoutfs_dirty_inode_item(inode, lock); + else + ret = 0; + down_write(&datinf->alloc_rwsem); - ret = truncate_one_extent(sb, inode, ino, iblock, last, - offline, lock); + if (ret == 0) + ret = truncate_one_extent(sb, inode, ino, iblock, last, + offline, lock); up_write(&datinf->alloc_rwsem); + + if (inode) + scoutfs_update_inode_item(inode, lock, &ind_locks); scoutfs_release_trans(sb); + if (inode) + scoutfs_inode_index_unlock(sb, &ind_locks); if (ret <= 0) break;