Browse Source

Merge tag 'gfs2-4.7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2

Pull GFS2 updates from Bob Peterson:
 "We've got nine patches this time:

   - Abhi Das has two patches that fix a GFS2 splice issue (and an
     adjustment).

   - Ben Marzinski has a patch which allows the proper unmount of a GFS2
     file system after hitting a withdraw error.

   - I have a patch to fix a problem where GFS2 would dereference an
     error value, plus three cosmetic / refactoring patches.

   - Daniel DeFreez has a patch to fix two glock reference count
     problems, where GFS2 was not properly "uninitializing" its glock
     holder on error paths.

   - Denys Vlasenko has a patch to change a function to not be inlined,
     thus reducing the memory footprint of the GFS2 module"

* tag 'gfs2-4.7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  GFS2: Refactor gfs2_remove_from_journal
  GFS2: Remove allocation parms from gfs2_rbm_find
  gfs2: use inode_lock/unlock instead of accessing i_mutex directly
  GFS2: Add calls to gfs2_holder_uninit in two error handlers
  GFS2: Don't dereference inode in gfs2_inode_lookup until it's valid
  GFS2: fs/gfs2/glock.c: Deinline do_error, save 1856 bytes
  gfs2: Use gfs2 wrapper to sync inode before calling generic_file_splice_read()
  GFS2: Get rid of dead code in inode_go_demote_ok
  GFS2: ignore unlock failures after withdraw
Linus Torvalds 9 years ago
parent
commit
be1332c099
9 changed files with 60 additions and 32 deletions
  1. 3 2
      fs/gfs2/aops.c
  2. 28 3
      fs/gfs2/file.c
  3. 9 2
      fs/gfs2/glock.c
  4. 0 7
      fs/gfs2/glops.c
  5. 3 3
      fs/gfs2/inode.c
  6. 4 3
      fs/gfs2/meta_io.c
  7. 6 2
      fs/gfs2/meta_io.h
  8. 6 10
      fs/gfs2/rgrp.c
  9. 1 0
      fs/gfs2/util.c

+ 3 - 2
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))
 		if (!list_empty(&bd->bd_list) && !buffer_pinned(bh))
 			list_del_init(&bd->bd_list);
 			list_del_init(&bd->bd_list);
 		else
 		else
-			gfs2_remove_from_journal(bh, current->journal_info, 0);
+			gfs2_remove_from_journal(bh, REMOVE_JDATA);
 	}
 	}
 	bh->b_bdev = NULL;
 	bh->b_bdev = NULL;
 	clear_buffer_mapped(bh);
 	clear_buffer_mapped(bh);
@@ -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);
 	gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, &gh);
 	rv = gfs2_glock_nq(&gh);
 	rv = gfs2_glock_nq(&gh);
 	if (rv)
 	if (rv)
-		return rv;
+		goto out_uninit;
 	rv = gfs2_ok_for_dio(ip, offset);
 	rv = gfs2_ok_for_dio(ip, offset);
 	if (rv != 1)
 	if (rv != 1)
 		goto out; /* dio not valid, fall back to buffered i/o */
 		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)
 				  gfs2_get_block_direct, NULL, NULL, 0);
 				  gfs2_get_block_direct, NULL, NULL, 0);
 out:
 out:
 	gfs2_glock_dq(&gh);
 	gfs2_glock_dq(&gh);
+out_uninit:
 	gfs2_holder_uninit(&gh);
 	gfs2_holder_uninit(&gh);
 	return rv;
 	return rv;
 }
 }

+ 28 - 3
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);
 	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
 	error = gfs2_glock_nq(&gh);
 	error = gfs2_glock_nq(&gh);
 	if (error)
 	if (error)
-		return error;
+		goto out_uninit;
 
 
 	fsflags = fsflags_cvt(gfs2_to_fsflags, ip->i_diskflags);
 	fsflags = fsflags_cvt(gfs2_to_fsflags, ip->i_diskflags);
 	if (!S_ISDIR(inode->i_mode) && ip->i_diskflags & GFS2_DIF_JDATA)
 	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;
 		error = -EFAULT;
 
 
 	gfs2_glock_dq(&gh);
 	gfs2_glock_dq(&gh);
+out_uninit:
 	gfs2_holder_uninit(&gh);
 	gfs2_holder_uninit(&gh);
 	return error;
 	return error;
 }
 }
@@ -953,6 +954,30 @@ out_uninit:
 	return ret;
 	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;
+
+	inode_lock(inode);
+
+	ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
+	if (ret) {
+		inode_unlock(inode);
+		return ret;
+	}
+
+	gfs2_glock_dq_uninit(&gh);
+	inode_unlock(inode);
+
+	return generic_file_splice_read(in, ppos, pipe, len, flags);
+}
+
+
 static ssize_t gfs2_file_splice_write(struct pipe_inode_info *pipe,
 static ssize_t gfs2_file_splice_write(struct pipe_inode_info *pipe,
 				      struct file *out, loff_t *ppos,
 				      struct file *out, loff_t *ppos,
 				      size_t len, unsigned int flags)
 				      size_t len, unsigned int flags)
@@ -1115,7 +1140,7 @@ const struct file_operations gfs2_file_fops = {
 	.fsync		= gfs2_fsync,
 	.fsync		= gfs2_fsync,
 	.lock		= gfs2_lock,
 	.lock		= gfs2_lock,
 	.flock		= gfs2_flock,
 	.flock		= gfs2_flock,
-	.splice_read	= generic_file_splice_read,
+	.splice_read	= gfs2_file_splice_read,
 	.splice_write	= gfs2_file_splice_write,
 	.splice_write	= gfs2_file_splice_write,
 	.setlease	= simple_nosetlease,
 	.setlease	= simple_nosetlease,
 	.fallocate	= gfs2_fallocate,
 	.fallocate	= gfs2_fallocate,
@@ -1143,7 +1168,7 @@ const struct file_operations gfs2_file_fops_nolock = {
 	.open		= gfs2_open,
 	.open		= gfs2_open,
 	.release	= gfs2_release,
 	.release	= gfs2_release,
 	.fsync		= gfs2_fsync,
 	.fsync		= gfs2_fsync,
-	.splice_read	= generic_file_splice_read,
+	.splice_read	= gfs2_file_splice_read,
 	.splice_write	= gfs2_file_splice_write,
 	.splice_write	= gfs2_file_splice_write,
 	.setlease	= generic_setlease,
 	.setlease	= generic_setlease,
 	.fallocate	= gfs2_fallocate,
 	.fallocate	= gfs2_fallocate,

+ 9 - 2
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;
 	struct gfs2_holder *gh, *tmp;
 
 
@@ -475,7 +475,14 @@ __acquires(&gl->gl_lockref.lock)
 	if (sdp->sd_lockstruct.ls_ops->lm_lock)	{
 	if (sdp->sd_lockstruct.ls_ops->lm_lock)	{
 		/* lock_dlm */
 		/* lock_dlm */
 		ret = sdp->sd_lockstruct.ls_ops->lm_lock(gl, target, lck_flags);
 		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);
 			pr_err("lm_lock ret %d\n", ret);
 			GLOCK_BUG_ON(gl, 1);
 			GLOCK_BUG_ON(gl, 1);
 		}
 		}

+ 0 - 7
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)
 static int inode_go_demote_ok(const struct gfs2_glock *gl)
 {
 {
 	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
 	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)
 	if (sdp->sd_jindex == gl->gl_object || sdp->sd_rindex == gl->gl_object)
 		return 0;
 		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;
 	return 1;
 }
 }
 
 

+ 3 - 3
fs/gfs2/inode.c

@@ -93,12 +93,12 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
 	int error;
 	int error;
 
 
 	inode = iget_locked(sb, (unsigned long)no_addr);
 	inode = iget_locked(sb, (unsigned long)no_addr);
-	ip = GFS2_I(inode);
-	ip->i_no_addr = no_addr;
-
 	if (!inode)
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
 		return ERR_PTR(-ENOMEM);
 
 
+	ip = GFS2_I(inode);
+	ip->i_no_addr = no_addr;
+
 	if (inode->i_state & I_NEW) {
 	if (inode->i_state & I_NEW) {
 		struct gfs2_sbd *sdp = GFS2_SB(inode);
 		struct gfs2_sbd *sdp = GFS2_SB(inode);
 		ip->i_no_formal_ino = no_formal_ino;
 		ip->i_no_formal_ino = no_formal_ino;

+ 4 - 3
fs/gfs2/meta_io.c

@@ -325,18 +325,19 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
 	return 0;
 	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 address_space *mapping = bh->b_page->mapping;
 	struct gfs2_sbd *sdp = gfs2_mapping2sbd(mapping);
 	struct gfs2_sbd *sdp = gfs2_mapping2sbd(mapping);
 	struct gfs2_bufdata *bd = bh->b_private;
 	struct gfs2_bufdata *bd = bh->b_private;
+	struct gfs2_trans *tr = current->journal_info;
 	int was_pinned = 0;
 	int was_pinned = 0;
 
 
 	if (test_clear_buffer_pinned(bh)) {
 	if (test_clear_buffer_pinned(bh)) {
 		trace_gfs2_pin(bd, 0);
 		trace_gfs2_pin(bd, 0);
 		atomic_dec(&sdp->sd_log_pinned);
 		atomic_dec(&sdp->sd_log_pinned);
 		list_del_init(&bd->bd_list);
 		list_del_init(&bd->bd_list);
-		if (meta)
+		if (meta == REMOVE_META)
 			tr->tr_num_buf_rm++;
 			tr->tr_num_buf_rm++;
 		else
 		else
 			tr->tr_num_databuf_rm++;
 			tr->tr_num_databuf_rm++;
@@ -376,7 +377,7 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen)
 		if (bh) {
 		if (bh) {
 			lock_buffer(bh);
 			lock_buffer(bh);
 			gfs2_log_lock(sdp);
 			gfs2_log_lock(sdp);
-			gfs2_remove_from_journal(bh, current->journal_info, 1);
+			gfs2_remove_from_journal(bh, REMOVE_META);
 			gfs2_log_unlock(sdp);
 			gfs2_log_unlock(sdp);
 			unlock_buffer(bh);
 			unlock_buffer(bh);
 			brelse(bh);
 			brelse(bh);

+ 6 - 2
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 int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);
 extern struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno,
 extern struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno,
 				       int create);
 				       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 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,
 extern int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
 				     struct buffer_head **bhp);
 				     struct buffer_head **bhp);

+ 6 - 10
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,
 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);
 
 
 
 
 /**
 /**
@@ -1511,7 +1510,7 @@ static void rg_mblk_search(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip,
 	if (WARN_ON(gfs2_rbm_from_block(&rbm, goal)))
 	if (WARN_ON(gfs2_rbm_from_block(&rbm, goal)))
 		return;
 		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) {
 	if (ret == 0) {
 		rs->rs_rbm = rbm;
 		rs->rs_rbm = rbm;
 		rs->rs_free = extlen;
 		rs->rs_free = extlen;
@@ -1638,7 +1637,6 @@ fail:
  * @ip: If set, check for reservations
  * @ip: If set, check for reservations
  * @nowrap: Stop looking at the end of the rgrp, rather than wrapping
  * @nowrap: Stop looking at the end of the rgrp, rather than wrapping
  *          around until we've reached the starting point.
  *          around until we've reached the starting point.
- * @ap: the allocation parameters
  *
  *
  * Side effects:
  * Side effects:
  * - If looking for free blocks, we set GBF_FULL on each bitmap which
  * - If looking for free blocks, we set GBF_FULL on each bitmap which
@@ -1650,8 +1648,7 @@ fail:
  */
  */
 
 
 static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext,
 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;
 	struct buffer_head *bh;
 	int initial_bii;
 	int initial_bii;
@@ -1772,7 +1769,7 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip
 	while (1) {
 	while (1) {
 		down_write(&sdp->sd_log_flush_lock);
 		down_write(&sdp->sd_log_flush_lock);
 		error = gfs2_rbm_find(&rbm, GFS2_BLKST_UNLINKED, NULL, NULL,
 		error = gfs2_rbm_find(&rbm, GFS2_BLKST_UNLINKED, NULL, NULL,
-				      true, NULL);
+				      true);
 		up_write(&sdp->sd_log_flush_lock);
 		up_write(&sdp->sd_log_flush_lock);
 		if (error == -ENOSPC)
 		if (error == -ENOSPC)
 			break;
 			break;
@@ -2329,12 +2326,11 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
 	int error;
 	int error;
 
 
 	gfs2_set_alloc_start(&rbm, ip, dinode);
 	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) {
 	if (error == -ENOSPC) {
 		gfs2_set_alloc_start(&rbm, ip, dinode);
 		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 */
 	/* Since all blocks are reserved in advance, this shouldn't happen */

+ 1 - 0
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");
 			fs_err(sdp, "telling LM to unmount\n");
 			lm->lm_unmount(sdp);
 			lm->lm_unmount(sdp);
 		}
 		}
+		set_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags);
 		fs_err(sdp, "withdrawn\n");
 		fs_err(sdp, "withdrawn\n");
 		dump_stack();
 		dump_stack();
 	}
 	}