]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
gfs2: Give up the iopen glock on contention
authorAndreas Gruenbacher <agruenba@redhat.com>
Mon, 13 Jan 2020 21:16:17 +0000 (22:16 +0100)
committerAndreas Gruenbacher <agruenba@redhat.com>
Fri, 5 Jun 2020 18:19:21 +0000 (20:19 +0200)
When there's contention on the iopen glock, it means that the link count
of the corresponding inode has dropped to zero on a remote node which is
now trying to delete the inode.  In that case, try to evict the inode so
that the iopen glock will be released, which will allow the remote node
to do its job.

When the inode is still open locally, the inode's reference count won't
drop to zero and so we'll keep holding the inode and its iopen glock.
The remote node will time out its request to grab the iopen glock, and
when the inode is finally closed locally, we'll try to delete it
ourself.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
fs/gfs2/glock.c
fs/gfs2/incore.h
fs/gfs2/super.c

index 0332086f7ab91b04b2870f94a983e32e83aa338a..bf7daa35f73f37aedd8d5bd64d4eebf81a585963 100644 (file)
@@ -774,6 +774,42 @@ bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation)
        return generation <= be64_to_cpu(ri->ri_generation_deleted);
 }
 
+static bool gfs2_try_evict(struct gfs2_glock *gl)
+{
+       struct gfs2_inode *ip;
+       bool evicted = false;
+
+       /*
+        * If there is contention on the iopen glock and we have an inode, try
+        * to grab and release the inode so that it can be evicted.  This will
+        * allow the remote node to go ahead and delete the inode without us
+        * having to do it, which will avoid rgrp glock thrashing.
+        *
+        * The remote node is likely still holding the corresponding inode
+        * glock, so it will run before we get to verify that the delete has
+        * happened below.
+        */
+       spin_lock(&gl->gl_lockref.lock);
+       ip = gl->gl_object;
+       if (ip && !igrab(&ip->i_inode))
+               ip = NULL;
+       spin_unlock(&gl->gl_lockref.lock);
+       if (ip) {
+               set_bit(GIF_DEFERRED_DELETE, &ip->i_flags);
+               d_prune_aliases(&ip->i_inode);
+               iput(&ip->i_inode);
+
+               /* If the inode was evicted, gl->gl_object will now be NULL. */
+               spin_lock(&gl->gl_lockref.lock);
+               ip = gl->gl_object;
+               if (ip)
+                       clear_bit(GIF_DEFERRED_DELETE, &ip->i_flags);
+               spin_unlock(&gl->gl_lockref.lock);
+               evicted = !ip;
+       }
+       return evicted;
+}
+
 static void delete_work_func(struct work_struct *work)
 {
        struct delayed_work *dwork = to_delayed_work(work);
@@ -792,6 +828,21 @@ static void delete_work_func(struct work_struct *work)
        if (test_bit(GLF_INODE_CREATING, &gl->gl_flags))
                goto out;
 
+       if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
+               /*
+                * If we can evict the inode, give the remote node trying to
+                * delete the inode some time before verifying that the delete
+                * has happened.  Otherwise, if we cause contention on the inode glock
+                * immediately, the remote node will think that we still have
+                * the inode in use, and so it will give up waiting.
+                */
+               if (gfs2_try_evict(gl)) {
+                       if (gfs2_queue_delete_work(gl, 5 * HZ))
+                               return;
+                       goto out;
+               }
+       }
+
        inode = gfs2_lookup_by_inum(sdp, no_addr, NULL, GFS2_BLKST_UNLINKED);
        if (!IS_ERR_OR_NULL(inode)) {
                d_prune_aliases(inode);
index fdcf7a2f06c5dba872d3b2ad28f0d36d7761f3e7..76ac2578e65802c0f179cc7a7286617c52fc0132 100644 (file)
@@ -399,6 +399,7 @@ enum {
        GIF_ORDERED             = 4,
        GIF_FREE_VFS_INODE      = 5,
        GIF_GLOP_PENDING        = 6,
+       GIF_DEFERRED_DELETE     = 7,
 };
 
 struct gfs2_inode {
index 71218a6fd9b49e2878a684f95016b663d3223fd4..7d8caf169efdcf8ad50364c59d49455596455b23 100644 (file)
@@ -1299,9 +1299,12 @@ static void gfs2_evict_inode(struct inode *inode)
        if (test_bit(GIF_ALLOC_FAILED, &ip->i_flags)) {
                BUG_ON(!gfs2_glock_is_locked_by_me(ip->i_gl));
                gfs2_holder_mark_uninitialized(&gh);
-               goto alloc_failed;
+               goto out_delete;
        }
 
+       if (test_bit(GIF_DEFERRED_DELETE, &ip->i_flags))
+               goto out;
+
        /* Deletes should never happen under memory pressure anymore.  */
        if (WARN_ON_ONCE(current->flags & PF_MEMALLOC))
                goto out;
@@ -1333,7 +1336,7 @@ static void gfs2_evict_inode(struct inode *inode)
        if (inode->i_nlink)
                goto out_truncate;
 
-alloc_failed:
+out_delete:
        if (gfs2_holder_initialized(&ip->i_iopen_gh) &&
            test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) {
                ip->i_iopen_gh.gh_flags |= GL_NOCACHE;