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);