10b61f8a4SDave Chinner // SPDX-License-Identifier: GPL-2.0 22a82b8beSDavid Chinner /* 32a82b8beSDavid Chinner * Copyright (c) 2006-2007 Silicon Graphics, Inc. 42cd2ef6aSChristoph Hellwig * Copyright (c) 2014 Christoph Hellwig. 52a82b8beSDavid Chinner * All Rights Reserved. 62a82b8beSDavid Chinner */ 72a82b8beSDavid Chinner #include "xfs.h" 85467b34bSDarrick J. Wong #include "xfs_shared.h" 9a4fbe6abSDave Chinner #include "xfs_format.h" 10239880efSDave Chinner #include "xfs_log_format.h" 11239880efSDave Chinner #include "xfs_trans_resv.h" 12239880efSDave Chinner #include "xfs_mount.h" 132a82b8beSDavid Chinner #include "xfs_inode.h" 142a82b8beSDavid Chinner #include "xfs_bmap.h" 158f7747adSDave Chinner #include "xfs_bmap_util.h" 162a82b8beSDavid Chinner #include "xfs_alloc.h" 172a82b8beSDavid Chinner #include "xfs_mru_cache.h" 180b1b213fSChristoph Hellwig #include "xfs_trace.h" 199bbafc71SDave Chinner #include "xfs_ag.h" 203fd129b6SDarrick J. Wong #include "xfs_ag_resv.h" 213e3673e3SBrian Foster #include "xfs_trans.h" 22f368b29bSDarrick J. Wong #include "xfs_filestream.h" 232a82b8beSDavid Chinner 242cd2ef6aSChristoph Hellwig struct xfs_fstrm_item { 2522328d71SChristoph Hellwig struct xfs_mru_cache_elem mru; 263054faceSDave Chinner struct xfs_perag *pag; /* AG in use for this directory */ 272cd2ef6aSChristoph Hellwig }; 282cd2ef6aSChristoph Hellwig 292cd2ef6aSChristoph Hellwig enum xfs_fstrm_alloc { 302cd2ef6aSChristoph Hellwig XFS_PICK_USERDATA = 1, 312cd2ef6aSChristoph Hellwig XFS_PICK_LOWSPACE = 2, 322cd2ef6aSChristoph Hellwig }; 332a82b8beSDavid Chinner 342cd2ef6aSChristoph Hellwig static void 352cd2ef6aSChristoph Hellwig xfs_fstrm_free_func( 367fcd3efaSChristoph Hellwig void *data, 372cd2ef6aSChristoph Hellwig struct xfs_mru_cache_elem *mru) 382cd2ef6aSChristoph Hellwig { 392cd2ef6aSChristoph Hellwig struct xfs_fstrm_item *item = 402cd2ef6aSChristoph Hellwig container_of(mru, struct xfs_fstrm_item, mru); 413054faceSDave Chinner struct xfs_perag *pag = item->pag; 422cd2ef6aSChristoph Hellwig 43571e2592SDave Chinner trace_xfs_filestream_free(pag, mru->key); 443054faceSDave Chinner atomic_dec(&pag->pagf_fstrms); 453054faceSDave Chinner xfs_perag_rele(pag); 462cd2ef6aSChristoph Hellwig 471919addaSChristoph Hellwig kmem_free(item); 482cd2ef6aSChristoph Hellwig } 492cd2ef6aSChristoph Hellwig 502a82b8beSDavid Chinner /* 51bd4f5d09SDave Chinner * Scan the AGs starting at start_agno looking for an AG that isn't in use and 52bd4f5d09SDave Chinner * has at least minlen blocks free. If no AG is found to match the allocation 53bd4f5d09SDave Chinner * requirements, pick the AG with the most free space in it. 542a82b8beSDavid Chinner */ 552a82b8beSDavid Chinner static int 562cd2ef6aSChristoph Hellwig xfs_filestream_pick_ag( 57f8f1ed1aSDave Chinner struct xfs_alloc_arg *args, 58bd4f5d09SDave Chinner xfs_ino_t pino, 59f8f1ed1aSDave Chinner xfs_agnumber_t start_agno, 602a82b8beSDavid Chinner int flags, 61ba34de8dSDave Chinner xfs_extlen_t *longest) 622a82b8beSDavid Chinner { 63bd4f5d09SDave Chinner struct xfs_mount *mp = args->mp; 642cd2ef6aSChristoph Hellwig struct xfs_perag *pag; 653054faceSDave Chinner struct xfs_perag *max_pag = NULL; 66ba34de8dSDave Chinner xfs_extlen_t minlen = *longest; 67*77ddc732SChristoph Hellwig xfs_extlen_t minfree, maxfree = 0; 68eb70aa2dSDave Chinner xfs_agnumber_t agno; 69bd4f5d09SDave Chinner bool first_pass = true; 70bd4f5d09SDave Chinner int err; 712a82b8beSDavid Chinner 722a82b8beSDavid Chinner /* 2% of an AG's blocks must be free for it to be chosen. */ 732a82b8beSDavid Chinner minfree = mp->m_sb.sb_agblocks / 50; 742a82b8beSDavid Chinner 75eb70aa2dSDave Chinner restart: 76eb70aa2dSDave Chinner for_each_perag_wrap(mp, start_agno, agno, pag) { 77bd4f5d09SDave Chinner trace_xfs_filestream_scan(pag, pino); 78ba34de8dSDave Chinner *longest = 0; 79ba34de8dSDave Chinner err = xfs_bmap_longest_free_extent(pag, NULL, longest); 80f48e2df8SDarrick J. Wong if (err) { 8105cf492aSDave Chinner if (err != -EAGAIN) 823054faceSDave Chinner break; 83f48e2df8SDarrick J. Wong /* Couldn't lock the AGF, skip this AG. */ 84eb70aa2dSDave Chinner err = 0; 85f8f1ed1aSDave Chinner continue; 862a82b8beSDavid Chinner } 872a82b8beSDavid Chinner 882a82b8beSDavid Chinner /* Keep track of the AG with the most free blocks. */ 892a82b8beSDavid Chinner if (pag->pagf_freeblks > maxfree) { 902a82b8beSDavid Chinner maxfree = pag->pagf_freeblks; 913054faceSDave Chinner if (max_pag) 923054faceSDave Chinner xfs_perag_rele(max_pag); 933054faceSDave Chinner atomic_inc(&pag->pag_active_ref); 943054faceSDave Chinner max_pag = pag; 952a82b8beSDavid Chinner } 962a82b8beSDavid Chinner 972a82b8beSDavid Chinner /* 982a82b8beSDavid Chinner * The AG reference count does two things: it enforces mutual 992a82b8beSDavid Chinner * exclusion when examining the suitability of an AG in this 1002a82b8beSDavid Chinner * loop, and it guards against two filestreams being established 1012a82b8beSDavid Chinner * in the same AG as each other. 1022a82b8beSDavid Chinner */ 103eb70aa2dSDave Chinner if (atomic_inc_return(&pag->pagf_fstrms) <= 1) { 104ba34de8dSDave Chinner if (((minlen && *longest >= minlen) || 1052a82b8beSDavid Chinner (!minlen && pag->pagf_freeblks >= minfree)) && 1067ac2ff8bSDave Chinner (!xfs_perag_prefers_metadata(pag) || 1077ac2ff8bSDave Chinner !(flags & XFS_PICK_USERDATA) || 1082a82b8beSDavid Chinner (flags & XFS_PICK_LOWSPACE))) { 1092a82b8beSDavid Chinner /* Break out, retaining the reference on the AG. */ 1102a82b8beSDavid Chinner break; 1112a82b8beSDavid Chinner } 112eb70aa2dSDave Chinner } 1132a82b8beSDavid Chinner 1142a82b8beSDavid Chinner /* Drop the reference on this AG, it's not usable. */ 1153054faceSDave Chinner atomic_dec(&pag->pagf_fstrms); 116eb70aa2dSDave Chinner } 1172a82b8beSDavid Chinner 118eb70aa2dSDave Chinner if (err) { 119eb70aa2dSDave Chinner xfs_perag_rele(pag); 120eb70aa2dSDave Chinner if (max_pag) 121eb70aa2dSDave Chinner xfs_perag_rele(max_pag); 122eb70aa2dSDave Chinner return err; 123eb70aa2dSDave Chinner } 1242a82b8beSDavid Chinner 125eb70aa2dSDave Chinner if (!pag) { 126bd4f5d09SDave Chinner /* 127bd4f5d09SDave Chinner * Allow a second pass to give xfs_bmap_longest_free_extent() 128bd4f5d09SDave Chinner * another attempt at locking AGFs that it might have skipped 129bd4f5d09SDave Chinner * over before we fail. 130bd4f5d09SDave Chinner */ 131bd4f5d09SDave Chinner if (first_pass) { 132bd4f5d09SDave Chinner first_pass = false; 133eb70aa2dSDave Chinner goto restart; 1342a82b8beSDavid Chinner } 1352a82b8beSDavid Chinner 136bd4f5d09SDave Chinner /* 137bd4f5d09SDave Chinner * We must be low on data space, so run a final lowspace 138bd4f5d09SDave Chinner * optimised selection pass if we haven't already. 139bd4f5d09SDave Chinner */ 1402a82b8beSDavid Chinner if (!(flags & XFS_PICK_LOWSPACE)) { 1412a82b8beSDavid Chinner flags |= XFS_PICK_LOWSPACE; 142eb70aa2dSDave Chinner goto restart; 1432a82b8beSDavid Chinner } 1442a82b8beSDavid Chinner 1452a82b8beSDavid Chinner /* 146eb70aa2dSDave Chinner * No unassociated AGs are available, so select the AG with the 147eb70aa2dSDave Chinner * most free space, regardless of whether it's already in use by 148f8f1ed1aSDave Chinner * another filestream. It none suit, just use whatever AG we can 149f8f1ed1aSDave Chinner * grab. 1502a82b8beSDavid Chinner */ 151eb70aa2dSDave Chinner if (!max_pag) { 152*77ddc732SChristoph Hellwig for_each_perag_wrap(args->mp, 0, start_agno, pag) { 153*77ddc732SChristoph Hellwig max_pag = pag; 154f8f1ed1aSDave Chinner break; 155f8f1ed1aSDave Chinner } 156*77ddc732SChristoph Hellwig 157*77ddc732SChristoph Hellwig /* Bail if there are no AGs at all to select from. */ 158*77ddc732SChristoph Hellwig if (!max_pag) 159*77ddc732SChristoph Hellwig return -ENOSPC; 160*77ddc732SChristoph Hellwig } 161*77ddc732SChristoph Hellwig 162*77ddc732SChristoph Hellwig pag = max_pag; 163*77ddc732SChristoph Hellwig atomic_inc(&pag->pagf_fstrms); 164eb70aa2dSDave Chinner } else if (max_pag) { 165eb70aa2dSDave Chinner xfs_perag_rele(max_pag); 166eb70aa2dSDave Chinner } 167eb70aa2dSDave Chinner 168*77ddc732SChristoph Hellwig trace_xfs_filestream_pick(pag, pino); 169f8f1ed1aSDave Chinner args->pag = pag; 1702cd2ef6aSChristoph Hellwig return 0; 1712a82b8beSDavid Chinner } 1722a82b8beSDavid Chinner 1732cd2ef6aSChristoph Hellwig static struct xfs_inode * 1742cd2ef6aSChristoph Hellwig xfs_filestream_get_parent( 1752cd2ef6aSChristoph Hellwig struct xfs_inode *ip) 1762a82b8beSDavid Chinner { 1772cd2ef6aSChristoph Hellwig struct inode *inode = VFS_I(ip), *dir = NULL; 1782cd2ef6aSChristoph Hellwig struct dentry *dentry, *parent; 1792a82b8beSDavid Chinner 1802cd2ef6aSChristoph Hellwig dentry = d_find_alias(inode); 1812cd2ef6aSChristoph Hellwig if (!dentry) 1822cd2ef6aSChristoph Hellwig goto out; 1832a82b8beSDavid Chinner 1842cd2ef6aSChristoph Hellwig parent = dget_parent(dentry); 1852cd2ef6aSChristoph Hellwig if (!parent) 1862cd2ef6aSChristoph Hellwig goto out_dput; 1872a82b8beSDavid Chinner 1882b0143b5SDavid Howells dir = igrab(d_inode(parent)); 1892cd2ef6aSChristoph Hellwig dput(parent); 1902a82b8beSDavid Chinner 1912cd2ef6aSChristoph Hellwig out_dput: 1922cd2ef6aSChristoph Hellwig dput(dentry); 1932cd2ef6aSChristoph Hellwig out: 1942cd2ef6aSChristoph Hellwig return dir ? XFS_I(dir) : NULL; 1952a82b8beSDavid Chinner } 1962a82b8beSDavid Chinner 1972a82b8beSDavid Chinner /* 198f38b46bbSDave Chinner * Lookup the mru cache for an existing association. If one exists and we can 199bd4f5d09SDave Chinner * use it, return with an active perag reference indicating that the allocation 200bd4f5d09SDave Chinner * will proceed with that association. 201f38b46bbSDave Chinner * 202f38b46bbSDave Chinner * If we have no association, or we cannot use the current one and have to 203bd4f5d09SDave Chinner * destroy it, return with longest = 0 to tell the caller to create a new 204bd4f5d09SDave Chinner * association. 205f38b46bbSDave Chinner */ 206bd4f5d09SDave Chinner static int 207bd4f5d09SDave Chinner xfs_filestream_lookup_association( 208f38b46bbSDave Chinner struct xfs_bmalloca *ap, 209f38b46bbSDave Chinner struct xfs_alloc_arg *args, 210bd4f5d09SDave Chinner xfs_ino_t pino, 211bd4f5d09SDave Chinner xfs_extlen_t *longest) 212f38b46bbSDave Chinner { 213bd4f5d09SDave Chinner struct xfs_mount *mp = args->mp; 214f38b46bbSDave Chinner struct xfs_perag *pag; 215f38b46bbSDave Chinner struct xfs_mru_cache_elem *mru; 216bd4f5d09SDave Chinner int error = 0; 217f38b46bbSDave Chinner 218bd4f5d09SDave Chinner *longest = 0; 219bd4f5d09SDave Chinner mru = xfs_mru_cache_lookup(mp->m_filestream, pino); 220f38b46bbSDave Chinner if (!mru) 221bd4f5d09SDave Chinner return 0; 222f8f1ed1aSDave Chinner /* 223f8f1ed1aSDave Chinner * Grab the pag and take an extra active reference for the caller whilst 224f8f1ed1aSDave Chinner * the mru item cannot go away. This means we'll pin the perag with 225f8f1ed1aSDave Chinner * the reference we get here even if the filestreams association is torn 226f8f1ed1aSDave Chinner * down immediately after we mark the lookup as done. 227f8f1ed1aSDave Chinner */ 2283054faceSDave Chinner pag = container_of(mru, struct xfs_fstrm_item, mru)->pag; 229f8f1ed1aSDave Chinner atomic_inc(&pag->pag_active_ref); 230f38b46bbSDave Chinner xfs_mru_cache_done(mp->m_filestream); 231f38b46bbSDave Chinner 232571e2592SDave Chinner trace_xfs_filestream_lookup(pag, ap->ip->i_ino); 233f38b46bbSDave Chinner 2343054faceSDave Chinner ap->blkno = XFS_AGB_TO_FSB(args->mp, pag->pag_agno, 0); 235f38b46bbSDave Chinner xfs_bmap_adjacent(ap); 236f38b46bbSDave Chinner 237bd4f5d09SDave Chinner /* 238bd4f5d09SDave Chinner * If there is very little free space before we start a filestreams 239bd4f5d09SDave Chinner * allocation, we're almost guaranteed to fail to find a large enough 240bd4f5d09SDave Chinner * free space available so just use the cached AG. 241bd4f5d09SDave Chinner */ 242bd4f5d09SDave Chinner if (ap->tp->t_flags & XFS_TRANS_LOWMODE) { 243bd4f5d09SDave Chinner *longest = 1; 244bd4f5d09SDave Chinner goto out_done; 245f38b46bbSDave Chinner } 246f38b46bbSDave Chinner 247bd4f5d09SDave Chinner error = xfs_bmap_longest_free_extent(pag, args->tp, longest); 248bd4f5d09SDave Chinner if (error == -EAGAIN) 249bd4f5d09SDave Chinner error = 0; 250bd4f5d09SDave Chinner if (error || *longest < args->maxlen) { 251bd4f5d09SDave Chinner /* We aren't going to use this perag */ 252bd4f5d09SDave Chinner *longest = 0; 253bd4f5d09SDave Chinner xfs_perag_rele(pag); 254bd4f5d09SDave Chinner return error; 255bd4f5d09SDave Chinner } 256bd4f5d09SDave Chinner 257bd4f5d09SDave Chinner out_done: 258f8f1ed1aSDave Chinner args->pag = pag; 259f38b46bbSDave Chinner return 0; 260f8f1ed1aSDave Chinner } 261f38b46bbSDave Chinner 262bd4f5d09SDave Chinner static int 263bd4f5d09SDave Chinner xfs_filestream_create_association( 264bd4f5d09SDave Chinner struct xfs_bmalloca *ap, 265bd4f5d09SDave Chinner struct xfs_alloc_arg *args, 266bd4f5d09SDave Chinner xfs_ino_t pino, 267bd4f5d09SDave Chinner xfs_extlen_t *longest) 268bd4f5d09SDave Chinner { 269bd4f5d09SDave Chinner struct xfs_mount *mp = args->mp; 270bd4f5d09SDave Chinner struct xfs_mru_cache_elem *mru; 271bd4f5d09SDave Chinner struct xfs_fstrm_item *item; 272bd4f5d09SDave Chinner xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, pino); 273bd4f5d09SDave Chinner int flags = 0; 274bd4f5d09SDave Chinner int error; 275bd4f5d09SDave Chinner 276f38b46bbSDave Chinner /* Changing parent AG association now, so remove the existing one. */ 277bd4f5d09SDave Chinner mru = xfs_mru_cache_remove(mp->m_filestream, pino); 278f38b46bbSDave Chinner if (mru) { 279f38b46bbSDave Chinner struct xfs_fstrm_item *item = 280f38b46bbSDave Chinner container_of(mru, struct xfs_fstrm_item, mru); 281f38b46bbSDave Chinner 282bd4f5d09SDave Chinner agno = (item->pag->pag_agno + 1) % mp->m_sb.sb_agcount; 283bd4f5d09SDave Chinner xfs_fstrm_free_func(mp, mru); 284bd4f5d09SDave Chinner } else if (xfs_is_inode32(mp)) { 285f38b46bbSDave Chinner xfs_agnumber_t rotorstep = xfs_rotorstep; 286bd4f5d09SDave Chinner 287bd4f5d09SDave Chinner agno = (mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount; 288f38b46bbSDave Chinner mp->m_agfrotor = (mp->m_agfrotor + 1) % 289f38b46bbSDave Chinner (mp->m_sb.sb_agcount * rotorstep); 290f38b46bbSDave Chinner } 2918f7747adSDave Chinner 292f8f1ed1aSDave Chinner ap->blkno = XFS_AGB_TO_FSB(args->mp, agno, 0); 293f8f1ed1aSDave Chinner xfs_bmap_adjacent(ap); 294bd4f5d09SDave Chinner 295ba34de8dSDave Chinner if (ap->datatype & XFS_ALLOC_USERDATA) 296ba34de8dSDave Chinner flags |= XFS_PICK_USERDATA; 297ba34de8dSDave Chinner if (ap->tp->t_flags & XFS_TRANS_LOWMODE) 298ba34de8dSDave Chinner flags |= XFS_PICK_LOWSPACE; 299ba34de8dSDave Chinner 300bd4f5d09SDave Chinner *longest = ap->length; 301bd4f5d09SDave Chinner error = xfs_filestream_pick_ag(args, pino, agno, flags, longest); 302f8f1ed1aSDave Chinner if (error) 303ba34de8dSDave Chinner return error; 304ba34de8dSDave Chinner 305bd4f5d09SDave Chinner /* 306bd4f5d09SDave Chinner * We are going to use this perag now, so create an assoication for it. 307bd4f5d09SDave Chinner * xfs_filestream_pick_ag() has already bumped the perag fstrms counter 308bd4f5d09SDave Chinner * for us, so all we need to do here is take another active reference to 309bd4f5d09SDave Chinner * the perag for the cached association. 310bd4f5d09SDave Chinner * 311bd4f5d09SDave Chinner * If we fail to store the association, we need to drop the fstrms 312bd4f5d09SDave Chinner * counter as well as drop the perag reference we take here for the 313bd4f5d09SDave Chinner * item. We do not need to return an error for this failure - as long as 314bd4f5d09SDave Chinner * we return a referenced AG, the allocation can still go ahead just 315bd4f5d09SDave Chinner * fine. 316bd4f5d09SDave Chinner */ 317bd4f5d09SDave Chinner item = kmem_alloc(sizeof(*item), KM_MAYFAIL); 318bd4f5d09SDave Chinner if (!item) 319bd4f5d09SDave Chinner goto out_put_fstrms; 320bd4f5d09SDave Chinner 321bd4f5d09SDave Chinner atomic_inc(&args->pag->pag_active_ref); 322bd4f5d09SDave Chinner item->pag = args->pag; 323bd4f5d09SDave Chinner error = xfs_mru_cache_insert(mp->m_filestream, pino, &item->mru); 324bd4f5d09SDave Chinner if (error) 325bd4f5d09SDave Chinner goto out_free_item; 326bd4f5d09SDave Chinner return 0; 327bd4f5d09SDave Chinner 328bd4f5d09SDave Chinner out_free_item: 329bd4f5d09SDave Chinner xfs_perag_rele(item->pag); 330bd4f5d09SDave Chinner kmem_free(item); 331bd4f5d09SDave Chinner out_put_fstrms: 332bd4f5d09SDave Chinner atomic_dec(&args->pag->pagf_fstrms); 333bd4f5d09SDave Chinner return 0; 334bd4f5d09SDave Chinner } 335bd4f5d09SDave Chinner 336bd4f5d09SDave Chinner /* 337bd4f5d09SDave Chinner * Search for an allocation group with a single extent large enough for 338bd4f5d09SDave Chinner * the request. First we look for an existing association and use that if it 339bd4f5d09SDave Chinner * is found. Otherwise, we create a new association by selecting an AG that fits 340bd4f5d09SDave Chinner * the allocation criteria. 341bd4f5d09SDave Chinner * 342bd4f5d09SDave Chinner * We return with a referenced perag in args->pag to indicate which AG we are 343bd4f5d09SDave Chinner * allocating into or an error with no references held. 344bd4f5d09SDave Chinner */ 345bd4f5d09SDave Chinner int 346bd4f5d09SDave Chinner xfs_filestream_select_ag( 347bd4f5d09SDave Chinner struct xfs_bmalloca *ap, 348bd4f5d09SDave Chinner struct xfs_alloc_arg *args, 349bd4f5d09SDave Chinner xfs_extlen_t *longest) 350bd4f5d09SDave Chinner { 351bd4f5d09SDave Chinner struct xfs_mount *mp = args->mp; 352bd4f5d09SDave Chinner struct xfs_inode *pip; 353bd4f5d09SDave Chinner xfs_ino_t ino = 0; 354bd4f5d09SDave Chinner int error = 0; 355bd4f5d09SDave Chinner 356bd4f5d09SDave Chinner *longest = 0; 357bd4f5d09SDave Chinner args->total = ap->total; 358bd4f5d09SDave Chinner pip = xfs_filestream_get_parent(ap->ip); 359bd4f5d09SDave Chinner if (pip) { 360bd4f5d09SDave Chinner ino = pip->i_ino; 361bd4f5d09SDave Chinner error = xfs_filestream_lookup_association(ap, args, ino, 362bd4f5d09SDave Chinner longest); 363bd4f5d09SDave Chinner xfs_irele(pip); 364bd4f5d09SDave Chinner if (error) 365bd4f5d09SDave Chinner return error; 366bd4f5d09SDave Chinner if (*longest >= args->maxlen) 367bd4f5d09SDave Chinner goto out_select; 368bd4f5d09SDave Chinner if (ap->tp->t_flags & XFS_TRANS_LOWMODE) 369bd4f5d09SDave Chinner goto out_select; 370bd4f5d09SDave Chinner } 371bd4f5d09SDave Chinner 372bd4f5d09SDave Chinner error = xfs_filestream_create_association(ap, args, ino, longest); 373bd4f5d09SDave Chinner if (error) 374bd4f5d09SDave Chinner return error; 375bd4f5d09SDave Chinner 376bd4f5d09SDave Chinner out_select: 377bd4f5d09SDave Chinner ap->blkno = XFS_AGB_TO_FSB(mp, args->pag->pag_agno, 0); 378bd4f5d09SDave Chinner return 0; 379ba34de8dSDave Chinner } 3808f7747adSDave Chinner 3812a82b8beSDavid Chinner void 3822a82b8beSDavid Chinner xfs_filestream_deassociate( 3832cd2ef6aSChristoph Hellwig struct xfs_inode *ip) 3842a82b8beSDavid Chinner { 38522328d71SChristoph Hellwig xfs_mru_cache_delete(ip->i_mount->m_filestream, ip->i_ino); 3862a82b8beSDavid Chinner } 3872cd2ef6aSChristoph Hellwig 3882cd2ef6aSChristoph Hellwig int 3892cd2ef6aSChristoph Hellwig xfs_filestream_mount( 3902cd2ef6aSChristoph Hellwig xfs_mount_t *mp) 3912cd2ef6aSChristoph Hellwig { 3922cd2ef6aSChristoph Hellwig /* 3932cd2ef6aSChristoph Hellwig * The filestream timer tunable is currently fixed within the range of 3942cd2ef6aSChristoph Hellwig * one second to four minutes, with five seconds being the default. The 3952cd2ef6aSChristoph Hellwig * group count is somewhat arbitrary, but it'd be nice to adhere to the 3962cd2ef6aSChristoph Hellwig * timer tunable to within about 10 percent. This requires at least 10 3972cd2ef6aSChristoph Hellwig * groups. 3982cd2ef6aSChristoph Hellwig */ 3997fcd3efaSChristoph Hellwig return xfs_mru_cache_create(&mp->m_filestream, mp, 4007fcd3efaSChristoph Hellwig xfs_fstrm_centisecs * 10, 10, xfs_fstrm_free_func); 4012cd2ef6aSChristoph Hellwig } 4022cd2ef6aSChristoph Hellwig 4032cd2ef6aSChristoph Hellwig void 4042cd2ef6aSChristoph Hellwig xfs_filestream_unmount( 4052cd2ef6aSChristoph Hellwig xfs_mount_t *mp) 4062cd2ef6aSChristoph Hellwig { 4072cd2ef6aSChristoph Hellwig xfs_mru_cache_destroy(mp->m_filestream); 4082cd2ef6aSChristoph Hellwig } 409