xfs_filestream.c (f38b46bbfa76a854c4c2a27b1617d66fefbb3f80) xfs_filestream.c (3054face139f9c77566a90a0524dd85c2f38c7f2)
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"

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

18#include "xfs_trace.h"
19#include "xfs_ag.h"
20#include "xfs_ag_resv.h"
21#include "xfs_trans.h"
22#include "xfs_filestream.h"
23
24struct xfs_fstrm_item {
25 struct xfs_mru_cache_elem mru;
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"

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

18#include "xfs_trace.h"
19#include "xfs_ag.h"
20#include "xfs_ag_resv.h"
21#include "xfs_trans.h"
22#include "xfs_filestream.h"
23
24struct xfs_fstrm_item {
25 struct xfs_mru_cache_elem mru;
26 xfs_agnumber_t ag; /* AG in use for this directory */
26 struct xfs_perag *pag; /* AG in use for this directory */
27};
28
29enum xfs_fstrm_alloc {
30 XFS_PICK_USERDATA = 1,
31 XFS_PICK_LOWSPACE = 2,
32};
33
34/*

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

45 int ret;
46
47 pag = xfs_perag_get(mp, agno);
48 ret = atomic_read(&pag->pagf_fstrms);
49 xfs_perag_put(pag);
50 return ret;
51}
52
27};
28
29enum xfs_fstrm_alloc {
30 XFS_PICK_USERDATA = 1,
31 XFS_PICK_LOWSPACE = 2,
32};
33
34/*

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

45 int ret;
46
47 pag = xfs_perag_get(mp, agno);
48 ret = atomic_read(&pag->pagf_fstrms);
49 xfs_perag_put(pag);
50 return ret;
51}
52
53static int
54xfs_filestream_get_ag(
55 xfs_mount_t *mp,
56 xfs_agnumber_t agno)
57{
58 struct xfs_perag *pag;
59 int ret;
60
61 pag = xfs_perag_get(mp, agno);
62 ret = atomic_inc_return(&pag->pagf_fstrms);
63 xfs_perag_put(pag);
64 return ret;
65}
66
67static void
53static void
68xfs_filestream_put_ag(
69 xfs_mount_t *mp,
70 xfs_agnumber_t agno)
71{
72 struct xfs_perag *pag;
73
74 pag = xfs_perag_get(mp, agno);
75 atomic_dec(&pag->pagf_fstrms);
76 xfs_perag_put(pag);
77}
78
79static void
80xfs_fstrm_free_func(
81 void *data,
82 struct xfs_mru_cache_elem *mru)
83{
54xfs_fstrm_free_func(
55 void *data,
56 struct xfs_mru_cache_elem *mru)
57{
84 struct xfs_mount *mp = data;
85 struct xfs_fstrm_item *item =
86 container_of(mru, struct xfs_fstrm_item, mru);
58 struct xfs_fstrm_item *item =
59 container_of(mru, struct xfs_fstrm_item, mru);
60 struct xfs_perag *pag = item->pag;
87
61
88 xfs_filestream_put_ag(mp, item->ag);
89 trace_xfs_filestream_free(mp, mru->key, item->ag);
62 trace_xfs_filestream_free(pag->pag_mount, mru->key, pag->pag_agno);
63 atomic_dec(&pag->pagf_fstrms);
64 xfs_perag_rele(pag);
90
91 kmem_free(item);
92}
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 *agp,
102 int flags,
103 xfs_extlen_t *longest)
104{
105 struct xfs_mount *mp = ip->i_mount;
106 struct xfs_fstrm_item *item;
107 struct xfs_perag *pag;
65
66 kmem_free(item);
67}
68
69/*
70 * Scan the AGs starting at startag looking for an AG that isn't in use and has
71 * at least minlen blocks free.
72 */
73static int
74xfs_filestream_pick_ag(
75 struct xfs_inode *ip,
76 xfs_agnumber_t *agp,
77 int flags,
78 xfs_extlen_t *longest)
79{
80 struct xfs_mount *mp = ip->i_mount;
81 struct xfs_fstrm_item *item;
82 struct xfs_perag *pag;
83 struct xfs_perag *max_pag = NULL;
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;
84 xfs_extlen_t minlen = *longest;
85 xfs_extlen_t free = 0, minfree, maxfree = 0;
86 xfs_agnumber_t startag = *agp;
87 xfs_agnumber_t ag = startag;
112 xfs_agnumber_t max_ag = NULLAGNUMBER;
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
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
88 int err, trylock, nscan;
89
90 ASSERT(S_ISDIR(VFS_I(ip)->i_mode));
91
92 /* 2% of an AG's blocks must be free for it to be chosen. */
93 minfree = mp->m_sb.sb_agblocks / 50;
94
95 *agp = NULLAGNUMBER;
96
97 /* For the first pass, don't sleep trying to init the per-AG. */
98 trylock = XFS_ALLOC_FLAG_TRYLOCK;
99
100 for (nscan = 0; 1; nscan++) {
101 trace_xfs_filestream_scan(mp, ip->i_ino, ag);
102
128 pag = xfs_perag_get(mp, ag);
103 err = 0;
104 pag = xfs_perag_grab(mp, ag);
105 if (!pag)
106 goto next_ag;
129 *longest = 0;
130 err = xfs_bmap_longest_free_extent(pag, NULL, longest);
131 if (err) {
107 *longest = 0;
108 err = xfs_bmap_longest_free_extent(pag, NULL, longest);
109 if (err) {
132 xfs_perag_put(pag);
110 xfs_perag_rele(pag);
133 if (err != -EAGAIN)
111 if (err != -EAGAIN)
134 return err;
112 break;
135 /* Couldn't lock the AGF, skip this AG. */
136 goto next_ag;
137 }
138
139 /* Keep track of the AG with the most free blocks. */
140 if (pag->pagf_freeblks > maxfree) {
141 maxfree = pag->pagf_freeblks;
113 /* Couldn't lock the AGF, skip this AG. */
114 goto next_ag;
115 }
116
117 /* Keep track of the AG with the most free blocks. */
118 if (pag->pagf_freeblks > maxfree) {
119 maxfree = pag->pagf_freeblks;
142 max_ag = ag;
120 if (max_pag)
121 xfs_perag_rele(max_pag);
122 atomic_inc(&pag->pag_active_ref);
123 max_pag = pag;
143 }
144
145 /*
146 * The AG reference count does two things: it enforces mutual
147 * exclusion when examining the suitability of an AG in this
148 * loop, and it guards against two filestreams being established
149 * in the same AG as each other.
150 */
124 }
125
126 /*
127 * The AG reference count does two things: it enforces mutual
128 * exclusion when examining the suitability of an AG in this
129 * loop, and it guards against two filestreams being established
130 * in the same AG as each other.
131 */
151 if (xfs_filestream_get_ag(mp, ag) > 1) {
152 xfs_filestream_put_ag(mp, ag);
132 if (atomic_inc_return(&pag->pagf_fstrms) > 1) {
133 atomic_dec(&pag->pagf_fstrms);
134 xfs_perag_rele(pag);
153 goto next_ag;
154 }
155
156 if (((minlen && *longest >= minlen) ||
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;
135 goto next_ag;
136 }
137
138 if (((minlen && *longest >= minlen) ||
139 (!minlen && pag->pagf_freeblks >= minfree)) &&
140 (!xfs_perag_prefers_metadata(pag) ||
141 !(flags & XFS_PICK_USERDATA) ||
142 (flags & XFS_PICK_LOWSPACE))) {
143
144 /* Break out, retaining the reference on the AG. */
145 free = pag->pagf_freeblks;
164 xfs_perag_put(pag);
165 *agp = ag;
166 break;
167 }
168
169 /* Drop the reference on this AG, it's not usable. */
146 break;
147 }
148
149 /* Drop the reference on this AG, it's not usable. */
170 xfs_filestream_put_ag(mp, ag);
150 atomic_dec(&pag->pagf_fstrms);
171next_ag:
151next_ag:
172 xfs_perag_put(pag);
173 /* Move to the next AG, wrapping to AG 0 if necessary. */
174 if (++ag >= mp->m_sb.sb_agcount)
175 ag = 0;
176
177 /* If a full pass of the AGs hasn't been done yet, continue. */
178 if (ag != startag)
179 continue;
180

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

189 flags |= XFS_PICK_LOWSPACE;
190 continue;
191 }
192
193 /*
194 * Take the AG with the most free space, regardless of whether
195 * it's already in use by another filestream.
196 */
152 /* Move to the next AG, wrapping to AG 0 if necessary. */
153 if (++ag >= mp->m_sb.sb_agcount)
154 ag = 0;
155
156 /* If a full pass of the AGs hasn't been done yet, continue. */
157 if (ag != startag)
158 continue;
159

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

168 flags |= XFS_PICK_LOWSPACE;
169 continue;
170 }
171
172 /*
173 * Take the AG with the most free space, regardless of whether
174 * it's already in use by another filestream.
175 */
197 if (max_ag != NULLAGNUMBER) {
198 xfs_filestream_get_ag(mp, max_ag);
176 if (max_pag) {
177 pag = max_pag;
178 atomic_inc(&pag->pagf_fstrms);
199 free = maxfree;
179 free = maxfree;
200 *agp = max_ag;
201 break;
202 }
203
204 /* take AG 0 if none matched */
205 trace_xfs_filestream_pick(ip, *agp, free, nscan);
206 *agp = 0;
207 return 0;
208 }
209
180 break;
181 }
182
183 /* take AG 0 if none matched */
184 trace_xfs_filestream_pick(ip, *agp, free, nscan);
185 *agp = 0;
186 return 0;
187 }
188
210 trace_xfs_filestream_pick(ip, *agp, free, nscan);
189 trace_xfs_filestream_pick(ip, pag ? pag->pag_agno : NULLAGNUMBER,
190 free, nscan);
211
191
212 if (*agp == NULLAGNUMBER)
192 if (max_pag)
193 xfs_perag_rele(max_pag);
194
195 if (err)
196 return err;
197
198 if (!pag) {
199 *agp = NULLAGNUMBER;
213 return 0;
200 return 0;
201 }
214
215 err = -ENOMEM;
216 item = kmem_alloc(sizeof(*item), KM_MAYFAIL);
217 if (!item)
218 goto out_put_ag;
219
202
203 err = -ENOMEM;
204 item = kmem_alloc(sizeof(*item), KM_MAYFAIL);
205 if (!item)
206 goto out_put_ag;
207
220 item->ag = *agp;
208 item->pag = pag;
221
222 err = xfs_mru_cache_insert(mp->m_filestream, ip->i_ino, &item->mru);
223 if (err) {
224 if (err == -EEXIST)
225 err = 0;
226 goto out_free_item;
227 }
228
209
210 err = xfs_mru_cache_insert(mp->m_filestream, ip->i_ino, &item->mru);
211 if (err) {
212 if (err == -EEXIST)
213 err = 0;
214 goto out_free_item;
215 }
216
217 *agp = pag->pag_agno;
229 return 0;
230
231out_free_item:
232 kmem_free(item);
233out_put_ag:
218 return 0;
219
220out_free_item:
221 kmem_free(item);
222out_put_ag:
234 xfs_filestream_put_ag(mp, *agp);
223 atomic_dec(&pag->pagf_fstrms);
224 xfs_perag_rele(pag);
235 return err;
236}
237
238static struct xfs_inode *
239xfs_filestream_get_parent(
240 struct xfs_inode *ip)
241{
242 struct inode *inode = VFS_I(ip), *dir = NULL;

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

279 struct xfs_perag *pag;
280 struct xfs_mru_cache_elem *mru;
281 int error;
282
283 mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
284 if (!mru)
285 goto out_default_agno;
286
225 return err;
226}
227
228static struct xfs_inode *
229xfs_filestream_get_parent(
230 struct xfs_inode *ip)
231{
232 struct inode *inode = VFS_I(ip), *dir = NULL;

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

269 struct xfs_perag *pag;
270 struct xfs_mru_cache_elem *mru;
271 int error;
272
273 mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
274 if (!mru)
275 goto out_default_agno;
276
287 *agno = container_of(mru, struct xfs_fstrm_item, mru)->ag;
277 pag = container_of(mru, struct xfs_fstrm_item, mru)->pag;
288 xfs_mru_cache_done(mp->m_filestream);
289
278 xfs_mru_cache_done(mp->m_filestream);
279
290 trace_xfs_filestream_lookup(mp, ap->ip->i_ino, *agno);
280 trace_xfs_filestream_lookup(mp, ap->ip->i_ino, pag->pag_agno);
291
281
292 ap->blkno = XFS_AGB_TO_FSB(args->mp, *agno, 0);
282 ap->blkno = XFS_AGB_TO_FSB(args->mp, pag->pag_agno, 0);
293 xfs_bmap_adjacent(ap);
294
283 xfs_bmap_adjacent(ap);
284
295 pag = xfs_perag_grab(mp, *agno);
296 if (!pag)
297 goto out_default_agno;
298
299 error = xfs_bmap_longest_free_extent(pag, args->tp, blen);
285 error = xfs_bmap_longest_free_extent(pag, args->tp, blen);
300 xfs_perag_rele(pag);
301 if (error) {
302 if (error != -EAGAIN)
303 return error;
304 *blen = 0;
305 }
306
307 /*
308 * We are done if there's still enough contiguous free space to succeed.
309 */
286 if (error) {
287 if (error != -EAGAIN)
288 return error;
289 *blen = 0;
290 }
291
292 /*
293 * We are done if there's still enough contiguous free space to succeed.
294 */
295 *agno = pag->pag_agno;
310 if (*blen >= args->maxlen)
311 return 0;
312
313 /* Changing parent AG association now, so remove the existing one. */
314 mru = xfs_mru_cache_remove(mp->m_filestream, pip->i_ino);
315 if (mru) {
316 struct xfs_fstrm_item *item =
317 container_of(mru, struct xfs_fstrm_item, mru);
296 if (*blen >= args->maxlen)
297 return 0;
298
299 /* Changing parent AG association now, so remove the existing one. */
300 mru = xfs_mru_cache_remove(mp->m_filestream, pip->i_ino);
301 if (mru) {
302 struct xfs_fstrm_item *item =
303 container_of(mru, struct xfs_fstrm_item, mru);
318 *agno = (item->ag + 1) % mp->m_sb.sb_agcount;
304 *agno = (item->pag->pag_agno + 1) % mp->m_sb.sb_agcount;
319 xfs_fstrm_free_func(mp, mru);
320 return 0;
321 }
322
323out_default_agno:
324 if (xfs_is_inode32(mp)) {
325 xfs_agnumber_t rotorstep = xfs_rotorstep;
326 *agno = (mp->m_agfrotor / rotorstep) %

--- 99 unchanged lines hidden ---
305 xfs_fstrm_free_func(mp, mru);
306 return 0;
307 }
308
309out_default_agno:
310 if (xfs_is_inode32(mp)) {
311 xfs_agnumber_t rotorstep = xfs_rotorstep;
312 *agno = (mp->m_agfrotor / rotorstep) %

--- 99 unchanged lines hidden ---