diff options
-rw-r--r-- | fs/xfs/xfs_alloc.c | 8 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap.c | 7 | ||||
-rw-r--r-- | fs/xfs/xfs_filestream.c | 13 | ||||
-rw-r--r-- | fs/xfs/xfs_fsops.c | 42 | ||||
-rw-r--r-- | fs/xfs/xfs_ialloc.c | 25 | ||||
-rw-r--r-- | fs/xfs/xfs_itable.c | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.c | 63 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 14 |
8 files changed, 86 insertions, 90 deletions
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 84070f2e0ba4..4d66bb75579c 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c | |||
@@ -2276,7 +2276,6 @@ xfs_alloc_vextent( | |||
2276 | * These three force us into a single a.g. | 2276 | * These three force us into a single a.g. |
2277 | */ | 2277 | */ |
2278 | args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); | 2278 | args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); |
2279 | down_read(&mp->m_peraglock); | ||
2280 | args->pag = xfs_perag_get(mp, args->agno); | 2279 | args->pag = xfs_perag_get(mp, args->agno); |
2281 | args->minleft = 0; | 2280 | args->minleft = 0; |
2282 | error = xfs_alloc_fix_freelist(args, 0); | 2281 | error = xfs_alloc_fix_freelist(args, 0); |
@@ -2286,14 +2285,12 @@ xfs_alloc_vextent( | |||
2286 | goto error0; | 2285 | goto error0; |
2287 | } | 2286 | } |
2288 | if (!args->agbp) { | 2287 | if (!args->agbp) { |
2289 | up_read(&mp->m_peraglock); | ||
2290 | trace_xfs_alloc_vextent_noagbp(args); | 2288 | trace_xfs_alloc_vextent_noagbp(args); |
2291 | break; | 2289 | break; |
2292 | } | 2290 | } |
2293 | args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); | 2291 | args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); |
2294 | if ((error = xfs_alloc_ag_vextent(args))) | 2292 | if ((error = xfs_alloc_ag_vextent(args))) |
2295 | goto error0; | 2293 | goto error0; |
2296 | up_read(&mp->m_peraglock); | ||
2297 | break; | 2294 | break; |
2298 | case XFS_ALLOCTYPE_START_BNO: | 2295 | case XFS_ALLOCTYPE_START_BNO: |
2299 | /* | 2296 | /* |
@@ -2345,7 +2342,6 @@ xfs_alloc_vextent( | |||
2345 | * Loop over allocation groups twice; first time with | 2342 | * Loop over allocation groups twice; first time with |
2346 | * trylock set, second time without. | 2343 | * trylock set, second time without. |
2347 | */ | 2344 | */ |
2348 | down_read(&mp->m_peraglock); | ||
2349 | for (;;) { | 2345 | for (;;) { |
2350 | args->pag = xfs_perag_get(mp, args->agno); | 2346 | args->pag = xfs_perag_get(mp, args->agno); |
2351 | if (no_min) args->minleft = 0; | 2347 | if (no_min) args->minleft = 0; |
@@ -2408,7 +2404,6 @@ xfs_alloc_vextent( | |||
2408 | } | 2404 | } |
2409 | xfs_perag_put(args->pag); | 2405 | xfs_perag_put(args->pag); |
2410 | } | 2406 | } |
2411 | up_read(&mp->m_peraglock); | ||
2412 | if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) { | 2407 | if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) { |
2413 | if (args->agno == sagno) | 2408 | if (args->agno == sagno) |
2414 | mp->m_agfrotor = (mp->m_agfrotor + 1) % | 2409 | mp->m_agfrotor = (mp->m_agfrotor + 1) % |
@@ -2438,7 +2433,6 @@ xfs_alloc_vextent( | |||
2438 | return 0; | 2433 | return 0; |
2439 | error0: | 2434 | error0: |
2440 | xfs_perag_put(args->pag); | 2435 | xfs_perag_put(args->pag); |
2441 | up_read(&mp->m_peraglock); | ||
2442 | return error; | 2436 | return error; |
2443 | } | 2437 | } |
2444 | 2438 | ||
@@ -2463,7 +2457,6 @@ xfs_free_extent( | |||
2463 | args.agno = XFS_FSB_TO_AGNO(args.mp, bno); | 2457 | args.agno = XFS_FSB_TO_AGNO(args.mp, bno); |
2464 | ASSERT(args.agno < args.mp->m_sb.sb_agcount); | 2458 | ASSERT(args.agno < args.mp->m_sb.sb_agcount); |
2465 | args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); | 2459 | args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); |
2466 | down_read(&args.mp->m_peraglock); | ||
2467 | args.pag = xfs_perag_get(args.mp, args.agno); | 2460 | args.pag = xfs_perag_get(args.mp, args.agno); |
2468 | if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING))) | 2461 | if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING))) |
2469 | goto error0; | 2462 | goto error0; |
@@ -2475,7 +2468,6 @@ xfs_free_extent( | |||
2475 | error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); | 2468 | error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); |
2476 | error0: | 2469 | error0: |
2477 | xfs_perag_put(args.pag); | 2470 | xfs_perag_put(args.pag); |
2478 | up_read(&args.mp->m_peraglock); | ||
2479 | return error; | 2471 | return error; |
2480 | } | 2472 | } |
2481 | 2473 | ||
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index a9b95d9cf2ad..7c6d9acd7154 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -2629,14 +2629,12 @@ xfs_bmap_btalloc( | |||
2629 | if (startag == NULLAGNUMBER) | 2629 | if (startag == NULLAGNUMBER) |
2630 | startag = ag = 0; | 2630 | startag = ag = 0; |
2631 | notinit = 0; | 2631 | notinit = 0; |
2632 | down_read(&mp->m_peraglock); | ||
2633 | pag = xfs_perag_get(mp, ag); | 2632 | pag = xfs_perag_get(mp, ag); |
2634 | while (blen < ap->alen) { | 2633 | while (blen < ap->alen) { |
2635 | if (!pag->pagf_init && | 2634 | if (!pag->pagf_init && |
2636 | (error = xfs_alloc_pagf_init(mp, args.tp, | 2635 | (error = xfs_alloc_pagf_init(mp, args.tp, |
2637 | ag, XFS_ALLOC_FLAG_TRYLOCK))) { | 2636 | ag, XFS_ALLOC_FLAG_TRYLOCK))) { |
2638 | xfs_perag_put(pag); | 2637 | xfs_perag_put(pag); |
2639 | up_read(&mp->m_peraglock); | ||
2640 | return error; | 2638 | return error; |
2641 | } | 2639 | } |
2642 | /* | 2640 | /* |
@@ -2669,10 +2667,8 @@ xfs_bmap_btalloc( | |||
2669 | 2667 | ||
2670 | error = xfs_filestream_new_ag(ap, &ag); | 2668 | error = xfs_filestream_new_ag(ap, &ag); |
2671 | xfs_perag_put(pag); | 2669 | xfs_perag_put(pag); |
2672 | if (error) { | 2670 | if (error) |
2673 | up_read(&mp->m_peraglock); | ||
2674 | return error; | 2671 | return error; |
2675 | } | ||
2676 | 2672 | ||
2677 | /* loop again to set 'blen'*/ | 2673 | /* loop again to set 'blen'*/ |
2678 | startag = NULLAGNUMBER; | 2674 | startag = NULLAGNUMBER; |
@@ -2688,7 +2684,6 @@ xfs_bmap_btalloc( | |||
2688 | pag = xfs_perag_get(mp, ag); | 2684 | pag = xfs_perag_get(mp, ag); |
2689 | } | 2685 | } |
2690 | xfs_perag_put(pag); | 2686 | xfs_perag_put(pag); |
2691 | up_read(&mp->m_peraglock); | ||
2692 | /* | 2687 | /* |
2693 | * Since the above loop did a BUF_TRYLOCK, it is | 2688 | * Since the above loop did a BUF_TRYLOCK, it is |
2694 | * possible that there is space for this request. | 2689 | * possible that there is space for this request. |
diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c index e61f2aa088a9..914d00d0f119 100644 --- a/fs/xfs/xfs_filestream.c +++ b/fs/xfs/xfs_filestream.c | |||
@@ -253,8 +253,7 @@ next_ag: | |||
253 | 253 | ||
254 | /* | 254 | /* |
255 | * 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 |
256 | * references and per-AG references as appropriate. Must be called with the | 256 | * references and per-AG references as appropriate. |
257 | * m_peraglock held in read mode. | ||
258 | */ | 257 | */ |
259 | static int | 258 | static int |
260 | _xfs_filestream_update_ag( | 259 | _xfs_filestream_update_ag( |
@@ -456,10 +455,10 @@ xfs_filestream_unmount( | |||
456 | } | 455 | } |
457 | 456 | ||
458 | /* | 457 | /* |
459 | * If the mount point's m_perag array is going to be reallocated, all | 458 | * If the mount point's m_perag tree is going to be modified, all |
460 | * outstanding cache entries must be flushed to avoid accessing reference count | 459 | * outstanding cache entries must be flushed to avoid accessing reference count |
461 | * addresses that have been freed. The call to xfs_filestream_flush() must be | 460 | * addresses that have been freed. The call to xfs_filestream_flush() must be |
462 | * made inside the block that holds the m_peraglock in write mode to do the | 461 | * made inside the block that holds the m_perag_lock in write mode to do the |
463 | * reallocation. | 462 | * reallocation. |
464 | */ | 463 | */ |
465 | void | 464 | void |
@@ -531,7 +530,6 @@ xfs_filestream_associate( | |||
531 | 530 | ||
532 | mp = pip->i_mount; | 531 | mp = pip->i_mount; |
533 | cache = mp->m_filestream; | 532 | cache = mp->m_filestream; |
534 | down_read(&mp->m_peraglock); | ||
535 | 533 | ||
536 | /* | 534 | /* |
537 | * We have a problem, Houston. | 535 | * We have a problem, Houston. |
@@ -548,10 +546,8 @@ xfs_filestream_associate( | |||
548 | * | 546 | * |
549 | * So, if we can't get the iolock without sleeping then just give up | 547 | * So, if we can't get the iolock without sleeping then just give up |
550 | */ | 548 | */ |
551 | if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL)) { | 549 | if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL)) |
552 | up_read(&mp->m_peraglock); | ||
553 | return 1; | 550 | return 1; |
554 | } | ||
555 | 551 | ||
556 | /* If the parent directory is already in the cache, use its AG. */ | 552 | /* If the parent directory is already in the cache, use its AG. */ |
557 | item = xfs_mru_cache_lookup(cache, pip->i_ino); | 553 | item = xfs_mru_cache_lookup(cache, pip->i_ino); |
@@ -606,7 +602,6 @@ exit_did_pick: | |||
606 | 602 | ||
607 | exit: | 603 | exit: |
608 | xfs_iunlock(pip, XFS_IOLOCK_EXCL); | 604 | xfs_iunlock(pip, XFS_IOLOCK_EXCL); |
609 | up_read(&mp->m_peraglock); | ||
610 | return -err; | 605 | return -err; |
611 | } | 606 | } |
612 | 607 | ||
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index a13919a6a364..37a6f62c57b6 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c | |||
@@ -167,27 +167,14 @@ xfs_growfs_data_private( | |||
167 | } | 167 | } |
168 | new = nb - mp->m_sb.sb_dblocks; | 168 | new = nb - mp->m_sb.sb_dblocks; |
169 | oagcount = mp->m_sb.sb_agcount; | 169 | oagcount = mp->m_sb.sb_agcount; |
170 | if (nagcount > oagcount) { | ||
171 | void *new_perag, *old_perag; | ||
172 | |||
173 | xfs_filestream_flush(mp); | ||
174 | |||
175 | new_perag = kmem_zalloc(sizeof(xfs_perag_t) * nagcount, | ||
176 | KM_MAYFAIL); | ||
177 | if (!new_perag) | ||
178 | return XFS_ERROR(ENOMEM); | ||
179 | |||
180 | down_write(&mp->m_peraglock); | ||
181 | memcpy(new_perag, mp->m_perag, sizeof(xfs_perag_t) * oagcount); | ||
182 | old_perag = mp->m_perag; | ||
183 | mp->m_perag = new_perag; | ||
184 | |||
185 | mp->m_flags |= XFS_MOUNT_32BITINODES; | ||
186 | nagimax = xfs_initialize_perag(mp, nagcount); | ||
187 | up_write(&mp->m_peraglock); | ||
188 | 170 | ||
189 | kmem_free(old_perag); | 171 | /* allocate the new per-ag structures */ |
172 | if (nagcount > oagcount) { | ||
173 | error = xfs_initialize_perag(mp, nagcount, &nagimax); | ||
174 | if (error) | ||
175 | return error; | ||
190 | } | 176 | } |
177 | |||
191 | tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS); | 178 | tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS); |
192 | tp->t_flags |= XFS_TRANS_RESERVE; | 179 | tp->t_flags |= XFS_TRANS_RESERVE; |
193 | if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp), | 180 | if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp), |
@@ -196,6 +183,11 @@ xfs_growfs_data_private( | |||
196 | return error; | 183 | return error; |
197 | } | 184 | } |
198 | 185 | ||
186 | /* | ||
187 | * Write new AG headers to disk. Non-transactional, but written | ||
188 | * synchronously so they are completed prior to the growfs transaction | ||
189 | * being logged. | ||
190 | */ | ||
199 | nfree = 0; | 191 | nfree = 0; |
200 | for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) { | 192 | for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) { |
201 | /* | 193 | /* |
@@ -359,6 +351,12 @@ xfs_growfs_data_private( | |||
359 | goto error0; | 351 | goto error0; |
360 | } | 352 | } |
361 | } | 353 | } |
354 | |||
355 | /* | ||
356 | * Update changed superblock fields transactionally. These are not | ||
357 | * seen by the rest of the world until the transaction commit applies | ||
358 | * them atomically to the superblock. | ||
359 | */ | ||
362 | if (nagcount > oagcount) | 360 | if (nagcount > oagcount) |
363 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount); | 361 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount); |
364 | if (nb > mp->m_sb.sb_dblocks) | 362 | if (nb > mp->m_sb.sb_dblocks) |
@@ -369,9 +367,9 @@ xfs_growfs_data_private( | |||
369 | if (dpct) | 367 | if (dpct) |
370 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct); | 368 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct); |
371 | error = xfs_trans_commit(tp, 0); | 369 | error = xfs_trans_commit(tp, 0); |
372 | if (error) { | 370 | if (error) |
373 | return error; | 371 | return error; |
374 | } | 372 | |
375 | /* New allocation groups fully initialized, so update mount struct */ | 373 | /* New allocation groups fully initialized, so update mount struct */ |
376 | if (nagimax) | 374 | if (nagimax) |
377 | mp->m_maxagi = nagimax; | 375 | mp->m_maxagi = nagimax; |
@@ -381,6 +379,8 @@ xfs_growfs_data_private( | |||
381 | mp->m_maxicount = icount << mp->m_sb.sb_inopblog; | 379 | mp->m_maxicount = icount << mp->m_sb.sb_inopblog; |
382 | } else | 380 | } else |
383 | mp->m_maxicount = 0; | 381 | mp->m_maxicount = 0; |
382 | |||
383 | /* update secondary superblocks. */ | ||
384 | for (agno = 1; agno < nagcount; agno++) { | 384 | for (agno = 1; agno < nagcount; agno++) { |
385 | error = xfs_read_buf(mp, mp->m_ddev_targp, | 385 | error = xfs_read_buf(mp, mp->m_ddev_targp, |
386 | XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), | 386 | XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), |
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 884ee1367f46..52c9d006c0e6 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
@@ -383,11 +383,9 @@ xfs_ialloc_ag_alloc( | |||
383 | newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0); | 383 | newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0); |
384 | be32_add_cpu(&agi->agi_count, newlen); | 384 | be32_add_cpu(&agi->agi_count, newlen); |
385 | be32_add_cpu(&agi->agi_freecount, newlen); | 385 | be32_add_cpu(&agi->agi_freecount, newlen); |
386 | down_read(&args.mp->m_peraglock); | ||
387 | pag = xfs_perag_get(args.mp, agno); | 386 | pag = xfs_perag_get(args.mp, agno); |
388 | pag->pagi_freecount += newlen; | 387 | pag->pagi_freecount += newlen; |
389 | xfs_perag_put(pag); | 388 | xfs_perag_put(pag); |
390 | up_read(&args.mp->m_peraglock); | ||
391 | agi->agi_newino = cpu_to_be32(newino); | 389 | agi->agi_newino = cpu_to_be32(newino); |
392 | 390 | ||
393 | /* | 391 | /* |
@@ -489,7 +487,6 @@ xfs_ialloc_ag_select( | |||
489 | */ | 487 | */ |
490 | agno = pagno; | 488 | agno = pagno; |
491 | flags = XFS_ALLOC_FLAG_TRYLOCK; | 489 | flags = XFS_ALLOC_FLAG_TRYLOCK; |
492 | down_read(&mp->m_peraglock); | ||
493 | for (;;) { | 490 | for (;;) { |
494 | pag = xfs_perag_get(mp, agno); | 491 | pag = xfs_perag_get(mp, agno); |
495 | if (!pag->pagi_init) { | 492 | if (!pag->pagi_init) { |
@@ -531,7 +528,6 @@ xfs_ialloc_ag_select( | |||
531 | goto nextag; | 528 | goto nextag; |
532 | } | 529 | } |
533 | xfs_perag_put(pag); | 530 | xfs_perag_put(pag); |
534 | up_read(&mp->m_peraglock); | ||
535 | return agbp; | 531 | return agbp; |
536 | } | 532 | } |
537 | } | 533 | } |
@@ -544,18 +540,14 @@ nextag: | |||
544 | * No point in iterating over the rest, if we're shutting | 540 | * No point in iterating over the rest, if we're shutting |
545 | * down. | 541 | * down. |
546 | */ | 542 | */ |
547 | if (XFS_FORCED_SHUTDOWN(mp)) { | 543 | if (XFS_FORCED_SHUTDOWN(mp)) |
548 | up_read(&mp->m_peraglock); | ||
549 | return NULL; | 544 | return NULL; |
550 | } | ||
551 | agno++; | 545 | agno++; |
552 | if (agno >= agcount) | 546 | if (agno >= agcount) |
553 | agno = 0; | 547 | agno = 0; |
554 | if (agno == pagno) { | 548 | if (agno == pagno) { |
555 | if (flags == 0) { | 549 | if (flags == 0) |
556 | up_read(&mp->m_peraglock); | ||
557 | return NULL; | 550 | return NULL; |
558 | } | ||
559 | flags = 0; | 551 | flags = 0; |
560 | } | 552 | } |
561 | } | 553 | } |
@@ -777,16 +769,13 @@ nextag: | |||
777 | *inop = NULLFSINO; | 769 | *inop = NULLFSINO; |
778 | return noroom ? ENOSPC : 0; | 770 | return noroom ? ENOSPC : 0; |
779 | } | 771 | } |
780 | down_read(&mp->m_peraglock); | ||
781 | pag = xfs_perag_get(mp, tagno); | 772 | pag = xfs_perag_get(mp, tagno); |
782 | if (pag->pagi_inodeok == 0) { | 773 | if (pag->pagi_inodeok == 0) { |
783 | xfs_perag_put(pag); | 774 | xfs_perag_put(pag); |
784 | up_read(&mp->m_peraglock); | ||
785 | goto nextag; | 775 | goto nextag; |
786 | } | 776 | } |
787 | error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp); | 777 | error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp); |
788 | xfs_perag_put(pag); | 778 | xfs_perag_put(pag); |
789 | up_read(&mp->m_peraglock); | ||
790 | if (error) | 779 | if (error) |
791 | goto nextag; | 780 | goto nextag; |
792 | agi = XFS_BUF_TO_AGI(agbp); | 781 | agi = XFS_BUF_TO_AGI(agbp); |
@@ -1015,9 +1004,7 @@ alloc_inode: | |||
1015 | goto error0; | 1004 | goto error0; |
1016 | be32_add_cpu(&agi->agi_freecount, -1); | 1005 | be32_add_cpu(&agi->agi_freecount, -1); |
1017 | xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); | 1006 | xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); |
1018 | down_read(&mp->m_peraglock); | ||
1019 | pag->pagi_freecount--; | 1007 | pag->pagi_freecount--; |
1020 | up_read(&mp->m_peraglock); | ||
1021 | 1008 | ||
1022 | error = xfs_check_agi_freecount(cur, agi); | 1009 | error = xfs_check_agi_freecount(cur, agi); |
1023 | if (error) | 1010 | if (error) |
@@ -1100,9 +1087,7 @@ xfs_difree( | |||
1100 | /* | 1087 | /* |
1101 | * Get the allocation group header. | 1088 | * Get the allocation group header. |
1102 | */ | 1089 | */ |
1103 | down_read(&mp->m_peraglock); | ||
1104 | error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); | 1090 | error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); |
1105 | up_read(&mp->m_peraglock); | ||
1106 | if (error) { | 1091 | if (error) { |
1107 | cmn_err(CE_WARN, | 1092 | cmn_err(CE_WARN, |
1108 | "xfs_difree: xfs_ialloc_read_agi() returned an error %d on %s. Returning error.", | 1093 | "xfs_difree: xfs_ialloc_read_agi() returned an error %d on %s. Returning error.", |
@@ -1169,11 +1154,9 @@ xfs_difree( | |||
1169 | be32_add_cpu(&agi->agi_count, -ilen); | 1154 | be32_add_cpu(&agi->agi_count, -ilen); |
1170 | be32_add_cpu(&agi->agi_freecount, -(ilen - 1)); | 1155 | be32_add_cpu(&agi->agi_freecount, -(ilen - 1)); |
1171 | xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT); | 1156 | xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT); |
1172 | down_read(&mp->m_peraglock); | ||
1173 | pag = xfs_perag_get(mp, agno); | 1157 | pag = xfs_perag_get(mp, agno); |
1174 | pag->pagi_freecount -= ilen - 1; | 1158 | pag->pagi_freecount -= ilen - 1; |
1175 | xfs_perag_put(pag); | 1159 | xfs_perag_put(pag); |
1176 | up_read(&mp->m_peraglock); | ||
1177 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen); | 1160 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen); |
1178 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1)); | 1161 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1)); |
1179 | 1162 | ||
@@ -1202,11 +1185,9 @@ xfs_difree( | |||
1202 | */ | 1185 | */ |
1203 | be32_add_cpu(&agi->agi_freecount, 1); | 1186 | be32_add_cpu(&agi->agi_freecount, 1); |
1204 | xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); | 1187 | xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); |
1205 | down_read(&mp->m_peraglock); | ||
1206 | pag = xfs_perag_get(mp, agno); | 1188 | pag = xfs_perag_get(mp, agno); |
1207 | pag->pagi_freecount++; | 1189 | pag->pagi_freecount++; |
1208 | xfs_perag_put(pag); | 1190 | xfs_perag_put(pag); |
1209 | up_read(&mp->m_peraglock); | ||
1210 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); | 1191 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); |
1211 | } | 1192 | } |
1212 | 1193 | ||
@@ -1328,9 +1309,7 @@ xfs_imap( | |||
1328 | xfs_buf_t *agbp; /* agi buffer */ | 1309 | xfs_buf_t *agbp; /* agi buffer */ |
1329 | int i; /* temp state */ | 1310 | int i; /* temp state */ |
1330 | 1311 | ||
1331 | down_read(&mp->m_peraglock); | ||
1332 | error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); | 1312 | error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); |
1333 | up_read(&mp->m_peraglock); | ||
1334 | if (error) { | 1313 | if (error) { |
1335 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " | 1314 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " |
1336 | "xfs_ialloc_read_agi() returned " | 1315 | "xfs_ialloc_read_agi() returned " |
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 62efab2f3839..940307a6a60b 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c | |||
@@ -420,9 +420,7 @@ xfs_bulkstat( | |||
420 | while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) { | 420 | while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) { |
421 | cond_resched(); | 421 | cond_resched(); |
422 | bp = NULL; | 422 | bp = NULL; |
423 | down_read(&mp->m_peraglock); | ||
424 | error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); | 423 | error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); |
425 | up_read(&mp->m_peraglock); | ||
426 | if (error) { | 424 | if (error) { |
427 | /* | 425 | /* |
428 | * Skip this allocation group and go to the next one. | 426 | * Skip this allocation group and go to the next one. |
@@ -849,9 +847,7 @@ xfs_inumbers( | |||
849 | agbp = NULL; | 847 | agbp = NULL; |
850 | while (left > 0 && agno < mp->m_sb.sb_agcount) { | 848 | while (left > 0 && agno < mp->m_sb.sb_agcount) { |
851 | if (agbp == NULL) { | 849 | if (agbp == NULL) { |
852 | down_read(&mp->m_peraglock); | ||
853 | error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); | 850 | error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); |
854 | up_read(&mp->m_peraglock); | ||
855 | if (error) { | 851 | if (error) { |
856 | /* | 852 | /* |
857 | * If we can't read the AGI of this ag, | 853 | * If we can't read the AGI of this ag, |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 9055b60730d0..c04dd83cb57c 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -209,13 +209,16 @@ STATIC void | |||
209 | xfs_free_perag( | 209 | xfs_free_perag( |
210 | xfs_mount_t *mp) | 210 | xfs_mount_t *mp) |
211 | { | 211 | { |
212 | if (mp->m_perag) { | 212 | xfs_agnumber_t agno; |
213 | int agno; | 213 | struct xfs_perag *pag; |
214 | 214 | ||
215 | for (agno = 0; agno < mp->m_maxagi; agno++) | 215 | for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { |
216 | if (mp->m_perag[agno].pagb_list) | 216 | spin_lock(&mp->m_perag_lock); |
217 | kmem_free(mp->m_perag[agno].pagb_list); | 217 | pag = radix_tree_delete(&mp->m_perag_tree, agno); |
218 | kmem_free(mp->m_perag); | 218 | spin_unlock(&mp->m_perag_lock); |
219 | ASSERT(pag); | ||
220 | kmem_free(pag->pagb_list); | ||
221 | kmem_free(pag); | ||
219 | } | 222 | } |
220 | } | 223 | } |
221 | 224 | ||
@@ -389,10 +392,11 @@ xfs_initialize_perag_icache( | |||
389 | } | 392 | } |
390 | } | 393 | } |
391 | 394 | ||
392 | xfs_agnumber_t | 395 | int |
393 | xfs_initialize_perag( | 396 | xfs_initialize_perag( |
394 | xfs_mount_t *mp, | 397 | xfs_mount_t *mp, |
395 | xfs_agnumber_t agcount) | 398 | xfs_agnumber_t agcount, |
399 | xfs_agnumber_t *maxagi) | ||
396 | { | 400 | { |
397 | xfs_agnumber_t index, max_metadata; | 401 | xfs_agnumber_t index, max_metadata; |
398 | xfs_perag_t *pag; | 402 | xfs_perag_t *pag; |
@@ -405,6 +409,33 @@ xfs_initialize_perag( | |||
405 | agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); | 409 | agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); |
406 | ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); | 410 | ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); |
407 | 411 | ||
412 | /* | ||
413 | * Walk the current per-ag tree so we don't try to initialise AGs | ||
414 | * that already exist (growfs case). Allocate and insert all the | ||
415 | * AGs we don't find ready for initialisation. | ||
416 | */ | ||
417 | for (index = 0; index < agcount; index++) { | ||
418 | pag = xfs_perag_get(mp, index); | ||
419 | if (pag) { | ||
420 | xfs_perag_put(pag); | ||
421 | continue; | ||
422 | } | ||
423 | pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL); | ||
424 | if (!pag) | ||
425 | return -ENOMEM; | ||
426 | if (radix_tree_preload(GFP_NOFS)) | ||
427 | return -ENOMEM; | ||
428 | spin_lock(&mp->m_perag_lock); | ||
429 | if (radix_tree_insert(&mp->m_perag_tree, index, pag)) { | ||
430 | BUG(); | ||
431 | spin_unlock(&mp->m_perag_lock); | ||
432 | kmem_free(pag); | ||
433 | return -EEXIST; | ||
434 | } | ||
435 | spin_unlock(&mp->m_perag_lock); | ||
436 | radix_tree_preload_end(); | ||
437 | } | ||
438 | |||
408 | /* Clear the mount flag if no inode can overflow 32 bits | 439 | /* Clear the mount flag if no inode can overflow 32 bits |
409 | * on this filesystem, or if specifically requested.. | 440 | * on this filesystem, or if specifically requested.. |
410 | */ | 441 | */ |
@@ -454,7 +485,9 @@ xfs_initialize_perag( | |||
454 | xfs_perag_put(pag); | 485 | xfs_perag_put(pag); |
455 | } | 486 | } |
456 | } | 487 | } |
457 | return index; | 488 | if (maxagi) |
489 | *maxagi = index; | ||
490 | return 0; | ||
458 | } | 491 | } |
459 | 492 | ||
460 | void | 493 | void |
@@ -1155,13 +1188,13 @@ xfs_mountfs( | |||
1155 | /* | 1188 | /* |
1156 | * Allocate and initialize the per-ag data. | 1189 | * Allocate and initialize the per-ag data. |
1157 | */ | 1190 | */ |
1158 | init_rwsem(&mp->m_peraglock); | 1191 | spin_lock_init(&mp->m_perag_lock); |
1159 | mp->m_perag = kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t), | 1192 | INIT_RADIX_TREE(&mp->m_perag_tree, GFP_NOFS); |
1160 | KM_MAYFAIL); | 1193 | error = xfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi); |
1161 | if (!mp->m_perag) | 1194 | if (error) { |
1195 | cmn_err(CE_WARN, "XFS: Failed per-ag init: %d", error); | ||
1162 | goto out_remove_uuid; | 1196 | goto out_remove_uuid; |
1163 | 1197 | } | |
1164 | mp->m_maxagi = xfs_initialize_perag(mp, sbp->sb_agcount); | ||
1165 | 1198 | ||
1166 | if (!sbp->sb_logblocks) { | 1199 | if (!sbp->sb_logblocks) { |
1167 | cmn_err(CE_WARN, "XFS: no log defined"); | 1200 | cmn_err(CE_WARN, "XFS: no log defined"); |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index f8a68a2319b5..cfa7a5d22e72 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -207,8 +207,8 @@ typedef struct xfs_mount { | |||
207 | uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */ | 207 | uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */ |
208 | uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ | 208 | uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ |
209 | uint m_in_maxlevels; /* max inobt btree levels. */ | 209 | uint m_in_maxlevels; /* max inobt btree levels. */ |
210 | struct xfs_perag *m_perag; /* per-ag accounting info */ | 210 | struct radix_tree_root m_perag_tree; /* per-ag accounting info */ |
211 | struct rw_semaphore m_peraglock; /* lock for m_perag (pointer) */ | 211 | spinlock_t m_perag_lock; /* lock for m_perag_tree */ |
212 | struct mutex m_growlock; /* growfs mutex */ | 212 | struct mutex m_growlock; /* growfs mutex */ |
213 | int m_fixedfsid[2]; /* unchanged for life of FS */ | 213 | int m_fixedfsid[2]; /* unchanged for life of FS */ |
214 | uint m_dmevmask; /* DMI events for this FS */ | 214 | uint m_dmevmask; /* DMI events for this FS */ |
@@ -389,7 +389,12 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d) | |||
389 | static inline struct xfs_perag * | 389 | static inline struct xfs_perag * |
390 | xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno) | 390 | xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno) |
391 | { | 391 | { |
392 | return &mp->m_perag[agno]; | 392 | struct xfs_perag *pag; |
393 | |||
394 | spin_lock(&mp->m_perag_lock); | ||
395 | pag = radix_tree_lookup(&mp->m_perag_tree, agno); | ||
396 | spin_unlock(&mp->m_perag_lock); | ||
397 | return pag; | ||
393 | } | 398 | } |
394 | 399 | ||
395 | static inline void | 400 | static inline void |
@@ -450,7 +455,8 @@ extern struct xfs_dmops xfs_dmcore_xfs; | |||
450 | #endif /* __KERNEL__ */ | 455 | #endif /* __KERNEL__ */ |
451 | 456 | ||
452 | extern void xfs_mod_sb(struct xfs_trans *, __int64_t); | 457 | extern void xfs_mod_sb(struct xfs_trans *, __int64_t); |
453 | extern xfs_agnumber_t xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t); | 458 | extern int xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t, |
459 | xfs_agnumber_t *); | ||
454 | extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *); | 460 | extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *); |
455 | extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t); | 461 | extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t); |
456 | 462 | ||