summaryrefslogtreecommitdiff
path: root/fs/udf
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2023-01-19 12:46:09 +0100
committerJan Kara <jack@suse.cz>2023-01-26 16:46:35 +0100
commitb9a861fd527ab123e76effb492b4eb7e8115d4ca (patch)
treef51dab17dc5495d57f675b37a7dbd6a131d2daf4 /fs/udf
parent96eeaaaea592079fcbf0b18a2b6f99165b32c942 (diff)
downloadlwn-b9a861fd527ab123e76effb492b4eb7e8115d4ca.tar.gz
lwn-b9a861fd527ab123e76effb492b4eb7e8115d4ca.zip
udf: Protect truncate and file type conversion with invalidate_lock
Protect truncate and file type conversion in udf_file_write_iter() with invalidate lock. That will allow us to serialize these paths with page faults so that the page fault can determine the file type in a racefree way. Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/udf')
-rw-r--r--fs/udf/file.c2
-rw-r--r--fs/udf/inode.c15
2 files changed, 11 insertions, 6 deletions
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 596d703fb6c8..cf050bdffd9e 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -150,7 +150,9 @@ static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
iocb->ki_pos + iov_iter_count(from))) {
+ filemap_invalidate_lock(inode->i_mapping);
retval = udf_expand_file_adinicb(inode);
+ filemap_invalidate_unlock(inode->i_mapping);
if (retval)
goto out;
}
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index b4e4aacdaabc..f57ef7d0a207 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1145,7 +1145,7 @@ struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block,
int udf_setsize(struct inode *inode, loff_t newsize)
{
- int err;
+ int err = 0;
struct udf_inode_info *iinfo;
unsigned int bsize = i_blocksize(inode);
@@ -1155,6 +1155,7 @@ int udf_setsize(struct inode *inode, loff_t newsize)
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return -EPERM;
+ filemap_invalidate_lock(inode->i_mapping);
iinfo = UDF_I(inode);
if (newsize > inode->i_size) {
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
@@ -1167,11 +1168,11 @@ int udf_setsize(struct inode *inode, loff_t newsize)
}
err = udf_expand_file_adinicb(inode);
if (err)
- return err;
+ goto out_unlock;
}
err = udf_extend_file(inode, newsize);
if (err)
- return err;
+ goto out_unlock;
set_size:
truncate_setsize(inode, newsize);
} else {
@@ -1189,14 +1190,14 @@ set_size:
err = block_truncate_page(inode->i_mapping, newsize,
udf_get_block);
if (err)
- return err;
+ goto out_unlock;
truncate_setsize(inode, newsize);
down_write(&iinfo->i_data_sem);
udf_clear_extent_cache(inode);
err = udf_truncate_extents(inode);
up_write(&iinfo->i_data_sem);
if (err)
- return err;
+ goto out_unlock;
}
update_time:
inode->i_mtime = inode->i_ctime = current_time(inode);
@@ -1204,7 +1205,9 @@ update_time:
udf_sync_inode(inode);
else
mark_inode_dirty(inode);
- return 0;
+out_unlock:
+ filemap_invalidate_unlock(inode->i_mapping);
+ return err;
}
/*