Commit b9a861fd authored by Jan Kara's avatar Jan Kara

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: default avatarJan Kara <jack@suse.cz>
parent 96eeaaae
...@@ -150,7 +150,9 @@ static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -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 && if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) + inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
iocb->ki_pos + iov_iter_count(from))) { iocb->ki_pos + iov_iter_count(from))) {
filemap_invalidate_lock(inode->i_mapping);
retval = udf_expand_file_adinicb(inode); retval = udf_expand_file_adinicb(inode);
filemap_invalidate_unlock(inode->i_mapping);
if (retval) if (retval)
goto out; goto out;
} }
......
...@@ -1145,7 +1145,7 @@ struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block, ...@@ -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 udf_setsize(struct inode *inode, loff_t newsize)
{ {
int err; int err = 0;
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
unsigned int bsize = i_blocksize(inode); unsigned int bsize = i_blocksize(inode);
...@@ -1155,6 +1155,7 @@ int udf_setsize(struct inode *inode, loff_t newsize) ...@@ -1155,6 +1155,7 @@ int udf_setsize(struct inode *inode, loff_t newsize)
if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return -EPERM; return -EPERM;
filemap_invalidate_lock(inode->i_mapping);
iinfo = UDF_I(inode); iinfo = UDF_I(inode);
if (newsize > inode->i_size) { if (newsize > inode->i_size) {
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
...@@ -1167,11 +1168,11 @@ int udf_setsize(struct inode *inode, loff_t newsize) ...@@ -1167,11 +1168,11 @@ int udf_setsize(struct inode *inode, loff_t newsize)
} }
err = udf_expand_file_adinicb(inode); err = udf_expand_file_adinicb(inode);
if (err) if (err)
return err; goto out_unlock;
} }
err = udf_extend_file(inode, newsize); err = udf_extend_file(inode, newsize);
if (err) if (err)
return err; goto out_unlock;
set_size: set_size:
truncate_setsize(inode, newsize); truncate_setsize(inode, newsize);
} else { } else {
...@@ -1189,14 +1190,14 @@ int udf_setsize(struct inode *inode, loff_t newsize) ...@@ -1189,14 +1190,14 @@ int udf_setsize(struct inode *inode, loff_t newsize)
err = block_truncate_page(inode->i_mapping, newsize, err = block_truncate_page(inode->i_mapping, newsize,
udf_get_block); udf_get_block);
if (err) if (err)
return err; goto out_unlock;
truncate_setsize(inode, newsize); truncate_setsize(inode, newsize);
down_write(&iinfo->i_data_sem); down_write(&iinfo->i_data_sem);
udf_clear_extent_cache(inode); udf_clear_extent_cache(inode);
err = udf_truncate_extents(inode); err = udf_truncate_extents(inode);
up_write(&iinfo->i_data_sem); up_write(&iinfo->i_data_sem);
if (err) if (err)
return err; goto out_unlock;
} }
update_time: update_time:
inode->i_mtime = inode->i_ctime = current_time(inode); inode->i_mtime = inode->i_ctime = current_time(inode);
...@@ -1204,7 +1205,9 @@ int udf_setsize(struct inode *inode, loff_t newsize) ...@@ -1204,7 +1205,9 @@ int udf_setsize(struct inode *inode, loff_t newsize)
udf_sync_inode(inode); udf_sync_inode(inode);
else else
mark_inode_dirty(inode); mark_inode_dirty(inode);
return 0; out_unlock:
filemap_invalidate_unlock(inode->i_mapping);
return err;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment