From 8e067b3d3feee562fe590bfc87206609f691efaa Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 6 Dec 2022 10:22:49 -0800 Subject: [PATCH] Truncate dirties zero tail extension When we truncate away from a partial block we need to zero its tail that was past i_size and dirty it so that it's written. We missed the typical vfs boilerplate of calling block_truncate_page from setattr->set_size that does this. We need to be a little careful to pass our file lock down to get_block and then queue the inode for writeback so its written out with the transaction. This follows the pattern in .write_end. Signed-off-by: Zach Brown --- kmod/src/data.c | 4 ++-- kmod/src/data.h | 3 +++ kmod/src/inode.c | 10 ++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/kmod/src/data.c b/kmod/src/data.c index 402e50b6..a9ee3689 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -631,8 +631,8 @@ static int scoutfs_get_block_read(struct inode *inode, sector_t iblock, return ret; } -static int scoutfs_get_block_write(struct inode *inode, sector_t iblock, - struct buffer_head *bh, int create) +int scoutfs_get_block_write(struct inode *inode, sector_t iblock, struct buffer_head *bh, + int create) { struct scoutfs_inode_info *si = SCOUTFS_I(inode); int ret; diff --git a/kmod/src/data.h b/kmod/src/data.h index c056915e..a34854eb 100644 --- a/kmod/src/data.h +++ b/kmod/src/data.h @@ -43,6 +43,9 @@ extern const struct file_operations scoutfs_file_fops; struct scoutfs_alloc; struct scoutfs_block_writer; +int scoutfs_get_block_write(struct inode *inode, sector_t iblock, struct buffer_head *bh, + int create); + int scoutfs_data_truncate_items(struct super_block *sb, struct inode *inode, u64 ino, u64 iblock, u64 last, bool offline, struct scoutfs_lock *lock); diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 6951a3de..6741bda7 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "format.h" #include "super.h" @@ -361,6 +362,7 @@ static int set_inode_size(struct inode *inode, struct scoutfs_lock *lock, { struct scoutfs_inode_info *si = SCOUTFS_I(inode); struct super_block *sb = inode->i_sb; + SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent); LIST_HEAD(ind_locks); int ret; @@ -371,6 +373,13 @@ static int set_inode_size(struct inode *inode, struct scoutfs_lock *lock, if (ret) return ret; + scoutfs_per_task_add(&si->pt_data_lock, &pt_ent, lock); + ret = block_truncate_page(inode->i_mapping, new_size, scoutfs_get_block_write); + scoutfs_per_task_del(&si->pt_data_lock, &pt_ent); + if (ret < 0) + goto unlock; + scoutfs_inode_queue_writeback(inode); + if (new_size != i_size_read(inode)) scoutfs_inode_inc_data_version(inode); @@ -382,6 +391,7 @@ static int set_inode_size(struct inode *inode, struct scoutfs_lock *lock, inode_inc_iversion(inode); scoutfs_update_inode_item(inode, lock, &ind_locks); +unlock: scoutfs_release_trans(sb); scoutfs_inode_index_unlock(sb, &ind_locks);