> On Apr 16, 2014, at 17:03, Brandon Mercer <yourcomputer...@gmail.com> wrote: > > On Wed, Apr 16, 2014 at 08:05:57PM +0000, Miod Vallat 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. >> >> Awesome. You've just trimmed my todolist by a few lines (-: >> And you've done it so that you do not force UFS2 support on >> tight-space-challenged boot blocks on other arches. >> >> All you need now is to merge your installboot changes into the MI >> installboot, and we'll be able to add ffs2 support in the installer on a >> per-platform basis. >> >> However, it is way too early to make ffs2 the default for newfs. >> >> Please commit your libsa changes at the earliest opportunity. > > Slightly revised diff. In my haste to make the compiler happy I likely > broke things. This diff properly casts the pointer. This work was done > by Pedro Martelletto for bitrig. I'll commit the diff below per miod's > request. > > 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 21:43:19 -0000 > @@ -0,0 +1,712 @@ > +/*- > + * 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, *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)
== NULL? > + 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 = (d_addrt *)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) == NULL? > + 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) if ((rc = read_inode(inumber, f)))? > + 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) if ((rc = read_inode(inumber, f)))? > + 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); No need to cast buf, it was declared as char *. > + } > + > + /* > + * 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) if ((rc = read_inode(inumber, f)))? > + 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; NULL? > + if (fp == (struct file *)0) NULL? > + 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); > +} Extra blank line. > + > +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) if ((rc = buf_read_file(f, &buf, &buf_size)))? > + 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 21:41:42 -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); >