diff options
Diffstat (limited to 'fs/xfs/xfs_filestream.c')
| -rw-r--r-- | fs/xfs/xfs_filestream.c | 42 | 
1 files changed, 14 insertions, 28 deletions
diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c index a631e1451abb..390850ee6603 100644 --- a/fs/xfs/xfs_filestream.c +++ b/fs/xfs/xfs_filestream.c  | |||
| @@ -140,6 +140,7 @@ _xfs_filestream_pick_ag( | |||
| 140 | int flags, | 140 | int flags, | 
| 141 | xfs_extlen_t minlen) | 141 | xfs_extlen_t minlen) | 
| 142 | { | 142 | { | 
| 143 | int streams, max_streams; | ||
| 143 | int err, trylock, nscan; | 144 | int err, trylock, nscan; | 
| 144 | xfs_extlen_t longest, free, minfree, maxfree = 0; | 145 | xfs_extlen_t longest, free, minfree, maxfree = 0; | 
| 145 | xfs_agnumber_t ag, max_ag = NULLAGNUMBER; | 146 | xfs_agnumber_t ag, max_ag = NULLAGNUMBER; | 
| @@ -155,15 +156,15 @@ _xfs_filestream_pick_ag( | |||
| 155 | trylock = XFS_ALLOC_FLAG_TRYLOCK; | 156 | trylock = XFS_ALLOC_FLAG_TRYLOCK; | 
| 156 | 157 | ||
| 157 | for (nscan = 0; 1; nscan++) { | 158 | for (nscan = 0; 1; nscan++) { | 
| 158 | 159 | pag = xfs_perag_get(mp, ag); | |
| 159 | TRACE_AG_SCAN(mp, ag, xfs_filestream_peek_ag(mp, ag)); | 160 | TRACE_AG_SCAN(mp, ag, atomic_read(&pag->pagf_fstrms)); | 
| 160 | |||
| 161 | pag = mp->m_perag + ag; | ||
| 162 | 161 | ||
| 163 | if (!pag->pagf_init) { | 162 | if (!pag->pagf_init) { | 
| 164 | err = xfs_alloc_pagf_init(mp, NULL, ag, trylock); | 163 | err = xfs_alloc_pagf_init(mp, NULL, ag, trylock); | 
| 165 | if (err && !trylock) | 164 | if (err && !trylock) { | 
| 165 | xfs_perag_put(pag); | ||
| 166 | return err; | 166 | return err; | 
| 167 | } | ||
| 167 | } | 168 | } | 
| 168 | 169 | ||
| 169 | /* Might fail sometimes during the 1st pass with trylock set. */ | 170 | /* Might fail sometimes during the 1st pass with trylock set. */ | 
| @@ -173,6 +174,7 @@ _xfs_filestream_pick_ag( | |||
| 173 | /* Keep track of the AG with the most free blocks. */ | 174 | /* Keep track of the AG with the most free blocks. */ | 
| 174 | if (pag->pagf_freeblks > maxfree) { | 175 | if (pag->pagf_freeblks > maxfree) { | 
| 175 | maxfree = pag->pagf_freeblks; | 176 | maxfree = pag->pagf_freeblks; | 
| 177 | max_streams = atomic_read(&pag->pagf_fstrms); | ||
| 176 | max_ag = ag; | 178 | max_ag = ag; | 
| 177 | } | 179 | } | 
| 178 | 180 | ||
| @@ -195,6 +197,8 @@ _xfs_filestream_pick_ag( | |||
| 195 | 197 | ||
| 196 | /* Break out, retaining the reference on the AG. */ | 198 | /* Break out, retaining the reference on the AG. */ | 
| 197 | free = pag->pagf_freeblks; | 199 | free = pag->pagf_freeblks; | 
| 200 | streams = atomic_read(&pag->pagf_fstrms); | ||
| 201 | xfs_perag_put(pag); | ||
| 198 | *agp = ag; | 202 | *agp = ag; | 
| 199 | break; | 203 | break; | 
| 200 | } | 204 | } | 
| @@ -202,6 +206,7 @@ _xfs_filestream_pick_ag( | |||
| 202 | /* Drop the reference on this AG, it's not usable. */ | 206 | /* Drop the reference on this AG, it's not usable. */ | 
| 203 | xfs_filestream_put_ag(mp, ag); | 207 | xfs_filestream_put_ag(mp, ag); | 
| 204 | next_ag: | 208 | next_ag: | 
| 209 | xfs_perag_put(pag); | ||
| 205 | /* Move to the next AG, wrapping to AG 0 if necessary. */ | 210 | /* Move to the next AG, wrapping to AG 0 if necessary. */ | 
| 206 | if (++ag >= mp->m_sb.sb_agcount) | 211 | if (++ag >= mp->m_sb.sb_agcount) | 
| 207 | ag = 0; | 212 | ag = 0; | 
| @@ -229,6 +234,7 @@ next_ag: | |||
| 229 | if (max_ag != NULLAGNUMBER) { | 234 | if (max_ag != NULLAGNUMBER) { | 
| 230 | xfs_filestream_get_ag(mp, max_ag); | 235 | xfs_filestream_get_ag(mp, max_ag); | 
| 231 | TRACE_AG_PICK1(mp, max_ag, maxfree); | 236 | TRACE_AG_PICK1(mp, max_ag, maxfree); | 
| 237 | streams = max_streams; | ||
| 232 | free = maxfree; | 238 | free = maxfree; | 
| 233 | *agp = max_ag; | 239 | *agp = max_ag; | 
| 234 | break; | 240 | break; | 
| @@ -240,16 +246,14 @@ next_ag: | |||
| 240 | return 0; | 246 | return 0; | 
| 241 | } | 247 | } | 
| 242 | 248 | ||
| 243 | TRACE_AG_PICK2(mp, startag, *agp, xfs_filestream_peek_ag(mp, *agp), | 249 | TRACE_AG_PICK2(mp, startag, *agp, streams, free, nscan, flags); | 
| 244 | free, nscan, flags); | ||
| 245 | 250 | ||
| 246 | return 0; | 251 | return 0; | 
| 247 | } | 252 | } | 
| 248 | 253 | ||
| 249 | /* | 254 | /* | 
| 250 | * Set the allocation group number for a file or a directory, updating inode | 255 | * Set the allocation group number for a file or a directory, updating inode | 
| 251 | * references and per-AG references as appropriate. Must be called with the | 256 | * references and per-AG references as appropriate. | 
| 252 | * m_peraglock held in read mode. | ||
| 253 | */ | 257 | */ | 
| 254 | static int | 258 | static int | 
| 255 | _xfs_filestream_update_ag( | 259 | _xfs_filestream_update_ag( | 
| @@ -451,20 +455,6 @@ xfs_filestream_unmount( | |||
| 451 | } | 455 | } | 
| 452 | 456 | ||
| 453 | /* | 457 | /* | 
| 454 | * If the mount point's m_perag array is going to be reallocated, all | ||
| 455 | * outstanding cache entries must be flushed to avoid accessing reference count | ||
| 456 | * addresses that have been freed. The call to xfs_filestream_flush() must be | ||
| 457 | * made inside the block that holds the m_peraglock in write mode to do the | ||
| 458 | * reallocation. | ||
| 459 | */ | ||
| 460 | void | ||
| 461 | xfs_filestream_flush( | ||
| 462 | xfs_mount_t *mp) | ||
| 463 | { | ||
| 464 | xfs_mru_cache_flush(mp->m_filestream); | ||
| 465 | } | ||
| 466 | |||
| 467 | /* | ||
| 468 | * Return the AG of the filestream the file or directory belongs to, or | 458 | * Return the AG of the filestream the file or directory belongs to, or | 
| 469 | * NULLAGNUMBER otherwise. | 459 | * NULLAGNUMBER otherwise. | 
| 470 | */ | 460 | */ | 
| @@ -526,7 +516,6 @@ xfs_filestream_associate( | |||
| 526 | 516 | ||
| 527 | mp = pip->i_mount; | 517 | mp = pip->i_mount; | 
| 528 | cache = mp->m_filestream; | 518 | cache = mp->m_filestream; | 
| 529 | down_read(&mp->m_peraglock); | ||
| 530 | 519 | ||
| 531 | /* | 520 | /* | 
| 532 | * We have a problem, Houston. | 521 | * We have a problem, Houston. | 
| @@ -543,10 +532,8 @@ xfs_filestream_associate( | |||
| 543 | * | 532 | * | 
| 544 | * So, if we can't get the iolock without sleeping then just give up | 533 | * So, if we can't get the iolock without sleeping then just give up | 
| 545 | */ | 534 | */ | 
| 546 | if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL)) { | 535 | if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL)) | 
| 547 | up_read(&mp->m_peraglock); | ||
| 548 | return 1; | 536 | return 1; | 
| 549 | } | ||
| 550 | 537 | ||
| 551 | /* If the parent directory is already in the cache, use its AG. */ | 538 | /* If the parent directory is already in the cache, use its AG. */ | 
| 552 | item = xfs_mru_cache_lookup(cache, pip->i_ino); | 539 | item = xfs_mru_cache_lookup(cache, pip->i_ino); | 
| @@ -601,7 +588,6 @@ exit_did_pick: | |||
| 601 | 588 | ||
| 602 | exit: | 589 | exit: | 
| 603 | xfs_iunlock(pip, XFS_IOLOCK_EXCL); | 590 | xfs_iunlock(pip, XFS_IOLOCK_EXCL); | 
| 604 | up_read(&mp->m_peraglock); | ||
| 605 | return -err; | 591 | return -err; | 
| 606 | } | 592 | } | 
| 607 | 593 | ||
