Ok folks, here is a patchset that MFC's the dirpref code from -current
    to -stable.  I have done some very simple testing, but I need a couple
    more eyes on the code.  I want to make sure that I have MFC'd all
    necessary rcs pieces.

    This is what I have MFC'd:

        1.36                    src/sbin/newfs/mkfs.c
        1.35                    src/sbin/newfs/newfs.c
        1.16                    src/sbin/tunefs/tunefs.c
        1.75                    src/sys/ufs/ffs/ffs_alloc.c
        1.144, 1.148, 1.159     src/sys/ufs/ffs/ffs_vfsops.c
        1.20                    src/sys/ufs/ffs/fs.h

        1.37                    src/sbin/newfs/newfs.8
        1.15                    src/sbin/tunefs/tunefs.8

        1.22, 1.25              src/sbin/fsck_ffs/setup.c (note: fsck/setup.c
                                                        in -stable)

    I have also incorporated the snapshot changes to the superblock (fs.h)
    and some of the initialization code for fsck (setup.c) to try to make
    the -stable fsck compatible with a -current filesystem.

    I intend to commit this patchset to -stable on Friday if no issues come
    up.

    testers testers...

                                                -Matt

Index: sbin/fsck/setup.c
===================================================================
RCS file: /home/ncvs/src/sbin/fsck/Attic/setup.c,v
retrieving revision 1.17.2.2
diff -u -r1.17.2.2 setup.c
--- sbin/fsck/setup.c   2001/02/06 20:39:09     1.17.2.2
+++ sbin/fsck/setup.c   2001/09/19 00:29:36
@@ -380,6 +380,11 @@
        memmove(altsblock.fs_ocsp, sblock.fs_ocsp, sizeof sblock.fs_ocsp);
        altsblock.fs_csp = sblock.fs_csp;
        altsblock.fs_maxcluster = sblock.fs_maxcluster;
+       altsblock.fs_contigdirs = sblock.fs_contigdirs;
+       altsblock.fs_avgfilesize = sblock.fs_avgfilesize;
+       altsblock.fs_avgfpdir = sblock.fs_avgfpdir;
+       altsblock.fs_pendingblocks = sblock.fs_pendingblocks;
+       altsblock.fs_pendinginodes = sblock.fs_pendinginodes;
        memmove(altsblock.fs_fsmnt, sblock.fs_fsmnt, sizeof sblock.fs_fsmnt);
        memmove(altsblock.fs_sparecon,
                sblock.fs_sparecon, sizeof sblock.fs_sparecon);
Index: sbin/newfs/mkfs.c
===================================================================
RCS file: /home/ncvs/src/sbin/newfs/mkfs.c,v
retrieving revision 1.29.2.5
diff -u -r1.29.2.5 mkfs.c
--- sbin/newfs/mkfs.c   2001/08/01 08:41:02     1.29.2.5
+++ sbin/newfs/mkfs.c   2001/09/19 00:07:12
@@ -36,7 +36,7 @@
 static char sccsid[] = "@(#)mkfs.c     8.11 (Berkeley) 5/3/95";
 #endif
 static const char rcsid[] =
-  "$FreeBSD: src/sbin/newfs/mkfs.c,v 1.29.2.5 2001/08/01 08:41:02 obrien Exp $";
+  "$FreeBSD: src/sbin/newfs/mkfs.c,v 1.36 2001/04/10 08:38:52 mckusick Exp $";
 #endif /* not lint */
 
 #include <err.h>
@@ -119,6 +119,8 @@
 extern int     nrpos;          /* # of distinguished rotational positions */
 extern int     bbsize;         /* boot block size */
 extern int     sbsize;         /* superblock size */
+extern int     avgfilesize;    /* expected average file size */
+extern int     avgfilesperdir; /* expected number of files per directory */
 extern u_long  memleft;        /* virtual memory available */
 extern caddr_t membase;        /* start address of memory based filesystem */
 extern char *  filename;
@@ -273,6 +275,17 @@
                printf("preposterous ntrak %d\n", sblock.fs_ntrak), exit(14);
        if (sblock.fs_nsect <= 0)
                printf("preposterous nsect %d\n", sblock.fs_nsect), exit(15);
+       /*
+        * collect and verify the filesystem density info
+        */
+       sblock.fs_avgfilesize = avgfilesize;
+       sblock.fs_avgfpdir = avgfilesperdir;
+       if (sblock.fs_avgfilesize <= 0)
+               printf("illegal expected average file size %d\n",
+                   sblock.fs_avgfilesize), exit(14);
+       if (sblock.fs_avgfpdir <= 0)
+               printf("illegal expected number of files per directory %d\n",
+                   sblock.fs_avgfpdir), exit(15);
        /*
         * collect and verify the block and fragment sizes
         */
Index: sbin/newfs/newfs.8
===================================================================
RCS file: /home/ncvs/src/sbin/newfs/newfs.8,v
retrieving revision 1.26.2.7
diff -u -r1.26.2.7 newfs.8
--- sbin/newfs/newfs.8  2001/07/22 11:32:31     1.26.2.7
+++ sbin/newfs/newfs.8  2001/09/19 00:27:33
@@ -30,7 +30,7 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)newfs.8    8.6 (Berkeley) 5/3/95
-.\" $FreeBSD: src/sbin/newfs/newfs.8,v 1.26.2.7 2001/07/22 11:32:31 dd Exp $
+.\" $FreeBSD: src/sbin/newfs/newfs.8,v 1.37 2001/04/10 10:36:43 nik Exp $
 .\"
 .Dd December 19, 2000
 .Dt NEWFS 8
@@ -50,6 +50,8 @@
 .Op Fl d Ar rotdelay
 .Op Fl e Ar maxbpg
 .Op Fl f Ar frag-size
+.Op Fl g Ar avgfilesize
+.Op Fl h Ar avfpdir
 .Op Fl i Ar bytes
 .Op Fl k Ar skew
 .Op Fl l Ar interleave
@@ -196,6 +198,10 @@
 and
 .Ar blocksize .
 The default is 1024 bytes.
+.It Fl g Ar avgfilesize
+The expected average file size for the file system.
+.It Fl h Ar avgfpdir
+The expected average number of files per directory on the file system.
 .It Fl i Ar number of bytes per inode
 Specify the density of inodes in the file system.
 The default is to create an inode for every
Index: sbin/newfs/newfs.c
===================================================================
RCS file: /home/ncvs/src/sbin/newfs/newfs.c,v
retrieving revision 1.30.2.4
diff -u -r1.30.2.4 newfs.c
--- sbin/newfs/newfs.c  2001/05/28 02:34:31     1.30.2.4
+++ sbin/newfs/newfs.c  2001/09/19 00:07:36
@@ -42,7 +42,7 @@
 static char sccsid[] = "@(#)newfs.c    8.13 (Berkeley) 5/1/95";
 #endif
 static const char rcsid[] =
-  "$FreeBSD: src/sbin/newfs/newfs.c,v 1.30.2.4 2001/05/28 02:34:31 obrien Exp $";
+  "$FreeBSD: src/sbin/newfs/newfs.c,v 1.35 2001/04/10 08:38:52 mckusick Exp $";
 #endif /* not lint */
 
 /*
@@ -162,9 +162,7 @@
  * The number of sectors are used to determine the size of a cyl-group.
  * Kirk suggested one or two meg per "cylinder" so we say two.
  */
-
 #define NTRACKS                1       /* number of heads */
-
 #define NSECTORS       4096    /* number of sectors */
 
 int    mfs;                    /* run as the memory based filesystem */
@@ -198,6 +196,8 @@
 int    rotdelay = ROTDELAY;    /* rotational delay between blocks */
 int    maxbpg;                 /* maximum blocks per file in a cyl group */
 int    nrpos = NRPOS;          /* # of distinguished rotational positions */
+int    avgfilesize = AVFILESIZ;/* expected average file size */
+int    avgfilesperdir = AFPDIR;/* expected number of files per directory */
 int    bbsize = BBSIZE;        /* boot block size */
 int    sbsize = SBSIZE;        /* superblock size */
 int    mntflags = MNT_ASYNC;   /* flags to be passed to mount */
@@ -249,8 +249,8 @@
        }
 
        opstring = mfs ?
-           "NF:T:Ua:b:c:d:e:f:i:m:o:s:" :
-           "NOS:T:Ua:b:c:d:e:f:i:k:l:m:n:o:p:r:s:t:u:vx:";
+           "NF:T:Ua:b:c:d:e:f:g:h:i:m:o:s:" :
+           "NOS:T:Ua:b:c:d:e:f:g:h:i:k:l:m:n:o:p:r:s:t:u:vx:";
        while ((ch = getopt(argc, argv, opstring)) != -1)
                switch (ch) {
                case 'N':
@@ -301,6 +301,14 @@
                        if ((fsize = atoi(optarg)) <= 0)
                                fatal("%s: bad fragment size", optarg);
                        break;
+               case 'g':
+                       if ((avgfilesize = atoi(optarg)) <= 0)
+                               fatal("%s: bad average file size", optarg);
+                       break;
+               case 'h':
+                       if ((avgfilesperdir = atoi(optarg)) <= 0)
+                               fatal("%s: bad average files per dir", optarg);
+                       break;
                case 'i':
                        if ((density = atoi(optarg)) <= 0)
                                fatal("%s: bad bytes per inode", optarg);
@@ -761,6 +769,8 @@
        fprintf(stderr, "\t-d rotational delay between contiguous blocks\n");
        fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
        fprintf(stderr, "\t-f frag size\n");
+       fprintf(stderr, "\t-g average file size\n");
+       fprintf(stderr, "\t-h average files per directory\n");
        fprintf(stderr, "\t-i number of bytes per inode\n");
        fprintf(stderr, "\t-k sector 0 skew, per track\n");
        fprintf(stderr, "\t-l hardware sector interleave\n");
Index: sbin/tunefs/tunefs.8
===================================================================
RCS file: /home/ncvs/src/sbin/tunefs/tunefs.8,v
retrieving revision 1.11.2.1
diff -u -r1.11.2.1 tunefs.8
--- sbin/tunefs/tunefs.8        2000/12/08 14:04:21     1.11.2.1
+++ sbin/tunefs/tunefs.8        2001/09/19 00:27:17
@@ -30,7 +30,7 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)tunefs.8   8.2 (Berkeley) 12/11/93
-.\" $FreeBSD: src/sbin/tunefs/tunefs.8,v 1.11.2.1 2000/12/08 14:04:21 ru Exp $
+.\" $FreeBSD: src/sbin/tunefs/tunefs.8,v 1.15 2001/04/10 10:36:44 nik Exp $
 .\"
 .Dd December 11, 1993
 .Dt TUNEFS 8
@@ -44,11 +44,13 @@
 .Op Fl a Ar maxcontig
 .Op Fl d Ar rotdelay
 .Op Fl e Ar maxbpg
+.Op Fl f Ar avgfilesize
 .Op Fl m Ar minfree
 .Bk -words
 .Op Fl n Ar enable | disable
 .Op Fl o Ar optimize_preference
 .Op Fl p
+.Op Fl s Ar avgfpdir
 .Ek
 .Op Ar special | Ar filesystem
 .Sh DESCRIPTION
@@ -92,6 +94,8 @@
 in a cylinder group before seeking elsewhere.
 For file systems with exclusively large files,
 this parameter should be set higher.
+.It Fl f Ar avgfilezsize
+Specify the expected average file size.
 .It Fl m Ar minfree
 Specify the percentage of space held back
 from normal users; the minimum free space threshold.
@@ -122,6 +126,8 @@
 obtained in the
 .Xr dumpfs 8
 manual page.
+.It Fl s Ar avgfpdir
+Specify the expected number of files per directory.
 .El
 .Sh ERRORS
 If
Index: sbin/tunefs/tunefs.c
===================================================================
RCS file: /home/ncvs/src/sbin/tunefs/tunefs.c,v
retrieving revision 1.11.2.3
diff -u -r1.11.2.3 tunefs.c
--- sbin/tunefs/tunefs.c        2001/08/01 23:13:18     1.11.2.3
+++ sbin/tunefs/tunefs.c        2001/09/19 00:50:46
@@ -180,6 +180,24 @@
                                sblock.fs_maxbpg = i;
                                continue;
 
+                       case 'f':
+                               name = "average file size";
+                               if (argc < 1)
+                                       errx(10, "-a: missing %s", name);
+                               argc--, argv++;
+                               i = atoi(*argv);
+                               if (i < 1)
+                                       errx(10, "%s must be >= 1 (was %s)", name, 
+*argv);
+                               if (sblock.fs_avgfilesize == i) {
+                                       warnx("%s remains unchanged as %d",
+                                               name, i);
+                               } else {
+                                       warnx("%s changes from %d to %d",
+                                               name, sblock.fs_avgfilesize, i);
+                                       sblock.fs_avgfilesize = i;
+                               }
+                               break;
+
                        case 'm':
                                name = "minimum percentage of free space";
                                if (argc < 1)
@@ -247,6 +265,24 @@
                                        warnx(OPTWARN, "space", "<", MINFREE);
                                continue;
 
+                       case 's':
+                               name = "expected number of files per directory";
+                               if (argc < 1)
+                                       errx(10, "-a: missing %s", name);
+                               argc--, argv++;
+                               i = atoi(*argv);
+                               if (i < 1)
+                                       errx(10, "%s must be >= 1 (was %s)", name, 
+*argv);
+                               if (sblock.fs_avgfpdir == i) {
+                                       warnx("%s remains unchanged as %d",
+                                               name, i);
+                               } else {
+                                       warnx("%s changes from %d to %d",
+                                               name, sblock.fs_avgfpdir, i);
+                                       sblock.fs_avgfpdir = i;
+                               }
+                               break;
+
                        default:
                                usage();
                        }
@@ -268,9 +304,9 @@
 usage()
 {
        fprintf(stderr, "%s\n%s\n%s\n",
-"usage: tunefs [-A] [-a maxcontig] [-d rotdelay] [-e maxbpg] [-m minfree]",
-"              [-p] [-n enable | disable] [-o optimize_preference]",
-"              [special | filesystem]");
+"usage: tunefs [-A] [-a maxcontig] [-d rotdelay] [-e maxbpg] [-f avgfilesize]",
+"              [-m minfree] [-p] [-n enable | disable] [-o space | time]",
+"              [-s filesperdir] [special | filesystem]");
        exit(2);
 }
 
@@ -327,6 +363,10 @@
              sblock.fs_rotdelay);
        warnx("maximum blocks per file in a cylinder group: (-e)  %d",
              sblock.fs_maxbpg);
+       warnx("average file size: (-f)                            %d",
+             sblock.fs_avgfilesize);
+       warnx("average number of files in a directory: (-s)       %d",
+             sblock.fs_avgfpdir);
        warnx("minimum percentage of free space: (-m)             %d%%",
              sblock.fs_minfree);
        warnx("optimization preference: (-o)                      %s",
Index: sys/ufs/ffs/ffs_alloc.c
===================================================================
RCS file: /home/ncvs/src/sys/ufs/ffs/ffs_alloc.c,v
retrieving revision 1.64.2.1
diff -u -r1.64.2.1 ffs_alloc.c
--- sys/ufs/ffs/ffs_alloc.c     2000/03/16 08:15:53     1.64.2.1
+++ sys/ufs/ffs/ffs_alloc.c     2001/09/19 00:33:51
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     @(#)ffs_alloc.c 8.18 (Berkeley) 5/26/95
- * $FreeBSD: src/sys/ufs/ffs/ffs_alloc.c,v 1.64.2.1 2000/03/16 08:15:53 ps Exp $
+ * $FreeBSD: src/sys/ufs/ffs/ffs_alloc.c,v 1.75 2001/04/10 08:38:59 mckusick Exp $
  */
 
 #include "opt_quota.h"
@@ -68,7 +68,7 @@
                                     int));
 static ufs_daddr_t ffs_clusteralloc __P((struct inode *, int, ufs_daddr_t,
            int));
-static ino_t   ffs_dirpref __P((struct fs *));
+static ino_t   ffs_dirpref __P((struct inode *));
 static ufs_daddr_t ffs_fragextend __P((struct inode *, int, long, int, int));
 static void    ffs_fserr __P((struct fs *, u_int, char *));
 static u_long  ffs_hashalloc
@@ -587,12 +587,23 @@
                goto noinodes;
 
        if ((mode & IFMT) == IFDIR)
-               ipref = ffs_dirpref(fs);
+               ipref = ffs_dirpref(pip);
        else
                ipref = pip->i_number;
        if (ipref >= fs->fs_ncg * fs->fs_ipg)
                ipref = 0;
        cg = ino_to_cg(fs, ipref);
+       /*
+        * Track number of dirs created one after another
+        * in a same cg without intervening by files.
+        */
+       if ((mode & IFMT) == IFDIR) {
+               if (fs->fs_contigdirs[cg] < 255)
+                       fs->fs_contigdirs[cg]++;
+       } else {
+               if (fs->fs_contigdirs[cg] > 0)
+                       fs->fs_contigdirs[cg]--;
+       }
        ino = (ino_t)ffs_hashalloc(pip, cg, (long)ipref, mode,
                                        (allocfcn_t *)ffs_nodealloccg);
        if (ino == 0)
@@ -627,28 +638,112 @@
 }
 
 /*
- * Find a cylinder to place a directory.
+ * Find a cylinder group to place a directory.
+ *
+ * The policy implemented by this algorithm is to allocate a
+ * directory inode in the same cylinder group as its parent
+ * directory, but also to reserve space for its files inodes
+ * and data. Restrict the number of directories which may be
+ * allocated one after another in the same cylinder group
+ * without intervening allocation of files.
  *
- * The policy implemented by this algorithm is to select from
- * among those cylinder groups with above the average number of
- * free inodes, the one with the smallest number of directories.
+ * If we allocate a first level directory then force allocation
+ * in another cylinder group.
  */
 static ino_t
-ffs_dirpref(fs)
-       register struct fs *fs;
+ffs_dirpref(pip)
+       struct inode *pip;
 {
-       int cg, minndir, mincg, avgifree;
+       register struct fs *fs;
+       int cg, prefcg, dirsize, cgsize;
+       int avgifree, avgbfree, avgndir, curdirsize;
+       int minifree, minbfree, maxndir;
+       int mincg, minndir;
+       int maxcontigdirs;
 
+       fs = pip->i_fs;
+
        avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg;
-       minndir = fs->fs_ipg;
-       mincg = 0;
-       for (cg = 0; cg < fs->fs_ncg; cg++)
-               if (fs->fs_cs(fs, cg).cs_ndir < minndir &&
-                   fs->fs_cs(fs, cg).cs_nifree >= avgifree) {
-                       mincg = cg;
-                       minndir = fs->fs_cs(fs, cg).cs_ndir;
+       avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
+       avgndir = fs->fs_cstotal.cs_ndir / fs->fs_ncg;
+
+       /*
+        * Force allocation in another cg if creating a first level dir.
+        */
+       if (ITOV(pip)->v_flag & VROOT) {
+               prefcg = arc4random() % fs->fs_ncg;
+               mincg = prefcg;
+               minndir = fs->fs_ipg;
+               for (cg = prefcg; cg < fs->fs_ncg; cg++)
+                       if (fs->fs_cs(fs, cg).cs_ndir < minndir &&
+                           fs->fs_cs(fs, cg).cs_nifree >= avgifree &&
+                           fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
+                               mincg = cg;
+                               minndir = fs->fs_cs(fs, cg).cs_ndir;
+                       }
+               for (cg = 0; cg < prefcg; cg++)
+                       if (fs->fs_cs(fs, cg).cs_ndir < minndir &&
+                           fs->fs_cs(fs, cg).cs_nifree >= avgifree &&
+                           fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
+                               mincg = cg;
+                               minndir = fs->fs_cs(fs, cg).cs_ndir;
+                       }
+               return ((ino_t)(fs->fs_ipg * mincg));
+       }
+
+       /*
+        * Count various limits which used for
+        * optimal allocation of a directory inode.
+        */
+       maxndir = min(avgndir + fs->fs_ipg / 16, fs->fs_ipg);
+       minifree = avgifree - fs->fs_ipg / 4;
+       if (minifree < 0)
+               minifree = 0;
+       minbfree = avgbfree - fs->fs_fpg / fs->fs_frag / 4;
+       if (minbfree < 0)
+               minbfree = 0;
+       cgsize = fs->fs_fsize * fs->fs_fpg;
+       dirsize = fs->fs_avgfilesize * fs->fs_avgfpdir;
+       curdirsize = avgndir ? (cgsize - avgbfree * fs->fs_bsize) / avgndir : 0;
+       if (dirsize < curdirsize)
+               dirsize = curdirsize;
+       maxcontigdirs = min(cgsize / dirsize, 255);
+       if (fs->fs_avgfpdir > 0)
+               maxcontigdirs = min(maxcontigdirs,
+                                   fs->fs_ipg / fs->fs_avgfpdir);
+       if (maxcontigdirs == 0)
+               maxcontigdirs = 1;
+
+       /*
+        * Limit number of dirs in one cg and reserve space for 
+        * regular files, but only if we have no deficit in
+        * inodes or space.
+        */
+       prefcg = ino_to_cg(fs, pip->i_number);
+       for (cg = prefcg; cg < fs->fs_ncg; cg++)
+               if (fs->fs_cs(fs, cg).cs_ndir < maxndir &&
+                   fs->fs_cs(fs, cg).cs_nifree >= minifree &&
+                   fs->fs_cs(fs, cg).cs_nbfree >= minbfree) {
+                       if (fs->fs_contigdirs[cg] < maxcontigdirs)
+                               return ((ino_t)(fs->fs_ipg * cg));
                }
-       return ((ino_t)(fs->fs_ipg * mincg));
+       for (cg = 0; cg < prefcg; cg++)
+               if (fs->fs_cs(fs, cg).cs_ndir < maxndir &&
+                   fs->fs_cs(fs, cg).cs_nifree >= minifree &&
+                   fs->fs_cs(fs, cg).cs_nbfree >= minbfree) {
+                       if (fs->fs_contigdirs[cg] < maxcontigdirs)
+                               return ((ino_t)(fs->fs_ipg * cg));
+               }
+       /*
+        * This is a backstop when we have deficit in space.
+        */
+       for (cg = prefcg; cg < fs->fs_ncg; cg++)
+               if (fs->fs_cs(fs, cg).cs_nifree >= avgifree)
+                       return ((ino_t)(fs->fs_ipg * cg));
+       for (cg = 0; cg < prefcg; cg++)
+               if (fs->fs_cs(fs, cg).cs_nifree >= avgifree)
+                       break;
+       return ((ino_t)(fs->fs_ipg * cg));
 }
 
 /*
Index: sys/ufs/ffs/ffs_vfsops.c
===================================================================
RCS file: /home/ncvs/src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.117.2.3
diff -u -r1.117.2.3 ffs_vfsops.c
--- sys/ufs/ffs/ffs_vfsops.c    2001/07/26 20:37:31     1.117.2.3
+++ sys/ufs/ffs/ffs_vfsops.c    2001/09/19 00:35:03
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     @(#)ffs_vfsops.c        8.31 (Berkeley) 5/20/95
- * $FreeBSD: src/sys/ufs/ffs/ffs_vfsops.c,v 1.117.2.3 2001/07/26 20:37:31 iedowse Exp 
$
+ * $FreeBSD: src/sys/ufs/ffs/ffs_vfsops.c,v 1.159 2001/09/09 23:48:28 iedowse Exp $
  */
 
 #include "opt_quota.h"
@@ -470,12 +470,18 @@
         */
        newfs->fs_csp = fs->fs_csp;
        newfs->fs_maxcluster = fs->fs_maxcluster;
+       newfs->fs_contigdirs = fs->fs_contigdirs;
        bcopy(newfs, fs, (u_int)fs->fs_sbsize);
        if (fs->fs_sbsize < SBSIZE)
                bp->b_flags |= B_INVAL;
        brelse(bp);
        mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
        ffs_oldfscompat(fs);
+       /* An old fsck may have zeroed these fields, so recheck them. */
+       if (fs->fs_avgfilesize <= 0)            /* XXX */
+               fs->fs_avgfilesize = AVFILESIZ; /* XXX */
+       if (fs->fs_avgfpdir <= 0)               /* XXX */
+               fs->fs_avgfpdir = AFPDIR;       /* XXX */
 
        /*
         * Step 3: re-read summary information from disk.
@@ -674,6 +680,7 @@
        blks = howmany(size, fs->fs_fsize);
        if (fs->fs_contigsumsize > 0)
                size += fs->fs_ncg * sizeof(int32_t);
+       size += fs->fs_ncg * sizeof(u_int8_t);
        space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
        fs->fs_csp = space;
        for (i = 0; i < blks; i += fs->fs_frag) {
@@ -694,7 +701,16 @@
                fs->fs_maxcluster = lp = space;
                for (i = 0; i < fs->fs_ncg; i++)
                        *lp++ = fs->fs_contigsumsize;
+               space = lp;
        }
+       size = fs->fs_ncg * sizeof(u_int8_t);
+       fs->fs_contigdirs = (u_int8_t *)space;
+       bzero(fs->fs_contigdirs, size);
+       /* Compatibility for old filesystems       XXX */
+       if (fs->fs_avgfilesize <= 0)            /* XXX */
+               fs->fs_avgfilesize = AVFILESIZ; /* XXX */
+       if (fs->fs_avgfpdir <= 0)               /* XXX */
+               fs->fs_avgfpdir = AFPDIR;       /* XXX */
        mp->mnt_data = (qaddr_t)ump;
        mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0];
        mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1];
Index: sys/ufs/ffs/fs.h
===================================================================
RCS file: /home/ncvs/src/sys/ufs/ffs/fs.h,v
retrieving revision 1.14.2.2
diff -u -r1.14.2.2 fs.h
--- sys/ufs/ffs/fs.h    2001/01/22 18:10:28     1.14.2.2
+++ sys/ufs/ffs/fs.h    2001/09/19 00:32:13
@@ -108,15 +108,17 @@
 /*
  * There is a 128-byte region in the superblock reserved for in-core
  * pointers to summary information. Originally this included an array
- * of pointers to blocks of struct csum; now there are just two
+ * of pointers to blocks of struct csum; now there are just three
  * pointers and the remaining space is padded with fs_ocsp[].
  *
  * NOCSPTRS determines the size of this padding. One pointer (fs_csp)
  * is taken away to point to a contiguous array of struct csum for
  * all cylinder groups; a second (fs_maxcluster) points to an array
- * of cluster sizes that is computed as cylinder groups are inspected.
+ * of cluster sizes that is computed as cylinder groups are inspected,
+ * and the third points to an array that tracks the creation of new
+ * directories.
  */
-#define        NOCSPTRS        ((128 / sizeof(void *)) - 2)
+#define        NOCSPTRS        ((128 / sizeof(void *)) - 3)
 
 /*
  * A summary of contiguous blocks of various sizes is maintained
@@ -142,6 +144,31 @@
 #define DEFAULTOPT     FS_OPTTIME
 
 /*
+ * Grigoriy Orlov <[EMAIL PROTECTED]> has done some extensive work to fine
+ * tune the layout preferences for directories within a filesystem.
+ * His algorithm can be tuned by adjusting the following parameters
+ * which tell the system the average file size and the average number
+ * of files per directory. These defaults are well selected for typical
+ * filesystems, but may need to be tuned for odd cases like filesystems
+ * being used for sqiud caches or news spools.
+ */
+#define AVFILESIZ      16384   /* expected average file size */
+#define AFPDIR         64      /* expected number of files per directory */
+
+/*
+ * The maximum number of snapshot nodes that can be associated
+ * with each filesystem. This limit affects only the number of
+ * snapshot files that can be recorded within the superblock so
+ * that they can be found when the filesystem is mounted. However,
+ * maintaining too many will slow the filesystem performance, so
+ * having this limit is a good idea.
+ *
+ * VALUE NOT IMPLEMENTED IN 4.x YET, RESERVED FROM -CURRENT SO SUPERBLOCKS
+ * REMAIN COMPATIBLE.
+ */
+#define FSMAXSNAP 20
+
+/*
  * Per cylinder group information; summarized in blocks allocated
  * from first cylinder group data blocks.  These blocks have to be
  * read in from fs_csaddr (size fs_cssize) in addition to the
@@ -227,11 +254,17 @@
 /* these fields retain the current block allocation info */
        int32_t  fs_cgrotor;            /* last cg searched */
        void    *fs_ocsp[NOCSPTRS];     /* padding; was list of fs_cs buffers */
+       u_int8_t *fs_contigdirs;        /* # of contiguously allocated dirs */
        struct csum *fs_csp;            /* cg summary info buffer for fs_cs */
        int32_t *fs_maxcluster;         /* max cluster in each cyl group */
        int32_t  fs_cpc;                /* cyl per cycle in postbl */
        int16_t  fs_opostbl[16][8];     /* old rotation block list head */
-       int32_t  fs_sparecon[50];       /* reserved for future constants */
+       int32_t  fs_snapinum[FSMAXSNAP];/* RESERVED FROM 5.x */
+       int32_t  fs_avgfilesize;        /* expected average file size */
+       int32_t  fs_avgfpdir;           /* expected # of files per directory */
+       int32_t  fs_sparecon[26];       /* reserved for future constants */
+       int32_t  fs_pendingblocks;      /* RESERVED FROM 5.x */
+       int32_t  fs_pendinginodes;      /* RESERVED FROM 5.x */
        int32_t  fs_contigsumsize;      /* size of cluster summary array */ 
        int32_t  fs_maxsymlinklen;      /* max length of an internal symlink */
        int32_t  fs_inodefmt;           /* format of on-disk inodes */

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-stable" in the body of the message

Reply via email to