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
xfs_fstrm_free_func(void * data,struct xfs_mru_cache_elem * mru)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
xfs_filestream_pick_ag(struct xfs_alloc_arg * args,xfs_ino_t pino,xfs_agnumber_t start_agno,int flags,xfs_extlen_t * longest)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 *
xfs_filestream_get_parent(struct xfs_inode * ip)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
xfs_filestream_lookup_association(struct xfs_bmalloca * ap,struct xfs_alloc_arg * args,xfs_ino_t pino,xfs_extlen_t * longest)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
xfs_filestream_create_association(struct xfs_bmalloca * ap,struct xfs_alloc_arg * args,xfs_ino_t pino,xfs_extlen_t * longest)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
xfs_filestream_select_ag(struct xfs_bmalloca * ap,struct xfs_alloc_arg * args,xfs_extlen_t * longest)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
xfs_filestream_deassociate(struct xfs_inode * ip)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
xfs_filestream_mount(xfs_mount_t * mp)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
xfs_filestream_unmount(xfs_mount_t * mp)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