summaryrefslogtreecommitdiffstats
path: root/fs/gfs2
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2017-08-01 11:49:42 -0500
committerBob Peterson <rpeterso@redhat.com>2017-08-10 10:49:13 -0500
commit6a1c8f6dcf815d96197a2723781cf700925d17ed (patch)
tree27df64a37b4101dd81605f35e387466ffb34071c /fs/gfs2
parent71c1b2136835c88c231f7a5e3dc618f7568f84f7 (diff)
downloadlinux-6a1c8f6dcf815d96197a2723781cf700925d17ed.tar.bz2
gfs2: Defer deleting inodes under memory pressure
When under memory pressure and an inode's link count has dropped to zero, defer deleting the inode to the delete workqueue. This avoids calling into DLM under memory pressure, which can deadlock. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r--fs/gfs2/super.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 4089dbe617a6..a83fe8260d2e 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1318,6 +1318,23 @@ static int gfs2_drop_inode(struct inode *inode)
if (test_bit(GLF_DEMOTE, &gl->gl_flags))
clear_nlink(inode);
}
+
+ /*
+ * When under memory pressure when an inode's link count has dropped to
+ * zero, defer deleting the inode to the delete workqueue. This avoids
+ * calling into DLM under memory pressure, which can deadlock.
+ */
+ if (!inode->i_nlink &&
+ unlikely(current->flags & PF_MEMALLOC) &&
+ gfs2_holder_initialized(&ip->i_iopen_gh)) {
+ struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
+
+ gfs2_glock_hold(gl);
+ if (queue_work(gfs2_delete_workqueue, &gl->gl_delete) == 0)
+ gfs2_glock_queue_put(gl);
+ return false;
+ }
+
return generic_drop_inode(inode);
}
@@ -1561,6 +1578,10 @@ static void gfs2_evict_inode(struct inode *inode)
goto alloc_failed;
}
+ /* Deletes should never happen under memory pressure anymore. */
+ if (WARN_ON_ONCE(current->flags & PF_MEMALLOC))
+ goto out;
+
/* Must not read inode block until block type has been verified */
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, &gh);
if (unlikely(error)) {