diff options
author | Nathan Scott <nathans@sgi.com> | 2006-03-13 21:34:16 -0500 |
---|---|---|
committer | Nathan Scott <nathans@sgi.com> | 2006-03-13 21:34:16 -0500 |
commit | a365bdd5e8fae9c592b9e4851d931016f9fdd868 (patch) | |
tree | a7f1692ad72f93526177c9d989c31427eef315e9 /fs | |
parent | 39269e29d4aad04252e0debec4c9b01bac16a257 (diff) |
[XFS] Reduce stack usage within xfs_bmapi by rearranging some code,
splitting realtime/btree allocators apart. Based on Glens original
patches.
SGI-PV: 947312
SGI-Modid: xfs-linux-melb:xfs-kern:25372a
Signed-off-by: Nathan Scott <nathans@sgi.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_bmap.c | 668 |
1 files changed, 345 insertions, 323 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index da8fa0cd79c1..9f0ed4869d47 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -2294,25 +2294,15 @@ xfs_bmap_extsize_align( | |||
2294 | 2294 | ||
2295 | #define XFS_ALLOC_GAP_UNITS 4 | 2295 | #define XFS_ALLOC_GAP_UNITS 4 |
2296 | 2296 | ||
2297 | /* | ||
2298 | * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. | ||
2299 | * It figures out where to ask the underlying allocator to put the new extent. | ||
2300 | */ | ||
2301 | STATIC int | 2297 | STATIC int |
2302 | xfs_bmap_alloc( | 2298 | xfs_bmap_adjacent( |
2303 | xfs_bmalloca_t *ap) /* bmap alloc argument struct */ | 2299 | xfs_bmalloca_t *ap) /* bmap alloc argument struct */ |
2304 | { | 2300 | { |
2305 | xfs_fsblock_t adjust; /* adjustment to block numbers */ | 2301 | xfs_fsblock_t adjust; /* adjustment to block numbers */ |
2306 | xfs_alloctype_t atype=0; /* type for allocation routines */ | ||
2307 | int error; /* error return value */ | ||
2308 | xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ | 2302 | xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ |
2309 | xfs_mount_t *mp; /* mount point structure */ | 2303 | xfs_mount_t *mp; /* mount point structure */ |
2310 | int nullfb; /* true if ap->firstblock isn't set */ | 2304 | int nullfb; /* true if ap->firstblock isn't set */ |
2311 | int rt; /* true if inode is realtime */ | 2305 | int rt; /* true if inode is realtime */ |
2312 | xfs_extlen_t prod = 0; /* product factor for allocators */ | ||
2313 | xfs_extlen_t ralen = 0; /* realtime allocation length */ | ||
2314 | xfs_extlen_t align; /* minimum allocation alignment */ | ||
2315 | xfs_rtblock_t rtx; | ||
2316 | 2306 | ||
2317 | #define ISVALID(x,y) \ | 2307 | #define ISVALID(x,y) \ |
2318 | (rt ? \ | 2308 | (rt ? \ |
@@ -2321,75 +2311,10 @@ xfs_bmap_alloc( | |||
2321 | XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount && \ | 2311 | XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount && \ |
2322 | XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks) | 2312 | XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks) |
2323 | 2313 | ||
2324 | /* | ||
2325 | * Set up variables. | ||
2326 | */ | ||
2327 | mp = ap->ip->i_mount; | 2314 | mp = ap->ip->i_mount; |
2328 | nullfb = ap->firstblock == NULLFSBLOCK; | 2315 | nullfb = ap->firstblock == NULLFSBLOCK; |
2329 | rt = XFS_IS_REALTIME_INODE(ap->ip) && ap->userdata; | 2316 | rt = XFS_IS_REALTIME_INODE(ap->ip) && ap->userdata; |
2330 | fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock); | 2317 | fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock); |
2331 | if (rt) { | ||
2332 | align = ap->ip->i_d.di_extsize ? | ||
2333 | ap->ip->i_d.di_extsize : mp->m_sb.sb_rextsize; | ||
2334 | /* Set prod to match the extent size */ | ||
2335 | prod = align / mp->m_sb.sb_rextsize; | ||
2336 | |||
2337 | error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp, | ||
2338 | align, rt, ap->eof, 0, | ||
2339 | ap->conv, &ap->off, &ap->alen); | ||
2340 | if (error) | ||
2341 | return error; | ||
2342 | ASSERT(ap->alen); | ||
2343 | ASSERT(ap->alen % mp->m_sb.sb_rextsize == 0); | ||
2344 | |||
2345 | /* | ||
2346 | * If the offset & length are not perfectly aligned | ||
2347 | * then kill prod, it will just get us in trouble. | ||
2348 | */ | ||
2349 | if (do_mod(ap->off, align) || ap->alen % align) | ||
2350 | prod = 1; | ||
2351 | /* | ||
2352 | * Set ralen to be the actual requested length in rtextents. | ||
2353 | */ | ||
2354 | ralen = ap->alen / mp->m_sb.sb_rextsize; | ||
2355 | /* | ||
2356 | * If the old value was close enough to MAXEXTLEN that | ||
2357 | * we rounded up to it, cut it back so it's valid again. | ||
2358 | * Note that if it's a really large request (bigger than | ||
2359 | * MAXEXTLEN), we don't hear about that number, and can't | ||
2360 | * adjust the starting point to match it. | ||
2361 | */ | ||
2362 | if (ralen * mp->m_sb.sb_rextsize >= MAXEXTLEN) | ||
2363 | ralen = MAXEXTLEN / mp->m_sb.sb_rextsize; | ||
2364 | /* | ||
2365 | * If it's an allocation to an empty file at offset 0, | ||
2366 | * pick an extent that will space things out in the rt area. | ||
2367 | */ | ||
2368 | if (ap->eof && ap->off == 0) { | ||
2369 | error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx); | ||
2370 | if (error) | ||
2371 | return error; | ||
2372 | ap->rval = rtx * mp->m_sb.sb_rextsize; | ||
2373 | } else | ||
2374 | ap->rval = 0; | ||
2375 | } else { | ||
2376 | align = (ap->userdata && ap->ip->i_d.di_extsize && | ||
2377 | (ap->ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)) ? | ||
2378 | ap->ip->i_d.di_extsize : 0; | ||
2379 | if (unlikely(align)) { | ||
2380 | error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp, | ||
2381 | align, rt, | ||
2382 | ap->eof, 0, ap->conv, | ||
2383 | &ap->off, &ap->alen); | ||
2384 | ASSERT(!error); | ||
2385 | ASSERT(ap->alen); | ||
2386 | } | ||
2387 | if (nullfb) | ||
2388 | ap->rval = XFS_INO_TO_FSB(mp, ap->ip->i_ino); | ||
2389 | else | ||
2390 | ap->rval = ap->firstblock; | ||
2391 | } | ||
2392 | |||
2393 | /* | 2318 | /* |
2394 | * If allocating at eof, and there's a previous real block, | 2319 | * If allocating at eof, and there's a previous real block, |
2395 | * try to use it's last block as our starting point. | 2320 | * try to use it's last block as our starting point. |
@@ -2514,281 +2439,378 @@ xfs_bmap_alloc( | |||
2514 | else if (gotbno != NULLFSBLOCK) | 2439 | else if (gotbno != NULLFSBLOCK) |
2515 | ap->rval = gotbno; | 2440 | ap->rval = gotbno; |
2516 | } | 2441 | } |
2442 | #undef ISVALID | ||
2443 | return 0; | ||
2444 | } | ||
2445 | |||
2446 | STATIC int | ||
2447 | xfs_bmap_rtalloc( | ||
2448 | xfs_bmalloca_t *ap) /* bmap alloc argument struct */ | ||
2449 | { | ||
2450 | xfs_alloctype_t atype = 0; /* type for allocation routines */ | ||
2451 | int error; /* error return value */ | ||
2452 | xfs_mount_t *mp; /* mount point structure */ | ||
2453 | xfs_extlen_t prod = 0; /* product factor for allocators */ | ||
2454 | xfs_extlen_t ralen = 0; /* realtime allocation length */ | ||
2455 | xfs_extlen_t align; /* minimum allocation alignment */ | ||
2456 | xfs_rtblock_t rtx; /* realtime extent number */ | ||
2457 | xfs_rtblock_t rtb; | ||
2458 | |||
2459 | mp = ap->ip->i_mount; | ||
2460 | align = ap->ip->i_d.di_extsize ? | ||
2461 | ap->ip->i_d.di_extsize : mp->m_sb.sb_rextsize; | ||
2462 | prod = align / mp->m_sb.sb_rextsize; | ||
2463 | error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp, | ||
2464 | align, 1, ap->eof, 0, | ||
2465 | ap->conv, &ap->off, &ap->alen); | ||
2466 | if (error) | ||
2467 | return error; | ||
2468 | ASSERT(ap->alen); | ||
2469 | ASSERT(ap->alen % mp->m_sb.sb_rextsize == 0); | ||
2470 | |||
2471 | /* | ||
2472 | * If the offset & length are not perfectly aligned | ||
2473 | * then kill prod, it will just get us in trouble. | ||
2474 | */ | ||
2475 | if (do_mod(ap->off, align) || ap->alen % align) | ||
2476 | prod = 1; | ||
2477 | /* | ||
2478 | * Set ralen to be the actual requested length in rtextents. | ||
2479 | */ | ||
2480 | ralen = ap->alen / mp->m_sb.sb_rextsize; | ||
2481 | /* | ||
2482 | * If the old value was close enough to MAXEXTLEN that | ||
2483 | * we rounded up to it, cut it back so it's valid again. | ||
2484 | * Note that if it's a really large request (bigger than | ||
2485 | * MAXEXTLEN), we don't hear about that number, and can't | ||
2486 | * adjust the starting point to match it. | ||
2487 | */ | ||
2488 | if (ralen * mp->m_sb.sb_rextsize >= MAXEXTLEN) | ||
2489 | ralen = MAXEXTLEN / mp->m_sb.sb_rextsize; | ||
2490 | /* | ||
2491 | * If it's an allocation to an empty file at offset 0, | ||
2492 | * pick an extent that will space things out in the rt area. | ||
2493 | */ | ||
2494 | if (ap->eof && ap->off == 0) { | ||
2495 | error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx); | ||
2496 | if (error) | ||
2497 | return error; | ||
2498 | ap->rval = rtx * mp->m_sb.sb_rextsize; | ||
2499 | } else { | ||
2500 | ap->rval = 0; | ||
2501 | } | ||
2502 | |||
2503 | xfs_bmap_adjacent(ap); | ||
2504 | |||
2505 | /* | ||
2506 | * Realtime allocation, done through xfs_rtallocate_extent. | ||
2507 | */ | ||
2508 | atype = ap->rval == 0 ? XFS_ALLOCTYPE_ANY_AG : XFS_ALLOCTYPE_NEAR_BNO; | ||
2509 | do_div(ap->rval, mp->m_sb.sb_rextsize); | ||
2510 | rtb = ap->rval; | ||
2511 | ap->alen = ralen; | ||
2512 | if ((error = xfs_rtallocate_extent(ap->tp, ap->rval, 1, ap->alen, | ||
2513 | &ralen, atype, ap->wasdel, prod, &rtb))) | ||
2514 | return error; | ||
2515 | if (rtb == NULLFSBLOCK && prod > 1 && | ||
2516 | (error = xfs_rtallocate_extent(ap->tp, ap->rval, 1, | ||
2517 | ap->alen, &ralen, atype, | ||
2518 | ap->wasdel, 1, &rtb))) | ||
2519 | return error; | ||
2520 | ap->rval = rtb; | ||
2521 | if (ap->rval != NULLFSBLOCK) { | ||
2522 | ap->rval *= mp->m_sb.sb_rextsize; | ||
2523 | ralen *= mp->m_sb.sb_rextsize; | ||
2524 | ap->alen = ralen; | ||
2525 | ap->ip->i_d.di_nblocks += ralen; | ||
2526 | xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); | ||
2527 | if (ap->wasdel) | ||
2528 | ap->ip->i_delayed_blks -= ralen; | ||
2529 | /* | ||
2530 | * Adjust the disk quota also. This was reserved | ||
2531 | * earlier. | ||
2532 | */ | ||
2533 | XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip, | ||
2534 | ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT : | ||
2535 | XFS_TRANS_DQ_RTBCOUNT, (long) ralen); | ||
2536 | } else { | ||
2537 | ap->alen = 0; | ||
2538 | } | ||
2539 | return 0; | ||
2540 | } | ||
2541 | |||
2542 | STATIC int | ||
2543 | xfs_bmap_btalloc( | ||
2544 | xfs_bmalloca_t *ap) /* bmap alloc argument struct */ | ||
2545 | { | ||
2546 | xfs_mount_t *mp; /* mount point structure */ | ||
2547 | xfs_alloctype_t atype = 0; /* type for allocation routines */ | ||
2548 | xfs_extlen_t align; /* minimum allocation alignment */ | ||
2549 | xfs_agnumber_t ag; | ||
2550 | xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ | ||
2551 | xfs_agnumber_t startag; | ||
2552 | xfs_alloc_arg_t args; | ||
2553 | xfs_extlen_t blen; | ||
2554 | xfs_extlen_t delta; | ||
2555 | xfs_extlen_t longest; | ||
2556 | xfs_extlen_t need; | ||
2557 | xfs_extlen_t nextminlen = 0; | ||
2558 | xfs_perag_t *pag; | ||
2559 | int nullfb; /* true if ap->firstblock isn't set */ | ||
2560 | int isaligned; | ||
2561 | int notinit; | ||
2562 | int tryagain; | ||
2563 | int error; | ||
2564 | |||
2565 | mp = ap->ip->i_mount; | ||
2566 | align = (ap->userdata && ap->ip->i_d.di_extsize && | ||
2567 | (ap->ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)) ? | ||
2568 | ap->ip->i_d.di_extsize : 0; | ||
2569 | if (unlikely(align)) { | ||
2570 | error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp, | ||
2571 | align, 0, ap->eof, 0, ap->conv, | ||
2572 | &ap->off, &ap->alen); | ||
2573 | ASSERT(!error); | ||
2574 | ASSERT(ap->alen); | ||
2575 | } | ||
2576 | nullfb = ap->firstblock == NULLFSBLOCK; | ||
2577 | fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock); | ||
2578 | if (nullfb) | ||
2579 | ap->rval = XFS_INO_TO_FSB(mp, ap->ip->i_ino); | ||
2580 | else | ||
2581 | ap->rval = ap->firstblock; | ||
2582 | |||
2583 | xfs_bmap_adjacent(ap); | ||
2584 | |||
2517 | /* | 2585 | /* |
2518 | * If allowed, use ap->rval; otherwise must use firstblock since | 2586 | * If allowed, use ap->rval; otherwise must use firstblock since |
2519 | * it's in the right allocation group. | 2587 | * it's in the right allocation group. |
2520 | */ | 2588 | */ |
2521 | if (nullfb || rt || XFS_FSB_TO_AGNO(mp, ap->rval) == fb_agno) | 2589 | if (nullfb || XFS_FSB_TO_AGNO(mp, ap->rval) == fb_agno) |
2522 | ; | 2590 | ; |
2523 | else | 2591 | else |
2524 | ap->rval = ap->firstblock; | 2592 | ap->rval = ap->firstblock; |
2525 | /* | 2593 | /* |
2526 | * Realtime allocation, done through xfs_rtallocate_extent. | 2594 | * Normal allocation, done through xfs_alloc_vextent. |
2527 | */ | 2595 | */ |
2528 | if (rt) { | 2596 | tryagain = isaligned = 0; |
2529 | #ifndef __KERNEL__ | 2597 | args.tp = ap->tp; |
2530 | ASSERT(0); | 2598 | args.mp = mp; |
2531 | #else | 2599 | args.fsbno = ap->rval; |
2532 | xfs_rtblock_t rtb; | 2600 | args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks); |
2533 | 2601 | blen = 0; | |
2534 | atype = ap->rval == 0 ? | 2602 | if (nullfb) { |
2535 | XFS_ALLOCTYPE_ANY_AG : XFS_ALLOCTYPE_NEAR_BNO; | 2603 | args.type = XFS_ALLOCTYPE_START_BNO; |
2536 | do_div(ap->rval, mp->m_sb.sb_rextsize); | 2604 | args.total = ap->total; |
2537 | rtb = ap->rval; | 2605 | /* |
2538 | ap->alen = ralen; | 2606 | * Find the longest available space. |
2539 | if ((error = xfs_rtallocate_extent(ap->tp, ap->rval, 1, ap->alen, | 2607 | * We're going to try for the whole allocation at once. |
2540 | &ralen, atype, ap->wasdel, prod, &rtb))) | 2608 | */ |
2541 | return error; | 2609 | startag = ag = XFS_FSB_TO_AGNO(mp, args.fsbno); |
2542 | if (rtb == NULLFSBLOCK && prod > 1 && | 2610 | notinit = 0; |
2543 | (error = xfs_rtallocate_extent(ap->tp, ap->rval, 1, | 2611 | down_read(&mp->m_peraglock); |
2544 | ap->alen, &ralen, atype, | 2612 | while (blen < ap->alen) { |
2545 | ap->wasdel, 1, &rtb))) | 2613 | pag = &mp->m_perag[ag]; |
2546 | return error; | 2614 | if (!pag->pagf_init && |
2547 | ap->rval = rtb; | 2615 | (error = xfs_alloc_pagf_init(mp, args.tp, |
2548 | if (ap->rval != NULLFSBLOCK) { | 2616 | ag, XFS_ALLOC_FLAG_TRYLOCK))) { |
2549 | ap->rval *= mp->m_sb.sb_rextsize; | 2617 | up_read(&mp->m_peraglock); |
2550 | ralen *= mp->m_sb.sb_rextsize; | 2618 | return error; |
2551 | ap->alen = ralen; | 2619 | } |
2552 | ap->ip->i_d.di_nblocks += ralen; | ||
2553 | xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); | ||
2554 | if (ap->wasdel) | ||
2555 | ap->ip->i_delayed_blks -= ralen; | ||
2556 | /* | 2620 | /* |
2557 | * Adjust the disk quota also. This was reserved | 2621 | * See xfs_alloc_fix_freelist... |
2558 | * earlier. | ||
2559 | */ | 2622 | */ |
2560 | XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip, | 2623 | if (pag->pagf_init) { |
2561 | ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT : | 2624 | need = XFS_MIN_FREELIST_PAG(pag, mp); |
2562 | XFS_TRANS_DQ_RTBCOUNT, | 2625 | delta = need > pag->pagf_flcount ? |
2563 | (long) ralen); | 2626 | need - pag->pagf_flcount : 0; |
2564 | } else | 2627 | longest = (pag->pagf_longest > delta) ? |
2565 | ap->alen = 0; | 2628 | (pag->pagf_longest - delta) : |
2566 | #endif /* __KERNEL__ */ | 2629 | (pag->pagf_flcount > 0 || |
2630 | pag->pagf_longest > 0); | ||
2631 | if (blen < longest) | ||
2632 | blen = longest; | ||
2633 | } else | ||
2634 | notinit = 1; | ||
2635 | if (++ag == mp->m_sb.sb_agcount) | ||
2636 | ag = 0; | ||
2637 | if (ag == startag) | ||
2638 | break; | ||
2639 | } | ||
2640 | up_read(&mp->m_peraglock); | ||
2641 | /* | ||
2642 | * Since the above loop did a BUF_TRYLOCK, it is | ||
2643 | * possible that there is space for this request. | ||
2644 | */ | ||
2645 | if (notinit || blen < ap->minlen) | ||
2646 | args.minlen = ap->minlen; | ||
2647 | /* | ||
2648 | * If the best seen length is less than the request | ||
2649 | * length, use the best as the minimum. | ||
2650 | */ | ||
2651 | else if (blen < ap->alen) | ||
2652 | args.minlen = blen; | ||
2653 | /* | ||
2654 | * Otherwise we've seen an extent as big as alen, | ||
2655 | * use that as the minimum. | ||
2656 | */ | ||
2657 | else | ||
2658 | args.minlen = ap->alen; | ||
2659 | } else if (ap->low) { | ||
2660 | args.type = XFS_ALLOCTYPE_FIRST_AG; | ||
2661 | args.total = args.minlen = ap->minlen; | ||
2662 | } else { | ||
2663 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | ||
2664 | args.total = ap->total; | ||
2665 | args.minlen = ap->minlen; | ||
2666 | } | ||
2667 | if (unlikely(ap->userdata && ap->ip->i_d.di_extsize && | ||
2668 | (ap->ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE))) { | ||
2669 | args.prod = ap->ip->i_d.di_extsize; | ||
2670 | if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod))) | ||
2671 | args.mod = (xfs_extlen_t)(args.prod - args.mod); | ||
2672 | } else if (unlikely(mp->m_sb.sb_blocksize >= NBPP)) { | ||
2673 | args.prod = 1; | ||
2674 | args.mod = 0; | ||
2675 | } else { | ||
2676 | args.prod = NBPP >> mp->m_sb.sb_blocklog; | ||
2677 | if ((args.mod = (xfs_extlen_t)(do_mod(ap->off, args.prod)))) | ||
2678 | args.mod = (xfs_extlen_t)(args.prod - args.mod); | ||
2567 | } | 2679 | } |
2568 | /* | 2680 | /* |
2569 | * Normal allocation, done through xfs_alloc_vextent. | 2681 | * If we are not low on available data blocks, and the |
2682 | * underlying logical volume manager is a stripe, and | ||
2683 | * the file offset is zero then try to allocate data | ||
2684 | * blocks on stripe unit boundary. | ||
2685 | * NOTE: ap->aeof is only set if the allocation length | ||
2686 | * is >= the stripe unit and the allocation offset is | ||
2687 | * at the end of file. | ||
2570 | */ | 2688 | */ |
2571 | else { | 2689 | if (!ap->low && ap->aeof) { |
2572 | xfs_agnumber_t ag; | 2690 | if (!ap->off) { |
2573 | xfs_alloc_arg_t args; | 2691 | args.alignment = mp->m_dalign; |
2574 | xfs_extlen_t blen; | 2692 | atype = args.type; |
2575 | xfs_extlen_t delta; | 2693 | isaligned = 1; |
2576 | int isaligned; | ||
2577 | xfs_extlen_t longest; | ||
2578 | xfs_extlen_t need; | ||
2579 | xfs_extlen_t nextminlen=0; | ||
2580 | int notinit; | ||
2581 | xfs_perag_t *pag; | ||
2582 | xfs_agnumber_t startag; | ||
2583 | int tryagain; | ||
2584 | |||
2585 | tryagain = isaligned = 0; | ||
2586 | args.tp = ap->tp; | ||
2587 | args.mp = mp; | ||
2588 | args.fsbno = ap->rval; | ||
2589 | args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks); | ||
2590 | blen = 0; | ||
2591 | if (nullfb) { | ||
2592 | args.type = XFS_ALLOCTYPE_START_BNO; | ||
2593 | args.total = ap->total; | ||
2594 | /* | ||
2595 | * Find the longest available space. | ||
2596 | * We're going to try for the whole allocation at once. | ||
2597 | */ | ||
2598 | startag = ag = XFS_FSB_TO_AGNO(mp, args.fsbno); | ||
2599 | notinit = 0; | ||
2600 | down_read(&mp->m_peraglock); | ||
2601 | while (blen < ap->alen) { | ||
2602 | pag = &mp->m_perag[ag]; | ||
2603 | if (!pag->pagf_init && | ||
2604 | (error = xfs_alloc_pagf_init(mp, args.tp, | ||
2605 | ag, XFS_ALLOC_FLAG_TRYLOCK))) { | ||
2606 | up_read(&mp->m_peraglock); | ||
2607 | return error; | ||
2608 | } | ||
2609 | /* | ||
2610 | * See xfs_alloc_fix_freelist... | ||
2611 | */ | ||
2612 | if (pag->pagf_init) { | ||
2613 | need = XFS_MIN_FREELIST_PAG(pag, mp); | ||
2614 | delta = need > pag->pagf_flcount ? | ||
2615 | need - pag->pagf_flcount : 0; | ||
2616 | longest = (pag->pagf_longest > delta) ? | ||
2617 | (pag->pagf_longest - delta) : | ||
2618 | (pag->pagf_flcount > 0 || | ||
2619 | pag->pagf_longest > 0); | ||
2620 | if (blen < longest) | ||
2621 | blen = longest; | ||
2622 | } else | ||
2623 | notinit = 1; | ||
2624 | if (++ag == mp->m_sb.sb_agcount) | ||
2625 | ag = 0; | ||
2626 | if (ag == startag) | ||
2627 | break; | ||
2628 | } | ||
2629 | up_read(&mp->m_peraglock); | ||
2630 | /* | 2694 | /* |
2631 | * Since the above loop did a BUF_TRYLOCK, it is | 2695 | * Adjust for alignment |
2632 | * possible that there is space for this request. | ||
2633 | */ | 2696 | */ |
2634 | if (notinit || blen < ap->minlen) | 2697 | if (blen > args.alignment && blen <= ap->alen) |
2635 | args.minlen = ap->minlen; | 2698 | args.minlen = blen - args.alignment; |
2699 | args.minalignslop = 0; | ||
2700 | } else { | ||
2636 | /* | 2701 | /* |
2637 | * If the best seen length is less than the request | 2702 | * First try an exact bno allocation. |
2638 | * length, use the best as the minimum. | 2703 | * If it fails then do a near or start bno |
2704 | * allocation with alignment turned on. | ||
2639 | */ | 2705 | */ |
2640 | else if (blen < ap->alen) | 2706 | atype = args.type; |
2641 | args.minlen = blen; | 2707 | tryagain = 1; |
2708 | args.type = XFS_ALLOCTYPE_THIS_BNO; | ||
2709 | args.alignment = 1; | ||
2642 | /* | 2710 | /* |
2643 | * Otherwise we've seen an extent as big as alen, | 2711 | * Compute the minlen+alignment for the |
2644 | * use that as the minimum. | 2712 | * next case. Set slop so that the value |
2713 | * of minlen+alignment+slop doesn't go up | ||
2714 | * between the calls. | ||
2645 | */ | 2715 | */ |
2716 | if (blen > mp->m_dalign && blen <= ap->alen) | ||
2717 | nextminlen = blen - mp->m_dalign; | ||
2646 | else | 2718 | else |
2647 | args.minlen = ap->alen; | 2719 | nextminlen = args.minlen; |
2648 | } else if (ap->low) { | 2720 | if (nextminlen + mp->m_dalign > args.minlen + 1) |
2649 | args.type = XFS_ALLOCTYPE_FIRST_AG; | 2721 | args.minalignslop = |
2650 | args.total = args.minlen = ap->minlen; | 2722 | nextminlen + mp->m_dalign - |
2651 | } else { | 2723 | args.minlen - 1; |
2652 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | 2724 | else |
2653 | args.total = ap->total; | 2725 | args.minalignslop = 0; |
2654 | args.minlen = ap->minlen; | ||
2655 | } | ||
2656 | if (unlikely(ap->userdata && ap->ip->i_d.di_extsize && | ||
2657 | (ap->ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE))) { | ||
2658 | args.prod = ap->ip->i_d.di_extsize; | ||
2659 | if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod))) | ||
2660 | args.mod = (xfs_extlen_t)(args.prod - args.mod); | ||
2661 | } else if (unlikely(mp->m_sb.sb_blocksize >= NBPP)) { | ||
2662 | args.prod = 1; | ||
2663 | args.mod = 0; | ||
2664 | } else { | ||
2665 | args.prod = NBPP >> mp->m_sb.sb_blocklog; | ||
2666 | if ((args.mod = (xfs_extlen_t)(do_mod(ap->off, args.prod)))) | ||
2667 | args.mod = (xfs_extlen_t)(args.prod - args.mod); | ||
2668 | } | 2726 | } |
2727 | } else { | ||
2728 | args.alignment = 1; | ||
2729 | args.minalignslop = 0; | ||
2730 | } | ||
2731 | args.minleft = ap->minleft; | ||
2732 | args.wasdel = ap->wasdel; | ||
2733 | args.isfl = 0; | ||
2734 | args.userdata = ap->userdata; | ||
2735 | if ((error = xfs_alloc_vextent(&args))) | ||
2736 | return error; | ||
2737 | if (tryagain && args.fsbno == NULLFSBLOCK) { | ||
2669 | /* | 2738 | /* |
2670 | * If we are not low on available data blocks, and the | 2739 | * Exact allocation failed. Now try with alignment |
2671 | * underlying logical volume manager is a stripe, and | 2740 | * turned on. |
2672 | * the file offset is zero then try to allocate data | ||
2673 | * blocks on stripe unit boundary. | ||
2674 | * NOTE: ap->aeof is only set if the allocation length | ||
2675 | * is >= the stripe unit and the allocation offset is | ||
2676 | * at the end of file. | ||
2677 | */ | 2741 | */ |
2678 | if (!ap->low && ap->aeof) { | 2742 | args.type = atype; |
2679 | if (!ap->off) { | 2743 | args.fsbno = ap->rval; |
2680 | args.alignment = mp->m_dalign; | 2744 | args.alignment = mp->m_dalign; |
2681 | atype = args.type; | 2745 | args.minlen = nextminlen; |
2682 | isaligned = 1; | 2746 | args.minalignslop = 0; |
2683 | /* | 2747 | isaligned = 1; |
2684 | * Adjust for alignment | 2748 | if ((error = xfs_alloc_vextent(&args))) |
2685 | */ | 2749 | return error; |
2686 | if (blen > args.alignment && blen <= ap->alen) | 2750 | } |
2687 | args.minlen = blen - args.alignment; | 2751 | if (isaligned && args.fsbno == NULLFSBLOCK) { |
2688 | args.minalignslop = 0; | 2752 | /* |
2689 | } else { | 2753 | * allocation failed, so turn off alignment and |
2690 | /* | 2754 | * try again. |
2691 | * First try an exact bno allocation. | 2755 | */ |
2692 | * If it fails then do a near or start bno | 2756 | args.type = atype; |
2693 | * allocation with alignment turned on. | 2757 | args.fsbno = ap->rval; |
2694 | */ | 2758 | args.alignment = 0; |
2695 | atype = args.type; | 2759 | if ((error = xfs_alloc_vextent(&args))) |
2696 | tryagain = 1; | 2760 | return error; |
2697 | args.type = XFS_ALLOCTYPE_THIS_BNO; | 2761 | } |
2698 | args.alignment = 1; | 2762 | if (args.fsbno == NULLFSBLOCK && nullfb && |
2699 | /* | 2763 | args.minlen > ap->minlen) { |
2700 | * Compute the minlen+alignment for the | 2764 | args.minlen = ap->minlen; |
2701 | * next case. Set slop so that the value | 2765 | args.type = XFS_ALLOCTYPE_START_BNO; |
2702 | * of minlen+alignment+slop doesn't go up | 2766 | args.fsbno = ap->rval; |
2703 | * between the calls. | ||
2704 | */ | ||
2705 | if (blen > mp->m_dalign && blen <= ap->alen) | ||
2706 | nextminlen = blen - mp->m_dalign; | ||
2707 | else | ||
2708 | nextminlen = args.minlen; | ||
2709 | if (nextminlen + mp->m_dalign > args.minlen + 1) | ||
2710 | args.minalignslop = | ||
2711 | nextminlen + mp->m_dalign - | ||
2712 | args.minlen - 1; | ||
2713 | else | ||
2714 | args.minalignslop = 0; | ||
2715 | } | ||
2716 | } else { | ||
2717 | args.alignment = 1; | ||
2718 | args.minalignslop = 0; | ||
2719 | } | ||
2720 | args.minleft = ap->minleft; | ||
2721 | args.wasdel = ap->wasdel; | ||
2722 | args.isfl = 0; | ||
2723 | args.userdata = ap->userdata; | ||
2724 | if ((error = xfs_alloc_vextent(&args))) | 2767 | if ((error = xfs_alloc_vextent(&args))) |
2725 | return error; | 2768 | return error; |
2726 | if (tryagain && args.fsbno == NULLFSBLOCK) { | 2769 | } |
2727 | /* | 2770 | if (args.fsbno == NULLFSBLOCK && nullfb) { |
2728 | * Exact allocation failed. Now try with alignment | 2771 | args.fsbno = 0; |
2729 | * turned on. | 2772 | args.type = XFS_ALLOCTYPE_FIRST_AG; |
2730 | */ | 2773 | args.total = ap->minlen; |
2731 | args.type = atype; | 2774 | args.minleft = 0; |
2732 | args.fsbno = ap->rval; | 2775 | if ((error = xfs_alloc_vextent(&args))) |
2733 | args.alignment = mp->m_dalign; | 2776 | return error; |
2734 | args.minlen = nextminlen; | 2777 | ap->low = 1; |
2735 | args.minalignslop = 0; | 2778 | } |
2736 | isaligned = 1; | 2779 | if (args.fsbno != NULLFSBLOCK) { |
2737 | if ((error = xfs_alloc_vextent(&args))) | 2780 | ap->firstblock = ap->rval = args.fsbno; |
2738 | return error; | 2781 | ASSERT(nullfb || fb_agno == args.agno || |
2739 | } | 2782 | (ap->low && fb_agno < args.agno)); |
2740 | if (isaligned && args.fsbno == NULLFSBLOCK) { | 2783 | ap->alen = args.len; |
2741 | /* | 2784 | ap->ip->i_d.di_nblocks += args.len; |
2742 | * allocation failed, so turn off alignment and | 2785 | xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); |
2743 | * try again. | 2786 | if (ap->wasdel) |
2744 | */ | 2787 | ap->ip->i_delayed_blks -= args.len; |
2745 | args.type = atype; | 2788 | /* |
2746 | args.fsbno = ap->rval; | 2789 | * Adjust the disk quota also. This was reserved |
2747 | args.alignment = 0; | 2790 | * earlier. |
2748 | if ((error = xfs_alloc_vextent(&args))) | 2791 | */ |
2749 | return error; | 2792 | XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip, |
2750 | } | 2793 | ap->wasdel ? XFS_TRANS_DQ_DELBCOUNT : |
2751 | if (args.fsbno == NULLFSBLOCK && nullfb && | 2794 | XFS_TRANS_DQ_BCOUNT, |
2752 | args.minlen > ap->minlen) { | 2795 | (long) args.len); |
2753 | args.minlen = ap->minlen; | 2796 | } else { |
2754 | args.type = XFS_ALLOCTYPE_START_BNO; | 2797 | ap->rval = NULLFSBLOCK; |
2755 | args.fsbno = ap->rval; | 2798 | ap->alen = 0; |
2756 | if ((error = xfs_alloc_vextent(&args))) | ||
2757 | return error; | ||
2758 | } | ||
2759 | if (args.fsbno == NULLFSBLOCK && nullfb) { | ||
2760 | args.fsbno = 0; | ||
2761 | args.type = XFS_ALLOCTYPE_FIRST_AG; | ||
2762 | args.total = ap->minlen; | ||
2763 | args.minleft = 0; | ||
2764 | if ((error = xfs_alloc_vextent(&args))) | ||
2765 | return error; | ||
2766 | ap->low = 1; | ||
2767 | } | ||
2768 | if (args.fsbno != NULLFSBLOCK) { | ||
2769 | ap->firstblock = ap->rval = args.fsbno; | ||
2770 | ASSERT(nullfb || fb_agno == args.agno || | ||
2771 | (ap->low && fb_agno < args.agno)); | ||
2772 | ap->alen = args.len; | ||
2773 | ap->ip->i_d.di_nblocks += args.len; | ||
2774 | xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); | ||
2775 | if (ap->wasdel) | ||
2776 | ap->ip->i_delayed_blks -= args.len; | ||
2777 | /* | ||
2778 | * Adjust the disk quota also. This was reserved | ||
2779 | * earlier. | ||
2780 | */ | ||
2781 | XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip, | ||
2782 | ap->wasdel ? XFS_TRANS_DQ_DELBCOUNT : | ||
2783 | XFS_TRANS_DQ_BCOUNT, | ||
2784 | (long) args.len); | ||
2785 | } else { | ||
2786 | ap->rval = NULLFSBLOCK; | ||
2787 | ap->alen = 0; | ||
2788 | } | ||
2789 | } | 2799 | } |
2790 | return 0; | 2800 | return 0; |
2791 | #undef ISVALID | 2801 | } |
2802 | |||
2803 | /* | ||
2804 | * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. | ||
2805 | * It figures out where to ask the underlying allocator to put the new extent. | ||
2806 | */ | ||
2807 | STATIC int | ||
2808 | xfs_bmap_alloc( | ||
2809 | xfs_bmalloca_t *ap) /* bmap alloc argument struct */ | ||
2810 | { | ||
2811 | if ((ap->ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && ap->userdata) | ||
2812 | return xfs_bmap_rtalloc(ap); | ||
2813 | return xfs_bmap_btalloc(ap); | ||
2792 | } | 2814 | } |
2793 | 2815 | ||
2794 | /* | 2816 | /* |