xref: /OK3568_Linux_fs/kernel/fs/xfs/xfs_filestream.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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