Skip to content

Commit bd16956

Browse files
Dave ChinnerFelix Blyakher
authored andcommitted
xfs: speed up free inode search
Don't search too far - abort if it is outside a certain radius and simply do a linear search for the first free inode. In AGs with a million inodes this can speed up allocation speed by 3-4x. [hch: ported to the new xfs_ialloc.c world order] Signed-off-by: Dave Chinner <dgc@sgi.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Alex Elder <aelder@sgi.com> Signed-off-by: Felix Blyakher <felixb@sgi.com>
1 parent 2187550 commit bd16956

File tree

2 files changed

+115
-27
lines changed

2 files changed

+115
-27
lines changed

fs/xfs/xfs_ag.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,15 @@ typedef struct xfs_perag
198198
xfs_agino_t pagi_count; /* number of allocated inodes */
199199
int pagb_count; /* pagb slots in use */
200200
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;
201210
#ifdef __KERNEL__
202211
spinlock_t pagb_lock; /* lock for pagb_list */
203212

fs/xfs/xfs_ialloc.c

Lines changed: 106 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,30 @@ xfs_ialloc_next_rec(
587587
return 0;
588588
}
589589

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+
}
590614

591615
/*
592616
* Visible inode allocation functions.
@@ -766,6 +790,8 @@ xfs_dialloc(
766790
*/
767791
agno = tagno;
768792
*IO_agbp = NULL;
793+
794+
restart_pagno:
769795
cur = xfs_inobt_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno));
770796
/*
771797
* If pagino is 0 (this is the root inode allocation) use newino.
@@ -782,8 +808,10 @@ xfs_dialloc(
782808
* If in the same AG as the parent, try to get near the parent.
783809
*/
784810
if (pagno == agno) {
811+
xfs_perag_t *pag = &mp->m_perag[agno];
785812
int doneleft; /* done, to the left */
786813
int doneright; /* done, to the right */
814+
int searchdistance = 10;
787815

788816
error = xfs_inobt_lookup(cur, pagino, XFS_LOOKUP_LE, &i);
789817
if (error)
@@ -813,22 +841,51 @@ xfs_dialloc(
813841
if (error)
814842
goto error0;
815843

816-
/* search left with tcur, back up 1 record */
817-
error = xfs_ialloc_next_rec(tcur, &trec, &doneleft, 1);
818-
if (error)
819-
goto error1;
844+
/*
845+
* Skip to last blocks looked up if same parent inode.
846+
*/
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;
820855

821-
/* search right with cur, go forward 1 record. */
822-
error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0);
823-
if (error)
824-
goto error1;
856+
error = xfs_ialloc_get_rec(cur, pag->pagl_rightrec,
857+
&rec, &doneright, 0);
858+
if (error)
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+
}
825871

826872
/*
827873
* Loop until we find an inode chunk with a free inode.
828874
*/
829875
while (!doneleft || !doneright) {
830876
int useleft; /* using left inode chunk this time */
831877

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+
832889
/* figure out the closer block if both are valid. */
833890
if (!doneleft && !doneright) {
834891
useleft = pagino -
@@ -843,12 +900,20 @@ xfs_dialloc(
843900
rec = trec;
844901
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
845902
cur = tcur;
903+
904+
pag->pagl_leftrec = trec.ir_startino;
905+
pag->pagl_rightrec = rec.ir_startino;
906+
pag->pagl_pagino = pagino;
846907
goto alloc_inode;
847908
}
848909

849910
/* free inodes to the right? */
850911
if (!useleft && rec.ir_freecount) {
851912
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;
852917
goto alloc_inode;
853918
}
854919

@@ -863,14 +928,28 @@ xfs_dialloc(
863928
if (error)
864929
goto error1;
865930
}
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;
867945
}
868946

869947
/*
870948
* In a different AG from the parent.
871949
* See if the most recently allocated block has any free.
872950
*/
873-
else if (be32_to_cpu(agi->agi_newino) != NULLAGINO) {
951+
newino:
952+
if (be32_to_cpu(agi->agi_newino) != NULLAGINO) {
874953
error = xfs_inobt_lookup(cur, be32_to_cpu(agi->agi_newino),
875954
XFS_LOOKUP_EQ, &i);
876955
if (error)
@@ -889,27 +968,27 @@ xfs_dialloc(
889968
goto alloc_inode;
890969
}
891970
}
971+
}
892972

893-
/*
894-
* None left in the last group, search the whole AG
895-
*/
896-
error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i);
973+
/*
974+
* None left in the last group, search the whole AG
975+
*/
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);
897989
if (error)
898990
goto error0;
899991
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-
}
913992
}
914993

915994
alloc_inode:

0 commit comments

Comments
 (0)