diff options
Diffstat (limited to 'sys/fs/ext2fs/ext2_alloc.c')
-rw-r--r-- | sys/fs/ext2fs/ext2_alloc.c | 101 |
1 files changed, 81 insertions, 20 deletions
diff --git a/sys/fs/ext2fs/ext2_alloc.c b/sys/fs/ext2fs/ext2_alloc.c index 6f24495..7abfe2b 100644 --- a/sys/fs/ext2fs/ext2_alloc.c +++ b/sys/fs/ext2fs/ext2_alloc.c @@ -59,6 +59,10 @@ static u_long ext2_hashalloc(struct inode *, int, long, int, int)); static daddr_t ext2_nodealloccg(struct inode *, int, daddr_t, int); static daddr_t ext2_mapsearch(struct m_ext2fs *, char *, daddr_t); +#ifdef FANCY_REALLOC +static int ext2_reallocblks(struct vop_reallocblks_args *); +#endif + /* * Allocate a block in the file system. * @@ -76,7 +80,6 @@ static daddr_t ext2_mapsearch(struct m_ext2fs *, char *, daddr_t); * 2) quadradically rehash into other cylinder groups, until an * available block is located. */ - int ext2_alloc(ip, lbn, bpref, size, cred, bnp) struct inode *ip; @@ -109,13 +112,17 @@ ext2_alloc(ip, lbn, bpref, size, cred, bnp) goto nospace; if (bpref >= fs->e2fs->e2fs_bcount) bpref = 0; - if (bpref == 0) + if (bpref == 0) cg = ino_to_cg(fs, ip->i_number); else cg = dtog(fs, bpref); bno = (daddr_t)ext2_hashalloc(ip, cg, bpref, fs->e2fs_bsize, ext2_alloccg); if (bno > 0) { + /* set next_alloc fields as done in block_getblk */ + ip->i_next_alloc_block = lbn; + ip->i_next_alloc_goal = bno; + ip->i_blocks += btodb(fs->e2fs_bsize); ip->i_flag |= IN_CHANGE | IN_UPDATE; *bnp = bno; @@ -144,13 +151,14 @@ nospace: */ #ifdef FANCY_REALLOC -#include <sys/sysctl.h> +SYSCTL_NODE(_vfs, OID_AUTO, ext2fs, CTLFLAG_RW, 0, "EXT2FS filesystem"); + static int doasyncfree = 1; -static int doreallocblks = 1; +SYSCTL_INT(_vfs_ext2fs, OID_AUTO, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, + "Use asychronous writes to update block pointers when freeing blocks"); -#ifdef OPT_DEBUG -SYSCTL_INT(_debug, 14, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, ""); -#endif /* OPT_DEBUG */ +static int doreallocblks = 1; +SYSCTL_INT(_vfs_ext2fs, OID_AUTO, doreallocblks, CTLFLAG_RW, &doreallocblks, 0, ""); #endif int @@ -222,7 +230,7 @@ return ENOSPC; /* * Find the preferred location for the cluster. */ - EXT2_LOCK(ump); + EXT2_LOCK(ump); pref = ext2_blkpref(ip, start_lbn, soff, sbap, blkno); /* * If the block range spans two block maps, get the second map. @@ -625,7 +633,8 @@ ext2_alloccg(struct inode *ip, int cg, daddr_t bpref, int size) struct m_ext2fs *fs; struct buf *bp; struct ext2mount *ump; - int error, bno, start, end, loc; + daddr_t bno, runstart, runlen; + int bit, loc, end, error, start; char *bbp; /* XXX ondisk32 */ fs = ip->i_e2fs; @@ -641,6 +650,15 @@ ext2_alloccg(struct inode *ip, int cg, daddr_t bpref, int size) EXT2_LOCK(ump); return (0); } + if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0) { + /* + * Another thread allocated the last block in this + * group while we were waiting for the buffer. + */ + brelse(bp); + EXT2_LOCK(ump); + return (0); + } bbp = (char *)bp->b_data; if (dtog(fs, bpref) != cg) @@ -666,18 +684,52 @@ ext2_alloccg(struct inode *ip, int cg, daddr_t bpref, int size) else start = 0; end = howmany(fs->e2fs->e2fs_fpg, NBBY) - start; +retry: + runlen = 0; + runstart = 0; for (loc = start; loc < end; loc++) { - if (bbp[loc] == 0) { - bno = loc * NBBY; - goto gotit; + if (bbp[loc] == (char)0xff) { + runlen = 0; + continue; } - } - for (loc = 0; loc < start; loc++) { - if (bbp[loc] == 0) { - bno = loc * NBBY; + + /* Start of a run, find the number of high clear bits. */ + if (runlen == 0) { + bit = fls(bbp[loc]); + runlen = NBBY - bit; + runstart = loc * NBBY + bit; + } else if (bbp[loc] == 0) { + /* Continue a run. */ + runlen += NBBY; + } else { + /* + * Finish the current run. If it isn't long + * enough, start a new one. + */ + bit = ffs(bbp[loc]) - 1; + runlen += bit; + if (runlen >= 8) { + bno = runstart; + goto gotit; + } + + /* Run was too short, start a new one. */ + bit = fls(bbp[loc]); + runlen = NBBY - bit; + runstart = loc * NBBY + bit; + } + + /* If the current run is long enough, use it. */ + if (runlen >= 8) { + bno = runstart; goto gotit; } } + if (start != 0) { + end = start; + start = 0; + goto retry; + } bno = ext2_mapsearch(fs, bbp, bpref); if (bno < 0){ @@ -687,13 +739,13 @@ ext2_alloccg(struct inode *ip, int cg, daddr_t bpref, int size) } gotit: #ifdef DIAGNOSTIC - if (isset(bbp, (daddr_t)bno)) { - printf("ext2fs_alloccgblk: cg=%d bno=%d fs=%s\n", - cg, bno, fs->e2fs_fsmnt); + if (isset(bbp, bno)) { + printf("ext2fs_alloccgblk: cg=%d bno=%jd fs=%s\n", + cg, (intmax_t)bno, fs->e2fs_fsmnt); panic("ext2fs_alloccg: dup alloc"); } #endif - setbit(bbp, (daddr_t)bno); + setbit(bbp, bno); EXT2_LOCK(ump); fs->e2fs->e2fs_fbcount--; fs->e2fs_gd[cg].ext2bgd_nbfree--; @@ -733,6 +785,15 @@ ext2_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode) EXT2_LOCK(ump); return (0); } + if (fs->e2fs_gd[cg].ext2bgd_nifree == 0) { + /* + * Another thread allocated the last i-node in this + * group while we were waiting for the buffer. + */ + brelse(bp); + EXT2_LOCK(ump); + return (0); + } ibp = (char *)bp->b_data; if (ipref) { ipref %= fs->e2fs->e2fs_ipg; |