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 --- |