diff options
Diffstat (limited to 'fs/btrfs/file.c')
| -rw-r--r-- | fs/btrfs/file.c | 40 | 
1 files changed, 34 insertions, 6 deletions
| diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index ca46a529d56b..361535c71c0f 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1106,6 +1106,25 @@ void btrfs_check_nocow_unlock(struct btrfs_inode *inode)  	btrfs_drew_write_unlock(&inode->root->snapshot_lock);  } +static void update_time_for_write(struct inode *inode) +{ +	struct timespec64 now, ctime; + +	if (IS_NOCMTIME(inode)) +		return; + +	now = current_time(inode); +	if (!timespec64_equal(&inode->i_mtime, &now)) +		inode->i_mtime = now; + +	ctime = inode_get_ctime(inode); +	if (!timespec64_equal(&ctime, &now)) +		inode_set_ctime_to_ts(inode, now); + +	if (IS_I_VERSION(inode)) +		inode_inc_iversion(inode); +} +  static int btrfs_write_check(struct kiocb *iocb, struct iov_iter *from,  			     size_t count)  { @@ -1137,10 +1156,7 @@ static int btrfs_write_check(struct kiocb *iocb, struct iov_iter *from,  	 * need to start yet another transaction to update the inode as we will  	 * update the inode when we finish writing whatever data we write.  	 */ -	if (!IS_NOCMTIME(inode)) { -		inode->i_mtime = inode_set_ctime_current(inode); -		inode_inc_iversion(inode); -	} +	update_time_for_write(inode);  	start_pos = round_down(pos, fs_info->sectorsize);  	oldsize = i_size_read(inode); @@ -1451,8 +1467,13 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)  	if (iocb->ki_flags & IOCB_NOWAIT)  		ilock_flags |= BTRFS_ILOCK_TRY; -	/* If the write DIO is within EOF, use a shared lock */ -	if (iocb->ki_pos + iov_iter_count(from) <= i_size_read(inode)) +	/* +	 * If the write DIO is within EOF, use a shared lock and also only if +	 * security bits will likely not be dropped by file_remove_privs() called +	 * from btrfs_write_check(). Either will need to be rechecked after the +	 * lock was acquired. +	 */ +	if (iocb->ki_pos + iov_iter_count(from) <= i_size_read(inode) && IS_NOSEC(inode))  		ilock_flags |= BTRFS_ILOCK_SHARED;  relock: @@ -1460,6 +1481,13 @@ relock:  	if (err < 0)  		return err; +	/* Shared lock cannot be used with security bits set. */ +	if ((ilock_flags & BTRFS_ILOCK_SHARED) && !IS_NOSEC(inode)) { +		btrfs_inode_unlock(BTRFS_I(inode), ilock_flags); +		ilock_flags &= ~BTRFS_ILOCK_SHARED; +		goto relock; +	} +  	err = generic_write_checks(iocb, from);  	if (err <= 0) {  		btrfs_inode_unlock(BTRFS_I(inode), ilock_flags); | 
