Commit b9a861fd authored by Jan Kara's avatar Jan Kara
Browse files

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
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;
	}
+9 −6
Original line number Diff line number Diff line
@@ -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 @@ int udf_setsize(struct inode *inode, loff_t newsize)
		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 @@ int udf_setsize(struct inode *inode, loff_t newsize)
		udf_sync_inode(inode);
	else
		mark_inode_dirty(inode);
	return 0;
out_unlock:
	filemap_invalidate_unlock(inode->i_mapping);
	return err;
}

/*