udf: Protect truncate and file type conversion with invalidate_lock
authorJan Kara <jack@suse.cz>
Thu, 19 Jan 2023 11:46:09 +0000 (12:46 +0100)
committerJan Kara <jack@suse.cz>
Thu, 26 Jan 2023 15:46:35 +0000 (16:46 +0100)
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>
fs/udf/file.c
fs/udf/inode.c

index 596d703fb6c89be001d67a3639ece36125352280..cf050bdffd9e1f398dd7ca5358c9163b99271ab6 100644 (file)
@@ -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;
        }
index b4e4aacdaabc2aac59c0c08fcaa3d0e4d54d77c2..f57ef7d0a2076d64cea61a020dd8c549a6968a29 100644 (file)
@@ -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;
 }
 
 /*