📄 xfs_rtalloc.c
字号:
/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_types.h"#include "xfs_bit.h"#include "xfs_log.h"#include "xfs_inum.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_bmap_btree.h"#include "xfs_alloc_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_btree.h"#include "xfs_ialloc.h"#include "xfs_alloc.h"#include "xfs_bmap.h"#include "xfs_rtalloc.h"#include "xfs_fsops.h"#include "xfs_error.h"#include "xfs_rw.h"#include "xfs_inode_item.h"#include "xfs_trans_space.h"/* * Prototypes for internal functions. */STATIC int xfs_rtallocate_range(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, xfs_extlen_t, xfs_buf_t **, xfs_fsblock_t *);STATIC int xfs_rtany_summary(xfs_mount_t *, xfs_trans_t *, int, int, xfs_rtblock_t, xfs_buf_t **, xfs_fsblock_t *, int *);STATIC int xfs_rtcheck_range(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, xfs_extlen_t, int, xfs_rtblock_t *, int *);STATIC int xfs_rtfind_back(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, xfs_rtblock_t, xfs_rtblock_t *);STATIC int xfs_rtfind_forw(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, xfs_rtblock_t, xfs_rtblock_t *);STATIC int xfs_rtget_summary( xfs_mount_t *, xfs_trans_t *, int, xfs_rtblock_t, xfs_buf_t **, xfs_fsblock_t *, xfs_suminfo_t *);STATIC int xfs_rtmodify_range(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, xfs_extlen_t, int);STATIC int xfs_rtmodify_summary(xfs_mount_t *, xfs_trans_t *, int, xfs_rtblock_t, int, xfs_buf_t **, xfs_fsblock_t *);/* * Internal functions. *//* * xfs_lowbit32: get low bit set out of 32-bit argument, -1 if none set. */STATIC intxfs_lowbit32( __uint32_t v){ if (v) return ffs(v) - 1; return -1;}/* * Allocate space to the bitmap or summary file, and zero it, for growfs. */STATIC int /* error */xfs_growfs_rt_alloc( xfs_mount_t *mp, /* file system mount point */ xfs_extlen_t oblocks, /* old count of blocks */ xfs_extlen_t nblocks, /* new count of blocks */ xfs_ino_t ino) /* inode number (bitmap/summary) */{ xfs_fileoff_t bno; /* block number in file */ xfs_buf_t *bp; /* temporary buffer for zeroing */ int cancelflags; /* flags for xfs_trans_cancel */ int committed; /* transaction committed flag */ xfs_daddr_t d; /* disk block address */ int error; /* error return value */ xfs_fsblock_t firstblock; /* first block allocated in xaction */ xfs_bmap_free_t flist; /* list of freed blocks */ xfs_fsblock_t fsbno; /* filesystem block for bno */ xfs_inode_t *ip; /* pointer to incore inode */ xfs_bmbt_irec_t map; /* block map output */ int nmap; /* number of block maps */ int resblks; /* space reservation */ xfs_trans_t *tp; /* transaction pointer */ /* * Allocate space to the file, as necessary. */ while (oblocks < nblocks) { tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_ALLOC); resblks = XFS_GROWFSRT_SPACE_RES(mp, nblocks - oblocks); cancelflags = 0; /* * Reserve space & log for one extent added to the file. */ if ((error = xfs_trans_reserve(tp, resblks, XFS_GROWRTALLOC_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_PERM_LOG_COUNT))) goto error_exit; cancelflags = XFS_TRANS_RELEASE_LOG_RES; /* * Lock the inode. */ if ((error = xfs_trans_iget(mp, tp, ino, 0, XFS_ILOCK_EXCL, &ip))) goto error_exit; XFS_BMAP_INIT(&flist, &firstblock); /* * Allocate blocks to the bitmap file. */ nmap = 1; cancelflags |= XFS_TRANS_ABORT; error = xfs_bmapi(tp, ip, oblocks, nblocks - oblocks, XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, &firstblock, resblks, &map, &nmap, &flist, NULL); if (!error && nmap < 1) error = XFS_ERROR(ENOSPC); if (error) goto error_exit; /* * Free any blocks freed up in the transaction, then commit. */ error = xfs_bmap_finish(&tp, &flist, &committed); if (error) goto error_exit; xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); /* * Now we need to clear the allocated blocks. * Do this one block per transaction, to keep it simple. */ cancelflags = 0; for (bno = map.br_startoff, fsbno = map.br_startblock; bno < map.br_startoff + map.br_blockcount; bno++, fsbno++) { tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_ZERO); /* * Reserve log for one block zeroing. */ if ((error = xfs_trans_reserve(tp, 0, XFS_GROWRTZERO_LOG_RES(mp), 0, 0, 0))) goto error_exit; /* * Lock the bitmap inode. */ if ((error = xfs_trans_iget(mp, tp, ino, 0, XFS_ILOCK_EXCL, &ip))) goto error_exit; /* * Get a buffer for the block. */ d = XFS_FSB_TO_DADDR(mp, fsbno); bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, 0); if (bp == NULL) { error = XFS_ERROR(EIO); goto error_exit; } memset(XFS_BUF_PTR(bp), 0, mp->m_sb.sb_blocksize); xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1); /* * Commit the transaction. */ xfs_trans_commit(tp, 0); } /* * Go on to the next extent, if any. */ oblocks = map.br_startoff + map.br_blockcount; } return 0;error_exit: xfs_trans_cancel(tp, cancelflags); return error;}/* * Attempt to allocate an extent minlen<=len<=maxlen starting from * bitmap block bbno. If we don't get maxlen then use prod to trim * the length, if given. Returns error; returns starting block in *rtblock. * The lengths are all in rtextents. */STATIC int /* error */xfs_rtallocate_extent_block( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t bbno, /* bitmap block number */ xfs_extlen_t minlen, /* minimum length to allocate */ xfs_extlen_t maxlen, /* maximum length to allocate */ xfs_extlen_t *len, /* out: actual length allocated */ xfs_rtblock_t *nextp, /* out: next block to try */ xfs_buf_t **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb, /* in/out: summary block number */ xfs_extlen_t prod, /* extent product factor */ xfs_rtblock_t *rtblock) /* out: start block allocated */{ xfs_rtblock_t besti; /* best rtblock found so far */ xfs_rtblock_t bestlen; /* best length found so far */ xfs_rtblock_t end; /* last rtblock in chunk */ int error; /* error value */ xfs_rtblock_t i; /* current rtblock trying */ xfs_rtblock_t next; /* next rtblock to try */ int stat; /* status from internal calls */ /* * Loop over all the extents starting in this bitmap block, * looking for one that's long enough. */ for (i = XFS_BLOCKTOBIT(mp, bbno), besti = -1, bestlen = 0, end = XFS_BLOCKTOBIT(mp, bbno + 1) - 1; i <= end; i++) { /* * See if there's a free extent of maxlen starting at i. * If it's not so then next will contain the first non-free. */ error = xfs_rtcheck_range(mp, tp, i, maxlen, 1, &next, &stat); if (error) { return error; } if (stat) { /* * i for maxlen is all free, allocate and return that. */ error = xfs_rtallocate_range(mp, tp, i, maxlen, rbpp, rsb); if (error) { return error; } *len = maxlen; *rtblock = i; return 0; } /* * In the case where we have a variable-sized allocation * request, figure out how big this free piece is, * and if it's big enough for the minimum, and the best * so far, remember it. */ if (minlen < maxlen) { xfs_rtblock_t thislen; /* this extent size */ thislen = next - i; if (thislen >= minlen && thislen > bestlen) { besti = i; bestlen = thislen; } } /* * If not done yet, find the start of the next free space. */ if (next < end) { error = xfs_rtfind_forw(mp, tp, next, end, &i); if (error) { return error; } } else break; } /* * Searched the whole thing & didn't find a maxlen free extent. */ if (minlen < maxlen && besti != -1) { xfs_extlen_t p; /* amount to trim length by */ /* * If size should be a multiple of prod, make that so. */ if (prod > 1 && (p = do_mod(bestlen, prod))) bestlen -= p; /* * Allocate besti for bestlen & return that. */ error = xfs_rtallocate_range(mp, tp, besti, bestlen, rbpp, rsb); if (error) { return error; } *len = bestlen; *rtblock = besti; return 0; } /* * Allocation failed. Set *nextp to the next block to try. */ *nextp = next; *rtblock = NULLRTBLOCK; return 0;}/* * Allocate an extent of length minlen<=len<=maxlen, starting at block * bno. If we don't get maxlen then use prod to trim the length, if given. * Returns error; returns starting block in *rtblock. * The lengths are all in rtextents. */STATIC int /* error */xfs_rtallocate_extent_exact( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t bno, /* starting block number to allocate */ xfs_extlen_t minlen, /* minimum length to allocate */ xfs_extlen_t maxlen, /* maximum length to allocate */ xfs_extlen_t *len, /* out: actual length allocated */ xfs_buf_t **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb, /* in/out: summary block number */ xfs_extlen_t prod, /* extent product factor */ xfs_rtblock_t *rtblock) /* out: start block allocated */{ int error; /* error value */ xfs_extlen_t i; /* extent length trimmed due to prod */ int isfree; /* extent is free */ xfs_rtblock_t next; /* next block to try (dummy) */ ASSERT(minlen % prod == 0 && maxlen % prod == 0); /* * Check if the range in question (for maxlen) is free. */ error = xfs_rtcheck_range(mp, tp, bno, maxlen, 1, &next, &isfree); if (error) { return error; } if (isfree) { /* * If it is, allocate it and return success. */ error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb); if (error) { return error; } *len = maxlen; *rtblock = bno; return 0; } /* * If not, allocate what there is, if it's at least minlen. */ maxlen = next - bno; if (maxlen < minlen) { /* * Failed, return failure status. */ *rtblock = NULLRTBLOCK; return 0; } /* * Trim off tail of extent, if prod is specified. */ if (prod > 1 && (i = maxlen % prod)) { maxlen -= i; if (maxlen < minlen) { /* * Now we can't do it, return failure status. */ *rtblock = NULLRTBLOCK; return 0; } } /* * Allocate what we can and return it. */ error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb); if (error) { return error; } *len = maxlen; *rtblock = bno; return 0;}/* * Allocate an extent of length minlen<=len<=maxlen, starting as near * to bno as possible. If we don't get maxlen then use prod to trim * the length, if given. The lengths are all in rtextents. */STATIC int /* error */xfs_rtallocate_extent_near( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t bno, /* starting block number to allocate */ xfs_extlen_t minlen, /* minimum length to allocate */ xfs_extlen_t maxlen, /* maximum length to allocate */ xfs_extlen_t *len, /* out: actual length allocated */ xfs_buf_t **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb, /* in/out: summary block number */ xfs_extlen_t prod, /* extent product factor */ xfs_rtblock_t *rtblock) /* out: start block allocated */{ int any; /* any useful extents from summary */ xfs_rtblock_t bbno; /* bitmap block number */ int error; /* error value */ int i; /* bitmap block offset (loop control) */ int j; /* secondary loop control */ int log2len; /* log2 of minlen */ xfs_rtblock_t n; /* next block to try */ xfs_rtblock_t r; /* result block */ ASSERT(minlen % prod == 0 && maxlen % prod == 0); /* * If the block number given is off the end, silently set it to * the last block. */ if (bno >= mp->m_sb.sb_rextents) bno = mp->m_sb.sb_rextents - 1; /* * Try the exact allocation first. */ error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen, len, rbpp, rsb, prod, &r); if (error) { return error; } /* * If the exact allocation worked, return that. */ if (r != NULLRTBLOCK) { *rtblock = r; return 0; } bbno = XFS_BITTOBLOCK(mp, bno); i = 0; log2len = xfs_highbit32(minlen); /* * Loop over all bitmap blocks (bbno + i is current block). */ for (;;) { /* * Get summary information of extents of all useful levels * starting in this bitmap block. */ error = xfs_rtany_summary(mp, tp, log2len, mp->m_rsumlevels - 1, bbno + i, rbpp, rsb, &any); if (error) { return error; } /* * If there are any useful extents starting here, try * allocating one. */ if (any) { /* * On the positive side of the starting location. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -