From 3e11e530415027a57936545957126aff49267b76 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Wed, 23 Mar 2016 14:29:59 -0400 Subject: GFS2: ignore unlock failures after withdraw After gfs2 has withdrawn the filesystem, it may still have many locks not in the unlocked state. If it is using lock_dlm, it will failed trying the unlocks since it has already unmounted the lock manager. Instead, it should set the SDF_SKIP_DLM_UNLOCK flag on withdraw, to signal that it can skip the lock_manager on unlocks, and failback to lock_nolock style unlocking. Signed-off-by: Benjamin Marzinski Signed-off-by: Bob Peterson --- fs/gfs2/glock.c | 9 ++++++++- fs/gfs2/util.c | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 6539131c52a2..2897ced5fca0 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -475,7 +475,14 @@ __acquires(&gl->gl_lockref.lock) if (sdp->sd_lockstruct.ls_ops->lm_lock) { /* lock_dlm */ ret = sdp->sd_lockstruct.ls_ops->lm_lock(gl, target, lck_flags); - if (ret) { + if (ret == -EINVAL && gl->gl_target == LM_ST_UNLOCKED && + target == LM_ST_UNLOCKED && + test_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags)) { + finish_xmote(gl, target); + if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) + gfs2_glock_put(gl); + } + else if (ret) { pr_err("lm_lock ret %d\n", ret); GLOCK_BUG_ON(gl, 1); } diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index cf645835710f..aee4485ad8a9 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -68,6 +68,7 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, const char *fmt, ...) fs_err(sdp, "telling LM to unmount\n"); lm->lm_unmount(sdp); } + set_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags); fs_err(sdp, "withdrawn\n"); dump_stack(); } -- cgit v1.2.3-58-ga151 From 73cc86252bd8a547349d2856497eceaf4f2d1766 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Fri, 1 Apr 2016 13:18:38 -0400 Subject: GFS2: Get rid of dead code in inode_go_demote_ok Function inode_go_demote_ok had some code that was only executed if gl_holders was not empty. However, if gl_holders was not empty, the only caller, demote_ok(), returns before inode_go_demote_ok would ever be called. Therefore, it's dead code, so I removed it. Signed-off-by: Bob Peterson Acked-by: Steven Whitehouse --- fs/gfs2/glops.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'fs') diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 437fd73e381e..5db59d444838 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -286,17 +286,10 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) static int inode_go_demote_ok(const struct gfs2_glock *gl) { struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; - struct gfs2_holder *gh; if (sdp->sd_jindex == gl->gl_object || sdp->sd_rindex == gl->gl_object) return 0; - if (!list_empty(&gl->gl_holders)) { - gh = list_entry(gl->gl_holders.next, struct gfs2_holder, gh_list); - if (gh->gh_list.next != &gl->gl_holders) - return 0; - } - return 1; } -- cgit v1.2.3-58-ga151 From 611526756a3d0fa7f4d1c519397ba8898f40443f Mon Sep 17 00:00:00 2001 From: Abhi Das Date: Tue, 5 Apr 2016 12:06:15 -0400 Subject: gfs2: Use gfs2 wrapper to sync inode before calling generic_file_splice_read() gfs2_file_splice_read() f_op grabs and releases the cluster-wide inode glock to sync the inode size to the latest. Without this, generic_file_splice_read() uses an older i_size value and can return EOF for valid offsets in the inode. Signed-off-by: Abhi Das Signed-off-by: Bob Peterson --- fs/gfs2/file.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index c9384f932975..fd9a10e4518d 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -950,6 +950,30 @@ out_uninit: return ret; } +static ssize_t gfs2_file_splice_read(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) +{ + struct inode *inode = in->f_mapping->host; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_holder gh; + int ret; + + mutex_lock(&inode->i_mutex); + + ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh); + if (ret) { + mutex_unlock(&inode->i_mutex); + return ret; + } + + gfs2_glock_dq_uninit(&gh); + mutex_unlock(&inode->i_mutex); + + return generic_file_splice_read(in, ppos, pipe, len, flags); +} + + static ssize_t gfs2_file_splice_write(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags) @@ -1112,7 +1136,7 @@ const struct file_operations gfs2_file_fops = { .fsync = gfs2_fsync, .lock = gfs2_lock, .flock = gfs2_flock, - .splice_read = generic_file_splice_read, + .splice_read = gfs2_file_splice_read, .splice_write = gfs2_file_splice_write, .setlease = simple_nosetlease, .fallocate = gfs2_fallocate, @@ -1140,7 +1164,7 @@ const struct file_operations gfs2_file_fops_nolock = { .open = gfs2_open, .release = gfs2_release, .fsync = gfs2_fsync, - .splice_read = generic_file_splice_read, + .splice_read = gfs2_file_splice_read, .splice_write = gfs2_file_splice_write, .setlease = generic_setlease, .fallocate = gfs2_fallocate, -- cgit v1.2.3-58-ga151 From a527b38e1475211b67eb59b3fadb40689f035529 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 12 Apr 2016 12:39:12 -0400 Subject: GFS2: fs/gfs2/glock.c: Deinline do_error, save 1856 bytes This function compiles to 522 bytes of machine code. Error paths are not very time critical. Signed-off-by: Denys Vlasenko Signed-off-by: Bob Peterson --- fs/gfs2/glock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 2897ced5fca0..3910cea1aa51 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -218,7 +218,7 @@ static void gfs2_holder_wake(struct gfs2_holder *gh) * */ -static inline void do_error(struct gfs2_glock *gl, const int ret) +static void do_error(struct gfs2_glock *gl, const int ret) { struct gfs2_holder *gh, *tmp; -- cgit v1.2.3-58-ga151 From e97321fa095f1ea7110d4d2ba446bd6141ed9a03 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 12 Apr 2016 16:14:26 -0400 Subject: GFS2: Don't dereference inode in gfs2_inode_lookup until it's valid Function gfs2_inode_lookup was dereferencing the inode, and after, it checks for the value being NULL. We need to check that first. Signed-off-by: Bob Peterson --- fs/gfs2/inode.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index bb30f9a72c65..aea002ea94a6 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -93,12 +93,12 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, int error; inode = iget_locked(sb, (unsigned long)no_addr); - ip = GFS2_I(inode); - ip->i_no_addr = no_addr; - if (!inode) return ERR_PTR(-ENOMEM); + ip = GFS2_I(inode); + ip->i_no_addr = no_addr; + if (inode->i_state & I_NEW) { struct gfs2_sbd *sdp = GFS2_SB(inode); ip->i_no_formal_ino = no_formal_ino; -- cgit v1.2.3-58-ga151 From 9c7fe83530a351845719acf1dda0587e8c743588 Mon Sep 17 00:00:00 2001 From: Daniel DeFreez Date: Tue, 19 Apr 2016 19:57:45 -0400 Subject: GFS2: Add calls to gfs2_holder_uninit in two error handlers This patch fixes two locations that do not call gfs2_holder_uninit if gfs2_glock_nq returns an error. Signed-off-by: Daniel DeFreez Signed-off-by: Bob Peterson --- fs/gfs2/aops.c | 3 ++- fs/gfs2/file.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index aa016e4b8bec..58dd0061134b 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -1063,7 +1063,7 @@ static ssize_t gfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter, gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, &gh); rv = gfs2_glock_nq(&gh); if (rv) - return rv; + goto out_uninit; rv = gfs2_ok_for_dio(ip, offset); if (rv != 1) goto out; /* dio not valid, fall back to buffered i/o */ @@ -1102,6 +1102,7 @@ static ssize_t gfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter, offset, gfs2_get_block_direct, NULL, NULL, 0); out: gfs2_glock_dq(&gh); +out_uninit: gfs2_holder_uninit(&gh); return rv; } diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index fd9a10e4518d..f33fd92e5f49 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -160,7 +160,7 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr) gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh); error = gfs2_glock_nq(&gh); if (error) - return error; + goto out_uninit; fsflags = fsflags_cvt(gfs2_to_fsflags, ip->i_diskflags); if (!S_ISDIR(inode->i_mode) && ip->i_diskflags & GFS2_DIF_JDATA) @@ -169,6 +169,7 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr) error = -EFAULT; gfs2_glock_dq(&gh); +out_uninit: gfs2_holder_uninit(&gh); return error; } -- cgit v1.2.3-58-ga151 From 80f4781d2c0ba63bf9ab4de90a6829a1368b80a3 Mon Sep 17 00:00:00 2001 From: Abhi Das Date: Mon, 2 May 2016 07:07:01 -0500 Subject: gfs2: use inode_lock/unlock instead of accessing i_mutex directly i_mutex has been replaced by i_rwsem and directly accessing the non-existent i_mutex breaks the kernel build. Signed-off-by: Abhi Das Signed-off-by: Bob Peterson --- fs/gfs2/file.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index f33fd92e5f49..374dd5327101 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -960,16 +960,16 @@ static ssize_t gfs2_file_splice_read(struct file *in, loff_t *ppos, struct gfs2_holder gh; int ret; - mutex_lock(&inode->i_mutex); + inode_lock(inode); ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh); if (ret) { - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); return ret; } gfs2_glock_dq_uninit(&gh); - mutex_unlock(&inode->i_mutex); + inode_unlock(inode); return generic_file_splice_read(in, ppos, pipe, len, flags); } -- cgit v1.2.3-58-ga151 From 8381e6022755863258a352128a55e375a766f50d Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 2 May 2016 09:42:49 -0500 Subject: GFS2: Remove allocation parms from gfs2_rbm_find Struct gfs2_alloc_parms ap is never referenced in function gfs2_rbm_find, so this patch removes it. Signed-off-by: Bob Peterson --- fs/gfs2/rgrp.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 07c0265aa195..8b580e535ad4 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -73,8 +73,7 @@ static const char valid_change[16] = { }; static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext, - const struct gfs2_inode *ip, bool nowrap, - const struct gfs2_alloc_parms *ap); + const struct gfs2_inode *ip, bool nowrap); /** @@ -1512,7 +1511,7 @@ static void rg_mblk_search(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip, if (WARN_ON(gfs2_rbm_from_block(&rbm, goal))) return; - ret = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, &extlen, ip, true, ap); + ret = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, &extlen, ip, true); if (ret == 0) { rs->rs_rbm = rbm; rs->rs_free = extlen; @@ -1639,7 +1638,6 @@ fail: * @ip: If set, check for reservations * @nowrap: Stop looking at the end of the rgrp, rather than wrapping * around until we've reached the starting point. - * @ap: the allocation parameters * * Side effects: * - If looking for free blocks, we set GBF_FULL on each bitmap which @@ -1651,8 +1649,7 @@ fail: */ static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext, - const struct gfs2_inode *ip, bool nowrap, - const struct gfs2_alloc_parms *ap) + const struct gfs2_inode *ip, bool nowrap) { struct buffer_head *bh; int initial_bii; @@ -1773,7 +1770,7 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip while (1) { down_write(&sdp->sd_log_flush_lock); error = gfs2_rbm_find(&rbm, GFS2_BLKST_UNLINKED, NULL, NULL, - true, NULL); + true); up_write(&sdp->sd_log_flush_lock); if (error == -ENOSPC) break; @@ -2330,12 +2327,11 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks, int error; gfs2_set_alloc_start(&rbm, ip, dinode); - error = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, NULL, ip, false, NULL); + error = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, NULL, ip, false); if (error == -ENOSPC) { gfs2_set_alloc_start(&rbm, ip, dinode); - error = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, NULL, NULL, false, - NULL); + error = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, NULL, NULL, false); } /* Since all blocks are reserved in advance, this shouldn't happen */ -- cgit v1.2.3-58-ga151 From 68cd4ce2caf22a81833eb1abfa075eb1cc39bfe2 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 2 May 2016 11:53:35 -0500 Subject: GFS2: Refactor gfs2_remove_from_journal This patch makes two simple changes to function gfs2_remove_from_journal. First, it removes the parameter that specifies the transaction. Since it's always passed in as current->journal_info, we might as well set that in the function rather than passing it in. Second, it changes the meta parameter to use an enum to make the code more clear. Signed-off-by: Bob Peterson Acked-by: Steven Whitehouse --- fs/gfs2/aops.c | 2 +- fs/gfs2/meta_io.c | 7 ++++--- fs/gfs2/meta_io.h | 8 ++++++-- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 58dd0061134b..e21a931ced53 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -977,7 +977,7 @@ static void gfs2_discard(struct gfs2_sbd *sdp, struct buffer_head *bh) if (!list_empty(&bd->bd_list) && !buffer_pinned(bh)) list_del_init(&bd->bd_list); else - gfs2_remove_from_journal(bh, current->journal_info, 0); + gfs2_remove_from_journal(bh, REMOVE_JDATA); } bh->b_bdev = NULL; clear_buffer_mapped(bh); diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index e137d96f1b17..8f3f1b863687 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -325,18 +325,19 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh) return 0; } -void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int meta) +void gfs2_remove_from_journal(struct buffer_head *bh, int meta) { struct address_space *mapping = bh->b_page->mapping; struct gfs2_sbd *sdp = gfs2_mapping2sbd(mapping); struct gfs2_bufdata *bd = bh->b_private; + struct gfs2_trans *tr = current->journal_info; int was_pinned = 0; if (test_clear_buffer_pinned(bh)) { trace_gfs2_pin(bd, 0); atomic_dec(&sdp->sd_log_pinned); list_del_init(&bd->bd_list); - if (meta) + if (meta == REMOVE_META) tr->tr_num_buf_rm++; else tr->tr_num_databuf_rm++; @@ -376,7 +377,7 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen) if (bh) { lock_buffer(bh); gfs2_log_lock(sdp); - gfs2_remove_from_journal(bh, current->journal_info, 1); + gfs2_remove_from_journal(bh, REMOVE_META); gfs2_log_unlock(sdp); unlock_buffer(bh); brelse(bh); diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index c5086c8af5ed..ffdf6aa3509d 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -57,8 +57,12 @@ extern int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, extern int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh); extern struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno, int create); -extern void gfs2_remove_from_journal(struct buffer_head *bh, - struct gfs2_trans *tr, int meta); +enum { + REMOVE_JDATA = 0, + REMOVE_META = 1, +}; + +extern void gfs2_remove_from_journal(struct buffer_head *bh, int meta); extern void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen); extern int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num, struct buffer_head **bhp); -- cgit v1.2.3-58-ga151