diff options
Diffstat (limited to 'fs/xfs/xfs_bmap.c')
| -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; | 
