diff options
| -rw-r--r-- | fs/xfs/xfs_ag.h | 9 | ||||
| -rw-r--r-- | fs/xfs/xfs_ialloc.c | 133 |
2 files changed, 115 insertions, 27 deletions
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index f24b50b68d03..a5d54bf4931b 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h | |||
| @@ -198,6 +198,15 @@ typedef struct xfs_perag | |||
| 198 | xfs_agino_t pagi_count; /* number of allocated inodes */ | 198 | xfs_agino_t pagi_count; /* number of allocated inodes */ |
| 199 | int pagb_count; /* pagb slots in use */ | 199 | int pagb_count; /* pagb slots in use */ |
| 200 | xfs_perag_busy_t *pagb_list; /* unstable blocks */ | 200 | xfs_perag_busy_t *pagb_list; /* unstable blocks */ |
| 201 | |||
| 202 | /* | ||
| 203 | * Inode allocation search lookup optimisation. | ||
| 204 | * If the pagino matches, the search for new inodes | ||
| 205 | * doesn't need to search the near ones again straight away | ||
| 206 | */ | ||
| 207 | xfs_agino_t pagl_pagino; | ||
| 208 | xfs_agino_t pagl_leftrec; | ||
| 209 | xfs_agino_t pagl_rightrec; | ||
| 201 | #ifdef __KERNEL__ | 210 | #ifdef __KERNEL__ |
| 202 | spinlock_t pagb_lock; /* lock for pagb_list */ | 211 | spinlock_t pagb_lock; /* lock for pagb_list */ |
| 203 | 212 | ||
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 748637cd70ff..d12d805f20a5 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
| @@ -587,6 +587,30 @@ xfs_ialloc_next_rec( | |||
| 587 | return 0; | 587 | return 0; |
| 588 | } | 588 | } |
| 589 | 589 | ||
| 590 | STATIC int | ||
| 591 | xfs_ialloc_get_rec( | ||
| 592 | struct xfs_btree_cur *cur, | ||
| 593 | xfs_agino_t agino, | ||
| 594 | xfs_inobt_rec_incore_t *rec, | ||
| 595 | int *done, | ||
| 596 | int left) | ||
| 597 | { | ||
| 598 | int error; | ||
| 599 | int i; | ||
| 600 | |||
| 601 | error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_EQ, &i); | ||
| 602 | if (error) | ||
| 603 | return error; | ||
| 604 | *done = !i; | ||
| 605 | if (i) { | ||
| 606 | error = xfs_inobt_get_rec(cur, rec, &i); | ||
| 607 | if (error) | ||
| 608 | return error; | ||
| 609 | XFS_WANT_CORRUPTED_RETURN(i == 1); | ||
| 610 | } | ||
| 611 | |||
| 612 | return 0; | ||
| 613 | } | ||
| 590 | 614 | ||
| 591 | /* | 615 | /* |
| 592 | * Visible inode allocation functions. | 616 | * Visible inode allocation functions. |
| @@ -766,6 +790,8 @@ nextag: | |||
| 766 | */ | 790 | */ |
| 767 | agno = tagno; | 791 | agno = tagno; |
| 768 | *IO_agbp = NULL; | 792 | *IO_agbp = NULL; |
| 793 | |||
| 794 | restart_pagno: | ||
| 769 | cur = xfs_inobt_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno)); | 795 | cur = xfs_inobt_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno)); |
| 770 | /* | 796 | /* |
| 771 | * If pagino is 0 (this is the root inode allocation) use newino. | 797 | * If pagino is 0 (this is the root inode allocation) use newino. |
| @@ -782,8 +808,10 @@ nextag: | |||
| 782 | * If in the same AG as the parent, try to get near the parent. | 808 | * If in the same AG as the parent, try to get near the parent. |
| 783 | */ | 809 | */ |
| 784 | if (pagno == agno) { | 810 | if (pagno == agno) { |
| 811 | xfs_perag_t *pag = &mp->m_perag[agno]; | ||
| 785 | int doneleft; /* done, to the left */ | 812 | int doneleft; /* done, to the left */ |
| 786 | int doneright; /* done, to the right */ | 813 | int doneright; /* done, to the right */ |
| 814 | int searchdistance = 10; | ||
| 787 | 815 | ||
| 788 | error = xfs_inobt_lookup(cur, pagino, XFS_LOOKUP_LE, &i); | 816 | error = xfs_inobt_lookup(cur, pagino, XFS_LOOKUP_LE, &i); |
| 789 | if (error) | 817 | if (error) |
| @@ -813,15 +841,33 @@ nextag: | |||
| 813 | if (error) | 841 | if (error) |
| 814 | goto error0; | 842 | goto error0; |
| 815 | 843 | ||
| 816 | /* search left with tcur, back up 1 record */ | 844 | /* |
| 817 | error = xfs_ialloc_next_rec(tcur, &trec, &doneleft, 1); | 845 | * Skip to last blocks looked up if same parent inode. |
| 818 | if (error) | 846 | */ |
| 819 | goto error1; | 847 | if (pagino != NULLAGINO && |
| 848 | pag->pagl_pagino == pagino && | ||
| 849 | pag->pagl_leftrec != NULLAGINO && | ||
| 850 | pag->pagl_rightrec != NULLAGINO) { | ||
| 851 | error = xfs_ialloc_get_rec(tcur, pag->pagl_leftrec, | ||
| 852 | &trec, &doneleft, 1); | ||
| 853 | if (error) | ||
| 854 | goto error1; | ||
| 820 | 855 | ||
| 821 | /* search right with cur, go forward 1 record. */ | 856 | error = xfs_ialloc_get_rec(cur, pag->pagl_rightrec, |
| 822 | error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0); | 857 | &rec, &doneright, 0); |
| 823 | if (error) | 858 | if (error) |
| 824 | goto error1; | 859 | goto error1; |
| 860 | } else { | ||
| 861 | /* search left with tcur, back up 1 record */ | ||
| 862 | error = xfs_ialloc_next_rec(tcur, &trec, &doneleft, 1); | ||
| 863 | if (error) | ||
| 864 | goto error1; | ||
| 865 | |||
| 866 | /* search right with cur, go forward 1 record. */ | ||
| 867 | error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0); | ||
| 868 | if (error) | ||
| 869 | goto error1; | ||
| 870 | } | ||
| 825 | 871 | ||
| 826 | /* | 872 | /* |
| 827 | * Loop until we find an inode chunk with a free inode. | 873 | * Loop until we find an inode chunk with a free inode. |
| @@ -829,6 +875,17 @@ nextag: | |||
| 829 | while (!doneleft || !doneright) { | 875 | while (!doneleft || !doneright) { |
| 830 | int useleft; /* using left inode chunk this time */ | 876 | int useleft; /* using left inode chunk this time */ |
| 831 | 877 | ||
| 878 | if (!--searchdistance) { | ||
| 879 | /* | ||
| 880 | * Not in range - save last search | ||
| 881 | * location and allocate a new inode | ||
| 882 | */ | ||
| 883 | pag->pagl_leftrec = trec.ir_startino; | ||
| 884 | pag->pagl_rightrec = rec.ir_startino; | ||
| 885 | pag->pagl_pagino = pagino; | ||
| 886 | goto newino; | ||
| 887 | } | ||
| 888 | |||
| 832 | /* figure out the closer block if both are valid. */ | 889 | /* figure out the closer block if both are valid. */ |
| 833 | if (!doneleft && !doneright) { | 890 | if (!doneleft && !doneright) { |
| 834 | useleft = pagino - | 891 | useleft = pagino - |
| @@ -843,12 +900,20 @@ nextag: | |||
| 843 | rec = trec; | 900 | rec = trec; |
| 844 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); | 901 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); |
| 845 | cur = tcur; | 902 | cur = tcur; |
| 903 | |||
| 904 | pag->pagl_leftrec = trec.ir_startino; | ||
| 905 | pag->pagl_rightrec = rec.ir_startino; | ||
| 906 | pag->pagl_pagino = pagino; | ||
| 846 | goto alloc_inode; | 907 | goto alloc_inode; |
| 847 | } | 908 | } |
| 848 | 909 | ||
| 849 | /* free inodes to the right? */ | 910 | /* free inodes to the right? */ |
| 850 | if (!useleft && rec.ir_freecount) { | 911 | if (!useleft && rec.ir_freecount) { |
| 851 | xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); | 912 | xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); |
| 913 | |||
| 914 | pag->pagl_leftrec = trec.ir_startino; | ||
| 915 | pag->pagl_rightrec = rec.ir_startino; | ||
| 916 | pag->pagl_pagino = pagino; | ||
| 852 | goto alloc_inode; | 917 | goto alloc_inode; |
| 853 | } | 918 | } |
| 854 | 919 | ||
| @@ -863,14 +928,28 @@ nextag: | |||
| 863 | if (error) | 928 | if (error) |
| 864 | goto error1; | 929 | goto error1; |
| 865 | } | 930 | } |
| 866 | ASSERT(!doneleft || !doneright); | 931 | |
| 932 | /* | ||
| 933 | * We've reached the end of the btree. because | ||
| 934 | * we are only searching a small chunk of the | ||
| 935 | * btree each search, there is obviously free | ||
| 936 | * inodes closer to the parent inode than we | ||
| 937 | * are now. restart the search again. | ||
| 938 | */ | ||
| 939 | pag->pagl_pagino = NULLAGINO; | ||
| 940 | pag->pagl_leftrec = NULLAGINO; | ||
| 941 | pag->pagl_rightrec = NULLAGINO; | ||
| 942 | xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); | ||
| 943 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); | ||
| 944 | goto restart_pagno; | ||
| 867 | } | 945 | } |
| 868 | 946 | ||
| 869 | /* | 947 | /* |
| 870 | * In a different AG from the parent. | 948 | * In a different AG from the parent. |
| 871 | * See if the most recently allocated block has any free. | 949 | * See if the most recently allocated block has any free. |
| 872 | */ | 950 | */ |
| 873 | else if (be32_to_cpu(agi->agi_newino) != NULLAGINO) { | 951 | newino: |
| 952 | if (be32_to_cpu(agi->agi_newino) != NULLAGINO) { | ||
| 874 | error = xfs_inobt_lookup(cur, be32_to_cpu(agi->agi_newino), | 953 | error = xfs_inobt_lookup(cur, be32_to_cpu(agi->agi_newino), |
| 875 | XFS_LOOKUP_EQ, &i); | 954 | XFS_LOOKUP_EQ, &i); |
| 876 | if (error) | 955 | if (error) |
| @@ -889,27 +968,27 @@ nextag: | |||
| 889 | goto alloc_inode; | 968 | goto alloc_inode; |
| 890 | } | 969 | } |
| 891 | } | 970 | } |
| 971 | } | ||
| 892 | 972 | ||
| 893 | /* | 973 | /* |
| 894 | * None left in the last group, search the whole AG | 974 | * None left in the last group, search the whole AG |
| 895 | */ | 975 | */ |
| 896 | error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); | 976 | error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); |
| 977 | if (error) | ||
| 978 | goto error0; | ||
| 979 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
| 980 | |||
| 981 | for (;;) { | ||
| 982 | error = xfs_inobt_get_rec(cur, &rec, &i); | ||
| 983 | if (error) | ||
| 984 | goto error0; | ||
| 985 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
| 986 | if (rec.ir_freecount > 0) | ||
| 987 | break; | ||
| 988 | error = xfs_btree_increment(cur, 0, &i); | ||
| 897 | if (error) | 989 | if (error) |
| 898 | goto error0; | 990 | goto error0; |
| 899 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 991 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
| 900 | |||
| 901 | for (;;) { | ||
| 902 | error = xfs_inobt_get_rec(cur, &rec, &i); | ||
| 903 | if (error) | ||
| 904 | goto error0; | ||
| 905 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
| 906 | if (rec.ir_freecount > 0) | ||
| 907 | break; | ||
| 908 | error = xfs_btree_increment(cur, 0, &i); | ||
| 909 | if (error) | ||
| 910 | goto error0; | ||
| 911 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
| 912 | } | ||
| 913 | } | 992 | } |
| 914 | 993 | ||
| 915 | alloc_inode: | 994 | alloc_inode: |
