diff options
-rw-r--r-- | fs/xfs/xfs_bmap.c | 220 |
1 files changed, 119 insertions, 101 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 1869fb973819..5c11e4d17010 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -2550,22 +2550,134 @@ xfs_bmap_rtalloc( | |||
2550 | } | 2550 | } |
2551 | 2551 | ||
2552 | STATIC int | 2552 | STATIC int |
2553 | xfs_bmap_btalloc_nullfb( | ||
2554 | struct xfs_bmalloca *ap, | ||
2555 | struct xfs_alloc_arg *args, | ||
2556 | xfs_extlen_t *blen) | ||
2557 | { | ||
2558 | struct xfs_mount *mp = ap->ip->i_mount; | ||
2559 | struct xfs_perag *pag; | ||
2560 | xfs_agnumber_t ag, startag; | ||
2561 | int notinit = 0; | ||
2562 | int error; | ||
2563 | |||
2564 | if (ap->userdata && xfs_inode_is_filestream(ap->ip)) | ||
2565 | args->type = XFS_ALLOCTYPE_NEAR_BNO; | ||
2566 | else | ||
2567 | args->type = XFS_ALLOCTYPE_START_BNO; | ||
2568 | args->total = ap->total; | ||
2569 | |||
2570 | /* | ||
2571 | * Search for an allocation group with a single extent large enough | ||
2572 | * for the request. If one isn't found, then adjust the minimum | ||
2573 | * allocation size to the largest space found. | ||
2574 | */ | ||
2575 | startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno); | ||
2576 | if (startag == NULLAGNUMBER) | ||
2577 | startag = ag = 0; | ||
2578 | |||
2579 | pag = xfs_perag_get(mp, ag); | ||
2580 | while (*blen < ap->alen) { | ||
2581 | if (!pag->pagf_init) { | ||
2582 | error = xfs_alloc_pagf_init(mp, args->tp, ag, | ||
2583 | XFS_ALLOC_FLAG_TRYLOCK); | ||
2584 | if (error) { | ||
2585 | xfs_perag_put(pag); | ||
2586 | return error; | ||
2587 | } | ||
2588 | } | ||
2589 | |||
2590 | /* | ||
2591 | * See xfs_alloc_fix_freelist... | ||
2592 | */ | ||
2593 | if (pag->pagf_init) { | ||
2594 | xfs_extlen_t longest; | ||
2595 | longest = xfs_alloc_longest_free_extent(mp, pag); | ||
2596 | if (*blen < longest) | ||
2597 | *blen = longest; | ||
2598 | } else | ||
2599 | notinit = 1; | ||
2600 | |||
2601 | if (xfs_inode_is_filestream(ap->ip)) { | ||
2602 | if (*blen >= ap->alen) | ||
2603 | break; | ||
2604 | |||
2605 | if (ap->userdata) { | ||
2606 | /* | ||
2607 | * If startag is an invalid AG, we've | ||
2608 | * come here once before and | ||
2609 | * xfs_filestream_new_ag picked the | ||
2610 | * best currently available. | ||
2611 | * | ||
2612 | * Don't continue looping, since we | ||
2613 | * could loop forever. | ||
2614 | */ | ||
2615 | if (startag == NULLAGNUMBER) | ||
2616 | break; | ||
2617 | |||
2618 | error = xfs_filestream_new_ag(ap, &ag); | ||
2619 | xfs_perag_put(pag); | ||
2620 | if (error) | ||
2621 | return error; | ||
2622 | |||
2623 | /* loop again to set 'blen'*/ | ||
2624 | startag = NULLAGNUMBER; | ||
2625 | pag = xfs_perag_get(mp, ag); | ||
2626 | continue; | ||
2627 | } | ||
2628 | } | ||
2629 | if (++ag == mp->m_sb.sb_agcount) | ||
2630 | ag = 0; | ||
2631 | if (ag == startag) | ||
2632 | break; | ||
2633 | xfs_perag_put(pag); | ||
2634 | pag = xfs_perag_get(mp, ag); | ||
2635 | } | ||
2636 | xfs_perag_put(pag); | ||
2637 | |||
2638 | /* | ||
2639 | * Since the above loop did a BUF_TRYLOCK, it is | ||
2640 | * possible that there is space for this request. | ||
2641 | */ | ||
2642 | if (notinit || *blen < ap->minlen) | ||
2643 | args->minlen = ap->minlen; | ||
2644 | /* | ||
2645 | * If the best seen length is less than the request | ||
2646 | * length, use the best as the minimum. | ||
2647 | */ | ||
2648 | else if (*blen < ap->alen) | ||
2649 | args->minlen = *blen; | ||
2650 | /* | ||
2651 | * Otherwise we've seen an extent as big as alen, | ||
2652 | * use that as the minimum. | ||
2653 | */ | ||
2654 | else | ||
2655 | args->minlen = ap->alen; | ||
2656 | |||
2657 | /* | ||
2658 | * set the failure fallback case to look in the selected | ||
2659 | * AG as the stream may have moved. | ||
2660 | */ | ||
2661 | if (xfs_inode_is_filestream(ap->ip)) | ||
2662 | ap->rval = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0); | ||
2663 | |||
2664 | return 0; | ||
2665 | } | ||
2666 | |||
2667 | STATIC int | ||
2553 | xfs_bmap_btalloc( | 2668 | xfs_bmap_btalloc( |
2554 | xfs_bmalloca_t *ap) /* bmap alloc argument struct */ | 2669 | xfs_bmalloca_t *ap) /* bmap alloc argument struct */ |
2555 | { | 2670 | { |
2556 | xfs_mount_t *mp; /* mount point structure */ | 2671 | xfs_mount_t *mp; /* mount point structure */ |
2557 | xfs_alloctype_t atype = 0; /* type for allocation routines */ | 2672 | xfs_alloctype_t atype = 0; /* type for allocation routines */ |
2558 | xfs_extlen_t align; /* minimum allocation alignment */ | 2673 | xfs_extlen_t align; /* minimum allocation alignment */ |
2559 | xfs_agnumber_t ag; | ||
2560 | xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ | 2674 | xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ |
2561 | xfs_agnumber_t startag; | 2675 | xfs_agnumber_t ag; |
2562 | xfs_alloc_arg_t args; | 2676 | xfs_alloc_arg_t args; |
2563 | xfs_extlen_t blen; | 2677 | xfs_extlen_t blen; |
2564 | xfs_extlen_t nextminlen = 0; | 2678 | xfs_extlen_t nextminlen = 0; |
2565 | xfs_perag_t *pag; | ||
2566 | int nullfb; /* true if ap->firstblock isn't set */ | 2679 | int nullfb; /* true if ap->firstblock isn't set */ |
2567 | int isaligned; | 2680 | int isaligned; |
2568 | int notinit; | ||
2569 | int tryagain; | 2681 | int tryagain; |
2570 | int error; | 2682 | int error; |
2571 | 2683 | ||
@@ -2612,103 +2724,9 @@ xfs_bmap_btalloc( | |||
2612 | args.firstblock = ap->firstblock; | 2724 | args.firstblock = ap->firstblock; |
2613 | blen = 0; | 2725 | blen = 0; |
2614 | if (nullfb) { | 2726 | if (nullfb) { |
2615 | if (ap->userdata && xfs_inode_is_filestream(ap->ip)) | 2727 | error = xfs_bmap_btalloc_nullfb(ap, &args, &blen); |
2616 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | 2728 | if (error) |
2617 | else | 2729 | return error; |
2618 | args.type = XFS_ALLOCTYPE_START_BNO; | ||
2619 | args.total = ap->total; | ||
2620 | |||
2621 | /* | ||
2622 | * Search for an allocation group with a single extent | ||
2623 | * large enough for the request. | ||
2624 | * | ||
2625 | * If one isn't found, then adjust the minimum allocation | ||
2626 | * size to the largest space found. | ||
2627 | */ | ||
2628 | startag = ag = XFS_FSB_TO_AGNO(mp, args.fsbno); | ||
2629 | if (startag == NULLAGNUMBER) | ||
2630 | startag = ag = 0; | ||
2631 | notinit = 0; | ||
2632 | pag = xfs_perag_get(mp, ag); | ||
2633 | while (blen < ap->alen) { | ||
2634 | if (!pag->pagf_init && | ||
2635 | (error = xfs_alloc_pagf_init(mp, args.tp, | ||
2636 | ag, XFS_ALLOC_FLAG_TRYLOCK))) { | ||
2637 | xfs_perag_put(pag); | ||
2638 | return error; | ||
2639 | } | ||
2640 | /* | ||
2641 | * See xfs_alloc_fix_freelist... | ||
2642 | */ | ||
2643 | if (pag->pagf_init) { | ||
2644 | xfs_extlen_t longest; | ||
2645 | longest = xfs_alloc_longest_free_extent(mp, pag); | ||
2646 | if (blen < longest) | ||
2647 | blen = longest; | ||
2648 | } else | ||
2649 | notinit = 1; | ||
2650 | |||
2651 | if (xfs_inode_is_filestream(ap->ip)) { | ||
2652 | if (blen >= ap->alen) | ||
2653 | break; | ||
2654 | |||
2655 | if (ap->userdata) { | ||
2656 | /* | ||
2657 | * If startag is an invalid AG, we've | ||
2658 | * come here once before and | ||
2659 | * xfs_filestream_new_ag picked the | ||
2660 | * best currently available. | ||
2661 | * | ||
2662 | * Don't continue looping, since we | ||
2663 | * could loop forever. | ||
2664 | */ | ||
2665 | if (startag == NULLAGNUMBER) | ||
2666 | break; | ||
2667 | |||
2668 | error = xfs_filestream_new_ag(ap, &ag); | ||
2669 | xfs_perag_put(pag); | ||
2670 | if (error) | ||
2671 | return error; | ||
2672 | |||
2673 | /* loop again to set 'blen'*/ | ||
2674 | startag = NULLAGNUMBER; | ||
2675 | pag = xfs_perag_get(mp, ag); | ||
2676 | continue; | ||
2677 | } | ||
2678 | } | ||
2679 | if (++ag == mp->m_sb.sb_agcount) | ||
2680 | ag = 0; | ||
2681 | if (ag == startag) | ||
2682 | break; | ||
2683 | xfs_perag_put(pag); | ||
2684 | pag = xfs_perag_get(mp, ag); | ||
2685 | } | ||
2686 | xfs_perag_put(pag); | ||
2687 | /* | ||
2688 | * Since the above loop did a BUF_TRYLOCK, it is | ||
2689 | * possible that there is space for this request. | ||
2690 | */ | ||
2691 | if (notinit || blen < ap->minlen) | ||
2692 | args.minlen = ap->minlen; | ||
2693 | /* | ||
2694 | * If the best seen length is less than the request | ||
2695 | * length, use the best as the minimum. | ||
2696 | */ | ||
2697 | else if (blen < ap->alen) | ||
2698 | args.minlen = blen; | ||
2699 | /* | ||
2700 | * Otherwise we've seen an extent as big as alen, | ||
2701 | * use that as the minimum. | ||
2702 | */ | ||
2703 | else | ||
2704 | args.minlen = ap->alen; | ||
2705 | |||
2706 | /* | ||
2707 | * set the failure fallback case to look in the selected | ||
2708 | * AG as the stream may have moved. | ||
2709 | */ | ||
2710 | if (xfs_inode_is_filestream(ap->ip)) | ||
2711 | ap->rval = args.fsbno = XFS_AGB_TO_FSB(mp, ag, 0); | ||
2712 | } else if (ap->low) { | 2730 | } else if (ap->low) { |
2713 | if (xfs_inode_is_filestream(ap->ip)) | 2731 | if (xfs_inode_is_filestream(ap->ip)) |
2714 | args.type = XFS_ALLOCTYPE_FIRST_AG; | 2732 | args.type = XFS_ALLOCTYPE_FIRST_AG; |