On Wed, Apr 16, 2014 at 06:37:08PM -0400, Brandon Mercer wrote:

> As I mentioned previously, this does more than just allow you to boot
> from TB disks. When I configure a 100GB disk in qemu-kvm it takes
> forever to format. On small flash installations, formatting is faster
> there as well. You don't need a 1TB disk to benefit from ffs2.

But bear in mind that ffs2 has more overhead in terms of metadata.
IMO, making it the default is not a good idea.

        -Otto

> 
> On Wed, Apr 16, 2014 at 3:57 PM, Brandon Mercer
> <yourcomputer...@gmail.com> wrote:
> > The other day I was doing an install in qemu-kvm and newfs was taking
> > forever, to the tune of hours. This is similar to formatting on arm
> > boards. In my quest to track down why, I discovered that ffs2 takes far
> > less time to format than ffs1 (about 30 seconds for the entire disk).
> >
> > I've put together a diff that updates the boot blocks on amd64 to be
> > able to boot ffs2. From there it's a one line change to make newfs
> > format ffs2 by default. Obviously this would need to happen for other
> > architectures as well and I'd be glad to tackle that if others see
> > this as worthwhile. Please let me know your thoughts.
> >
> > Brandon
> >
> >
> > Index: sbin/newfs/newfs.c
> > ===================================================================
> > RCS file: /cvs/src/sbin/newfs/newfs.c,v
> > retrieving revision 1.95
> > diff -u -p -u -r1.95 newfs.c
> > --- sbin/newfs/newfs.c  22 Nov 2013 04:12:48 -0000      1.95
> > +++ sbin/newfs/newfs.c  16 Apr 2014 17:47:02 -0000
> > @@ -112,7 +112,7 @@ u_short     dkcksum(struct disklabel *);
> >
> >  int    mfs;                    /* run as the memory based filesystem */
> >  int    Nflag;                  /* run without writing file system */
> > -int    Oflag = 1;              /* 0 = 4.3BSD ffs, 1 = 4.4BSD ffs, 2 = ffs2 
> > */
> > +int    Oflag = 2;              /* 0 = 4.3BSD ffs, 1 = 4.4BSD ffs, 2 = ffs2 
> > */
> >  daddr_t        fssize;                 /* file system size in 512-byte 
> > blocks */
> >  long long      sectorsize;             /* bytes/sector */
> >  int    fsize = 0;              /* fragment size */
> >
> > Index: arch/amd64/stand/biosboot/biosboot.S
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/amd64/stand/biosboot/biosboot.S,v
> > retrieving revision 1.7
> > diff -u -p -r1.7 biosboot.S
> > --- arch/amd64/stand/biosboot/biosboot.S        5 Jul 2011 17:38:54 -0000   
> >     1.7
> > +++ arch/amd64/stand/biosboot/biosboot.S        16 Apr 2014 17:22:25 -0000
> > @@ -108,6 +108,9 @@
> >   *                     While this can be calculated as
> >   *                     howmany(di_size, fs_bsize) it takes us too
> >   *                     many code bytes to do it.
> > + * blkskew     uint8t  the skew used to parse di_db[]. this is set to four 
> > by
> > + *                     installboot for ffs2 (due to 64-bit blocks) and 
> > should
> > + *                     be zero for ffs1.
> >   *
> >   * All of these are patched directly into the code where they are used
> >   * (once only, each), to save space.
> > @@ -121,7 +124,7 @@
> >   */
> >
> >         .globl  inodeblk, inodedbl, fs_bsize_p, fsbtodb, p_offset, nblocks
> > -       .globl  fs_bsize_s, force_chs
> > +       .globl  fs_bsize_s, force_chs, blkskew
> >         .type   inodeblk, @function
> >         .type   inodedbl, @function
> >         .type   fs_bsize_p, @function
> > @@ -130,6 +133,7 @@
> >         .type   p_offset, @function
> >         .type   nblocks, @function
> >         .type   force_chs, @function
> > +       .type   blkskew, @function
> >
> >
> >  /* Clobbers %ax, maybe more */
> > @@ -460,7 +464,8 @@ load_blocks:
> >
> >         /* Get the next filesystem block number into %eax */
> >         lodsl                   /* %eax = *(%si++), make sure 0x66 0xad */
> > -
> > +blkskew = .+2
> > +       addw    $0x90, %si      /* adjust %si if needed (for ffs2) */
> >         pushal                          /* Save all 32-bit registers */
> >
> >         /*
> > Index: arch/amd64/stand/boot/Makefile
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/amd64/stand/boot/Makefile,v
> > retrieving revision 1.26
> > diff -u -p -r1.26 Makefile
> > --- arch/amd64/stand/boot/Makefile      28 Dec 2013 15:16:28 -0000      1.26
> > +++ arch/amd64/stand/boot/Makefile      16 Apr 2014 17:22:51 -0000
> > @@ -38,7 +38,7 @@ SRCS+=        alloc.c ctime.c exit.c memcmp.c m
> >  SRCS+= close.c closeall.c cons.c cread.c dev.c disklabel.c dkcksum.c 
> > fstat.c \
> >         lseek.c open.c read.c readdir.c stat.c
> >  SRCS+= elf32.c elf64.c loadfile.c
> > -SRCS+= ufs.c
> > +SRCS+= ufs.c ufs2.c
> >  .if ${SOFTRAID:L} == "yes"
> >  SRCS+= aes_xts.c explicit_bzero.c hmac_sha1.c pbkdf2.c rijndael.c sha1.c
> >  .endif
> > Index: arch/amd64/stand/boot/conf.c
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/amd64/stand/boot/conf.c,v
> > retrieving revision 1.31
> > diff -u -p -r1.31 conf.c
> > --- arch/amd64/stand/boot/conf.c        18 Feb 2014 13:56:02 -0000      1.31
> > +++ arch/amd64/stand/boot/conf.c        16 Apr 2014 17:25:17 -0000
> > @@ -31,6 +31,7 @@
> >  #include <netinet/in.h>
> >  #include <libsa.h>
> >  #include <lib/libsa/ufs.h>
> > +#include <lib/libsa/ufs2.h>
> >  #ifdef notdef
> >  #include <lib/libsa/cd9660.h>
> >  #include <lib/libsa/fat.h>
> > @@ -66,6 +67,8 @@ int nibprobes = nitems(probe_list);
> >  struct fs_ops file_system[] = {
> >         { ufs_open,    ufs_close,    ufs_read,    ufs_write,    ufs_seek,
> >           ufs_stat,    ufs_readdir    },
> > +       { ufs2_open,    ufs2_close,    ufs2_read,    ufs2_write,    
> > ufs2_seek,
> > +         ufs2_stat,    ufs2_readdir    },
> >  #ifdef notdef
> >         { fat_open,    fat_close,    fat_read,    fat_write,    fat_seek,
> >           fat_stat,    fat_readdir    },
> > Index: arch/amd64/stand/installboot/installboot.c
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/amd64/stand/installboot/installboot.c,v
> > retrieving revision 1.27
> > diff -u -p -r1.27 installboot.c
> > --- arch/amd64/stand/installboot/installboot.c  13 Nov 2013 04:11:34 -0000  
> >     1.27
> > +++ arch/amd64/stand/installboot/installboot.c  16 Apr 2014 17:38:00 -0000
> > @@ -2,6 +2,7 @@
> >  /*     $NetBSD: installboot.c,v 1.5 1995/11/17 23:23:50 gwr Exp $ */
> >
> >  /*
> > + * Copyright (c) 2013 Pedro Martelletto
> >   * Copyright (c) 2011 Joel Sing <js...@openbsd.org>
> >   * Copyright (c) 2010 Otto Moerbeek <o...@openbsd.org>
> >   * Copyright (c) 2003 Tom Cosgrove <tom.cosgr...@arches-consulting.com>
> > @@ -91,6 +92,7 @@ struct sym_data pbr_symbols[] = {
> >         {"_inodeblk",   4},
> >         {"_inodedbl",   4},
> >         {"_nblocks",    2},
> > +       {"_blkskew",    1},
> >         {NULL}
> >  };
> >
> > @@ -104,6 +106,8 @@ struct sym_data pbr_symbols[] = {
> >  static char    *loadproto(char *, long *);
> >  static int     getbootparams(char *, int, struct disklabel *);
> >  static void    devread(int, void *, daddr_t, size_t, char *);
> > +static int     sbchk(struct fs *, daddr_t);
> > +static void    sbread(int, daddr_t, struct fs **);
> >  static void    sym_set_value(struct sym_data *, char *, u_int32_t);
> >  static void    pbr_set_symbols(char *, char *, struct sym_data *);
> >  static void    usage(void);
> > @@ -412,6 +416,76 @@ devread(int fd, void *buf, daddr_t blk,
> >  }
> >
> >  static char sblock[SBSIZE];
> > +static const daddr_t sbtry[] = SBLOCKSEARCH;
> > +
> > +static int
> > +sbchk(struct fs *fs, daddr_t sbloc)
> > +{
> > +       if (verbose)
> > +               warnx("looking for superblock at %lld", sbloc);
> > +
> > +       if (fs->fs_magic != FS_UFS2_MAGIC && fs->fs_magic != FS_UFS1_MAGIC) 
> > {
> > +               if (verbose)
> > +                       warnx("bad superblock magic 0x%x", fs->fs_magic);
> > +               return (0);
> > +       }
> > +
> > +       /*
> > +        * Looking for an FFS1 file system at SBLOCK_UFS2 will find the
> > +        * wrong superblock for file systems with 64k block size.
> > +        */
> > +       if (fs->fs_magic == FS_UFS1_MAGIC && sbloc == SBLOCK_UFS2) {
> > +               if (verbose)
> > +                       warnx("skipping ffs1 superblock at %lld", sbloc);
> > +               return (0);
> > +       }
> > +
> > +       if (fs->fs_bsize <= 0 ||
> > +           fs->fs_bsize < sizeof(struct fs) ||
> > +           fs->fs_bsize > MAXBSIZE) {
> > +               if (verbose)
> > +                       warnx("invalid superblock block size %d",
> > +                           fs->fs_bsize);
> > +               return (0);
> > +       }
> > +
> > +       if (fs->fs_sbsize <= 0 || fs->fs_sbsize > SBSIZE) {
> > +               if (verbose)
> > +                       warnx("invalid superblock size %d", fs->fs_sbsize);
> > +               return (0);
> > +       }
> > +
> > +       if (fs->fs_inopb <= 0) {
> > +               if (verbose)
> > +                       warnx("invalid superblock inodes/block %d",
> > +                           fs->fs_inopb);
> > +               return (0);
> > +       }
> > +
> > +       if (verbose)
> > +               warnx("found valid %s superblock",
> > +                   fs->fs_magic == FS_UFS2_MAGIC ? "ffs2" : "ffs1");
> > +
> > +       return (1);
> > +}
> > +
> > +static void
> > +sbread(int fd, daddr_t poffset, struct fs **fs)
> > +{
> > +       int i;
> > +       daddr_t sboff;
> > +
> > +       for (i = 0; sbtry[i] != -1; i++) {
> > +               sboff = sbtry[i] / DEV_BSIZE;
> > +               devread(fd, sblock, poffset + sboff, SBSIZE, "superblock");
> > +               *fs = (struct fs *)sblock;
> > +               if (sbchk(*fs, sbtry[i]))
> > +                       break;
> > +       }
> > +
> > +       if (sbtry[i] == -1)
> > +               errx(1, "couldn't find ffs superblock");
> > +}
> >
> >  /*
> >   * Read information about /boot's inode, then put this and filesystem
> > @@ -427,11 +501,13 @@ getbootparams(char *boot, int devfd, str
> >         struct fs       *fs;
> >         char            *buf;
> >         u_int           blk, *ap;
> > -       struct ufs1_dinode      *ip;
> > +       struct ufs1_dinode      *ip1;
> > +       struct ufs2_dinode      *ip2;
> >         int             ndb;
> >         int             mib[3];
> >         size_t          size;
> >         dev_t           dev;
> > +       int             skew;
> >
> >         /*
> >          * Open 2nd-level boot program and record enough details about
> > @@ -488,16 +564,7 @@ getbootparams(char *boot, int devfd, str
> >         pp = &dl->d_partitions[DISKPART(statbuf.st_dev)];
> >         close(fd);
> >
> > -       /* Read superblock. */
> > -       devread(devfd, sblock, DL_SECTOBLK(dl, DL_GETPOFFSET(pp)) + SBLOCK,
> > -           SBSIZE, "superblock");
> > -       fs = (struct fs *)sblock;
> > -
> > -       /* Sanity-check super-block. */
> > -       if (fs->fs_magic != FS_MAGIC)
> > -               errx(1, "Bad magic number in superblock");
> > -       if (fs->fs_inopb <= 0)
> > -               err(1, "Bad inopb=%d in superblock", fs->fs_inopb);
> > +       sbread(devfd, DL_SECTOBLK(dl, pp->p_offset), &fs);
> >
> >         /* Read inode. */
> >         if ((buf = malloc(fs->fs_bsize)) == NULL)
> > @@ -505,15 +572,25 @@ getbootparams(char *boot, int devfd, str
> >
> >         blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino));
> >
> > -       devread(devfd, buf, DL_SECTOBLK(dl, DL_GETPOFFSET(pp)) + blk,
> > -           fs->fs_bsize, "inode");
> > -       ip = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino);
> > -
> >         /*
> >          * Have the inode.  Figure out how many filesystem blocks (not disk
> >          * sectors) there are for biosboot to load.
> >          */
> > -       ndb = howmany(ip->di_size, fs->fs_bsize);
> > +       devread(devfd, buf, DL_SECTOBLK(dl, pp->p_offset) + blk,
> > +           fs->fs_bsize, "inode");
> > +       if (fs->fs_magic == FS_UFS2_MAGIC) {
> > +               ip2 = (struct ufs2_dinode *)(buf) +
> > +                   ino_to_fsbo(fs, statbuf.st_ino);
> > +               ndb = howmany(ip2->di_size, fs->fs_bsize);
> > +               ap = (u_int *)ip2->di_db;
> > +               skew = sizeof(u_int32_t);
> > +       } else {
> > +               ip1 = (struct ufs1_dinode *)(buf) +
> > +                   ino_to_fsbo(fs, statbuf.st_ino);
> > +               ndb = howmany(ip1->di_size, fs->fs_bsize);
> > +               ap = (u_int *)ip1->di_db;
> > +               skew = 0;
> > +       }
> >         if (ndb <= 0)
> >                 errx(1, "No blocks to load");
> >
> > @@ -542,10 +619,10 @@ getbootparams(char *boot, int devfd, str
> >         sym_set_value(pbr_symbols, "_p_offset", pp->p_offset);
> >         sym_set_value(pbr_symbols, "_inodeblk",
> >             ino_to_fsba(fs, statbuf.st_ino));
> > -       ap = ip->di_db;
> >         sym_set_value(pbr_symbols, "_inodedbl",
> >             ((((char *)ap) - buf) + INODEOFF));
> >         sym_set_value(pbr_symbols, "_nblocks", ndb);
> > +       sym_set_value(pbr_symbols, "_blkskew", skew);
> >
> >         if (verbose) {
> >                 fprintf(stderr, "%s is %d blocks x %d bytes\n",
> > @@ -555,6 +632,8 @@ getbootparams(char *boot, int devfd, str
> >                     ffs(fs->fs_fsize / dl->d_secsize) - 1,
> >                     DL_GETPOFFSET(pp), ino_to_fsba(fs, statbuf.st_ino),
> >                     (unsigned int)((((char *)ap) - buf) + INODEOFF));
> > +               fprintf(stderr, "expecting %d-bit fs blocks (skew %d)\n",
> > +                   skew ? 64 : 32, skew);
> >         }
> >
> >         return 0;
> > @@ -762,6 +841,7 @@ sr_installboot(int devfd)
> >         sym_set_value(pbr_symbols, "_inodeblk", inodeblk);
> >         sym_set_value(pbr_symbols, "_inodedbl", inodedbl);
> >         sym_set_value(pbr_symbols, "_nblocks", nblocks);
> > +       sym_set_value(pbr_symbols, "_blkskew", 0);
> >
> >         if (verbose)
> >                 fprintf(stderr, "%s is %d blocks x %d bytes\n",
> > Index: lib/libsa/ufs2.c
> > ===================================================================
> > RCS file: lib/libsa/ufs2.c
> > diff -N lib/libsa/ufs2.c
> > --- /dev/null   1 Jan 1970 00:00:00 -0000
> > +++ lib/libsa/ufs2.c    16 Apr 2014 19:21:00 -0000
> > @@ -0,0 +1,713 @@
> > +/*-
> > + * Copyright (c) 1993
> > + *     The Regents of the University of California.  All rights reserved.
> > + *
> > + * This code is derived from software contributed to Berkeley by
> > + * The Mach Operating System project at Carnegie-Mellon University.
> > + *
> > + * Redistribution and use in source and binary forms, with or without
> > + * modification, are permitted provided that the following conditions
> > + * are met:
> > + * 1. Redistributions of source code must retain the above copyright
> > + *    notice, this list of conditions and the following disclaimer.
> > + * 2. Redistributions in binary form must reproduce the above copyright
> > + *    notice, this list of conditions and the following disclaimer in the
> > + *    documentation and/or other materials provided with the distribution.
> > + * 3. Neither the name of the University nor the names of its contributors
> > + *    may be used to endorse or promote products derived from this software
> > + *    without specific prior written permission.
> > + *
> > + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
> > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
> > PURPOSE
> > + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
> > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
> > CONSEQUENTIAL
> > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
> > STRICT
> > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 
> > WAY
> > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> > + * SUCH DAMAGE.
> > + *
> > + *
> > + * Copyright (c) 1990, 1991 Carnegie Mellon University
> > + * All Rights Reserved.
> > + *
> > + * Author: David Golub
> > + *
> > + * Permission to use, copy, modify and distribute this software and its
> > + * documentation is hereby granted, provided that both the copyright
> > + * notice and this permission notice appear in all copies of the
> > + * software, derivative works or modified versions, and any portions
> > + * thereof, and that both notices appear in supporting documentation.
> > + *
> > + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
> > + * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
> > + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
> > + *
> > + * Carnegie Mellon requests users of this software to return to
> > + *
> > + *  Software Distribution Coordinator  or  software.distribut...@cs.cmu.edu
> > + *  School of Computer Science
> > + *  Carnegie Mellon University
> > + *  Pittsburgh PA 15213-3890
> > + *
> > + * any improvements or extensions that they make and grant Carnegie the
> > + * rights to redistribute these changes.
> > + */
> > +
> > +/*
> > + *     Stand-alone file reading package.
> > + */
> > +
> > +#include <sys/param.h>
> > +#include <sys/time.h>
> > +#include <sys/stat.h>
> > +#include <ufs/ffs/fs.h>
> > +#include <ufs/ufs/dinode.h>
> > +#include <ufs/ufs/dir.h>
> > +#include <lib/libkern/libkern.h>
> > +
> > +#include "stand.h"
> > +#include "ufs2.h"
> > +
> > +/*
> > + * In-core open file.
> > + */
> > +struct file {
> > +       off_t           f_seekp;        /* seek pointer */
> > +       struct fs       *f_fs;          /* pointer to super-block */
> > +       struct ufs2_dinode      f_di;           /* copy of on-disk inode */
> > +       int             f_nindir[NIADDR];
> > +                                       /* number of blocks mapped by
> > +                                          indirect block at level i */
> > +       char            *f_blk[NIADDR]; /* buffer for indirect block at
> > +                                          level i */
> > +       size_t          f_blksize[NIADDR];
> > +                                       /* size of buffer */
> > +       daddr_t         f_blkno[NIADDR];/* disk address of block in buffer 
> > */
> > +       char            *f_buf;         /* buffer for data block */
> > +       size_t          f_buf_size;     /* size of data block */
> > +       daddr_t         f_buf_blkno;    /* block number of data block */
> > +};
> > +
> > +static int     read_inode(ufsino_t, struct open_file *);
> > +static int     block_map(struct open_file *, daddr_t, daddr_t *);
> > +static int     buf_read_file(struct open_file *, char **, size_t *);
> > +static int     search_directory(char *, struct open_file *, ufsino_t *);
> > +static int     ufs2_close_internal(struct file *);
> > +#ifdef COMPAT_UFS
> > +static void    ffs_oldfscompat(struct fs *);
> > +#endif
> > +
> > +/*
> > + * Read a new inode into a file structure.
> > + */
> > +static int
> > +read_inode(ufsino_t inumber, struct open_file *f)
> > +{
> > +       struct file *fp = (struct file *)f->f_fsdata;
> > +       struct fs *fs = fp->f_fs;
> > +       char *buf;
> > +       size_t rsize;
> > +       int rc;
> > +
> > +       /*
> > +        * Read inode and save it.
> > +        */
> > +       buf = alloc(fs->fs_bsize);
> > +       twiddle();
> > +       rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
> > +           fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, buf, 
> > &rsize);
> > +       if (rc)
> > +               goto out;
> > +       if (rsize != (size_t)fs->fs_bsize) {
> > +               rc = EIO;
> > +               goto out;
> > +       }
> > +
> > +       {
> > +               struct ufs2_dinode *dp;
> > +
> > +               dp = (struct ufs2_dinode *)buf;
> > +               fp->f_di = dp[ino_to_fsbo(fs, inumber)];
> > +       }
> > +
> > +       /*
> > +        * Clear out the old buffers
> > +        */
> > +       {
> > +               int level;
> > +
> > +               for (level = 0; level < NIADDR; level++)
> > +                       fp->f_blkno[level] = -1;
> > +               fp->f_buf_blkno = -1;
> > +               fp->f_seekp = 0;
> > +       }
> > +out:
> > +       free(buf, fs->fs_bsize);
> > +       return (rc);
> > +}
> > +
> > +/*
> > + * Given an offset in a file, find the disk block number that
> > + * contains that block.
> > + */
> > +static int
> > +block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p)
> > +{
> > +       struct file *fp = (struct file *)f->f_fsdata;
> > +       daddr_t ind_block_num;
> > +       char *ind_p;
> > +       struct fs *fs = fp->f_fs;
> > +       int level, idx, rc;
> > +
> > +       /*
> > +        * Index structure of an inode:
> > +        *
> > +        * di_db[0..NDADDR-1]   hold block numbers for blocks
> > +        *                      0..NDADDR-1
> > +        *
> > +        * di_ib[0]             index block 0 is the single indirect block
> > +        *                      holds block numbers for blocks
> > +        *                      NDADDR .. NDADDR + NINDIR(fs)-1
> > +        *
> > +        * di_ib[1]             index block 1 is the double indirect block
> > +        *                      holds block numbers for INDEX blocks for 
> > blocks
> > +        *                      NDADDR + NINDIR(fs) ..
> > +        *                      NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
> > +        *
> > +        * di_ib[2]             index block 2 is the triple indirect block
> > +        *                      holds block numbers for double-indirect
> > +        *                      blocks for blocks
> > +        *                      NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
> > +        *                      NDADDR + NINDIR(fs) + NINDIR(fs)**2
> > +        *                              + NINDIR(fs)**3 - 1
> > +        */
> > +
> > +       if (file_block < NDADDR) {
> > +               /* Direct block. */
> > +               *disk_block_p = fp->f_di.di_db[file_block];
> > +               return (0);
> > +       }
> > +
> > +       file_block -= NDADDR;
> > +
> > +       /*
> > +        * nindir[0] = NINDIR
> > +        * nindir[1] = NINDIR**2
> > +        * nindir[2] = NINDIR**3
> > +        *      etc
> > +        */
> > +       for (level = 0; level < NIADDR; level++) {
> > +               if (file_block < fp->f_nindir[level])
> > +                       break;
> > +               file_block -= fp->f_nindir[level];
> > +       }
> > +       if (level == NIADDR) {
> > +               /* Block number too high */
> > +               return (EFBIG);
> > +       }
> > +
> > +       ind_block_num = fp->f_di.di_ib[level];
> > +
> > +       for (; level >= 0; level--) {
> > +               if (ind_block_num == 0) {
> > +                       *disk_block_p = 0;      /* missing */
> > +                       return (0);
> > +               }
> > +
> > +               if (fp->f_blkno[level] != ind_block_num) {
> > +                       if (fp->f_blk[level] == (char *)0)
> > +                               fp->f_blk[level] =
> > +                                   alloc(fs->fs_bsize);
> > +                       twiddle();
> > +                       rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
> > +                           fsbtodb(fp->f_fs, ind_block_num), fs->fs_bsize,
> > +                           fp->f_blk[level], &fp->f_blksize[level]);
> > +                       if (rc)
> > +                               return (rc);
> > +                       if (fp->f_blksize[level] != (size_t)fs->fs_bsize)
> > +                               return (EIO);
> > +                       fp->f_blkno[level] = ind_block_num;
> > +               }
> > +
> > +               ind_p = fp->f_blk[level];
> > +
> > +               if (level > 0) {
> > +                       idx = file_block / fp->f_nindir[level - 1];
> > +                       file_block %= fp->f_nindir[level - 1];
> > +               } else
> > +                       idx = file_block;
> > +
> > +               ind_block_num = ind_p[idx];
> > +       }
> > +
> > +       *disk_block_p = ind_block_num;
> > +       return (0);
> > +}
> > +
> > +/*
> > + * Read a portion of a file into an internal buffer.  Return
> > + * the location in the buffer and the amount in the buffer.
> > + */
> > +static int
> > +buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
> > +{
> > +       struct file *fp = (struct file *)f->f_fsdata;
> > +       struct fs *fs = fp->f_fs;
> > +       daddr_t file_block, disk_block;
> > +       size_t block_size;
> > +       long off;
> > +       int rc;
> > +
> > +       off = blkoff(fs, fp->f_seekp);
> > +       file_block = lblkno(fs, fp->f_seekp);
> > +       block_size = dblksize(fs, &fp->f_di, file_block);
> > +
> > +       if (file_block != fp->f_buf_blkno) {
> > +               rc = block_map(f, file_block, &disk_block);
> > +               if (rc)
> > +                       return (rc);
> > +
> > +               if (fp->f_buf == (char *)0)
> > +                       fp->f_buf = alloc(fs->fs_bsize);
> > +
> > +               if (disk_block == 0) {
> > +                       bzero(fp->f_buf, block_size);
> > +                       fp->f_buf_size = block_size;
> > +               } else {
> > +                       twiddle();
> > +                       rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
> > +                           fsbtodb(fs, disk_block),
> > +                           block_size, fp->f_buf, &fp->f_buf_size);
> > +                       if (rc)
> > +                               return (rc);
> > +               }
> > +
> > +               fp->f_buf_blkno = file_block;
> > +       }
> > +
> > +       /*
> > +        * Return address of byte in buffer corresponding to
> > +        * offset, and size of remainder of buffer after that
> > +        * byte.
> > +        */
> > +       *buf_p = fp->f_buf + off;
> > +       *size_p = block_size - off;
> > +
> > +       /*
> > +        * But truncate buffer at end of file.
> > +        */
> > +       if (*size_p > fp->f_di.di_size - fp->f_seekp)
> > +               *size_p = fp->f_di.di_size - fp->f_seekp;
> > +
> > +       return (0);
> > +}
> > +
> > +/*
> > + * Search a directory for a name and return its
> > + * i_number.
> > + */
> > +static int
> > +search_directory(char *name, struct open_file *f, ufsino_t *inumber_p)
> > +{
> > +       struct file *fp = (struct file *)f->f_fsdata;
> > +       int namlen, length, rc;
> > +       struct direct *dp, *edp;
> > +       size_t buf_size;
> > +       char *buf;
> > +
> > +       length = strlen(name);
> > +
> > +       fp->f_seekp = 0;
> > +       while (fp->f_seekp < fp->f_di.di_size) {
> > +               rc = buf_read_file(f, &buf, &buf_size);
> > +               if (rc)
> > +                       return (rc);
> > +
> > +               dp = (struct direct *)buf;
> > +               edp = (struct direct *)(buf + buf_size);
> > +               while (dp < edp) {
> > +                       if (dp->d_ino == 0)
> > +                               goto next;
> > +#if BYTE_ORDER == LITTLE_ENDIAN
> > +                       if (fp->f_fs->fs_maxsymlinklen <= 0)
> > +                               namlen = dp->d_type;
> > +                       else
> > +#endif
> > +                               namlen = dp->d_namlen;
> > +                       if (namlen == length &&
> > +                           !strcmp(name, dp->d_name)) {
> > +                               /* found entry */
> > +                               *inumber_p = dp->d_ino;
> > +                               return (0);
> > +                       }
> > +               next:
> > +                       dp = (struct direct *)((char *)dp + dp->d_reclen);
> > +               }
> > +               fp->f_seekp += buf_size;
> > +       }
> > +       return (ENOENT);
> > +}
> > +
> > +/*
> > + * Open a file.
> > + */
> > +int
> > +ufs2_open(char *path, struct open_file *f)
> > +{
> > +       char namebuf[MAXPATHLEN+1], *cp, *ncp, *buf = NULL;
> > +       ufsino_t inumber, parent_inumber;
> > +       int rc, c, nlinks = 0;
> > +       struct file *fp;
> > +       size_t buf_size;
> > +       struct fs *fs;
> > +
> > +       /* allocate file system specific data structure */
> > +       fp = alloc(sizeof(struct file));
> > +       bzero(fp, sizeof(struct file));
> > +       f->f_fsdata = (void *)fp;
> > +
> > +       /* allocate space and read super block */
> > +       fs = alloc(SBSIZE);
> > +       fp->f_fs = fs;
> > +       twiddle();
> > +       rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
> > +           SBLOCK_UFS2 / DEV_BSIZE, SBSIZE, (char *)fs, &buf_size);
> > +       if (rc)
> > +               goto out;
> > +
> > +       if (buf_size != SBSIZE || fs->fs_magic != FS_UFS2_MAGIC ||
> > +           fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
> > +               rc = EINVAL;
> > +               goto out;
> > +       }
> > +#ifdef COMPAT_UFS
> > +       ffs_oldfscompat(fs);
> > +#endif
> > +
> > +       /*
> > +        * Calculate indirect block levels.
> > +        */
> > +       {
> > +               int mult;
> > +               int level;
> > +
> > +               mult = 1;
> > +               for (level = 0; level < NIADDR; level++) {
> > +                       mult *= NINDIR(fs);
> > +                       fp->f_nindir[level] = mult;
> > +               }
> > +       }
> > +
> > +       inumber = ROOTINO;
> > +       if ((rc = read_inode(inumber, f)) != 0)
> > +               goto out;
> > +
> > +       cp = path;
> > +       while (*cp) {
> > +
> > +               /*
> > +                * Remove extra separators
> > +                */
> > +               while (*cp == '/')
> > +                       cp++;
> > +               if (*cp == '\0')
> > +                       break;
> > +
> > +               /*
> > +                * Check that current node is a directory.
> > +                */
> > +               if ((fp->f_di.di_mode & IFMT) != IFDIR) {
> > +                       rc = ENOTDIR;
> > +                       goto out;
> > +               }
> > +
> > +               /*
> > +                * Get next component of path name.
> > +                */
> > +               {
> > +                       int len = 0;
> > +
> > +                       ncp = cp;
> > +                       while ((c = *cp) != '\0' && c != '/') {
> > +                               if (++len > MAXNAMLEN) {
> > +                                       rc = ENOENT;
> > +                                       goto out;
> > +                               }
> > +                               cp++;
> > +                       }
> > +                       *cp = '\0';
> > +               }
> > +
> > +               /*
> > +                * Look up component in current directory.
> > +                * Save directory inumber in case we find a
> > +                * symbolic link.
> > +                */
> > +               parent_inumber = inumber;
> > +               rc = search_directory(ncp, f, &inumber);
> > +               *cp = c;
> > +               if (rc)
> > +                       goto out;
> > +
> > +               /*
> > +                * Open next component.
> > +                */
> > +               if ((rc = read_inode(inumber, f)) != 0)
> > +                       goto out;
> > +
> > +               /*
> > +                * Check for symbolic link.
> > +                */
> > +               if ((fp->f_di.di_mode & IFMT) == IFLNK) {
> > +                       int link_len = fp->f_di.di_size;
> > +                       int len;
> > +
> > +                       len = strlen(cp);
> > +
> > +                       if (link_len + len > MAXPATHLEN ||
> > +                           ++nlinks > MAXSYMLINKS) {
> > +                               rc = ENOENT;
> > +                               goto out;
> > +                       }
> > +
> > +                       bcopy(cp, &namebuf[link_len], len + 1);
> > +
> > +                       if (link_len < fs->fs_maxsymlinklen) {
> > +                               bcopy(fp->f_di.di_shortlink, namebuf,
> > +                                   (unsigned) link_len);
> > +                       } else {
> > +                               /*
> > +                                * Read file for symbolic link
> > +                                */
> > +                               size_t buf_size;
> > +                               daddr_t disk_block;
> > +                               struct fs *fs = fp->f_fs;
> > +
> > +                               if (!buf)
> > +                                       buf = alloc(fs->fs_bsize);
> > +                               rc = block_map(f, 0, &disk_block);
> > +                               if (rc)
> > +                                       goto out;
> > +
> > +                               twiddle();
> > +                               rc = (f->f_dev->dv_strategy)(f->f_devdata,
> > +                                   F_READ, fsbtodb(fs, disk_block),
> > +                                   fs->fs_bsize, buf, &buf_size);
> > +                               if (rc)
> > +                                       goto out;
> > +
> > +                               bcopy((char *)buf, namebuf, 
> > (unsigned)link_len);
> > +                       }
> > +
> > +                       /*
> > +                        * If relative pathname, restart at parent 
> > directory.
> > +                        * If absolute pathname, restart at root.
> > +                        */
> > +                       cp = namebuf;
> > +                       if (*cp != '/')
> > +                               inumber = parent_inumber;
> > +                       else
> > +                               inumber = ROOTINO;
> > +
> > +                       if ((rc = read_inode(inumber, f)) != 0)
> > +                               goto out;
> > +               }
> > +       }
> > +
> > +       /*
> > +        * Found terminal component.
> > +        */
> > +       rc = 0;
> > +out:
> > +       if (buf)
> > +               free(buf, fs->fs_bsize);
> > +       if (rc)
> > +               (void)ufs2_close_internal(fp);
> > +
> > +       return (rc);
> > +}
> > +
> > +int
> > +ufs2_close(struct open_file *f)
> > +{
> > +       struct file *fp = (struct file *)f->f_fsdata;
> > +
> > +       f->f_fsdata = (void *)0;
> > +       if (fp == (struct file *)0)
> > +               return (0);
> > +
> > +       return (ufs2_close_internal(fp));
> > +}
> > +
> > +static int
> > +ufs2_close_internal(struct file *fp)
> > +{
> > +       int level;
> > +
> > +       for (level = 0; level < NIADDR; level++) {
> > +               if (fp->f_blk[level])
> > +                       free(fp->f_blk[level], fp->f_fs->fs_bsize);
> > +       }
> > +       if (fp->f_buf)
> > +               free(fp->f_buf, fp->f_fs->fs_bsize);
> > +       free(fp->f_fs, SBSIZE);
> > +       free(fp, sizeof(struct file));
> > +       return (0);
> > +}
> > +
> > +/*
> > + * Copy a portion of a file into kernel memory.
> > + * Cross block boundaries when necessary.
> > + */
> > +int
> > +ufs2_read(struct open_file *f, void *start, size_t size, size_t *resid)
> > +{
> > +       struct file *fp = (struct file *)f->f_fsdata;
> > +       char *buf, *addr = start;
> > +       size_t csize, buf_size;
> > +       int rc = 0;
> > +
> > +       while (size != 0) {
> > +               if (fp->f_seekp >= fp->f_di.di_size)
> > +                       break;
> > +
> > +               rc = buf_read_file(f, &buf, &buf_size);
> > +               if (rc)
> > +                       break;
> > +
> > +               csize = size;
> > +               if (csize > buf_size)
> > +                       csize = buf_size;
> > +
> > +               bcopy(buf, addr, csize);
> > +
> > +               fp->f_seekp += csize;
> > +               addr += csize;
> > +               size -= csize;
> > +       }
> > +       if (resid)
> > +               *resid = size;
> > +       return (rc);
> > +}
> > +
> > +/*
> > + * Not implemented.
> > + */
> > +int
> > +ufs2_write(struct open_file *f, void *start, size_t size, size_t *resid)
> > +{
> > +
> > +       return (EROFS);
> > +}
> > +
> > +off_t
> > +ufs2_seek(struct open_file *f, off_t offset, int where)
> > +{
> > +       struct file *fp = (struct file *)f->f_fsdata;
> > +
> > +       switch (where) {
> > +       case SEEK_SET:
> > +               fp->f_seekp = offset;
> > +               break;
> > +       case SEEK_CUR:
> > +               fp->f_seekp += offset;
> > +               break;
> > +       case SEEK_END:
> > +               fp->f_seekp = fp->f_di.di_size - offset;
> > +               break;
> > +       default:
> > +               return (-1);
> > +       }
> > +       return (fp->f_seekp);
> > +}
> > +
> > +int
> > +ufs2_stat(struct open_file *f, struct stat *sb)
> > +{
> > +       struct file *fp = (struct file *)f->f_fsdata;
> > +
> > +       /* only important stuff */
> > +       sb->st_mode = fp->f_di.di_mode;
> > +       sb->st_uid = fp->f_di.di_uid;
> > +       sb->st_gid = fp->f_di.di_gid;
> > +       sb->st_size = fp->f_di.di_size;
> > +       return (0);
> > +}
> > +
> > +#ifndef        NO_READDIR
> > +int
> > +ufs2_readdir(struct open_file *f, char *name)
> > +{
> > +       struct file *fp = (struct file *)f->f_fsdata;
> > +       struct direct *dp, *edp;
> > +       size_t buf_size;
> > +       int rc, namlen;
> > +       char *buf;
> > +
> > +       if (name == NULL)
> > +               fp->f_seekp = 0;
> > +       else {
> > +                       /* end of dir */
> > +               if (fp->f_seekp >= fp->f_di.di_size) {
> > +                       *name = '\0';
> > +                       return -1;
> > +               }
> > +
> > +               do {
> > +                       if ((rc = buf_read_file(f, &buf, &buf_size)) != 0)
> > +                               return rc;
> > +
> > +                       dp = (struct direct *)buf;
> > +                       edp = (struct direct *)(buf + buf_size);
> > +                       while (dp < edp && dp->d_ino == 0)
> > +                               dp = (struct direct *)((char *)dp + 
> > dp->d_reclen);
> > +                       fp->f_seekp += buf_size -
> > +                           ((u_int8_t *)edp - (u_int8_t *)dp);
> > +               } while (dp >= edp);
> > +
> > +#if BYTE_ORDER == LITTLE_ENDIAN
> > +               if (fp->f_fs->fs_maxsymlinklen <= 0)
> > +                       namlen = dp->d_type;
> > +               else
> > +#endif
> > +                       namlen = dp->d_namlen;
> > +               strncpy(name, dp->d_name, namlen + 1);
> > +
> > +               fp->f_seekp += dp->d_reclen;
> > +       }
> > +
> > +       return 0;
> > +}
> > +#endif
> > +
> > +#ifdef COMPAT_UFS
> > +/*
> > + * Sanity checks for old file systems.
> > + *
> > + * XXX - goes away some day.
> > + */
> > +static void
> > +ffs_oldfscompat(struct fs *fs)
> > +{
> > +       int i;
> > +
> > +       fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);       /* XXX */
> > +       fs->fs_interleave = max(fs->fs_interleave, 1);          /* XXX */
> > +       if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
> > +               fs->fs_nrpos = 8;                               /* XXX */
> > +       if (fs->fs_inodefmt < FS_44INODEFMT) {                  /* XXX */
> > +               quad_t sizepb = fs->fs_bsize;                   /* XXX */
> > +                                                               /* XXX */
> > +               fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
> > +               for (i = 0; i < NIADDR; i++) {                  /* XXX */
> > +                       sizepb *= NINDIR(fs);                   /* XXX */
> > +                       fs->fs_maxfilesize += sizepb;           /* XXX */
> > +               }                                               /* XXX */
> > +               fs->fs_qbmask = ~fs->fs_bmask;                  /* XXX */
> > +               fs->fs_qfmask = ~fs->fs_fmask;                  /* XXX */
> > +       }                                                       /* XXX */
> > +}
> > +#endif
> > Index: lib/libsa/ufs2.h
> > ===================================================================
> > RCS file: lib/libsa/ufs2.h
> > diff -N lib/libsa/ufs2.h
> > --- /dev/null   1 Jan 1970 00:00:00 -0000
> > +++ lib/libsa/ufs2.h    16 Apr 2014 17:39:44 -0000
> > @@ -0,0 +1,38 @@
> > +/*-
> > + * Copyright (c) 1993
> > + *     The Regents of the University of California.  All rights reserved.
> > + *
> > + * Redistribution and use in source and binary forms, with or without
> > + * modification, are permitted provided that the following conditions
> > + * are met:
> > + * 1. Redistributions of source code must retain the above copyright
> > + *    notice, this list of conditions and the following disclaimer.
> > + * 2. Redistributions in binary form must reproduce the above copyright
> > + *    notice, this list of conditions and the following disclaimer in the
> > + *    documentation and/or other materials provided with the distribution.
> > + * 3. Neither the name of the University nor the names of its contributors
> > + *    may be used to endorse or promote products derived from this software
> > + *    without specific prior written permission.
> > + *
> > + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
> > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
> > PURPOSE
> > + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
> > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
> > CONSEQUENTIAL
> > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
> > STRICT
> > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 
> > WAY
> > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> > + * SUCH DAMAGE.
> > + *
> > + *     @(#)ufs.h       8.1 (Berkeley) 6/11/93
> > + */
> > +
> > +int    ufs2_open(char *, struct open_file *);
> > +int    ufs2_close(struct open_file *);
> > +int    ufs2_read(struct open_file *, void *, size_t, size_t *);
> > +int    ufs2_write(struct open_file *, void *, size_t, size_t *);
> > +int    ufs2_stat(struct open_file *, struct stat *);
> > +int    ufs2_readdir(struct open_file *, char *);
> > +off_t  ufs2_seek(struct open_file *, off_t, int);

Reply via email to