diff mbox series

[02/11] xfs: refactor the predicate part of xfs_free_eofblocks

Message ID 161543195167.1947934.16237799936089844524.stgit@magnolia (mailing list archive)
State New
Headers show
Series xfs: deferred inode inactivation | expand

Commit Message

Darrick J. Wong March 11, 2021, 3:05 a.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

Refactor the part of _free_eofblocks that decides if it's really going
to truncate post-EOF blocks into a separate helper function.  The
upcoming deferred inode inactivation patch requires us to be able to
decide this prior to actual inactivation.  No functionality changes.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/xfs_bmap_util.c |  129 ++++++++++++++++++++++++++++--------------------
 fs/xfs/xfs_bmap_util.h |    1 
 2 files changed, 76 insertions(+), 54 deletions(-)

Comments

Christoph Hellwig March 11, 2021, 1:09 p.m. UTC | #1
On Wed, Mar 10, 2021 at 07:05:51PM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
> 
> Refactor the part of _free_eofblocks that decides if it's really going
> to truncate post-EOF blocks into a separate helper function.  The
> upcoming deferred inode inactivation patch requires us to be able to
> decide this prior to actual inactivation.  No functionality changes.
> 
> Signed-off-by: Darrick J. Wong <djwong@kernel.org>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>
Christoph Hellwig March 15, 2021, 6:46 p.m. UTC | #2
Going further through the series actually made me go back to this one,
so a few more comments:

>  /*
> + * Decide if this inode have post-EOF blocks.  The caller is responsible
> + * for knowing / caring about the PREALLOC/APPEND flags.

Please spell out the XFS_DIFLAG_ here, as this really confused me.  In
fact even with that it still confuses me, as "caller is responsible"
here really means: only call this if you previously called
xfs_can_free_eofblocks and it return true.

Which brings me to the structure of this:  I think without much pain
we can ensure xfs_can_free_eofblocks is always called with the iolock,
in which case we really should merge xfs_can_free_eofblocks and this
new helper to avoid the rather confusing fact that we have two similarly
named helper doing similiar but not the same thing.

>  int
> +xfs_has_eofblocks(
> +	struct xfs_inode	*ip,
> +	bool			*has)

I also think the calling convention can be simplified here.  If an
error occurs we obviously do not want to free the eofblocks.  So
instead of returning two calues we can just return a single bool.
Darrick J. Wong March 18, 2021, 4:33 a.m. UTC | #3
On Mon, Mar 15, 2021 at 06:46:15PM +0000, Christoph Hellwig wrote:
> Going further through the series actually made me go back to this one,
> so a few more comments:
> 
> >  /*
> > + * Decide if this inode have post-EOF blocks.  The caller is responsible
> > + * for knowing / caring about the PREALLOC/APPEND flags.
> 
> Please spell out the XFS_DIFLAG_ here, as this really confused me.  In
> fact even with that it still confuses me, as "caller is responsible"
> here really means: only call this if you previously called
> xfs_can_free_eofblocks and it return true.

Sorry about that; I'll spell them out in the future.

> Which brings me to the structure of this:  I think without much pain
> we can ensure xfs_can_free_eofblocks is always called with the iolock,
> in which case we really should merge xfs_can_free_eofblocks and this
> new helper to avoid the rather confusing fact that we have two similarly
> named helper doing similiar but not the same thing.

I'll have a look into that tomorrow morning. :)

> >  int
> > +xfs_has_eofblocks(
> > +	struct xfs_inode	*ip,
> > +	bool			*has)
> 
> I also think the calling convention can be simplified here.  If an
> error occurs we obviously do not want to free the eofblocks.  So
> instead of returning two calues we can just return a single bool.

Yeah, this area needs some simplification.  Will do.

--D
Darrick J. Wong March 19, 2021, 1:48 a.m. UTC | #4
On Wed, Mar 17, 2021 at 09:33:29PM -0700, Darrick J. Wong wrote:
> On Mon, Mar 15, 2021 at 06:46:15PM +0000, Christoph Hellwig wrote:
> > Going further through the series actually made me go back to this one,
> > so a few more comments:
> > 
> > >  /*
> > > + * Decide if this inode have post-EOF blocks.  The caller is responsible
> > > + * for knowing / caring about the PREALLOC/APPEND flags.
> > 
> > Please spell out the XFS_DIFLAG_ here, as this really confused me.  In
> > fact even with that it still confuses me, as "caller is responsible"
> > here really means: only call this if you previously called
> > xfs_can_free_eofblocks and it return true.
> 
> Sorry about that; I'll spell them out in the future.
> 
> > Which brings me to the structure of this:  I think without much pain
> > we can ensure xfs_can_free_eofblocks is always called with the iolock,
> > in which case we really should merge xfs_can_free_eofblocks and this
> > new helper to avoid the rather confusing fact that we have two similarly
> > named helper doing similiar but not the same thing.
> 
> I'll have a look into that tomorrow morning. :)

The only change that was necessary was moving the can_free_eofblocks
call in the blockgc code until after we've taken the IOLOCK.

> > >  int
> > > +xfs_has_eofblocks(
> > > +	struct xfs_inode	*ip,
> > > +	bool			*has)
> > 
> > I also think the calling convention can be simplified here.  If an
> > error occurs we obviously do not want to free the eofblocks.  So
> > instead of returning two calues we can just return a single bool.
> 
> Yeah, this area needs some simplification.  Will do.

I moved all the stuff in this function upwards into
xfs_can_free_eofblocks and it seems to work ok.

--D

> 
> --D
diff mbox series

Patch

diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index e7d68318e6a5..21aa38183ae9 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -628,27 +628,23 @@  xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
 }
 
 /*
- * This is called to free any blocks beyond eof. The caller must hold
- * IOLOCK_EXCL unless we are in the inode reclaim path and have the only
- * reference to the inode.
+ * Decide if this inode have post-EOF blocks.  The caller is responsible
+ * for knowing / caring about the PREALLOC/APPEND flags.
  */
 int
-xfs_free_eofblocks(
-	struct xfs_inode	*ip)
+xfs_has_eofblocks(
+	struct xfs_inode	*ip,
+	bool			*has)
 {
-	struct xfs_trans	*tp;
-	int			error;
+	struct xfs_bmbt_irec	imap;
+	struct xfs_mount	*mp = ip->i_mount;
 	xfs_fileoff_t		end_fsb;
 	xfs_fileoff_t		last_fsb;
 	xfs_filblks_t		map_len;
 	int			nimaps;
-	struct xfs_bmbt_irec	imap;
-	struct xfs_mount	*mp = ip->i_mount;
+	int			error;
 
-	/*
-	 * Figure out if there are any blocks beyond the end
-	 * of the file.  If not, then there is nothing to do.
-	 */
+	*has = false;
 	end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip));
 	last_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
 	if (last_fsb <= end_fsb)
@@ -660,55 +656,80 @@  xfs_free_eofblocks(
 	error = xfs_bmapi_read(ip, end_fsb, map_len, &imap, &nimaps, 0);
 	xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
+	if (error || nimaps == 0)
+		return error;
+
+	*has = imap.br_startblock != HOLESTARTBLOCK || ip->i_delayed_blks;
+	return 0;
+}
+
+/*
+ * This is called to free any blocks beyond eof. The caller must hold
+ * IOLOCK_EXCL unless we are in the inode reclaim path and have the only
+ * reference to the inode.
+ */
+int
+xfs_free_eofblocks(
+	struct xfs_inode	*ip)
+{
+	struct xfs_trans	*tp;
+	struct xfs_mount	*mp = ip->i_mount;
+	bool			has;
+	int			error;
+
 	/*
 	 * If there are blocks after the end of file, truncate the file to its
 	 * current size to free them up.
 	 */
-	if (!error && (nimaps != 0) &&
-	    (imap.br_startblock != HOLESTARTBLOCK ||
-	     ip->i_delayed_blks)) {
-		/*
-		 * Attach the dquots to the inode up front.
-		 */
-		error = xfs_qm_dqattach(ip);
-		if (error)
-			return error;
+	error = xfs_has_eofblocks(ip, &has);
+	if (error || !has)
+		return error;
 
-		/* wait on dio to ensure i_size has settled */
-		inode_dio_wait(VFS_I(ip));
+	/*
+	 * Attach the dquots to the inode up front.
+	 */
+	error = xfs_qm_dqattach(ip);
+	if (error)
+		return error;
 
-		error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0,
-				&tp);
-		if (error) {
-			ASSERT(XFS_FORCED_SHUTDOWN(mp));
-			return error;
-		}
+	/* wait on dio to ensure i_size has settled */
+	inode_dio_wait(VFS_I(ip));
 
-		xfs_ilock(ip, XFS_ILOCK_EXCL);
-		xfs_trans_ijoin(tp, ip, 0);
-
-		/*
-		 * Do not update the on-disk file size.  If we update the
-		 * on-disk file size and then the system crashes before the
-		 * contents of the file are flushed to disk then the files
-		 * may be full of holes (ie NULL files bug).
-		 */
-		error = xfs_itruncate_extents_flags(&tp, ip, XFS_DATA_FORK,
-					XFS_ISIZE(ip), XFS_BMAPI_NODISCARD);
-		if (error) {
-			/*
-			 * If we get an error at this point we simply don't
-			 * bother truncating the file.
-			 */
-			xfs_trans_cancel(tp);
-		} else {
-			error = xfs_trans_commit(tp);
-			if (!error)
-				xfs_inode_clear_eofblocks_tag(ip);
-		}
-
-		xfs_iunlock(ip, XFS_ILOCK_EXCL);
+	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
+	if (error) {
+		ASSERT(XFS_FORCED_SHUTDOWN(mp));
+		return error;
 	}
+
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
+	xfs_trans_ijoin(tp, ip, 0);
+
+	/*
+	 * Do not update the on-disk file size.  If we update the
+	 * on-disk file size and then the system crashes before the
+	 * contents of the file are flushed to disk then the files
+	 * may be full of holes (ie NULL files bug).
+	 */
+	error = xfs_itruncate_extents_flags(&tp, ip, XFS_DATA_FORK,
+				XFS_ISIZE(ip), XFS_BMAPI_NODISCARD);
+	if (error)
+		goto err_cancel;
+
+	error = xfs_trans_commit(tp);
+	if (error)
+		goto out_unlock;
+
+	xfs_inode_clear_eofblocks_tag(ip);
+	goto out_unlock;
+
+err_cancel:
+	/*
+	 * If we get an error at this point we simply don't
+	 * bother truncating the file.
+	 */
+	xfs_trans_cancel(tp);
+out_unlock:
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	return error;
 }
 
diff --git a/fs/xfs/xfs_bmap_util.h b/fs/xfs/xfs_bmap_util.h
index 9f993168b55b..af07a4a20d7c 100644
--- a/fs/xfs/xfs_bmap_util.h
+++ b/fs/xfs/xfs_bmap_util.h
@@ -63,6 +63,7 @@  int	xfs_insert_file_space(struct xfs_inode *, xfs_off_t offset,
 				xfs_off_t len);
 
 /* EOF block manipulation functions */
+int	xfs_has_eofblocks(struct xfs_inode *ip, bool *has);
 bool	xfs_can_free_eofblocks(struct xfs_inode *ip, bool force);
 int	xfs_free_eofblocks(struct xfs_inode *ip);