Skip to content

Commit f2e70d8

Browse files
AstralBobAndreas Gruenbacher
authored andcommitted
gfs2: fix GL_SKIP node_scope problems
Before this patch, when a glock was locked, the very first holder on the queue would unlock the lockref and call the go_instantiate glops function (if one existed), unless GL_SKIP was specified. When we introduced the new node-scope concept, we allowed multiple holders to lock glocks in EX mode and share the lock. But node-scope introduced a new problem: if the first holder has GL_SKIP and the next one does NOT, since it is not the first holder on the queue, the go_instantiate op was not called. Eventually the GL_SKIP holder may call the instantiate sub-function (e.g. gfs2_rgrp_bh_get) but there was still a window of time in which another non-GL_SKIP holder assumes the instantiate function had been called by the first holder. In the case of rgrp glocks, this led to a NULL pointer dereference on the buffer_heads. This patch tries to fix the problem by introducing two new glock flags: GLF_INSTANTIATE_NEEDED, which keeps track of when the instantiate function needs to be called to "fill in" or "read in" the object before it is referenced. GLF_INSTANTIATE_IN_PROG which is used to determine when a process is in the process of reading in the object. Whenever a function needs to reference the object, it checks the GLF_INSTANTIATE_NEEDED flag, and if set, it sets GLF_INSTANTIATE_IN_PROG and calls the glops "go_instantiate" function. As before, the gl_lockref spin_lock is unlocked during the IO operation, which may take a relatively long amount of time to complete. While unlocked, if another process determines go_instantiate is still needed, it sees GLF_INSTANTIATE_IN_PROG is set, and waits for the go_instantiate glop operation to be completed. Once GLF_INSTANTIATE_IN_PROG is cleared, it needs to check GLF_INSTANTIATE_NEEDED again because the other process's go_instantiate operation may not have been successful. Functions that previously called the instantiate sub-functions now call directly into gfs2_instantiate so the new bits are managed properly. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
1 parent e6f8560 commit f2e70d8

7 files changed

Lines changed: 61 additions & 20 deletions

File tree

fs/gfs2/glock.c

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -479,12 +479,42 @@ find_first_strong_holder(struct gfs2_glock *gl)
479479
* Returns: 0 if instantiate was successful, 2 if type specific operation is
480480
* underway, or error.
481481
*/
482-
static int gfs2_instantiate(struct gfs2_holder *gh)
482+
int gfs2_instantiate(struct gfs2_holder *gh)
483483
{
484484
struct gfs2_glock *gl = gh->gh_gl;
485485
const struct gfs2_glock_operations *glops = gl->gl_ops;
486+
int ret;
487+
488+
again:
489+
if (!test_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags))
490+
return 0;
486491

487-
return glops->go_instantiate(gh);
492+
/*
493+
* Since we unlock the lockref lock, we set a flag to indicate
494+
* instantiate is in progress.
495+
*/
496+
if (test_bit(GLF_INSTANTIATE_IN_PROG, &gl->gl_flags)) {
497+
wait_on_bit(&gl->gl_flags, GLF_INSTANTIATE_IN_PROG,
498+
TASK_UNINTERRUPTIBLE);
499+
/*
500+
* Here we just waited for a different instantiate to finish.
501+
* But that may not have been successful, as when a process
502+
* locks an inode glock _before_ it has an actual inode to
503+
* instantiate into. So we check again. This process might
504+
* have an inode to instantiate, so might be successful.
505+
*/
506+
goto again;
507+
}
508+
509+
set_bit(GLF_INSTANTIATE_IN_PROG, &gl->gl_flags);
510+
511+
ret = glops->go_instantiate(gh);
512+
if (!ret)
513+
clear_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags);
514+
clear_bit(GLF_INSTANTIATE_IN_PROG, &gl->gl_flags);
515+
smp_mb__after_atomic();
516+
wake_up_bit(&gl->gl_flags, GLF_INSTANTIATE_IN_PROG);
517+
return ret;
488518
}
489519

490520
/**
@@ -526,7 +556,7 @@ __acquires(&gl->gl_lockref.lock)
526556
incompat_holders_demoted = true;
527557
first_gh = gh;
528558
}
529-
if (gh->gh_list.prev == &gl->gl_holders &&
559+
if (test_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags) &&
530560
!(gh->gh_flags & GL_SKIP) && gl->gl_ops->go_instantiate) {
531561
lock_released = true;
532562
spin_unlock(&gl->gl_lockref.lock);
@@ -1162,7 +1192,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
11621192

11631193
atomic_inc(&sdp->sd_glock_disposal);
11641194
gl->gl_node.next = NULL;
1165-
gl->gl_flags = 0;
1195+
gl->gl_flags = glops->go_instantiate ? BIT(GLF_INSTANTIATE_NEEDED) : 0;
11661196
gl->gl_name = name;
11671197
lockdep_set_subclass(&gl->gl_lockref.lock, glops->go_subclass);
11681198
gl->gl_lockref.count = 1;
@@ -2326,6 +2356,10 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl)
23262356
*p++ = 'P';
23272357
if (test_bit(GLF_FREEING, gflags))
23282358
*p++ = 'x';
2359+
if (test_bit(GLF_INSTANTIATE_NEEDED, gflags))
2360+
*p++ = 'n';
2361+
if (test_bit(GLF_INSTANTIATE_IN_PROG, gflags))
2362+
*p++ = 'N';
23292363
*p = 0;
23302364
return buf;
23312365
}

fs/gfs2/glock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ extern void gfs2_holder_reinit(unsigned int state, u16 flags,
204204
extern void gfs2_holder_uninit(struct gfs2_holder *gh);
205205
extern int gfs2_glock_nq(struct gfs2_holder *gh);
206206
extern int gfs2_glock_poll(struct gfs2_holder *gh);
207+
extern int gfs2_instantiate(struct gfs2_holder *gh);
207208
extern int gfs2_glock_wait(struct gfs2_holder *gh);
208209
extern int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs);
209210
extern void gfs2_glock_dq(struct gfs2_holder *gh);

fs/gfs2/glops.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)
357357
truncate_inode_pages(mapping, 0);
358358
if (ip) {
359359
set_bit(GIF_INVALID, &ip->i_flags);
360+
set_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags);
360361
forget_all_cached_acls(&ip->i_inode);
361362
security_inode_invalidate_secctx(&ip->i_inode);
362363
gfs2_dir_hash_inval(ip);
@@ -495,13 +496,13 @@ static int inode_go_instantiate(struct gfs2_holder *gh)
495496
struct gfs2_inode *ip = gl->gl_object;
496497
int error = 0;
497498

498-
if (!ip)
499-
return 0;
499+
if (!ip) /* no inode to populate - read it in later */
500+
goto out;
500501

501502
if (test_bit(GIF_INVALID, &ip->i_flags)) {
502503
error = gfs2_inode_refresh(ip);
503504
if (error)
504-
return error;
505+
goto out;
505506
}
506507

507508
if (gh->gh_state != LM_ST_DEFERRED)
@@ -515,9 +516,10 @@ static int inode_go_instantiate(struct gfs2_holder *gh)
515516
list_add(&ip->i_trunc_list, &sdp->sd_trunc_list);
516517
spin_unlock(&sdp->sd_trunc_lock);
517518
wake_up(&sdp->sd_quota_wait);
518-
return 1;
519+
error = 1;
519520
}
520521

522+
out:
521523
return error;
522524
}
523525

fs/gfs2/incore.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ struct gfs2_alloc_parms {
316316

317317
enum {
318318
GLF_LOCK = 1,
319+
GLF_INSTANTIATE_NEEDED = 2, /* needs instantiate */
319320
GLF_DEMOTE = 3,
320321
GLF_PENDING_DEMOTE = 4,
321322
GLF_DEMOTE_IN_PROGRESS = 5,
@@ -325,6 +326,7 @@ enum {
325326
GLF_REPLY_PENDING = 9,
326327
GLF_INITIAL = 10,
327328
GLF_FROZEN = 11,
329+
GLF_INSTANTIATE_IN_PROG = 12, /* instantiate happening now */
328330
GLF_LRU = 13,
329331
GLF_OBJECT = 14, /* Used only for tracing */
330332
GLF_BLOCKING = 15,

fs/gfs2/inode.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
183183

184184
glock_set_object(ip->i_gl, ip);
185185
set_bit(GIF_INVALID, &ip->i_flags);
186+
set_bit(GLF_INSTANTIATE_NEEDED, &ip->i_gl->gl_flags);
186187
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
187188
if (unlikely(error))
188189
goto fail;
@@ -196,7 +197,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
196197

197198
if (type == DT_UNKNOWN) {
198199
/* Inode glock must be locked already */
199-
error = gfs2_inode_refresh(GFS2_I(inode));
200+
error = gfs2_instantiate(&i_gh);
200201
if (error)
201202
goto fail;
202203
} else {

fs/gfs2/rgrp.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,8 +1238,7 @@ static int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
12381238
rgd->rd_rgl->rl_unlinked = cpu_to_be32(count_unlinked(rgd));
12391239
gfs2_rgrp_ondisk2lvb(rgd->rd_rgl,
12401240
rgd->rd_bits[0].bi_bh->b_data);
1241-
}
1242-
else if (sdp->sd_args.ar_rgrplvb) {
1241+
} else if (sdp->sd_args.ar_rgrplvb) {
12431242
if (!gfs2_rgrp_lvb_valid(rgd)){
12441243
gfs2_consist_rgrpd(rgd);
12451244
error = -EIO;
@@ -1257,19 +1256,18 @@ static int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
12571256
bi->bi_bh = NULL;
12581257
gfs2_assert_warn(sdp, !bi->bi_clone);
12591258
}
1260-
12611259
return error;
12621260
}
12631261

1264-
static int update_rgrp_lvb(struct gfs2_rgrpd *rgd)
1262+
static int update_rgrp_lvb(struct gfs2_rgrpd *rgd, struct gfs2_holder *gh)
12651263
{
12661264
u32 rl_flags;
12671265

12681266
if (rgd->rd_flags & GFS2_RDF_UPTODATE)
12691267
return 0;
12701268

12711269
if (cpu_to_be32(GFS2_MAGIC) != rgd->rd_rgl->rl_magic)
1272-
return gfs2_rgrp_bh_get(rgd);
1270+
return gfs2_instantiate(gh);
12731271

12741272
rl_flags = be32_to_cpu(rgd->rd_rgl->rl_flags);
12751273
rl_flags &= ~GFS2_RDF_MASK;
@@ -1312,6 +1310,7 @@ void gfs2_rgrp_brelse(struct gfs2_rgrpd *rgd)
13121310
bi->bi_bh = NULL;
13131311
}
13141312
}
1313+
set_bit(GLF_INSTANTIATE_NEEDED, &rgd->rd_gl->gl_flags);
13151314
}
13161315

13171316
int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
@@ -2110,7 +2109,8 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap)
21102109
gfs2_rgrp_congested(rs->rs_rgd, loops))
21112110
goto skip_rgrp;
21122111
if (sdp->sd_args.ar_rgrplvb) {
2113-
error = update_rgrp_lvb(rs->rs_rgd);
2112+
error = update_rgrp_lvb(rs->rs_rgd,
2113+
&ip->i_rgd_gh);
21142114
if (unlikely(error)) {
21152115
rgrp_unlock_local(rs->rs_rgd);
21162116
gfs2_glock_dq_uninit(&ip->i_rgd_gh);
@@ -2125,8 +2125,11 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap)
21252125
(loops == 0 && target > rs->rs_rgd->rd_extfail_pt))
21262126
goto skip_rgrp;
21272127

2128-
if (sdp->sd_args.ar_rgrplvb)
2129-
gfs2_rgrp_bh_get(rs->rs_rgd);
2128+
if (sdp->sd_args.ar_rgrplvb) {
2129+
error = gfs2_instantiate(&ip->i_rgd_gh);
2130+
if (error)
2131+
goto skip_rgrp;
2132+
}
21302133

21312134
/* Get a reservation if we don't already have one */
21322135
if (!gfs2_rs_active(rs))
@@ -2762,8 +2765,6 @@ void gfs2_rlist_free(struct gfs2_rgrp_list *rlist)
27622765

27632766
void rgrp_lock_local(struct gfs2_rgrpd *rgd)
27642767
{
2765-
GLOCK_BUG_ON(rgd->rd_gl, !gfs2_glock_is_held_excl(rgd->rd_gl) &&
2766-
!test_bit(SDF_NORECOVERY, &rgd->rd_sbd->sd_flags));
27672768
mutex_lock(&rgd->rd_mutex);
27682769
}
27692770

fs/gfs2/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1245,7 +1245,7 @@ static enum dinode_demise evict_should_delete(struct inode *inode,
12451245
return SHOULD_NOT_DELETE_DINODE;
12461246

12471247
if (test_bit(GIF_INVALID, &ip->i_flags)) {
1248-
ret = gfs2_inode_refresh(ip);
1248+
ret = gfs2_instantiate(gh);
12491249
if (ret)
12501250
return SHOULD_NOT_DELETE_DINODE;
12511251
}

0 commit comments

Comments
 (0)