]> git.dujemihanovic.xyz Git - linux.git/commitdiff
btrfs: add lockdep annotations for the ordered extents wait event
authorIoannis Angelakopoulos <iangelak@fb.com>
Mon, 25 Jul 2022 22:11:59 +0000 (15:11 -0700)
committerDavid Sterba <dsterba@suse.com>
Mon, 26 Sep 2022 10:27:53 +0000 (12:27 +0200)
This wait event is very similar to the pending ordered wait event in the
sense that it occurs in a different context than the condition signaling
for the event. The signaling occurs in btrfs_remove_ordered_extent()
while the wait event is implemented in btrfs_start_ordered_extent() in
fs/btrfs/ordered-data.c

However, in this case a thread must not acquire the lockdep map for the
ordered extents wait event when the ordered extent is related to a free
space inode. That is because lockdep creates dependencies between locks
acquired both in execution paths related to normal inodes and paths
related to free space inodes, thus leading to false positives.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Ioannis Angelakopoulos <iangelak@fb.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/inode.c
fs/btrfs/ordered-data.c

index 8bd9a6d5ade6111c9db83a6e25e3142a8485faf7..804962f97452dd8a40fb8c54f35909e7eb3984fd 100644 (file)
@@ -1100,6 +1100,7 @@ struct btrfs_fs_info {
        struct lockdep_map btrfs_trans_num_extwriters_map;
        struct lockdep_map btrfs_state_change_map[4];
        struct lockdep_map btrfs_trans_pending_ordered_map;
+       struct lockdep_map btrfs_ordered_extent_map;
 
 #ifdef CONFIG_BTRFS_FS_REF_VERIFY
        spinlock_t ref_verify_lock;
index 393553fdfed65d334f768b95151a9d87d438a2e4..e0e1730e67d78fb79a5220097b83024c56e04919 100644 (file)
@@ -2993,6 +2993,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
        btrfs_lockdep_init_map(fs_info, btrfs_trans_num_writers);
        btrfs_lockdep_init_map(fs_info, btrfs_trans_num_extwriters);
        btrfs_lockdep_init_map(fs_info, btrfs_trans_pending_ordered);
+       btrfs_lockdep_init_map(fs_info, btrfs_ordered_extent);
        btrfs_state_lockdep_init_map(fs_info, btrfs_trans_commit_start,
                                     BTRFS_LOCKDEP_TRANS_COMMIT_START);
        btrfs_state_lockdep_init_map(fs_info, btrfs_trans_unblocked,
index 1372210869b14cda075d3e10fb583ac98d2d4a07..b069557270558b39bda1071ed3fe56c2e0b06e21 100644 (file)
@@ -3225,6 +3225,8 @@ int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
                clear_bits |= EXTENT_DELALLOC_NEW;
 
        freespace_inode = btrfs_is_free_space_inode(inode);
+       if (!freespace_inode)
+               btrfs_lockdep_acquire(fs_info, btrfs_ordered_extent);
 
        if (test_bit(BTRFS_ORDERED_IOERR, &ordered_extent->flags)) {
                ret = -EIO;
@@ -8959,6 +8961,7 @@ void btrfs_destroy_inode(struct inode *vfs_inode)
        struct btrfs_ordered_extent *ordered;
        struct btrfs_inode *inode = BTRFS_I(vfs_inode);
        struct btrfs_root *root = inode->root;
+       bool freespace_inode;
 
        WARN_ON(!hlist_empty(&vfs_inode->i_dentry));
        WARN_ON(vfs_inode->i_data.nrpages);
@@ -8980,6 +8983,12 @@ void btrfs_destroy_inode(struct inode *vfs_inode)
        if (!root)
                return;
 
+       /*
+        * If this is a free space inode do not take the ordered extents lockdep
+        * map.
+        */
+       freespace_inode = btrfs_is_free_space_inode(inode);
+
        while (1) {
                ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1);
                if (!ordered)
@@ -8988,6 +8997,10 @@ void btrfs_destroy_inode(struct inode *vfs_inode)
                        btrfs_err(root->fs_info,
                                  "found ordered extent %llu %llu on inode cleanup",
                                  ordered->file_offset, ordered->num_bytes);
+
+                       if (!freespace_inode)
+                               btrfs_lockdep_acquire(root->fs_info, btrfs_ordered_extent);
+
                        btrfs_remove_ordered_extent(inode, ordered);
                        btrfs_put_ordered_extent(ordered);
                        btrfs_put_ordered_extent(ordered);
index 2a4cb6db42d1c19aa06dd0adbdc98b702722a9d2..eb24a6d20ff8ea44b6d9d58107b94b92a9f60be0 100644 (file)
@@ -524,6 +524,13 @@ void btrfs_remove_ordered_extent(struct btrfs_inode *btrfs_inode,
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct rb_node *node;
        bool pending;
+       bool freespace_inode;
+
+       /*
+        * If this is a free space inode the thread has not acquired the ordered
+        * extents lockdep map.
+        */
+       freespace_inode = btrfs_is_free_space_inode(btrfs_inode);
 
        btrfs_lockdep_acquire(fs_info, btrfs_trans_pending_ordered);
        /* This is paired with btrfs_add_ordered_extent. */
@@ -597,6 +604,8 @@ void btrfs_remove_ordered_extent(struct btrfs_inode *btrfs_inode,
        }
        spin_unlock(&root->ordered_extent_lock);
        wake_up(&entry->wait);
+       if (!freespace_inode)
+               btrfs_lockdep_release(fs_info, btrfs_ordered_extent);
 }
 
 static void btrfs_run_ordered_extent_work(struct btrfs_work *work)
@@ -715,9 +724,16 @@ void btrfs_start_ordered_extent(struct btrfs_ordered_extent *entry, int wait)
        u64 start = entry->file_offset;
        u64 end = start + entry->num_bytes - 1;
        struct btrfs_inode *inode = BTRFS_I(entry->inode);
+       bool freespace_inode;
 
        trace_btrfs_ordered_extent_start(inode, entry);
 
+       /*
+        * If this is a free space inode do not take the ordered extents lockdep
+        * map.
+        */
+       freespace_inode = btrfs_is_free_space_inode(inode);
+
        /*
         * pages in the range can be dirty, clean or writeback.  We
         * start IO on any dirty ones so the wait doesn't stall waiting
@@ -726,6 +742,8 @@ void btrfs_start_ordered_extent(struct btrfs_ordered_extent *entry, int wait)
        if (!test_bit(BTRFS_ORDERED_DIRECT, &entry->flags))
                filemap_fdatawrite_range(inode->vfs_inode.i_mapping, start, end);
        if (wait) {
+               if (!freespace_inode)
+                       btrfs_might_wait_for_event(inode->root->fs_info, btrfs_ordered_extent);
                wait_event(entry->wait, test_bit(BTRFS_ORDERED_COMPLETE,
                                                 &entry->flags));
        }