aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2017-08-01 12:45:23 -0400
committerBob Peterson <rpeterso@redhat.com>2017-08-10 11:45:21 -0400
commit71c1b2136835c88c231f7a5e3dc618f7568f84f7 (patch)
tree73a9839b924775b9e91e47a7f5a1288cc583d31c
parenteebd2e813f7ef688e22cd0b68aea78fb3d1ef19c (diff)
gfs2: gfs2_evict_inode: Put glocks asynchronously
gfs2_evict_inode is called to free inodes under memory pressure. The function calls into DLM when an inode's last cluster-wide reference goes away (remote unlink) and to release the glock and associated DLM lock before finally destroying the inode. However, if DLM is blocked on memory to become available, calling into DLM again will deadlock. Avoid that by decoupling releasing glocks from destroying inodes in that case: with gfs2_glock_queue_put, glocks will be dequeued asynchronously in work queue context, when the associated inodes have likely already been destroyed. With this change, inodes can end up being unlinked, remote-unlink can be triggered, and then the inode can be reallocated before all remote-unlink callbacks are processed. To detect that, revalidate the link count in gfs2_evict_inode to make sure we're not deleting an allocated, referenced inode. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> Signed-off-by: Bob Peterson <rpeterso@redhat.com>
-rw-r--r--fs/gfs2/glock.c10
-rw-r--r--fs/gfs2/glock.h2
-rw-r--r--fs/gfs2/super.c30
3 files changed, 39 insertions, 3 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 11d48b964047..5ad757f0ce60 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -171,7 +171,7 @@ void gfs2_glock_free(struct gfs2_glock *gl)
171 * 171 *
172 */ 172 */
173 173
174static void gfs2_glock_hold(struct gfs2_glock *gl) 174void gfs2_glock_hold(struct gfs2_glock *gl)
175{ 175{
176 GLOCK_BUG_ON(gl, __lockref_is_dead(&gl->gl_lockref)); 176 GLOCK_BUG_ON(gl, __lockref_is_dead(&gl->gl_lockref));
177 lockref_get(&gl->gl_lockref); 177 lockref_get(&gl->gl_lockref);
@@ -264,6 +264,14 @@ static void __gfs2_glock_put(struct gfs2_glock *gl)
264 sdp->sd_lockstruct.ls_ops->lm_put_lock(gl); 264 sdp->sd_lockstruct.ls_ops->lm_put_lock(gl);
265} 265}
266 266
267/*
268 * Cause the glock to be put in work queue context.
269 */
270void gfs2_glock_queue_put(struct gfs2_glock *gl)
271{
272 gfs2_glock_queue_work(gl, 0);
273}
274
267/** 275/**
268 * gfs2_glock_put() - Decrement reference count on glock 276 * gfs2_glock_put() - Decrement reference count on glock
269 * @gl: The glock to put 277 * @gl: The glock to put
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index 526d2123f758..5e12220cc0c2 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -182,7 +182,9 @@ static inline struct address_space *gfs2_glock2aspace(struct gfs2_glock *gl)
182extern int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, 182extern int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
183 const struct gfs2_glock_operations *glops, 183 const struct gfs2_glock_operations *glops,
184 int create, struct gfs2_glock **glp); 184 int create, struct gfs2_glock **glp);
185extern void gfs2_glock_hold(struct gfs2_glock *gl);
185extern void gfs2_glock_put(struct gfs2_glock *gl); 186extern void gfs2_glock_put(struct gfs2_glock *gl);
187extern void gfs2_glock_queue_put(struct gfs2_glock *gl);
186extern void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, 188extern void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state,
187 u16 flags, struct gfs2_holder *gh); 189 u16 flags, struct gfs2_holder *gh);
188extern void gfs2_holder_reinit(unsigned int state, u16 flags, 190extern void gfs2_holder_reinit(unsigned int state, u16 flags,
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 6c39bb1ec100..4089dbe617a6 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1502,6 +1502,22 @@ out_qs:
1502} 1502}
1503 1503
1504/** 1504/**
1505 * gfs2_glock_put_eventually
1506 * @gl: The glock to put
1507 *
1508 * When under memory pressure, trigger a deferred glock put to make sure we
1509 * won't call into DLM and deadlock. Otherwise, put the glock directly.
1510 */
1511
1512static void gfs2_glock_put_eventually(struct gfs2_glock *gl)
1513{
1514 if (current->flags & PF_MEMALLOC)
1515 gfs2_glock_queue_put(gl);
1516 else
1517 gfs2_glock_put(gl);
1518}
1519
1520/**
1505 * gfs2_evict_inode - Remove an inode from cache 1521 * gfs2_evict_inode - Remove an inode from cache
1506 * @inode: The inode to evict 1522 * @inode: The inode to evict
1507 * 1523 *
@@ -1564,6 +1580,12 @@ static void gfs2_evict_inode(struct inode *inode)
1564 goto out_truncate; 1580 goto out_truncate;
1565 } 1581 }
1566 1582
1583 /*
1584 * The inode may have been recreated in the meantime.
1585 */
1586 if (inode->i_nlink)
1587 goto out_truncate;
1588
1567alloc_failed: 1589alloc_failed:
1568 if (gfs2_holder_initialized(&ip->i_iopen_gh) && 1590 if (gfs2_holder_initialized(&ip->i_iopen_gh) &&
1569 test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { 1591 test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) {
@@ -1653,12 +1675,16 @@ out:
1653 glock_clear_object(ip->i_gl, ip); 1675 glock_clear_object(ip->i_gl, ip);
1654 wait_on_bit_io(&ip->i_flags, GIF_GLOP_PENDING, TASK_UNINTERRUPTIBLE); 1676 wait_on_bit_io(&ip->i_flags, GIF_GLOP_PENDING, TASK_UNINTERRUPTIBLE);
1655 gfs2_glock_add_to_lru(ip->i_gl); 1677 gfs2_glock_add_to_lru(ip->i_gl);
1656 gfs2_glock_put(ip->i_gl); 1678 gfs2_glock_put_eventually(ip->i_gl);
1657 ip->i_gl = NULL; 1679 ip->i_gl = NULL;
1658 if (gfs2_holder_initialized(&ip->i_iopen_gh)) { 1680 if (gfs2_holder_initialized(&ip->i_iopen_gh)) {
1659 glock_clear_object(ip->i_iopen_gh.gh_gl, ip); 1681 struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
1682
1683 glock_clear_object(gl, ip);
1660 ip->i_iopen_gh.gh_flags |= GL_NOCACHE; 1684 ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
1685 gfs2_glock_hold(gl);
1661 gfs2_glock_dq_uninit(&ip->i_iopen_gh); 1686 gfs2_glock_dq_uninit(&ip->i_iopen_gh);
1687 gfs2_glock_put_eventually(gl);
1662 } 1688 }
1663} 1689}
1664 1690