Commit a14b78ad authored by Goldwyn Rodrigues's avatar Goldwyn Rodrigues Committed by David Sterba
Browse files

btrfs: introduce btrfs_inode_lock()/unlock()



btrfs_inode_lock/unlock() are wrappers around inode locks, separating
the type of lock and actual locking.

- 0 - default, exclusive lock
- BTRFS_ILOCK_SHARED - for shared locks, for possible parallel DIO
- BTRFS_ILOCK_TRY - for the RWF_NOWAIT sequence

The bits SHARED and TRY can be combined together.

Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarGoldwyn Rodrigues <rgoldwyn@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent b8d8e1fd
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -3070,6 +3070,13 @@ extern const struct iomap_ops btrfs_dio_iomap_ops;
extern const struct iomap_dio_ops btrfs_dio_ops;
extern const struct iomap_dio_ops btrfs_sync_dops;

/* Inode locking type flags, by default the exclusive lock is taken */
#define BTRFS_ILOCK_SHARED	(1U << 0)
#define BTRFS_ILOCK_TRY 	(1U << 1)

int btrfs_inode_lock(struct inode *inode, unsigned int ilock_flags);
void btrfs_inode_unlock(struct inode *inode, unsigned int ilock_flags);

/* ioctl.c */
long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+17 −16
Original line number Diff line number Diff line
@@ -1894,7 +1894,7 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
	 * is protected by inode lock. So we cannot unlock it here.
	 */
	if (pos + iov_iter_count(from) <= inode->i_size) {
		inode_unlock(inode);
		btrfs_inode_unlock(inode, 0);
		relock = true;
	}
	down_read(&BTRFS_I(inode)->dio_sem);
@@ -1915,7 +1915,7 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)

	up_read(&BTRFS_I(inode)->dio_sem);
	if (relock)
		inode_lock(inode);
		btrfs_inode_lock(inode, 0);

	if (written < 0 || !iov_iter_count(from))
		return written;
@@ -1956,6 +1956,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
	ssize_t num_written = 0;
	const bool sync = iocb->ki_flags & IOCB_DSYNC;
	ssize_t err;
	unsigned int ilock_flags = 0;

	/*
	 * If the fs flips readonly due to some impossible error, although we
@@ -1969,22 +1970,22 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
	    (iocb->ki_flags & IOCB_NOWAIT))
		return -EOPNOTSUPP;

	if (iocb->ki_flags & IOCB_NOWAIT) {
		if (!inode_trylock(inode))
			return -EAGAIN;
	} else {
		inode_lock(inode);
	}
	if (iocb->ki_flags & IOCB_NOWAIT)
		ilock_flags |= BTRFS_ILOCK_TRY;

	err = btrfs_inode_lock(inode, ilock_flags);
	if (err < 0)
		return err;

	err = generic_write_checks(iocb, from);
	if (err <= 0) {
		inode_unlock(inode);
		btrfs_inode_unlock(inode, ilock_flags);
		return err;
	}

	err = btrfs_write_check(iocb, from, err);
	if (err < 0) {
		inode_unlock(inode);
		btrfs_inode_unlock(inode, ilock_flags);
		return err;
	}

@@ -2030,7 +2031,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
		num_written = btrfs_buffered_write(iocb, from);
	}

	inode_unlock(inode);
	btrfs_inode_unlock(inode, ilock_flags);

	/*
	 * We also have to set last_sub_trans to the current log transid,
@@ -3330,7 +3331,7 @@ static long btrfs_fallocate(struct file *file, int mode,
			return ret;
	}

	inode_lock(inode);
	btrfs_inode_lock(inode, 0);

	if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size) {
		ret = inode_newsize_ok(inode, offset + len);
@@ -3569,9 +3570,9 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence)
		return generic_file_llseek(file, offset, whence);
	case SEEK_DATA:
	case SEEK_HOLE:
		inode_lock_shared(inode);
		btrfs_inode_lock(inode, BTRFS_ILOCK_SHARED);
		offset = find_desired_extent(inode, offset, whence);
		inode_unlock_shared(inode);
		btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
		break;
	}

@@ -3615,10 +3616,10 @@ static ssize_t btrfs_direct_read(struct kiocb *iocb, struct iov_iter *to)
	if (check_direct_read(btrfs_sb(inode->i_sb), to, iocb->ki_pos))
		return 0;

	inode_lock_shared(inode);
	btrfs_inode_lock(inode, BTRFS_ILOCK_SHARED);
	ret = iomap_dio_rw(iocb, to, &btrfs_dio_iomap_ops, &btrfs_dio_ops,
			   is_sync_kiocb(iocb));
	inode_unlock_shared(inode);
	btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
	return ret;
}

+45 −0
Original line number Diff line number Diff line
@@ -95,6 +95,51 @@ static void __endio_write_update_ordered(struct btrfs_inode *inode,
					 const u64 offset, const u64 bytes,
					 const bool uptodate);

/*
 * btrfs_inode_lock - lock inode i_rwsem based on arguments passed
 *
 * ilock_flags can have the following bit set:
 *
 * BTRFS_ILOCK_SHARED - acquire a shared lock on the inode
 * BTRFS_ILOCK_TRY - try to acquire the lock, if fails on first attempt
 *		     return -EAGAIN
 */
int btrfs_inode_lock(struct inode *inode, unsigned int ilock_flags)
{
	if (ilock_flags & BTRFS_ILOCK_SHARED) {
		if (ilock_flags & BTRFS_ILOCK_TRY) {
			if (!inode_trylock_shared(inode))
				return -EAGAIN;
			else
				return 0;
		}
		inode_lock_shared(inode);
	} else {
		if (ilock_flags & BTRFS_ILOCK_TRY) {
			if (!inode_trylock(inode))
				return -EAGAIN;
			else
				return 0;
		}
		inode_lock(inode);
	}
	return 0;
}

/*
 * btrfs_inode_unlock - unock inode i_rwsem
 *
 * ilock_flags should contain the same bits set as passed to btrfs_inode_lock()
 * to decide whether the lock acquired is shared or exclusive.
 */
void btrfs_inode_unlock(struct inode *inode, unsigned int ilock_flags)
{
	if (ilock_flags & BTRFS_ILOCK_SHARED)
		inode_unlock_shared(inode);
	else
		inode_unlock(inode);
}

/*
 * Cleanup all submitted ordered extents in specified range to handle errors
 * from the btrfs_run_delalloc_range() callback.