^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2006-2007 Silicon Graphics, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2014 Christoph Hellwig.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * All Rights Reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include "xfs.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include "xfs_shared.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include "xfs_format.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "xfs_log_format.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "xfs_trans_resv.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "xfs_sb.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "xfs_mount.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "xfs_inode.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "xfs_bmap.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "xfs_alloc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "xfs_mru_cache.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "xfs_trace.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "xfs_ag_resv.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "xfs_trans.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "xfs_filestream.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct xfs_fstrm_item {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct xfs_mru_cache_elem mru;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) xfs_agnumber_t ag; /* AG in use for this directory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) enum xfs_fstrm_alloc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) XFS_PICK_USERDATA = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) XFS_PICK_LOWSPACE = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * Allocation group filestream associations are tracked with per-ag atomic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * counters. These counters allow xfs_filestream_pick_ag() to tell whether a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * particular AG already has active filestreams associated with it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) xfs_filestream_peek_ag(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) xfs_mount_t *mp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) xfs_agnumber_t agno)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct xfs_perag *pag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) pag = xfs_perag_get(mp, agno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) ret = atomic_read(&pag->pagf_fstrms);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) xfs_perag_put(pag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) xfs_filestream_get_ag(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) xfs_mount_t *mp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) xfs_agnumber_t agno)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct xfs_perag *pag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) pag = xfs_perag_get(mp, agno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) ret = atomic_inc_return(&pag->pagf_fstrms);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) xfs_perag_put(pag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) xfs_filestream_put_ag(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) xfs_mount_t *mp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) xfs_agnumber_t agno)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct xfs_perag *pag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) pag = xfs_perag_get(mp, agno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) atomic_dec(&pag->pagf_fstrms);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) xfs_perag_put(pag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) xfs_fstrm_free_func(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) void *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct xfs_mru_cache_elem *mru)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct xfs_mount *mp = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct xfs_fstrm_item *item =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) container_of(mru, struct xfs_fstrm_item, mru);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) xfs_filestream_put_ag(mp, item->ag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) trace_xfs_filestream_free(mp, mru->key, item->ag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) kmem_free(item);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * Scan the AGs starting at startag looking for an AG that isn't in use and has
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * at least minlen blocks free.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) xfs_filestream_pick_ag(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct xfs_inode *ip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) xfs_agnumber_t startag,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) xfs_agnumber_t *agp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) int flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) xfs_extlen_t minlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) struct xfs_mount *mp = ip->i_mount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct xfs_fstrm_item *item;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct xfs_perag *pag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) xfs_extlen_t longest, free = 0, minfree, maxfree = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) xfs_agnumber_t ag, max_ag = NULLAGNUMBER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) int err, trylock, nscan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) ASSERT(S_ISDIR(VFS_I(ip)->i_mode));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* 2% of an AG's blocks must be free for it to be chosen. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) minfree = mp->m_sb.sb_agblocks / 50;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) ag = startag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) *agp = NULLAGNUMBER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* For the first pass, don't sleep trying to init the per-AG. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) trylock = XFS_ALLOC_FLAG_TRYLOCK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) for (nscan = 0; 1; nscan++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) trace_xfs_filestream_scan(mp, ip->i_ino, ag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) pag = xfs_perag_get(mp, ag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (!pag->pagf_init) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) err = xfs_alloc_pagf_init(mp, NULL, ag, trylock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) xfs_perag_put(pag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (err != -EAGAIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /* Couldn't lock the AGF, skip this AG. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* Keep track of the AG with the most free blocks. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (pag->pagf_freeblks > maxfree) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) maxfree = pag->pagf_freeblks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) max_ag = ag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * The AG reference count does two things: it enforces mutual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * exclusion when examining the suitability of an AG in this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * loop, and it guards against two filestreams being established
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * in the same AG as each other.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (xfs_filestream_get_ag(mp, ag) > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) xfs_filestream_put_ag(mp, ag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) goto next_ag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) longest = xfs_alloc_longest_free_extent(pag,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) xfs_alloc_min_freelist(mp, pag),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (((minlen && longest >= minlen) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) (!minlen && pag->pagf_freeblks >= minfree)) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) (!pag->pagf_metadata || !(flags & XFS_PICK_USERDATA) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) (flags & XFS_PICK_LOWSPACE))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /* Break out, retaining the reference on the AG. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) free = pag->pagf_freeblks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) xfs_perag_put(pag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) *agp = ag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /* Drop the reference on this AG, it's not usable. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) xfs_filestream_put_ag(mp, ag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) next_ag:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) xfs_perag_put(pag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /* Move to the next AG, wrapping to AG 0 if necessary. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (++ag >= mp->m_sb.sb_agcount)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) ag = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /* If a full pass of the AGs hasn't been done yet, continue. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (ag != startag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) /* Allow sleeping in xfs_alloc_pagf_init() on the 2nd pass. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (trylock != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) trylock = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) /* Finally, if lowspace wasn't set, set it for the 3rd pass. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (!(flags & XFS_PICK_LOWSPACE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) flags |= XFS_PICK_LOWSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) * Take the AG with the most free space, regardless of whether
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * it's already in use by another filestream.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (max_ag != NULLAGNUMBER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) xfs_filestream_get_ag(mp, max_ag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) free = maxfree;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) *agp = max_ag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /* take AG 0 if none matched */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) trace_xfs_filestream_pick(ip, *agp, free, nscan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) *agp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) trace_xfs_filestream_pick(ip, *agp, free, nscan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (*agp == NULLAGNUMBER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) item = kmem_alloc(sizeof(*item), KM_MAYFAIL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (!item)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) goto out_put_ag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) item->ag = *agp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) err = xfs_mru_cache_insert(mp->m_filestream, ip->i_ino, &item->mru);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (err == -EEXIST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) goto out_free_item;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) out_free_item:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) kmem_free(item);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) out_put_ag:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) xfs_filestream_put_ag(mp, *agp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static struct xfs_inode *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) xfs_filestream_get_parent(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct xfs_inode *ip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) struct inode *inode = VFS_I(ip), *dir = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) struct dentry *dentry, *parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) dentry = d_find_alias(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (!dentry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) parent = dget_parent(dentry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (!parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) goto out_dput;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) dir = igrab(d_inode(parent));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) dput(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) out_dput:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) dput(dentry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) return dir ? XFS_I(dir) : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) * Find the right allocation group for a file, either by finding an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) * existing file stream or creating a new one.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) * Returns NULLAGNUMBER in case of an error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) xfs_agnumber_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) xfs_filestream_lookup_ag(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) struct xfs_inode *ip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) struct xfs_mount *mp = ip->i_mount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) struct xfs_inode *pip = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) xfs_agnumber_t startag, ag = NULLAGNUMBER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) struct xfs_mru_cache_elem *mru;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) ASSERT(S_ISREG(VFS_I(ip)->i_mode));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) pip = xfs_filestream_get_parent(ip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (!pip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return NULLAGNUMBER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (mru) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) ag = container_of(mru, struct xfs_fstrm_item, mru)->ag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) xfs_mru_cache_done(mp->m_filestream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) trace_xfs_filestream_lookup(mp, ip->i_ino, ag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) * Set the starting AG using the rotor for inode32, otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) * use the directory inode's AG.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (mp->m_flags & XFS_MOUNT_32BITINODES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) xfs_agnumber_t rotorstep = xfs_rotorstep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) startag = (mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) mp->m_agfrotor = (mp->m_agfrotor + 1) %
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) (mp->m_sb.sb_agcount * rotorstep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) startag = XFS_INO_TO_AGNO(mp, pip->i_ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (xfs_filestream_pick_ag(pip, startag, &ag, 0, 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) ag = NULLAGNUMBER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) xfs_irele(pip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) return ag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) * Pick a new allocation group for the current file and its file stream.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) * This is called when the allocator can't find a suitable extent in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) * current AG, and we have to move the stream into a new AG with more space.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) xfs_filestream_new_ag(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) struct xfs_bmalloca *ap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) xfs_agnumber_t *agp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) struct xfs_inode *ip = ap->ip, *pip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) struct xfs_mount *mp = ip->i_mount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) xfs_extlen_t minlen = ap->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) xfs_agnumber_t startag = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) int flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) struct xfs_mru_cache_elem *mru;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) *agp = NULLAGNUMBER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) pip = xfs_filestream_get_parent(ip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (!pip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) mru = xfs_mru_cache_remove(mp->m_filestream, pip->i_ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) if (mru) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) struct xfs_fstrm_item *item =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) container_of(mru, struct xfs_fstrm_item, mru);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) startag = (item->ag + 1) % mp->m_sb.sb_agcount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (ap->datatype & XFS_ALLOC_USERDATA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) flags |= XFS_PICK_USERDATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) if (ap->tp->t_flags & XFS_TRANS_LOWMODE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) flags |= XFS_PICK_LOWSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) err = xfs_filestream_pick_ag(pip, startag, agp, flags, minlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) * Only free the item here so we skip over the old AG earlier.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (mru)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) xfs_fstrm_free_func(mp, mru);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) xfs_irele(pip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if (*agp == NULLAGNUMBER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) *agp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) xfs_filestream_deassociate(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) struct xfs_inode *ip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) xfs_mru_cache_delete(ip->i_mount->m_filestream, ip->i_ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) xfs_filestream_mount(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) xfs_mount_t *mp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) * The filestream timer tunable is currently fixed within the range of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) * one second to four minutes, with five seconds being the default. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) * group count is somewhat arbitrary, but it'd be nice to adhere to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * timer tunable to within about 10 percent. This requires at least 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) * groups.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) return xfs_mru_cache_create(&mp->m_filestream, mp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) xfs_fstrm_centisecs * 10, 10, xfs_fstrm_free_func);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) xfs_filestream_unmount(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) xfs_mount_t *mp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) xfs_mru_cache_destroy(mp->m_filestream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }