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