From: Christoph Hellwig <hch@lst.de>
Cc: linux-xfs@vger.kernel.org, Brian Foster <bfoster@redhat.com>,
"Darrick J . Wong" <darrick.wong@oracle.com>
Subject: [PATCH 03/27] xfs: pull up iolock from xfs_free_eofblocks()
Date: Mon, 27 Mar 2017 10:48:58 +0200 [thread overview]
Message-ID: <20170327084922.11691-4-hch@lst.de> (raw)
In-Reply-To: <20170327084922.11691-1-hch@lst.de>
From: Brian Foster <bfoster@redhat.com>
commit a36b926180cda375ac2ec89e1748b47137cfc51c upstream.
xfs_free_eofblocks() requires the IOLOCK_EXCL lock, but is called from
different contexts where the lock may or may not be held. The
need_iolock parameter exists for this reason, to indicate whether
xfs_free_eofblocks() must acquire the iolock itself before it can
proceed.
This is ugly and confusing. Simplify the semantics of
xfs_free_eofblocks() to require the caller to acquire the iolock
appropriately and kill the need_iolock parameter. While here, the mp
param can be removed as well as the xfs_mount is accessible from the
xfs_inode structure. This patch does not change behavior.
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
fs/xfs/xfs_bmap_util.c | 41 ++++++++++++++++------------------------
fs/xfs/xfs_bmap_util.h | 3 +--
fs/xfs/xfs_icache.c | 24 +++++++++++++++---------
fs/xfs/xfs_inode.c | 51 +++++++++++++++++++++++++++-----------------------
4 files changed, 60 insertions(+), 59 deletions(-)
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index efb8ccd6bbf2..d8ac76ca05a2 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -917,17 +917,18 @@ xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
*/
int
xfs_free_eofblocks(
- xfs_mount_t *mp,
- xfs_inode_t *ip,
- bool need_iolock)
+ struct xfs_inode *ip)
{
- xfs_trans_t *tp;
- int error;
- xfs_fileoff_t end_fsb;
- xfs_fileoff_t last_fsb;
- xfs_filblks_t map_len;
- int nimaps;
- xfs_bmbt_irec_t imap;
+ struct xfs_trans *tp;
+ int error;
+ 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;
+
+ ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
/*
* Figure out if there are any blocks beyond the end
@@ -944,6 +945,10 @@ xfs_free_eofblocks(
error = xfs_bmapi_read(ip, end_fsb, map_len, &imap, &nimaps, 0);
xfs_iunlock(ip, XFS_ILOCK_SHARED);
+ /*
+ * 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)) {
@@ -954,22 +959,10 @@ xfs_free_eofblocks(
if (error)
return error;
- /*
- * There are blocks after the end of file.
- * Free them up now by truncating the file to
- * its current size.
- */
- if (need_iolock) {
- if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL))
- return -EAGAIN;
- }
-
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0,
&tp);
if (error) {
ASSERT(XFS_FORCED_SHUTDOWN(mp));
- if (need_iolock)
- xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return error;
}
@@ -997,8 +990,6 @@ xfs_free_eofblocks(
}
xfs_iunlock(ip, XFS_ILOCK_EXCL);
- if (need_iolock)
- xfs_iunlock(ip, XFS_IOLOCK_EXCL);
}
return error;
}
@@ -1415,7 +1406,7 @@ xfs_shift_file_space(
* into the accessible region of the file.
*/
if (xfs_can_free_eofblocks(ip, true)) {
- error = xfs_free_eofblocks(mp, ip, false);
+ error = xfs_free_eofblocks(ip);
if (error)
return error;
}
diff --git a/fs/xfs/xfs_bmap_util.h b/fs/xfs/xfs_bmap_util.h
index 68a621a8e0c0..f1005393785c 100644
--- a/fs/xfs/xfs_bmap_util.h
+++ b/fs/xfs/xfs_bmap_util.h
@@ -63,8 +63,7 @@ int xfs_insert_file_space(struct xfs_inode *, xfs_off_t offset,
/* EOF block manipulation functions */
bool xfs_can_free_eofblocks(struct xfs_inode *ip, bool force);
-int xfs_free_eofblocks(struct xfs_mount *mp, struct xfs_inode *ip,
- bool need_iolock);
+int xfs_free_eofblocks(struct xfs_inode *ip);
int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
struct xfs_swapext *sx);
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 29cc9886a3cb..e4b382aabf9f 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -1324,7 +1324,7 @@ xfs_inode_free_eofblocks(
int flags,
void *args)
{
- int ret;
+ int ret = 0;
struct xfs_eofblocks *eofb = args;
bool need_iolock = true;
int match;
@@ -1360,19 +1360,25 @@ xfs_inode_free_eofblocks(
return 0;
/*
- * A scan owner implies we already hold the iolock. Skip it in
- * xfs_free_eofblocks() to avoid deadlock. This also eliminates
- * the possibility of EAGAIN being returned.
+ * A scan owner implies we already hold the iolock. Skip it here
+ * to avoid deadlock.
*/
if (eofb->eof_scan_owner == ip->i_ino)
need_iolock = false;
}
- ret = xfs_free_eofblocks(ip->i_mount, ip, need_iolock);
-
- /* don't revisit the inode if we're not waiting */
- if (ret == -EAGAIN && !(flags & SYNC_WAIT))
- ret = 0;
+ /*
+ * If the caller is waiting, return -EAGAIN to keep the background
+ * scanner moving and revisit the inode in a subsequent pass.
+ */
+ if (need_iolock && !xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
+ if (flags & SYNC_WAIT)
+ ret = -EAGAIN;
+ return ret;
+ }
+ ret = xfs_free_eofblocks(ip);
+ if (need_iolock)
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return ret;
}
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index a1c7e138dbca..f9f44cb56fe8 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1701,32 +1701,34 @@ xfs_release(
if (xfs_can_free_eofblocks(ip, false)) {
/*
+ * Check if the inode is being opened, written and closed
+ * frequently and we have delayed allocation blocks outstanding
+ * (e.g. streaming writes from the NFS server), truncating the
+ * blocks past EOF will cause fragmentation to occur.
+ *
+ * In this case don't do the truncation, but we have to be
+ * careful how we detect this case. Blocks beyond EOF show up as
+ * i_delayed_blks even when the inode is clean, so we need to
+ * truncate them away first before checking for a dirty release.
+ * Hence on the first dirty close we will still remove the
+ * speculative allocation, but after that we will leave it in
+ * place.
+ */
+ if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE))
+ return 0;
+ /*
* If we can't get the iolock just skip truncating the blocks
* past EOF because we could deadlock with the mmap_sem
- * otherwise. We'll get another chance to drop them once the
+ * otherwise. We'll get another chance to drop them once the
* last reference to the inode is dropped, so we'll never leak
* blocks permanently.
- *
- * Further, check if the inode is being opened, written and
- * closed frequently and we have delayed allocation blocks
- * outstanding (e.g. streaming writes from the NFS server),
- * truncating the blocks past EOF will cause fragmentation to
- * occur.
- *
- * In this case don't do the truncation, either, but we have to
- * be careful how we detect this case. Blocks beyond EOF show
- * up as i_delayed_blks even when the inode is clean, so we
- * need to truncate them away first before checking for a dirty
- * release. Hence on the first dirty close we will still remove
- * the speculative allocation, but after that we will leave it
- * in place.
*/
- if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE))
- return 0;
-
- error = xfs_free_eofblocks(mp, ip, true);
- if (error && error != -EAGAIN)
- return error;
+ if (xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
+ error = xfs_free_eofblocks(ip);
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+ if (error)
+ return error;
+ }
/* delalloc blocks after truncation means it really is dirty */
if (ip->i_delayed_blks)
@@ -1913,8 +1915,11 @@ xfs_inactive(
* cache. Post-eof blocks must be freed, lest we end up with
* broken free space accounting.
*/
- if (xfs_can_free_eofblocks(ip, true))
- xfs_free_eofblocks(mp, ip, false);
+ if (xfs_can_free_eofblocks(ip, true)) {
+ xfs_ilock(ip, XFS_IOLOCK_EXCL);
+ xfs_free_eofblocks(ip);
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+ }
return;
}
--
2.11.0
next prev parent reply other threads:[~2017-03-27 8:50 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-03-27 8:48 Christoph Hellwig
2017-03-27 8:48 ` [PATCH 01/27] xfs: only update mount/resv fields on success in __xfs_ag_resv_init Christoph Hellwig
2017-03-27 8:48 ` [PATCH 02/27] xfs: use per-AG reservations for the finobt Christoph Hellwig
2017-03-27 8:48 ` Christoph Hellwig [this message]
2017-03-27 8:48 ` [PATCH 04/27] xfs: sync eofblocks scans under iolock are livelock prone Christoph Hellwig
2017-03-27 8:49 ` [PATCH 05/27] xfs: fix eofblocks race with file extending async dio writes Christoph Hellwig
2017-03-27 8:49 ` [PATCH 06/27] xfs: fix toctou race when locking an inode to access the data map Christoph Hellwig
2017-03-27 8:49 ` [PATCH 07/27] xfs: fail _dir_open when readahead fails Christoph Hellwig
2017-03-27 8:49 ` [PATCH 08/27] xfs: filter out obviously bad btree pointers Christoph Hellwig
2017-03-27 8:49 ` [PATCH 09/27] xfs: check for obviously bad level values in the bmbt root Christoph Hellwig
2017-03-27 8:49 ` [PATCH 10/27] xfs: verify free block header fields Christoph Hellwig
2017-03-27 8:49 ` [PATCH 11/27] xfs: allow unwritten extents in the CoW fork Christoph Hellwig
2017-03-27 8:49 ` [PATCH 12/27] xfs: mark speculative prealloc CoW fork extents unwritten Christoph Hellwig
2017-03-27 8:49 ` [PATCH 13/27] xfs: reset b_first_retry_time when clear the retry status of xfs_buf_t Christoph Hellwig
2017-03-27 8:49 ` [PATCH 14/27] xfs: reject all unaligned direct writes to reflinked files Christoph Hellwig
2017-03-27 8:49 ` [PATCH 15/27] xfs: update ctime and mtime on clone destinatation inodes Christoph Hellwig
2017-03-27 8:49 ` [PATCH 16/27] xfs: don't fail xfs_extent_busy allocation Christoph Hellwig
2017-03-27 8:49 ` [PATCH 17/27] xfs: handle indlen shortage on delalloc extent merge Christoph Hellwig
2017-03-27 8:49 ` [PATCH 18/27] xfs: split indlen reservations fairly when under reserved Christoph Hellwig
2017-03-27 8:49 ` [PATCH 19/27] xfs: fix uninitialized variable in _reflink_convert_cow Christoph Hellwig
2017-03-27 8:49 ` [PATCH 20/27] xfs: don't reserve blocks for right shift transactions Christoph Hellwig
2017-03-27 8:49 ` [PATCH 21/27] xfs: Use xfs_icluster_size_fsb() to calculate inode chunk alignment Christoph Hellwig
2017-03-27 8:49 ` [PATCH 22/27] xfs: tune down agno asserts in the bmap code Christoph Hellwig
2017-03-27 8:49 ` [PATCH 23/27] xfs: only reclaim unwritten COW extents periodically Christoph Hellwig
2017-03-27 8:49 ` [PATCH 24/27] xfs: fix and streamline error handling in xfs_end_io Christoph Hellwig
2017-03-27 8:49 ` [PATCH 25/27] xfs: Use xfs_icluster_size_fsb() to calculate inode alignment mask Christoph Hellwig
2017-03-27 8:49 ` [PATCH 26/27] xfs: use iomap new flag for newly allocated delalloc blocks Christoph Hellwig
2017-03-27 8:49 ` [PATCH 27/27] xfs: try any AG when allocating the first btree block when reflinking Christoph Hellwig
-- strict thread matches above, loose matches on Subject: below --
2017-04-01 6:39 4.9-stable updates for XFS Christoph Hellwig
2017-04-01 6:40 ` [PATCH 03/27] xfs: pull up iolock from xfs_free_eofblocks() Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170327084922.11691-4-hch@lst.de \
--to=hch@lst.de \
--cc=bfoster@redhat.com \
--cc=darrick.wong@oracle.com \
--cc=linux-xfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).