btrfs: introduce btrfs_inode_lock()/unlock()
authorGoldwyn Rodrigues <rgoldwyn@suse.com>
Thu, 24 Sep 2020 16:39:16 +0000 (11:39 -0500)
committerDavid Sterba <dsterba@suse.com>
Tue, 8 Dec 2020 14:53:47 +0000 (15:53 +0100)
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: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/ctree.h
fs/btrfs/file.c
fs/btrfs/inode.c

index 5244400d5c238b5d26920941474358f797f792c0..6ee7252f51c060e04c73fb3d1611c6b2ac500d0f 100644 (file)
@@ -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);
index b30ce769ae8b0f8a721fc9e26b257d39ac9d3824..fe1daa44f325b5048f8161883807090cd36b0b91 100644 (file)
@@ -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;
 }
 
index 6fd561ac98667bc530e87d62ad6eb4936e6b82a7..3eea0d0be8a0d4c6c6739877c8f2ef800a7d160e 100644 (file)
@@ -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.