Both function contain the same basic loop over all AGs. Merge the two by creating three passes in the loop instead of duplicating the code. Signed-off-by: Christoph Hellwig <hch@xxxxxx> --- fs/xfs/xfs_ialloc.c | 179 +++++++++++++++------------------------------------- 1 file changed, 55 insertions(+), 124 deletions(-) Index: xfs/fs/xfs/xfs_ialloc.c =================================================================== --- xfs.orig/fs/xfs/xfs_ialloc.c 2012-07-02 12:25:24.365774992 +0200 +++ xfs/fs/xfs/xfs_ialloc.c 2012-07-02 12:26:14.325774734 +0200 @@ -439,114 +439,6 @@ xfs_ialloc_next_ag( } /* - * Select an allocation group to look for a free inode in, based on the parent - * inode and then mode. Return the allocation group buffer. - */ -STATIC xfs_agnumber_t -xfs_ialloc_ag_select( - xfs_trans_t *tp, /* transaction pointer */ - xfs_ino_t parent, /* parent directory inode number */ - umode_t mode, /* bits set to indicate file type */ - int okalloc) /* ok to allocate more space */ -{ - xfs_agnumber_t agcount; /* number of ag's in the filesystem */ - xfs_agnumber_t agno; /* current ag number */ - int flags; /* alloc buffer locking flags */ - xfs_extlen_t ineed; /* blocks needed for inode allocation */ - xfs_extlen_t longest = 0; /* longest extent available */ - xfs_mount_t *mp; /* mount point structure */ - int needspace; /* file mode implies space allocated */ - xfs_perag_t *pag; /* per allocation group data */ - xfs_agnumber_t pagno; /* parent (starting) ag number */ - int error; - - /* - * Files of these types need at least one block if length > 0 - * (and they won't fit in the inode, but that's hard to figure out). - */ - needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode); - mp = tp->t_mountp; - agcount = mp->m_maxagi; - if (S_ISDIR(mode)) - pagno = xfs_ialloc_next_ag(mp); - else { - pagno = XFS_INO_TO_AGNO(mp, parent); - if (pagno >= agcount) - pagno = 0; - } - - ASSERT(pagno < agcount); - - /* - * Loop through allocation groups, looking for one with a little - * free space in it. Note we don't look for free inodes, exactly. - * Instead, we include whether there is a need to allocate inodes - * to mean that blocks must be allocated for them, - * if none are currently free. - */ - agno = pagno; - flags = XFS_ALLOC_FLAG_TRYLOCK; - for (;;) { - pag = xfs_perag_get(mp, agno); - if (!pag->pagi_inodeok) { - xfs_ialloc_next_ag(mp); - goto nextag; - } - - if (!pag->pagi_init) { - error = xfs_ialloc_pagi_init(mp, tp, agno); - if (error) - goto nextag; - } - - if (pag->pagi_freecount) { - xfs_perag_put(pag); - return agno; - } - - if (!okalloc) - goto nextag; - - if (!pag->pagf_init) { - error = xfs_alloc_pagf_init(mp, tp, agno, flags); - if (error) - goto nextag; - } - - /* - * Is there enough free space for the file plus a block of - * inodes? (if we need to allocate some)? - */ - ineed = XFS_IALLOC_BLOCKS(mp); - longest = pag->pagf_longest; - if (!longest) - longest = pag->pagf_flcount > 0; - - if (pag->pagf_freeblks >= needspace + ineed && - longest >= ineed) { - xfs_perag_put(pag); - return agno; - } -nextag: - xfs_perag_put(pag); - /* - * No point in iterating over the rest, if we're shutting - * down. - */ - if (XFS_FORCED_SHUTDOWN(mp)) - return NULLAGNUMBER; - agno++; - if (agno >= agcount) - agno = 0; - if (agno == pagno) { - if (flags == 0) - return NULLAGNUMBER; - flags = 0; - } - } -} - -/* * Try to retrieve the next record to the left/right from the current one. */ STATIC int @@ -901,10 +793,10 @@ xfs_dialloc( struct xfs_buf *agbp; xfs_agnumber_t agno; int error; - int ialloced; int noroom = 0; xfs_agnumber_t start_agno; struct xfs_perag *pag; + int pass; if (*IO_agbp) { /* @@ -917,16 +809,6 @@ xfs_dialloc( } /* - * We do not have an agbp, so select an initial allocation - * group for inode allocation. - */ - start_agno = xfs_ialloc_ag_select(tp, parent, mode, okalloc); - if (start_agno == NULLAGNUMBER) { - *inop = NULLFSINO; - return 0; - } - - /* * If we have already hit the ceiling of inode blocks then clear * okalloc so we scan all available agi structures for a free * inode. @@ -938,12 +820,31 @@ xfs_dialloc( } /* - * Loop until we find an allocation group that either has free inodes - * or in which we can allocate some inodes. Iterate through the - * allocation groups upward, wrapping at the end. + * For directories start with a new allocation groups, for other file + * types aim to find an inode close to the parent. */ + if (S_ISDIR(mode)) { + start_agno = xfs_ialloc_next_ag(mp); + ASSERT(start_agno < mp->m_maxagi); + } else { + start_agno = XFS_INO_TO_AGNO(mp, parent); + if (start_agno >= mp->m_maxagi) + start_agno = 0; + } + + /* + * Loop through allocation groups, looking for one with a little + * free space in it. Note we don't look for free inodes, exactly. + * Instead, we include whether there is a need to allocate inodes + * to mean that blocks must be allocated for them, if none are + * currently free. + */ + *inop = NULLFSINO; agno = start_agno; + pass = 0; for (;;) { + int ialloced; + pag = xfs_perag_get(mp, agno); if (!pag->pagi_inodeok) { xfs_ialloc_next_ag(mp); @@ -980,6 +881,33 @@ xfs_dialloc( goto nextag; } + if (!pag->pagf_init) { + int flags = pass ? 0 : XFS_ALLOC_FLAG_TRYLOCK; + + error = xfs_alloc_pagf_init(mp, tp, agno, flags); + if (error) + goto out_error; + } + + if (pass < 2) { + /* + * Is there enough free space for the file plus a block + * of inodes? + */ + xfs_extlen_t longest = pag->pagf_longest; + int needspace = + S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode); + + if (!longest) + longest = pag->pagf_flcount > 0; + + if (pag->pagf_freeblks < + XFS_IALLOC_BLOCKS(mp) + needspace) + goto nextag; + if (longest < XFS_IALLOC_BLOCKS(mp)) + goto nextag; + } + error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced); if (error) { xfs_trans_brelse(tp, agbp); @@ -1012,8 +940,11 @@ nextag: if (++agno == mp->m_sb.sb_agcount) agno = 0; if (agno == start_agno) { - *inop = NULLFSINO; - return noroom ? ENOSPC : 0; + if (pass == 2) { + *inop = NULLFSINO; + return noroom ? ENOSPC : 0; + } + pass++; } } _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs