xfs_filestream.c (a52dc2ad363088d0e0ab05a71f0496e2377e5cc9) xfs_filestream.c (ba34de8defe013e4062bdc2ed57d748d6807a96a)
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"

--- 84 unchanged lines hidden (view full) ---

93
94/*
95 * Scan the AGs starting at startag looking for an AG that isn't in use and has
96 * at least minlen blocks free.
97 */
98static int
99xfs_filestream_pick_ag(
100 struct xfs_inode *ip,
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"

--- 84 unchanged lines hidden (view full) ---

93
94/*
95 * Scan the AGs starting at startag looking for an AG that isn't in use and has
96 * at least minlen blocks free.
97 */
98static int
99xfs_filestream_pick_ag(
100 struct xfs_inode *ip,
101 xfs_agnumber_t startag,
102 xfs_agnumber_t *agp,
103 int flags,
101 xfs_agnumber_t *agp,
102 int flags,
104 xfs_extlen_t minlen)
103 xfs_extlen_t *longest)
105{
106 struct xfs_mount *mp = ip->i_mount;
107 struct xfs_fstrm_item *item;
108 struct xfs_perag *pag;
104{
105 struct xfs_mount *mp = ip->i_mount;
106 struct xfs_fstrm_item *item;
107 struct xfs_perag *pag;
109 xfs_extlen_t longest, free = 0, minfree, maxfree = 0;
110 xfs_agnumber_t ag, max_ag = NULLAGNUMBER;
108 xfs_extlen_t minlen = *longest;
109 xfs_extlen_t free = 0, minfree, maxfree = 0;
110 xfs_agnumber_t startag = *agp;
111 xfs_agnumber_t ag = startag;
112 xfs_agnumber_t max_ag = NULLAGNUMBER;
111 int err, trylock, nscan;
112
113 ASSERT(S_ISDIR(VFS_I(ip)->i_mode));
114
115 /* 2% of an AG's blocks must be free for it to be chosen. */
116 minfree = mp->m_sb.sb_agblocks / 50;
117
113 int err, trylock, nscan;
114
115 ASSERT(S_ISDIR(VFS_I(ip)->i_mode));
116
117 /* 2% of an AG's blocks must be free for it to be chosen. */
118 minfree = mp->m_sb.sb_agblocks / 50;
119
118 ag = startag;
119 *agp = NULLAGNUMBER;
120
121 /* For the first pass, don't sleep trying to init the per-AG. */
122 trylock = XFS_ALLOC_FLAG_TRYLOCK;
123
124 for (nscan = 0; 1; nscan++) {
125 trace_xfs_filestream_scan(mp, ip->i_ino, ag);
126
127 pag = xfs_perag_get(mp, ag);
120 *agp = NULLAGNUMBER;
121
122 /* For the first pass, don't sleep trying to init the per-AG. */
123 trylock = XFS_ALLOC_FLAG_TRYLOCK;
124
125 for (nscan = 0; 1; nscan++) {
126 trace_xfs_filestream_scan(mp, ip->i_ino, ag);
127
128 pag = xfs_perag_get(mp, ag);
128 longest = 0;
129 err = xfs_bmap_longest_free_extent(pag, NULL, &longest);
129 *longest = 0;
130 err = xfs_bmap_longest_free_extent(pag, NULL, longest);
130 if (err) {
131 xfs_perag_put(pag);
132 if (err != -EAGAIN)
133 return err;
134 /* Couldn't lock the AGF, skip this AG. */
135 goto next_ag;
136 }
137

--- 9 unchanged lines hidden (view full) ---

147 * loop, and it guards against two filestreams being established
148 * in the same AG as each other.
149 */
150 if (xfs_filestream_get_ag(mp, ag) > 1) {
151 xfs_filestream_put_ag(mp, ag);
152 goto next_ag;
153 }
154
131 if (err) {
132 xfs_perag_put(pag);
133 if (err != -EAGAIN)
134 return err;
135 /* Couldn't lock the AGF, skip this AG. */
136 goto next_ag;
137 }
138

--- 9 unchanged lines hidden (view full) ---

148 * loop, and it guards against two filestreams being established
149 * in the same AG as each other.
150 */
151 if (xfs_filestream_get_ag(mp, ag) > 1) {
152 xfs_filestream_put_ag(mp, ag);
153 goto next_ag;
154 }
155
155 if (((minlen && longest >= minlen) ||
156 if (((minlen && *longest >= minlen) ||
156 (!minlen && pag->pagf_freeblks >= minfree)) &&
157 (!xfs_perag_prefers_metadata(pag) ||
158 !(flags & XFS_PICK_USERDATA) ||
159 (flags & XFS_PICK_LOWSPACE))) {
160
161 /* Break out, retaining the reference on the AG. */
162 free = pag->pagf_freeblks;
163 xfs_perag_put(pag);

--- 90 unchanged lines hidden (view full) ---

254
255out_dput:
256 dput(dentry);
257out:
258 return dir ? XFS_I(dir) : NULL;
259}
260
261/*
157 (!minlen && pag->pagf_freeblks >= minfree)) &&
158 (!xfs_perag_prefers_metadata(pag) ||
159 !(flags & XFS_PICK_USERDATA) ||
160 (flags & XFS_PICK_LOWSPACE))) {
161
162 /* Break out, retaining the reference on the AG. */
163 free = pag->pagf_freeblks;
164 xfs_perag_put(pag);

--- 90 unchanged lines hidden (view full) ---

255
256out_dput:
257 dput(dentry);
258out:
259 return dir ? XFS_I(dir) : NULL;
260}
261
262/*
262 * Pick a new allocation group for the current file and its file stream.
263 *
264 * This is called when the allocator can't find a suitable extent in the
265 * current AG, and we have to move the stream into a new AG with more space.
266 */
267static int
268xfs_filestream_new_ag(
269 struct xfs_bmalloca *ap,
270 xfs_agnumber_t *agp)
271{
272 struct xfs_inode *ip = ap->ip, *pip;
273 struct xfs_mount *mp = ip->i_mount;
274 xfs_extlen_t minlen = ap->length;
275 xfs_agnumber_t startag = 0;
276 int flags = 0;
277 int err = 0;
278 struct xfs_mru_cache_elem *mru;
279
280 *agp = NULLAGNUMBER;
281
282 pip = xfs_filestream_get_parent(ip);
283 if (!pip)
284 goto exit;
285
286 mru = xfs_mru_cache_remove(mp->m_filestream, pip->i_ino);
287 if (mru) {
288 struct xfs_fstrm_item *item =
289 container_of(mru, struct xfs_fstrm_item, mru);
290 startag = (item->ag + 1) % mp->m_sb.sb_agcount;
291 }
292
293 if (ap->datatype & XFS_ALLOC_USERDATA)
294 flags |= XFS_PICK_USERDATA;
295 if (ap->tp->t_flags & XFS_TRANS_LOWMODE)
296 flags |= XFS_PICK_LOWSPACE;
297
298 err = xfs_filestream_pick_ag(pip, startag, agp, flags, minlen);
299
300 /*
301 * Only free the item here so we skip over the old AG earlier.
302 */
303 if (mru)
304 xfs_fstrm_free_func(mp, mru);
305
306 xfs_irele(pip);
307exit:
308 if (*agp == NULLAGNUMBER)
309 *agp = 0;
310 return err;
311}
312
313/*
314 * Search for an allocation group with a single extent large enough for
315 * the request. If one isn't found, then the largest available free extent is
316 * returned as the best length possible.
317 */
318int
319xfs_filestream_select_ag(
320 struct xfs_bmalloca *ap,
321 struct xfs_alloc_arg *args,
322 xfs_extlen_t *blen)
323{
324 struct xfs_mount *mp = ap->ip->i_mount;
325 struct xfs_perag *pag;
326 struct xfs_inode *pip = NULL;
327 xfs_agnumber_t agno = NULLAGNUMBER;
328 struct xfs_mru_cache_elem *mru;
263 * Search for an allocation group with a single extent large enough for
264 * the request. If one isn't found, then the largest available free extent is
265 * returned as the best length possible.
266 */
267int
268xfs_filestream_select_ag(
269 struct xfs_bmalloca *ap,
270 struct xfs_alloc_arg *args,
271 xfs_extlen_t *blen)
272{
273 struct xfs_mount *mp = ap->ip->i_mount;
274 struct xfs_perag *pag;
275 struct xfs_inode *pip = NULL;
276 xfs_agnumber_t agno = NULLAGNUMBER;
277 struct xfs_mru_cache_elem *mru;
278 int flags = 0;
329 int error;
330
331 args->total = ap->total;
332 *blen = 0;
333
334 pip = xfs_filestream_get_parent(ap->ip);
335 if (!pip) {
336 agno = 0;
279 int error;
280
281 args->total = ap->total;
282 *blen = 0;
283
284 pip = xfs_filestream_get_parent(ap->ip);
285 if (!pip) {
286 agno = 0;
337 goto new_ag;
287 goto out_select;
338 }
339
340 mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
341 if (mru) {
342 agno = container_of(mru, struct xfs_fstrm_item, mru)->ag;
343 xfs_mru_cache_done(mp->m_filestream);
288 }
289
290 mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
291 if (mru) {
292 agno = container_of(mru, struct xfs_fstrm_item, mru)->ag;
293 xfs_mru_cache_done(mp->m_filestream);
294 mru = NULL;
344
345 trace_xfs_filestream_lookup(mp, ap->ip->i_ino, agno);
346 xfs_irele(pip);
347
348 ap->blkno = XFS_AGB_TO_FSB(args->mp, agno, 0);
349 xfs_bmap_adjacent(ap);
350
351 pag = xfs_perag_grab(mp, agno);
352 if (pag) {
353 error = xfs_bmap_longest_free_extent(pag, args->tp, blen);
354 xfs_perag_rele(pag);
355 if (error) {
356 if (error != -EAGAIN)
295
296 trace_xfs_filestream_lookup(mp, ap->ip->i_ino, agno);
297 xfs_irele(pip);
298
299 ap->blkno = XFS_AGB_TO_FSB(args->mp, agno, 0);
300 xfs_bmap_adjacent(ap);
301
302 pag = xfs_perag_grab(mp, agno);
303 if (pag) {
304 error = xfs_bmap_longest_free_extent(pag, args->tp, blen);
305 xfs_perag_rele(pag);
306 if (error) {
307 if (error != -EAGAIN)
357 return error;
308 goto out_error;
358 *blen = 0;
359 }
360 }
361 if (*blen >= args->maxlen)
362 goto out_select;
363 } else if (xfs_is_inode32(mp)) {
364 xfs_agnumber_t rotorstep = xfs_rotorstep;
365 agno = (mp->m_agfrotor / rotorstep) %
366 mp->m_sb.sb_agcount;
367 mp->m_agfrotor = (mp->m_agfrotor + 1) %
368 (mp->m_sb.sb_agcount * rotorstep);
309 *blen = 0;
310 }
311 }
312 if (*blen >= args->maxlen)
313 goto out_select;
314 } else if (xfs_is_inode32(mp)) {
315 xfs_agnumber_t rotorstep = xfs_rotorstep;
316 agno = (mp->m_agfrotor / rotorstep) %
317 mp->m_sb.sb_agcount;
318 mp->m_agfrotor = (mp->m_agfrotor + 1) %
319 (mp->m_sb.sb_agcount * rotorstep);
369 xfs_irele(pip);
370 } else {
371 agno = XFS_INO_TO_AGNO(mp, pip->i_ino);
320 } else {
321 agno = XFS_INO_TO_AGNO(mp, pip->i_ino);
372 xfs_irele(pip);
373 }
374
322 }
323
375new_ag:
324 /* Changing parent AG association now, so remove the existing one. */
325 mru = xfs_mru_cache_remove(mp->m_filestream, pip->i_ino);
326 if (mru) {
327 struct xfs_fstrm_item *item =
328 container_of(mru, struct xfs_fstrm_item, mru);
329 agno = (item->ag + 1) % mp->m_sb.sb_agcount;
330 xfs_fstrm_free_func(mp, mru);
331 }
376 ap->blkno = XFS_AGB_TO_FSB(args->mp, agno, 0);
377 xfs_bmap_adjacent(ap);
378
379 /*
380 * If there is very little free space before we start a filestreams
381 * allocation, we're almost guaranteed to fail to find a better AG with
382 * larger free space available so we don't even try.
383 */
384 if (ap->tp->t_flags & XFS_TRANS_LOWMODE)
332 ap->blkno = XFS_AGB_TO_FSB(args->mp, agno, 0);
333 xfs_bmap_adjacent(ap);
334
335 /*
336 * If there is very little free space before we start a filestreams
337 * allocation, we're almost guaranteed to fail to find a better AG with
338 * larger free space available so we don't even try.
339 */
340 if (ap->tp->t_flags & XFS_TRANS_LOWMODE)
385 return 0;
341 goto out_select;
386
342
387 error = xfs_filestream_new_ag(ap, &agno);
343 if (ap->datatype & XFS_ALLOC_USERDATA)
344 flags |= XFS_PICK_USERDATA;
345 if (ap->tp->t_flags & XFS_TRANS_LOWMODE)
346 flags |= XFS_PICK_LOWSPACE;
347
348 *blen = ap->length;
349 error = xfs_filestream_pick_ag(pip, &agno, flags, blen);
388 if (error)
350 if (error)
389 return error;
351 goto out_error;
390 if (agno == NULLAGNUMBER) {
391 agno = 0;
352 if (agno == NULLAGNUMBER) {
353 agno = 0;
392 goto out_select;
354 goto out_irele;
393 }
394
395 pag = xfs_perag_grab(mp, agno);
396 if (!pag)
355 }
356
357 pag = xfs_perag_grab(mp, agno);
358 if (!pag)
397 goto out_select;
359 goto out_irele;
398
399 error = xfs_bmap_longest_free_extent(pag, args->tp, blen);
400 xfs_perag_rele(pag);
401 if (error) {
402 if (error != -EAGAIN)
360
361 error = xfs_bmap_longest_free_extent(pag, args->tp, blen);
362 xfs_perag_rele(pag);
363 if (error) {
364 if (error != -EAGAIN)
403 return error;
365 goto out_error;
404 *blen = 0;
405 }
406
366 *blen = 0;
367 }
368
369out_irele:
370 xfs_irele(pip);
407out_select:
408 ap->blkno = XFS_AGB_TO_FSB(mp, agno, 0);
409 return 0;
371out_select:
372 ap->blkno = XFS_AGB_TO_FSB(mp, agno, 0);
373 return 0;
410}
411
374
375out_error:
376 xfs_irele(pip);
377 return error;
412
378
379}
380
413void
414xfs_filestream_deassociate(
415 struct xfs_inode *ip)
416{
417 xfs_mru_cache_delete(ip->i_mount->m_filestream, ip->i_ino);
418}
419
420int

--- 20 unchanged lines hidden ---
381void
382xfs_filestream_deassociate(
383 struct xfs_inode *ip)
384{
385 xfs_mru_cache_delete(ip->i_mount->m_filestream, ip->i_ino);
386}
387
388int

--- 20 unchanged lines hidden ---