From df68f20f56084cffd15add2d7652bcdfb38cd875 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 5 Jun 2017 13:14:16 -0500 Subject: GFS2: Remove gl_list from glock structure The gl_list is no longer used nor needed in the glock structure, so this patch eliminates it. Signed-off-by: Bob Peterson --- fs/gfs2/incore.h | 1 - 1 file changed, 1 deletion(-) (limited to 'fs/gfs2/incore.h') diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index b7cf65d13561..097adb1b3188 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -336,7 +336,6 @@ enum { }; struct gfs2_glock { - struct hlist_bl_node gl_list; unsigned long gl_flags; /* GLF_... */ struct lm_lockname gl_name; -- cgit v1.2.3 From 722f6f62a563108dc0f311bd86120b8fbfa0c6df Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 20 Jun 2017 09:52:57 -0500 Subject: GFS2: Eliminate vestigial sd_log_flush_wrapped Superblock variable sd_log_flush_wrapped is set, but never referenced, so this patch eliminates it. Signed-off-by: Bob Peterson --- fs/gfs2/incore.h | 1 - fs/gfs2/log.c | 3 --- fs/gfs2/lops.c | 4 +--- 3 files changed, 1 insertion(+), 7 deletions(-) (limited to 'fs/gfs2/incore.h') diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 097adb1b3188..638c0203f242 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -820,7 +820,6 @@ struct gfs2_sbd { wait_queue_head_t sd_reserving_log_wait; unsigned int sd_log_flush_head; - u64 sd_log_flush_wrapped; spinlock_t sd_ail_lock; struct list_head sd_ail1_list; diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index f865b96374df..32aa1f05c7ea 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -722,7 +722,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); sdp->sd_log_flush_head = sdp->sd_log_head; - sdp->sd_log_flush_wrapped = 0; tr = sdp->sd_log_tr; if (tr) { sdp->sd_log_tr = NULL; @@ -775,7 +774,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, } atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */ trace_gfs2_log_blocks(sdp, -1); - sdp->sd_log_flush_wrapped = 0; log_write_header(sdp, 0); sdp->sd_log_head = sdp->sd_log_flush_head; } @@ -880,7 +878,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list)); sdp->sd_log_flush_head = sdp->sd_log_head; - sdp->sd_log_flush_wrapped = 0; log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index b1f9144b42c7..2d4ce25a105f 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -134,10 +134,8 @@ static void gfs2_log_incr_head(struct gfs2_sbd *sdp) BUG_ON((sdp->sd_log_flush_head == sdp->sd_log_tail) && (sdp->sd_log_flush_head != sdp->sd_log_head)); - if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) { + if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) sdp->sd_log_flush_head = 0; - sdp->sd_log_flush_wrapped = 1; - } } static u64 gfs2_log_bmap(struct gfs2_sbd *sdp) -- cgit v1.2.3 From 4fd1a5795214bc6405f14691c1344ae8c3f17215 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 30 Jun 2017 07:47:15 -0500 Subject: gfs2: Get rid of flush_delayed_work in gfs2_evict_inode So far, gfs2_evict_inode clears gl->gl_object and then flushes the glock work queue to make sure that inode glops which dereference gl->gl_object have finished running before the inode is destroyed. However, flushing the work queue may do more work than needed, and in particular, it may call into DLM, which we want to avoid here. Use a bit lock (GIF_GLOP_PENDING) to synchronize between the inode glops and gfs2_evict_inode instead to get rid of the flushing. In addition, flush the work queues of existing glocks before reusing them for new inodes to get those glocks into a known state: the glock state engine currently doesn't handle glock re-appropriation correctly. (We may be able to fix the glock state engine instead later.) Based on a patch by Steven Whitehouse . Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson --- fs/gfs2/glock.h | 7 +++++++ fs/gfs2/glops.c | 39 ++++++++++++++++++++++++++++++++------- fs/gfs2/incore.h | 1 + fs/gfs2/inode.c | 7 ++++--- fs/gfs2/super.c | 4 ++-- 5 files changed, 46 insertions(+), 12 deletions(-) (limited to 'fs/gfs2/incore.h') diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index ab1ef322f7a5..9ad4a6ac6c84 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -257,4 +257,11 @@ static inline bool gfs2_holder_initialized(struct gfs2_holder *gh) return gh->gh_gl; } +static inline void glock_set_object(struct gfs2_glock *gl, void *object) +{ + spin_lock(&gl->gl_lockref.lock); + gl->gl_object = object; + spin_unlock(&gl->gl_lockref.lock); +} + #endif /* __GLOCK_DOT_H__ */ diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 5db59d444838..7449b19135c3 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -197,6 +197,27 @@ static void rgrp_go_inval(struct gfs2_glock *gl, int flags) rgd->rd_flags &= ~GFS2_RDF_UPTODATE; } +static struct gfs2_inode *gfs2_glock2inode(struct gfs2_glock *gl) +{ + struct gfs2_inode *ip; + + spin_lock(&gl->gl_lockref.lock); + ip = gl->gl_object; + if (ip) + set_bit(GIF_GLOP_PENDING, &ip->i_flags); + spin_unlock(&gl->gl_lockref.lock); + return ip; +} + +static void gfs2_clear_glop_pending(struct gfs2_inode *ip) +{ + if (!ip) + return; + + clear_bit_unlock(GIF_GLOP_PENDING, &ip->i_flags); + wake_up_bit(&ip->i_flags, GIF_GLOP_PENDING); +} + /** * inode_go_sync - Sync the dirty data and/or metadata for an inode glock * @gl: the glock protecting the inode @@ -205,25 +226,24 @@ static void rgrp_go_inval(struct gfs2_glock *gl, int flags) static void inode_go_sync(struct gfs2_glock *gl) { - struct gfs2_inode *ip = gl->gl_object; + struct gfs2_inode *ip = gfs2_glock2inode(gl); + int isreg = ip && S_ISREG(ip->i_inode.i_mode); struct address_space *metamapping = gfs2_glock2aspace(gl); int error; - if (ip && !S_ISREG(ip->i_inode.i_mode)) - ip = NULL; - if (ip) { + if (isreg) { if (test_and_clear_bit(GIF_SW_PAGED, &ip->i_flags)) unmap_shared_mapping_range(ip->i_inode.i_mapping, 0, 0); inode_dio_wait(&ip->i_inode); } if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) - return; + goto out; GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE); gfs2_log_flush(gl->gl_name.ln_sbd, gl, NORMAL_FLUSH); filemap_fdatawrite(metamapping); - if (ip) { + if (isreg) { struct address_space *mapping = ip->i_inode.i_mapping; filemap_fdatawrite(mapping); error = filemap_fdatawait(mapping); @@ -238,6 +258,9 @@ static void inode_go_sync(struct gfs2_glock *gl) */ smp_mb__before_atomic(); clear_bit(GLF_DIRTY, &gl->gl_flags); + +out: + gfs2_clear_glop_pending(ip); } /** @@ -253,7 +276,7 @@ static void inode_go_sync(struct gfs2_glock *gl) static void inode_go_inval(struct gfs2_glock *gl, int flags) { - struct gfs2_inode *ip = gl->gl_object; + struct gfs2_inode *ip = gfs2_glock2inode(gl); gfs2_assert_withdraw(gl->gl_name.ln_sbd, !atomic_read(&gl->gl_ail_count)); @@ -274,6 +297,8 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) } if (ip && S_ISREG(ip->i_inode.i_mode)) truncate_inode_pages(ip->i_inode.i_mapping, 0); + + gfs2_clear_glop_pending(ip); } /** diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 638c0203f242..01af34cb589d 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -385,6 +385,7 @@ enum { GIF_SW_PAGED = 3, GIF_ORDERED = 4, GIF_FREE_VFS_INODE = 5, + GIF_GLOP_PENDING = 6, }; struct gfs2_inode { diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 9f605ea4810c..912d4e66fabc 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -144,7 +144,8 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); if (unlikely(error)) goto fail; - ip->i_gl->gl_object = ip; + flush_delayed_work(&ip->i_gl->gl_work); + glock_set_object(ip->i_gl, ip); error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl); if (unlikely(error)) @@ -173,8 +174,8 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); if (unlikely(error)) goto fail_put; - - ip->i_iopen_gh.gh_gl->gl_object = ip; + flush_delayed_work(&ip->i_iopen_gh.gh_gl->gl_work); + glock_set_object(ip->i_iopen_gh.gh_gl, ip); gfs2_glock_put(io_gl); io_gl = NULL; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 29b0473f6e74..7d12c1232c42 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1631,8 +1631,8 @@ out: gfs2_ordered_del_inode(ip); clear_inode(inode); gfs2_dir_hash_inval(ip); - ip->i_gl->gl_object = NULL; - flush_delayed_work(&ip->i_gl->gl_work); + glock_set_object(ip->i_gl, NULL); + wait_on_bit_io(&ip->i_flags, GIF_GLOP_PENDING, TASK_UNINTERRUPTIBLE); gfs2_glock_add_to_lru(ip->i_gl); gfs2_glock_put(ip->i_gl); ip->i_gl = NULL; -- cgit v1.2.3 From 6f6597baae206c544c49ad7f1129d5adc1e9019d Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 30 Jun 2017 07:55:08 -0500 Subject: gfs2: Protect gl->gl_object by spin lock Put all remaining accesses to gl->gl_object under the gl->gl_lockref.lock spinlock to prevent races. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson --- fs/gfs2/bmap.c | 2 +- fs/gfs2/dir.c | 4 ++-- fs/gfs2/glops.c | 17 ++++++++++++++--- fs/gfs2/incore.h | 2 ++ fs/gfs2/inode.c | 8 ++++---- fs/gfs2/lops.c | 2 +- fs/gfs2/rgrp.c | 6 ++---- fs/gfs2/super.c | 11 +++++++---- fs/gfs2/xattr.c | 4 ++-- 9 files changed, 35 insertions(+), 21 deletions(-) (limited to 'fs/gfs2/incore.h') diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 3814a60e0aea..56e2943ff994 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -970,7 +970,7 @@ more_rgrps: continue; bn = be64_to_cpu(*p); if (gfs2_holder_initialized(rd_gh)) { - rgd = (struct gfs2_rgrpd *)rd_gh->gh_gl->gl_object; + rgd = gfs2_glock2rgrp(rd_gh->gh_gl); gfs2_assert_withdraw(sdp, gfs2_glock_is_locked_by_me(rd_gh->gh_gl)); } else { diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 96a7487b09b6..db427658ccd9 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -2032,8 +2032,8 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE); for (x = 0; x < rlist.rl_rgrps; x++) { - struct gfs2_rgrpd *rgd; - rgd = rlist.rl_ghs[x].gh_gl->gl_object; + struct gfs2_rgrpd *rgd = gfs2_glock2rgrp(rlist.rl_ghs[x].gh_gl); + rg_blocks += rgd->rd_length; } diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 7449b19135c3..5e69636d4dd3 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -137,7 +137,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) * * Called when demoting or unlocking an EX glock. We must flush * to disk all dirty buffers/pages relating to this glock, and must not - * not return to caller to demote/unlock the glock until I/O is complete. + * return to caller to demote/unlock the glock until I/O is complete. */ static void rgrp_go_sync(struct gfs2_glock *gl) @@ -184,7 +184,7 @@ static void rgrp_go_inval(struct gfs2_glock *gl, int flags) { struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct address_space *mapping = &sdp->sd_aspace; - struct gfs2_rgrpd *rgd = gl->gl_object; + struct gfs2_rgrpd *rgd = gfs2_glock2rgrp(gl); if (rgd) gfs2_rgrp_brelse(rgd); @@ -209,6 +209,17 @@ static struct gfs2_inode *gfs2_glock2inode(struct gfs2_glock *gl) return ip; } +struct gfs2_rgrpd *gfs2_glock2rgrp(struct gfs2_glock *gl) +{ + struct gfs2_rgrpd *rgd; + + spin_lock(&gl->gl_lockref.lock); + rgd = gl->gl_object; + spin_unlock(&gl->gl_lockref.lock); + + return rgd; +} + static void gfs2_clear_glop_pending(struct gfs2_inode *ip) { if (!ip) @@ -566,7 +577,7 @@ static int freeze_go_demote_ok(const struct gfs2_glock *gl) */ static void iopen_go_callback(struct gfs2_glock *gl, bool remote) { - struct gfs2_inode *ip = (struct gfs2_inode *)gl->gl_object; + struct gfs2_inode *ip = gl->gl_object; struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; if (!remote || (sdp->sd_vfs->s_flags & MS_RDONLY)) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 01af34cb589d..de4238493d80 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -857,5 +857,7 @@ static inline void gfs2_sbstats_inc(const struct gfs2_glock *gl, int which) preempt_enable(); } +extern struct gfs2_rgrpd *gfs2_glock2rgrp(struct gfs2_glock *gl); + #endif /* __INCORE_DOT_H__ */ diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 912d4e66fabc..50108fa724c7 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -202,14 +202,14 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, fail_refresh: ip->i_iopen_gh.gh_flags |= GL_NOCACHE; - ip->i_iopen_gh.gh_gl->gl_object = NULL; + glock_set_object(ip->i_iopen_gh.gh_gl, NULL); gfs2_glock_dq_uninit(&ip->i_iopen_gh); fail_put: if (io_gl) gfs2_glock_put(io_gl); if (gfs2_holder_initialized(&i_gh)) gfs2_glock_dq_uninit(&i_gh); - ip->i_gl->gl_object = NULL; + glock_set_object(ip->i_gl, NULL); fail: iget_failed(inode); return ERR_PTR(error); @@ -706,7 +706,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, if (error) goto fail_free_inode; - ip->i_gl->gl_object = ip; + glock_set_object(ip->i_gl, ip); error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); if (error) goto fail_free_inode; @@ -732,7 +732,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, if (error) goto fail_gunlock2; - ip->i_iopen_gh.gh_gl->gl_object = ip; + glock_set_object(ip->i_iopen_gh.gh_gl, ip); gfs2_glock_put(io_gl); gfs2_set_iop(inode); insert_inode_hash(inode); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 2d4ce25a105f..b50106bf2902 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -71,7 +71,7 @@ static void maybe_release_space(struct gfs2_bufdata *bd) { struct gfs2_glock *gl = bd->bd_gl; struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; - struct gfs2_rgrpd *rgd = gl->gl_object; + struct gfs2_rgrpd *rgd = gfs2_glock2rgrp(gl); unsigned int index = bd->bd_bh->b_blocknr - gl->gl_name.ln_number; struct gfs2_bitmap *bi = rgd->rd_bits + index; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 83c9909ff14a..836e38ba5d0a 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -705,9 +705,7 @@ void gfs2_clear_rgrpd(struct gfs2_sbd *sdp) rb_erase(n, &sdp->sd_rindex_tree); if (gl) { - spin_lock(&gl->gl_lockref.lock); - gl->gl_object = NULL; - spin_unlock(&gl->gl_lockref.lock); + glock_set_object(gl, NULL); gfs2_glock_add_to_lru(gl); gfs2_glock_put(gl); } @@ -917,7 +915,7 @@ static int read_rindex_entry(struct gfs2_inode *ip) error = rgd_insert(rgd); spin_unlock(&sdp->sd_rindex_spin); if (!error) { - rgd->rd_gl->gl_object = rgd; + glock_set_object(rgd->rd_gl, rgd); rgd->rd_gl->gl_vm.start = (rgd->rd_addr * bsize) & PAGE_MASK; rgd->rd_gl->gl_vm.end = PAGE_ALIGN((rgd->rd_addr + rgd->rd_length) * bsize) - 1; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 7d12c1232c42..bd5ad6c5514e 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1105,9 +1105,12 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host gfs2_holder_uninit(gh); error = err; } else { - if (!error) - error = statfs_slow_fill( - gh->gh_gl->gl_object, sc); + if (!error) { + struct gfs2_rgrpd *rgd = + gfs2_glock2rgrp(gh->gh_gl); + + error = statfs_slow_fill(rgd, sc); + } gfs2_glock_dq_uninit(gh); } } @@ -1637,7 +1640,7 @@ out: gfs2_glock_put(ip->i_gl); ip->i_gl = NULL; if (gfs2_holder_initialized(&ip->i_iopen_gh)) { - ip->i_iopen_gh.gh_gl->gl_object = NULL; + glock_set_object(ip->i_iopen_gh.gh_gl, NULL); ip->i_iopen_gh.gh_flags |= GL_NOCACHE; gfs2_glock_dq_uninit(&ip->i_iopen_gh); } diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index d87721aeb575..54179554c7d2 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c @@ -1327,8 +1327,8 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE); for (x = 0; x < rlist.rl_rgrps; x++) { - struct gfs2_rgrpd *rgd; - rgd = rlist.rl_ghs[x].gh_gl->gl_object; + struct gfs2_rgrpd *rgd = gfs2_glock2rgrp(rlist.rl_ghs[x].gh_gl); + rg_blocks += rgd->rd_length; } -- cgit v1.2.3