LCOV - code coverage report
Current view: top level - fs/xfs - xfs_filestream.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-acha @ Mon Jul 31 20:08:06 PDT 2023 Lines: 146 173 84.4 %
Date: 2023-07-31 20:08:07 Functions: 9 9 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (c) 2006-2007 Silicon Graphics, Inc.
       4             :  * Copyright (c) 2014 Christoph Hellwig.
       5             :  * All Rights Reserved.
       6             :  */
       7             : #include "xfs.h"
       8             : #include "xfs_shared.h"
       9             : #include "xfs_format.h"
      10             : #include "xfs_log_format.h"
      11             : #include "xfs_trans_resv.h"
      12             : #include "xfs_mount.h"
      13             : #include "xfs_inode.h"
      14             : #include "xfs_bmap.h"
      15             : #include "xfs_bmap_util.h"
      16             : #include "xfs_alloc.h"
      17             : #include "xfs_mru_cache.h"
      18             : #include "xfs_trace.h"
      19             : #include "xfs_ag.h"
      20             : #include "xfs_ag_resv.h"
      21             : #include "xfs_trans.h"
      22             : #include "xfs_filestream.h"
      23             : 
      24             : struct xfs_fstrm_item {
      25             :         struct xfs_mru_cache_elem       mru;
      26             :         struct xfs_perag                *pag; /* AG in use for this directory */
      27             : };
      28             : 
      29             : enum xfs_fstrm_alloc {
      30             :         XFS_PICK_USERDATA = 1,
      31             :         XFS_PICK_LOWSPACE = 2,
      32             : };
      33             : 
      34             : static void
      35        1667 : xfs_fstrm_free_func(
      36             :         void                    *data,
      37             :         struct xfs_mru_cache_elem *mru)
      38             : {
      39        1667 :         struct xfs_fstrm_item   *item =
      40        1667 :                 container_of(mru, struct xfs_fstrm_item, mru);
      41        1667 :         struct xfs_perag        *pag = item->pag;
      42             : 
      43        1667 :         trace_xfs_filestream_free(pag, mru->key);
      44        1667 :         atomic_dec(&pag->pagf_fstrms);
      45        1667 :         xfs_perag_rele(pag);
      46             : 
      47        1667 :         kmem_free(item);
      48        1667 : }
      49             : 
      50             : /*
      51             :  * Scan the AGs starting at start_agno looking for an AG that isn't in use and
      52             :  * has at least minlen blocks free. If no AG is found to match the allocation
      53             :  * requirements, pick the AG with the most free space in it.
      54             :  */
      55             : static int
      56        1666 : xfs_filestream_pick_ag(
      57             :         struct xfs_alloc_arg    *args,
      58             :         xfs_ino_t               pino,
      59             :         xfs_agnumber_t          start_agno,
      60             :         int                     flags,
      61             :         xfs_extlen_t            *longest)
      62             : {
      63        1666 :         struct xfs_mount        *mp = args->mp;
      64        1666 :         struct xfs_perag        *pag;
      65        1666 :         struct xfs_perag        *max_pag = NULL;
      66        1666 :         xfs_extlen_t            minlen = *longest;
      67        1666 :         xfs_extlen_t            free = 0, minfree, maxfree = 0;
      68        1666 :         xfs_agnumber_t          agno;
      69        1666 :         bool                    first_pass = true;
      70        1666 :         int                     err;
      71             : 
      72             :         /* 2% of an AG's blocks must be free for it to be chosen. */
      73        1666 :         minfree = mp->m_sb.sb_agblocks / 50;
      74             : 
      75             : restart:
      76       78457 :         for_each_perag_wrap(mp, start_agno, agno, pag) {
      77       77170 :                 trace_xfs_filestream_scan(pag, pino);
      78       77170 :                 *longest = 0;
      79       77170 :                 err = xfs_bmap_longest_free_extent(pag, NULL, longest);
      80       77168 :                 if (err) {
      81           0 :                         if (err != -EAGAIN)
      82             :                                 break;
      83             :                         /* Couldn't lock the AGF, skip this AG. */
      84           0 :                         err = 0;
      85           0 :                         continue;
      86             :                 }
      87             : 
      88             :                 /* Keep track of the AG with the most free blocks. */
      89       77168 :                 if (pag->pagf_freeblks > maxfree) {
      90        5011 :                         maxfree = pag->pagf_freeblks;
      91        5011 :                         if (max_pag)
      92        3344 :                                 xfs_perag_rele(max_pag);
      93        5011 :                         atomic_inc(&pag->pag_active_ref);
      94             :                         max_pag = pag;
      95             :                 }
      96             : 
      97             :                 /*
      98             :                  * The AG reference count does two things: it enforces mutual
      99             :                  * exclusion when examining the suitability of an AG in this
     100             :                  * loop, and it guards against two filestreams being established
     101             :                  * in the same AG as each other.
     102             :                  */
     103      154337 :                 if (atomic_inc_return(&pag->pagf_fstrms) <= 1) {
     104       60538 :                         if (((minlen && *longest >= minlen) ||
     105        1238 :                              (!minlen && pag->pagf_freeblks >= minfree)) &&
     106             :                             (!xfs_perag_prefers_metadata(pag) ||
     107           0 :                              !(flags & XFS_PICK_USERDATA) ||
     108             :                              (flags & XFS_PICK_LOWSPACE))) {
     109             :                                 /* Break out, retaining the reference on the AG. */
     110        1238 :                                 free = pag->pagf_freeblks;
     111        1238 :                                 break;
     112             :                         }
     113             :                 }
     114             : 
     115             :                 /* Drop the reference on this AG, it's not usable. */
     116       75932 :                 atomic_dec(&pag->pagf_fstrms);
     117             :         }
     118             : 
     119        2525 :         if (err) {
     120           0 :                 xfs_perag_rele(pag);
     121           0 :                 if (max_pag)
     122           0 :                         xfs_perag_rele(max_pag);
     123           0 :                 return err;
     124             :         }
     125             : 
     126        2525 :         if (!pag) {
     127             :                 /*
     128             :                  * Allow a second pass to give xfs_bmap_longest_free_extent()
     129             :                  * another attempt at locking AGFs that it might have skipped
     130             :                  * over before we fail.
     131             :                  */
     132        1287 :                 if (first_pass) {
     133         429 :                         first_pass = false;
     134         429 :                         goto restart;
     135             :                 }
     136             : 
     137             :                 /*
     138             :                  * We must be low on data space, so run a final lowspace
     139             :                  * optimised selection pass if we haven't already.
     140             :                  */
     141         858 :                 if (!(flags & XFS_PICK_LOWSPACE)) {
     142         429 :                         flags |= XFS_PICK_LOWSPACE;
     143         429 :                         goto restart;
     144             :                 }
     145             : 
     146             :                 /*
     147             :                  * No unassociated AGs are available, so select the AG with the
     148             :                  * most free space, regardless of whether it's already in use by
     149             :                  * another filestream. It none suit, just use whatever AG we can
     150             :                  * grab.
     151             :                  */
     152         429 :                 if (!max_pag) {
     153           0 :                         for_each_perag_wrap(args->mp, 0, start_agno, args->pag)
     154             :                                 break;
     155           0 :                         atomic_inc(&args->pag->pagf_fstrms);
     156           0 :                         *longest = 0;
     157             :                 } else {
     158         429 :                         pag = max_pag;
     159         429 :                         free = maxfree;
     160         429 :                         atomic_inc(&pag->pagf_fstrms);
     161             :                 }
     162        1238 :         } else if (max_pag) {
     163        1238 :                 xfs_perag_rele(max_pag);
     164             :         }
     165             : 
     166        1667 :         trace_xfs_filestream_pick(pag, pino, free);
     167        1667 :         args->pag = pag;
     168        1667 :         return 0;
     169             : 
     170             : }
     171             : 
     172             : static struct xfs_inode *
     173       11222 : xfs_filestream_get_parent(
     174             :         struct xfs_inode        *ip)
     175             : {
     176       11222 :         struct inode            *inode = VFS_I(ip), *dir = NULL;
     177       11222 :         struct dentry           *dentry, *parent;
     178             : 
     179       11222 :         dentry = d_find_alias(inode);
     180       11222 :         if (!dentry)
     181           0 :                 goto out;
     182             : 
     183       11222 :         parent = dget_parent(dentry);
     184       11224 :         if (!parent)
     185           0 :                 goto out_dput;
     186             : 
     187       11224 :         dir = igrab(d_inode(parent));
     188       11221 :         dput(parent);
     189             : 
     190       11222 : out_dput:
     191       11222 :         dput(dentry);
     192             : out:
     193       11225 :         return dir ? XFS_I(dir) : NULL;
     194             : }
     195             : 
     196             : /*
     197             :  * Lookup the mru cache for an existing association. If one exists and we can
     198             :  * use it, return with an active perag reference indicating that the allocation
     199             :  * will proceed with that association.
     200             :  *
     201             :  * If we have no association, or we cannot use the current one and have to
     202             :  * destroy it, return with longest = 0 to tell the caller to create a new
     203             :  * association.
     204             :  */
     205             : static int
     206       11220 : xfs_filestream_lookup_association(
     207             :         struct xfs_bmalloca     *ap,
     208             :         struct xfs_alloc_arg    *args,
     209             :         xfs_ino_t               pino,
     210             :         xfs_extlen_t            *longest)
     211             : {
     212       11220 :         struct xfs_mount        *mp = args->mp;
     213       11220 :         struct xfs_perag        *pag;
     214       11220 :         struct xfs_mru_cache_elem *mru;
     215       11220 :         int                     error = 0;
     216             : 
     217       11220 :         *longest = 0;
     218       11220 :         mru = xfs_mru_cache_lookup(mp->m_filestream, pino);
     219       11227 :         if (!mru)
     220             :                 return 0;
     221             :         /*
     222             :          * Grab the pag and take an extra active reference for the caller whilst
     223             :          * the mru item cannot go away. This means we'll pin the perag with
     224             :          * the reference we get here even if the filestreams association is torn
     225             :          * down immediately after we mark the lookup as done.
     226             :          */
     227       10425 :         pag = container_of(mru, struct xfs_fstrm_item, mru)->pag;
     228       10425 :         atomic_inc(&pag->pag_active_ref);
     229       10425 :         xfs_mru_cache_done(mp->m_filestream);
     230             : 
     231       10425 :         trace_xfs_filestream_lookup(pag, ap->ip->i_ino);
     232             : 
     233       10425 :         ap->blkno = XFS_AGB_TO_FSB(args->mp, pag->pag_agno, 0);
     234       10425 :         xfs_bmap_adjacent(ap);
     235             : 
     236             :         /*
     237             :          * If there is very little free space before we start a filestreams
     238             :          * allocation, we're almost guaranteed to fail to find a large enough
     239             :          * free space available so just use the cached AG.
     240             :          */
     241       10425 :         if (ap->tp->t_flags & XFS_TRANS_LOWMODE) {
     242           0 :                 *longest = 1;
     243           0 :                 goto out_done;
     244             :         }
     245             : 
     246       10425 :         error = xfs_bmap_longest_free_extent(pag, args->tp, longest);
     247       10423 :         if (error == -EAGAIN)
     248             :                 error = 0;
     249       10423 :         if (error || *longest < args->maxlen) {
     250             :                 /* We aren't going to use this perag */
     251         865 :                 *longest = 0;
     252         865 :                 xfs_perag_rele(pag);
     253         865 :                 return error;
     254             :         }
     255             : 
     256        9558 : out_done:
     257        9558 :         args->pag = pag;
     258        9558 :         return 0;
     259             : }
     260             : 
     261             : static int
     262        1666 : xfs_filestream_create_association(
     263             :         struct xfs_bmalloca     *ap,
     264             :         struct xfs_alloc_arg    *args,
     265             :         xfs_ino_t               pino,
     266             :         xfs_extlen_t            *longest)
     267             : {
     268        1666 :         struct xfs_mount        *mp = args->mp;
     269        1666 :         struct xfs_mru_cache_elem *mru;
     270        1666 :         struct xfs_fstrm_item   *item;
     271        1666 :         xfs_agnumber_t          agno = XFS_INO_TO_AGNO(mp, pino);
     272        1666 :         int                     flags = 0;
     273        1666 :         int                     error;
     274             : 
     275             :         /* Changing parent AG association now, so remove the existing one. */
     276        1666 :         mru = xfs_mru_cache_remove(mp->m_filestream, pino);
     277        1665 :         if (mru) {
     278         865 :                 struct xfs_fstrm_item *item =
     279         865 :                         container_of(mru, struct xfs_fstrm_item, mru);
     280             : 
     281         865 :                 agno = (item->pag->pag_agno + 1) % mp->m_sb.sb_agcount;
     282         865 :                 xfs_fstrm_free_func(mp, mru);
     283        1600 :         } else if (xfs_is_inode32(mp)) {
     284           0 :                 xfs_agnumber_t   rotorstep = xfs_rotorstep;
     285             : 
     286           0 :                 agno = (mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount;
     287           0 :                 mp->m_agfrotor = (mp->m_agfrotor + 1) %
     288           0 :                                  (mp->m_sb.sb_agcount * rotorstep);
     289             :         }
     290             : 
     291        1665 :         ap->blkno = XFS_AGB_TO_FSB(args->mp, agno, 0);
     292        1665 :         xfs_bmap_adjacent(ap);
     293             : 
     294        1666 :         if (ap->datatype & XFS_ALLOC_USERDATA)
     295        1666 :                 flags |= XFS_PICK_USERDATA;
     296        1666 :         if (ap->tp->t_flags & XFS_TRANS_LOWMODE)
     297           0 :                 flags |= XFS_PICK_LOWSPACE;
     298             : 
     299        1666 :         *longest = ap->length;
     300        1666 :         error = xfs_filestream_pick_ag(args, pino, agno, flags, longest);
     301        1667 :         if (error)
     302             :                 return error;
     303             : 
     304             :         /*
     305             :          * We are going to use this perag now, so create an assoication for it.
     306             :          * xfs_filestream_pick_ag() has already bumped the perag fstrms counter
     307             :          * for us, so all we need to do here is take another active reference to
     308             :          * the perag for the cached association.
     309             :          *
     310             :          * If we fail to store the association, we need to drop the fstrms
     311             :          * counter as well as drop the perag reference we take here for the
     312             :          * item. We do not need to return an error for this failure - as long as
     313             :          * we return a referenced AG, the allocation can still go ahead just
     314             :          * fine.
     315             :          */
     316        1667 :         item = kmem_alloc(sizeof(*item), KM_MAYFAIL);
     317        1667 :         if (!item)
     318           0 :                 goto out_put_fstrms;
     319             : 
     320        1667 :         atomic_inc(&args->pag->pag_active_ref);
     321        1667 :         item->pag = args->pag;
     322        1667 :         error = xfs_mru_cache_insert(mp->m_filestream, pino, &item->mru);
     323        1667 :         if (error)
     324           0 :                 goto out_free_item;
     325             :         return 0;
     326             : 
     327             : out_free_item:
     328           0 :         xfs_perag_rele(item->pag);
     329           0 :         kmem_free(item);
     330           0 : out_put_fstrms:
     331           0 :         atomic_dec(&args->pag->pagf_fstrms);
     332             :         return 0;
     333             : }
     334             : 
     335             : /*
     336             :  * Search for an allocation group with a single extent large enough for
     337             :  * the request. First we look for an existing association and use that if it
     338             :  * is found. Otherwise, we create a new association by selecting an AG that fits
     339             :  * the allocation criteria.
     340             :  *
     341             :  * We return with a referenced perag in args->pag to indicate which AG we are
     342             :  * allocating into or an error with no references held.
     343             :  */
     344             : int
     345       11222 : xfs_filestream_select_ag(
     346             :         struct xfs_bmalloca     *ap,
     347             :         struct xfs_alloc_arg    *args,
     348             :         xfs_extlen_t            *longest)
     349             : {
     350       11222 :         struct xfs_mount        *mp = args->mp;
     351       11222 :         struct xfs_inode        *pip;
     352       11222 :         xfs_ino_t               ino = 0;
     353       11222 :         int                     error = 0;
     354             : 
     355       11222 :         *longest = 0;
     356       11222 :         args->total = ap->total;
     357       11222 :         pip = xfs_filestream_get_parent(ap->ip);
     358       11221 :         if (pip) {
     359       11221 :                 ino = pip->i_ino;
     360       11221 :                 error = xfs_filestream_lookup_association(ap, args, ino,
     361             :                                 longest);
     362       11226 :                 xfs_irele(pip);
     363       11225 :                 if (error)
     364             :                         return error;
     365       11225 :                 if (*longest >= args->maxlen)
     366        9559 :                         goto out_select;
     367        1666 :                 if (ap->tp->t_flags & XFS_TRANS_LOWMODE)
     368           0 :                         goto out_select;
     369             :         }
     370             : 
     371        1666 :         error = xfs_filestream_create_association(ap, args, ino, longest);
     372        1667 :         if (error)
     373             :                 return error;
     374             : 
     375        1667 : out_select:
     376       11226 :         ap->blkno = XFS_AGB_TO_FSB(mp, args->pag->pag_agno, 0);
     377       11226 :         return 0;
     378             : }
     379             : 
     380             : void
     381         802 : xfs_filestream_deassociate(
     382             :         struct xfs_inode        *ip)
     383             : {
     384         802 :         xfs_mru_cache_delete(ip->i_mount->m_filestream, ip->i_ino);
     385         802 : }
     386             : 
     387             : int
     388       24125 : xfs_filestream_mount(
     389             :         xfs_mount_t     *mp)
     390             : {
     391             :         /*
     392             :          * The filestream timer tunable is currently fixed within the range of
     393             :          * one second to four minutes, with five seconds being the default.  The
     394             :          * group count is somewhat arbitrary, but it'd be nice to adhere to the
     395             :          * timer tunable to within about 10 percent.  This requires at least 10
     396             :          * groups.
     397             :          */
     398       48250 :         return xfs_mru_cache_create(&mp->m_filestream, mp,
     399       24125 :                         xfs_fstrm_centisecs * 10, 10, xfs_fstrm_free_func);
     400             : }
     401             : 
     402             : void
     403       24132 : xfs_filestream_unmount(
     404             :         xfs_mount_t     *mp)
     405             : {
     406       24132 :         xfs_mru_cache_destroy(mp->m_filestream);
     407       24132 : }

Generated by: LCOV version 1.14