@@ -3053,6 +3053,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;
+/* ilock flags definition */
+#define BTRFS_ILOCK_SHARED (1 << 0)
+#define BTRFS_ILOCK_TRY (1 << 1)
+
+int btrfs_inode_lock(struct inode *inode, int ilock_flags);
+void btrfs_inode_unlock(struct inode *inode, 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);
@@ -1975,7 +1975,7 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
* not unlock the i_mutex at this case.
*/
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);
@@ -1996,7 +1996,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;
@@ -2037,6 +2037,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;
+ int ilock_flags = 0;
/*
* If BTRFS flips readonly due to some impossible error,
@@ -2050,16 +2051,16 @@ 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 = btrfs_write_check(iocb, from);
if (err <= 0) {
- inode_unlock(inode);
+ btrfs_inode_unlock(inode, ilock_flags);
return err;
}
@@ -2105,7 +2106,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,
@@ -3405,7 +3406,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);
@@ -3644,9 +3645,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;
}
@@ -3690,10 +3691,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;
}
@@ -96,6 +96,51 @@ static void __endio_write_update_ordered(struct btrfs_inode *inode,
const u64 offset, const u64 bytes,
const bool uptodate);
+/*
+ * btrfs_inode_lock() - Lock 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, 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 i_rwsem
+ * ilock_flags should contain the same bits set as passed to
+ * btrfs_inode_lock() to decide whether the lock acquired is shared
+ * of exclusive.
+ */
+void btrfs_inode_unlock(struct inode *inode, 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.