summaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_filestream.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2023-02-13 09:14:55 +1100
committerDave Chinner <dchinner@redhat.com>2023-02-13 09:14:55 +1100
commit8f7747ad8c52cde585b9456f6dbd1984af7b97bc (patch)
treeed3c6af2a35b2148556a1ad7688e77bb46e25b51 /fs/xfs/xfs_filestream.c
parent05cf492a8d01f48d4b8d8f0b93f2d75de7349f12 (diff)
downloadlinux-stable-8f7747ad8c52cde585b9456f6dbd1984af7b97bc.tar.gz
linux-stable-8f7747ad8c52cde585b9456f6dbd1984af7b97bc.tar.bz2
linux-stable-8f7747ad8c52cde585b9456f6dbd1984af7b97bc.zip
xfs: move xfs_bmap_btalloc_filestreams() to xfs_filestreams.c
xfs_bmap_btalloc_filestreams() calls two filestreams functions to select the AG to allocate from. Both those functions end up in the same selection function that iterates all AGs multiple times. Worst case, xfs_bmap_btalloc_filestreams() can iterate all AGs 4 times just to select the initial AG to allocate in. Move the AG selection to fs/xfs/xfs_filestreams.c as a single interface so that the inefficient AG interation is contained entirely within the filestreams code. This will allow the implementation to be simplified and made more efficient in future patches. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Diffstat (limited to 'fs/xfs/xfs_filestream.c')
-rw-r--r--fs/xfs/xfs_filestream.c100
1 files changed, 98 insertions, 2 deletions
diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c
index 2eb702034d05..a641404aa9a6 100644
--- a/fs/xfs/xfs_filestream.c
+++ b/fs/xfs/xfs_filestream.c
@@ -12,6 +12,7 @@
#include "xfs_mount.h"
#include "xfs_inode.h"
#include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
#include "xfs_alloc.h"
#include "xfs_mru_cache.h"
#include "xfs_trace.h"
@@ -263,7 +264,7 @@ out:
*
* Returns NULLAGNUMBER in case of an error.
*/
-xfs_agnumber_t
+static xfs_agnumber_t
xfs_filestream_lookup_ag(
struct xfs_inode *ip)
{
@@ -312,7 +313,7 @@ out:
* This is called when the allocator can't find a suitable extent in the
* current AG, and we have to move the stream into a new AG with more space.
*/
-int
+static int
xfs_filestream_new_ag(
struct xfs_bmalloca *ap,
xfs_agnumber_t *agp)
@@ -358,6 +359,101 @@ exit:
return err;
}
+static int
+xfs_filestreams_select_lengths(
+ struct xfs_bmalloca *ap,
+ struct xfs_alloc_arg *args,
+ xfs_extlen_t *blen)
+{
+ struct xfs_mount *mp = ap->ip->i_mount;
+ struct xfs_perag *pag;
+ xfs_agnumber_t start_agno;
+ int error;
+
+ args->total = ap->total;
+
+ start_agno = XFS_FSB_TO_AGNO(mp, ap->blkno);
+ if (start_agno == NULLAGNUMBER)
+ start_agno = 0;
+
+ pag = xfs_perag_grab(mp, start_agno);
+ if (pag) {
+ error = xfs_bmap_longest_free_extent(pag, args->tp, blen);
+ xfs_perag_rele(pag);
+ if (error) {
+ if (error != -EAGAIN)
+ return error;
+ *blen = 0;
+ }
+ }
+
+ if (*blen < args->maxlen) {
+ xfs_agnumber_t agno = start_agno;
+
+ error = xfs_filestream_new_ag(ap, &agno);
+ if (error)
+ return error;
+ if (agno == NULLAGNUMBER)
+ goto out_select;
+
+ pag = xfs_perag_grab(mp, agno);
+ if (!pag)
+ goto out_select;
+
+ error = xfs_bmap_longest_free_extent(pag, args->tp, blen);
+ xfs_perag_rele(pag);
+ if (error) {
+ if (error != -EAGAIN)
+ return error;
+ *blen = 0;
+ }
+ start_agno = agno;
+ }
+
+out_select:
+ /*
+ * Set the failure fallback case to look in the selected AG as stream
+ * may have moved.
+ */
+ ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, start_agno, 0);
+ return 0;
+}
+
+/*
+ * Search for an allocation group with a single extent large enough for
+ * the request. If one isn't found, then the largest available free extent is
+ * returned as the best length possible.
+ */
+int
+xfs_filestream_select_ag(
+ struct xfs_bmalloca *ap,
+ struct xfs_alloc_arg *args,
+ xfs_extlen_t *blen)
+{
+ xfs_agnumber_t start_agno = xfs_filestream_lookup_ag(ap->ip);
+
+ /* Determine the initial block number we will target for allocation. */
+ if (start_agno == NULLAGNUMBER)
+ start_agno = 0;
+ ap->blkno = XFS_AGB_TO_FSB(args->mp, start_agno, 0);
+ xfs_bmap_adjacent(ap);
+
+ /*
+ * If there is very little free space before we start a filestreams
+ * allocation, we're almost guaranteed to fail to find a better AG with
+ * larger free space available so we don't even try.
+ */
+ if (ap->tp->t_flags & XFS_TRANS_LOWMODE)
+ return 0;
+
+ /*
+ * Search for an allocation group with a single extent large enough for
+ * the request. If one isn't found, then adjust the minimum allocation
+ * size to the largest space found.
+ */
+ return xfs_filestreams_select_lengths(ap, args, blen);
+}
+
void
xfs_filestream_deassociate(
struct xfs_inode *ip)