Author: jhb
Date: Tue Feb  1 18:21:45 2011
New Revision: 218175
URL: http://svn.freebsd.org/changeset/base/218175

Log:
  - Set the next_alloc fields for an i-node after allocating a new block
    so that future allocations start with most recently allocated block
    rather than the beginning of the filesystem.
  - Fix ext2_alloccg() to properly scan for 8 block chunks that are not
    aligned on 8-bit boundaries.  Previously this was causing new blocks
    to be allocated in a highly fragmented fashion (block 0 of a file at
    lbn N, block 1 at lbn N + 8, block 2 at lbn N + 16, etc.).
  - Cosmetic tweaks to the currently-disabled fancy realloc sysctls.
  
  PR:           kern/153584
  Discussed with:       bde
  Tested by:    Pedro F. Giffuni  giffunip at yahoo, Zheng Liu (lz)

Modified:
  head/sys/fs/ext2fs/ext2_alloc.c

Modified: head/sys/fs/ext2fs/ext2_alloc.c
==============================================================================
--- head/sys/fs/ext2fs/ext2_alloc.c     Tue Feb  1 17:42:57 2011        
(r218174)
+++ head/sys/fs/ext2fs/ext2_alloc.c     Tue Feb  1 18:21:45 2011        
(r218175)
@@ -59,6 +59,10 @@ static u_long        ext2_hashalloc(struct inod
                                                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.
  *
@@ -108,13 +112,17 @@ ext2_alloc(ip, lbn, bpref, size, cred, b
                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;
@@ -143,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
@@ -624,7 +633,8 @@ ext2_alloccg(struct inode *ip, int cg, d
        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;
@@ -665,18 +675,52 @@ ext2_alloccg(struct inode *ip, int cg, d
        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){
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to