Commit 8c2618a6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull gfs2 updates from Andreas Gruenbacher:

 - Make sure transactions won't be started recursively in
   gfs2_block_zero_range (bug introduced in 5.4 when switching to
   iomap_zero_range)

 - Fix a glock holder refcount leak introduced in the iopen glock
   locking scheme rework merged in 5.8.

 - A few other small improvements (debugging, stack usage, comment
   fixes).

* tag 'gfs2-for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: When gfs2_dirty_inode gets a glock error, dump the glock
  gfs2: Never call gfs2_block_zero_range with an open transaction
  gfs2: print details on transactions that aren't properly ended
  gfs2: Fix inaccurate comment
  fs: Fix typo in comment
  gfs2: Fix refcount leak in gfs2_glock_poke
  gfs2: Pass glock holder to gfs2_file_direct_{read,write}
  gfs2: Add some flags missing from glock output
parents 163c3e3d e28c02b9
Loading
Loading
Loading
Loading
+39 −30
Original line number Diff line number Diff line
@@ -1351,9 +1351,15 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
	return ret;
}

/*
 * NOTE: Never call gfs2_block_zero_range with an open transaction because it
 * uses iomap write to perform its actions, which begin their own transactions
 * (iomap_begin, page_prepare, etc.)
 */
static int gfs2_block_zero_range(struct inode *inode, loff_t from,
				 unsigned int length)
{
	BUG_ON(current->journal_info);
	return iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops);
}

@@ -1414,6 +1420,16 @@ static int trunc_start(struct inode *inode, u64 newsize)
	u64 oldsize = inode->i_size;
	int error;

	if (!gfs2_is_stuffed(ip)) {
		unsigned int blocksize = i_blocksize(inode);
		unsigned int offs = newsize & (blocksize - 1);
		if (offs) {
			error = gfs2_block_zero_range(inode, newsize,
						      blocksize - offs);
			if (error)
				return error;
		}
	}
	if (journaled)
		error = gfs2_trans_begin(sdp, RES_DINODE + RES_JDATA, GFS2_JTRUNC_REVOKES);
	else
@@ -1427,19 +1443,10 @@ static int trunc_start(struct inode *inode, u64 newsize)

	gfs2_trans_add_meta(ip->i_gl, dibh);

	if (gfs2_is_stuffed(ip)) {
	if (gfs2_is_stuffed(ip))
		gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + newsize);
	} else {
		unsigned int blocksize = i_blocksize(inode);
		unsigned int offs = newsize & (blocksize - 1);
		if (offs) {
			error = gfs2_block_zero_range(inode, newsize,
						      blocksize - offs);
			if (error)
				goto out;
		}
	else
		ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG;
	}

	i_size_write(inode, newsize);
	ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
@@ -2448,25 +2455,7 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)
	loff_t start, end;
	int error;

	start = round_down(offset, blocksize);
	end = round_up(offset + length, blocksize) - 1;
	error = filemap_write_and_wait_range(inode->i_mapping, start, end);
	if (error)
		return error;

	if (gfs2_is_jdata(ip))
		error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA,
					 GFS2_JTRUNC_REVOKES);
	else
		error = gfs2_trans_begin(sdp, RES_DINODE, 0);
	if (error)
		return error;

	if (gfs2_is_stuffed(ip)) {
		error = stuffed_zero_range(inode, offset, length);
		if (error)
			goto out;
	} else {
	if (!gfs2_is_stuffed(ip)) {
		unsigned int start_off, end_len;

		start_off = offset & (blocksize - 1);
@@ -2489,6 +2478,26 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)
		}
	}

	start = round_down(offset, blocksize);
	end = round_up(offset + length, blocksize) - 1;
	error = filemap_write_and_wait_range(inode->i_mapping, start, end);
	if (error)
		return error;

	if (gfs2_is_jdata(ip))
		error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA,
					 GFS2_JTRUNC_REVOKES);
	else
		error = gfs2_trans_begin(sdp, RES_DINODE, 0);
	if (error)
		return error;

	if (gfs2_is_stuffed(ip)) {
		error = stuffed_zero_range(inode, offset, length);
		if (error)
			goto out;
	}

	if (gfs2_is_jdata(ip)) {
		BUG_ON(!current->journal_info);
		gfs2_journaled_truncate_range(inode, offset, length);
+15 −16
Original line number Diff line number Diff line
@@ -781,39 +781,39 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
	return ret ? ret : ret1;
}

static ssize_t gfs2_file_direct_read(struct kiocb *iocb, struct iov_iter *to)
static ssize_t gfs2_file_direct_read(struct kiocb *iocb, struct iov_iter *to,
				     struct gfs2_holder *gh)
{
	struct file *file = iocb->ki_filp;
	struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
	size_t count = iov_iter_count(to);
	struct gfs2_holder gh;
	ssize_t ret;

	if (!count)
		return 0; /* skip atime */

	gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, &gh);
	ret = gfs2_glock_nq(&gh);
	gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, gh);
	ret = gfs2_glock_nq(gh);
	if (ret)
		goto out_uninit;

	ret = iomap_dio_rw(iocb, to, &gfs2_iomap_ops, NULL,
			   is_sync_kiocb(iocb));

	gfs2_glock_dq(&gh);
	gfs2_glock_dq(gh);
out_uninit:
	gfs2_holder_uninit(&gh);
	gfs2_holder_uninit(gh);
	return ret;
}

static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
				      struct gfs2_holder *gh)
{
	struct file *file = iocb->ki_filp;
	struct inode *inode = file->f_mapping->host;
	struct gfs2_inode *ip = GFS2_I(inode);
	size_t len = iov_iter_count(from);
	loff_t offset = iocb->ki_pos;
	struct gfs2_holder gh;
	ssize_t ret;

	/*
@@ -824,8 +824,8 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
	 * unfortunately, have the option of only flushing a range like the
	 * VFS does.
	 */
	gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, &gh);
	ret = gfs2_glock_nq(&gh);
	gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, 0, gh);
	ret = gfs2_glock_nq(gh);
	if (ret)
		goto out_uninit;

@@ -838,9 +838,9 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
	if (ret == -ENOTBLK)
		ret = 0;
out:
	gfs2_glock_dq(&gh);
	gfs2_glock_dq(gh);
out_uninit:
	gfs2_holder_uninit(&gh);
	gfs2_holder_uninit(gh);
	return ret;
}

@@ -852,7 +852,7 @@ static ssize_t gfs2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
	ssize_t ret;

	if (iocb->ki_flags & IOCB_DIRECT) {
		ret = gfs2_file_direct_read(iocb, to);
		ret = gfs2_file_direct_read(iocb, to, &gh);
		if (likely(ret != -ENOTBLK))
			return ret;
		iocb->ki_flags &= ~IOCB_DIRECT;
@@ -901,13 +901,12 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
	struct file *file = iocb->ki_filp;
	struct inode *inode = file_inode(file);
	struct gfs2_inode *ip = GFS2_I(inode);
	struct gfs2_holder gh;
	ssize_t ret;

	gfs2_size_hint(file, iocb->ki_pos, iov_iter_count(from));

	if (iocb->ki_flags & IOCB_APPEND) {
		struct gfs2_holder gh;

		ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
		if (ret)
			return ret;
@@ -931,7 +930,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
		struct address_space *mapping = file->f_mapping;
		ssize_t buffered, ret2;

		ret = gfs2_file_direct_write(iocb, from);
		ret = gfs2_file_direct_write(iocb, from, &gh);
		if (ret < 0 || !iov_iter_count(from))
			goto out_unlock;

+9 −1
Original line number Diff line number Diff line
@@ -790,9 +790,11 @@ static void gfs2_glock_poke(struct gfs2_glock *gl)
	struct gfs2_holder gh;
	int error;

	error = gfs2_glock_nq_init(gl, LM_ST_SHARED, flags, &gh);
	gfs2_holder_init(gl, LM_ST_SHARED, flags, &gh);
	error = gfs2_glock_nq(&gh);
	if (!error)
		gfs2_glock_dq(&gh);
	gfs2_holder_uninit(&gh);
}

static bool gfs2_try_evict(struct gfs2_glock *gl)
@@ -2106,6 +2108,12 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl)
		*p++ = 'o';
	if (test_bit(GLF_BLOCKING, gflags))
		*p++ = 'b';
	if (test_bit(GLF_INODE_CREATING, gflags))
		*p++ = 'c';
	if (test_bit(GLF_PENDING_DELETE, gflags))
		*p++ = 'P';
	if (test_bit(GLF_FREEING, gflags))
		*p++ = 'x';
	*p = 0;
	return buf;
}
+1 −1
Original line number Diff line number Diff line
@@ -1092,7 +1092,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
 * or the total number of used blocks (pinned blocks plus AIL blocks)
 * is greater than thresh2.
 *
 * At mount time thresh1 is 1/3rd of journal size, thresh2 is 2/3rd of
 * At mount time thresh1 is 2/5ths of journal size, thresh2 is 4/5ths of
 * journal size.
 *
 * Returns: errno
+1 −0
Original line number Diff line number Diff line
@@ -566,6 +566,7 @@ static void gfs2_dirty_inode(struct inode *inode, int flags)
		ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
		if (ret) {
			fs_err(sdp, "dirty_inode: glock %d\n", ret);
			gfs2_dump_glock(NULL, ip->i_gl, true);
			return;
		}
		need_unlock = 1;
Loading