]> Zhao Yanbai Git Server - minix.git/commitdiff
import netbsd ext2fs fsck and newfs
authorBen Gras <ben@minix3.org>
Thu, 22 Dec 2011 16:54:36 +0000 (17:54 +0100)
committerBen Gras <ben@minix3.org>
Thu, 22 Dec 2011 22:07:23 +0000 (23:07 +0100)
61 files changed:
commands/setup/setup.sh
common/include/minix/partition.h
common/include/sys/disklabel.h
lib/nbsd_libc/uuid/uuid_create.c
nbsd_include/Makefile
nbsd_include/ufs/chfs/chfs.h [new file with mode: 0644]
nbsd_include/ufs/chfs/chfs_args.h [new file with mode: 0644]
nbsd_include/ufs/chfs/chfs_inode.h [new file with mode: 0644]
nbsd_include/ufs/chfs/chfs_pool.h [new file with mode: 0644]
nbsd_include/ufs/chfs/debug.h [new file with mode: 0644]
nbsd_include/ufs/chfs/ebh.h [new file with mode: 0644]
nbsd_include/ufs/chfs/ebh_media.h [new file with mode: 0644]
nbsd_include/ufs/chfs/ebh_misc.h [new file with mode: 0644]
nbsd_include/ufs/chfs/media.h [new file with mode: 0644]
nbsd_include/ufs/ext2fs/ext2fs.h [new file with mode: 0644]
nbsd_include/ufs/ext2fs/ext2fs_dinode.h [new file with mode: 0644]
nbsd_include/ufs/ext2fs/ext2fs_dir.h [new file with mode: 0644]
nbsd_include/ufs/ext2fs/ext2fs_extern.h [new file with mode: 0644]
nbsd_include/ufs/ffs/ffs_extern.h [new file with mode: 0644]
nbsd_include/ufs/ffs/fs.h [new file with mode: 0644]
nbsd_include/ufs/lfs/lfs.h [new file with mode: 0644]
nbsd_include/ufs/lfs/lfs_extern.h [new file with mode: 0644]
nbsd_include/ufs/mfs/mfs_extern.h [new file with mode: 0644]
nbsd_include/ufs/mfs/mfsnode.h [new file with mode: 0644]
nbsd_include/ufs/ufs/dinode.h [new file with mode: 0644]
nbsd_include/ufs/ufs/dir.h [new file with mode: 0644]
nbsd_include/ufs/ufs/dirhash.h [new file with mode: 0644]
nbsd_include/ufs/ufs/extattr.h [new file with mode: 0644]
nbsd_include/ufs/ufs/inode.h [new file with mode: 0644]
nbsd_include/ufs/ufs/quota.h [new file with mode: 0644]
nbsd_include/ufs/ufs/quota1.h [new file with mode: 0644]
nbsd_include/ufs/ufs/quota2.h [new file with mode: 0644]
nbsd_include/ufs/ufs/ufs_bswap.h [new file with mode: 0644]
nbsd_include/ufs/ufs/ufs_extern.h [new file with mode: 0644]
nbsd_include/ufs/ufs/ufs_quota.h [new file with mode: 0644]
nbsd_include/ufs/ufs/ufs_wapbl.h [new file with mode: 0644]
nbsd_include/ufs/ufs/ufsmount.h [new file with mode: 0644]
sbin/Makefile
sbin/fsck/fsck.c
sbin/fsck/partutil.c
sbin/fsck_ext2fs/Makefile [new file with mode: 0644]
sbin/fsck_ext2fs/dir.c [new file with mode: 0644]
sbin/fsck_ext2fs/ext2fs_bswap.c [new file with mode: 0644]
sbin/fsck_ext2fs/extern.h [new file with mode: 0644]
sbin/fsck_ext2fs/fsck.h [new file with mode: 0644]
sbin/fsck_ext2fs/fsck_ext2fs.8 [new file with mode: 0644]
sbin/fsck_ext2fs/inode.c [new file with mode: 0644]
sbin/fsck_ext2fs/main.c [new file with mode: 0644]
sbin/fsck_ext2fs/pass1.c [new file with mode: 0644]
sbin/fsck_ext2fs/pass1b.c [new file with mode: 0644]
sbin/fsck_ext2fs/pass2.c [new file with mode: 0644]
sbin/fsck_ext2fs/pass3.c [new file with mode: 0644]
sbin/fsck_ext2fs/pass4.c [new file with mode: 0644]
sbin/fsck_ext2fs/pass5.c [new file with mode: 0644]
sbin/fsck_ext2fs/setup.c [new file with mode: 0644]
sbin/fsck_ext2fs/utilities.c [new file with mode: 0644]
sbin/newfs_ext2fs/Makefile [new file with mode: 0644]
sbin/newfs_ext2fs/extern.h [new file with mode: 0644]
sbin/newfs_ext2fs/mke2fs.c [new file with mode: 0644]
sbin/newfs_ext2fs/newfs_ext2fs.8 [new file with mode: 0644]
sbin/newfs_ext2fs/newfs_ext2fs.c [new file with mode: 0644]

index 8b045d42323c39d407de948dd2c344e29a2f9997..311dbd3e7f02487eae07ceb2bcf9fcc3736a15da 100644 (file)
@@ -23,6 +23,10 @@ TOTALMB="`expr 3 + $USRKB / 1024 + $ROOTMB`"
 ROOTFILES="`cat /.rootfiles`"
 USRFILES="`cat /.usrfiles`"
 
+if [ -z "$FSTYPE" ]
+then   FSTYPE=mfs
+fi
+
 if [ "$TOTALMB" -lt 1 ]
 then    
        echo "Are you really running from CD?"
@@ -459,17 +463,17 @@ if [ "$nohome" = 0 ]
 then
        if [ ! "$auto" = r ]
        then    echo "Creating /dev/$home for /home .."
-               mkfs.mfs -B $blocksizebytes /dev/$home || exit
+               mkfs.$FSTYPE -B $blocksizebytes /dev/$home || exit
        fi
 else   echo "Skipping /home"
 fi
 
 echo "Creating /dev/$usr for /usr .."
-mkfs.mfs -B $blocksizebytes /dev/$usr || exit
+mkfs.$FSTYPE -B $blocksizebytes /dev/$usr || exit
 
 if [ "$nohome" = 0 ]
 then
-       fshome="/dev/$home      /home   mfs     rw      0       2"
+       fshome="/dev/$home      /home   $FSTYPE rw      0       2"
 else   fshome=""
 fi
 
@@ -504,7 +508,7 @@ ln -s /usr/log /mnt/var/log
 # CD remnants that aren't for the installed system
 rm /mnt/etc/issue /mnt/CD /mnt/.* 2>/dev/null
 echo >/mnt/etc/fstab "/dev/$root       /       mfs     rw      0       1
-/dev/$usr      /usr    mfs     rw      0       2
+/dev/$usr      /usr    $FSTYPE rw      0       2
 $fshome"
 
                                        # National keyboard map.
index 0cbd9930c852336c90a0c966d00d5525f2a8352d..07f64b4366dbb44925550ad787df3ae5bedf987e 100644 (file)
 #include <minix/types.h>
 #endif
 
+#include <minix/u64.h>
+
+int minix_sizeup(char *name, u64_t *bytes);
+
 struct partition {
   u64_t base;          /* byte offset to the partition start */
   u64_t size;          /* number of bytes in the partition */
index ff424ea6f536dc93ec98f81dc61c8d804ec6902c..5d2c0e70076c943ad40460f54da724db8a0da42b 100644 (file)
@@ -180,6 +180,7 @@ struct disklabel {
        uint16_t d_npartitions; /* number of partitions in following */
        uint32_t d_bbsize;              /* size of boot area at sn0, bytes */
        uint32_t d_sbsize;              /* max size of fs superblock, bytes */
+#ifndef __minix
        struct  partition {             /* the partition table */
                uint32_t p_size;        /* number of sectors in partition */
                uint32_t p_offset;      /* starting sector */
@@ -199,6 +200,7 @@ struct disklabel {
 #define        p_cpg   __partition_u1.cpg
 #define        p_sgs   __partition_u1.sgs
        } d_partitions[MAXPARTITIONS];  /* actually may be more */
+#endif
 };
 
 #if defined(__HAVE_OLD_DISKLABEL) && !HAVE_NBTOOL_CONFIG_H
index bb40f20d578595819e0c5bd0c0ff7c6e051c4326..da1fe28e13c89a6efdc936967fe850b908a096c4 100644 (file)
@@ -38,6 +38,31 @@ __RCSID("$NetBSD: uuid_create.c,v 1.1 2004/09/13 21:44:54 thorpej Exp $");
 
 #include <uuid.h>
 
+#ifdef __minix
+#include <paths.h>
+#include <fcntl.h>
+/* Fake a uuidgen() syscall */
+int uuidgen(struct uuid *store, int count)
+{
+       int rfd;
+
+       if((rfd = open(_PATH_RANDOM, O_RDONLY)) < 0) {
+               return -1;
+       }
+
+       while(count--) {
+               if(read(rfd, store++, sizeof(*store)) < sizeof(*store)) {
+                       close(rfd);
+                       return -1;
+               }
+       }
+
+       close(rfd);
+
+       return 0;
+}
+#endif
+
 /*
  * uuid_create() - create an UUID.
  * See also:
index f5e5e19bb87114450354771e061310070cbebe98..04309c7c0483d13256657270f70e0e7bc9c7f9c9 100644 (file)
@@ -24,6 +24,20 @@ INCS=        a.out.h aio.h ar.h assert.h atomic.h \
        strings.h stringlist.h struct.h sysexits.h tar.h time.h \
        ttyent.h tzfile.h ucontext.h ulimit.h unistd.h util.h utime.h utmp.h \
        utmpx.h uuid.h varargs.h vis.h wchar.h wctype.h wordexp.h
+
+INCS +=        ufs/chfs/chfs.h ufs/chfs/chfs_args.h ufs/chfs/chfs_inode.h \
+       ufs/chfs/chfs_pool.h ufs/chfs/debug.h ufs/chfs/ebh.h \
+       ufs/chfs/ebh_media.h ufs/chfs/ebh_misc.h ufs/chfs/media.h \
+       ufs/ext2fs/ext2fs.h ufs/ext2fs/ext2fs_dinode.h \
+       ufs/ext2fs/ext2fs_dir.h ufs/ext2fs/ext2fs_extern.h \
+       ufs/ffs/ffs_extern.h ufs/ffs/fs.h ufs/lfs/lfs.h \
+       ufs/lfs/lfs_extern.h ufs/mfs/mfs_extern.h ufs/mfs/mfsnode.h \
+       ufs/ufs/dinode.h ufs/ufs/dir.h ufs/ufs/dirhash.h \
+       ufs/ufs/extattr.h ufs/ufs/inode.h ufs/ufs/quota.h \
+       ufs/ufs/quota1.h ufs/ufs/quota2.h ufs/ufs/ufs_bswap.h \
+       ufs/ufs/ufs_extern.h ufs/ufs/ufs_quota.h ufs/ufs/ufs_wapbl.h \
+       ufs/ufs/ufsmount.h \
+
 .else
 INCS=  a.out.h aio.h ar.h assert.h atomic.h \
        bitstring.h bm.h cdbr.h cdbw.h complex.h cpio.h ctype.h \
diff --git a/nbsd_include/ufs/chfs/chfs.h b/nbsd_include/ufs/chfs/chfs.h
new file mode 100644 (file)
index 0000000..53fc3d6
--- /dev/null
@@ -0,0 +1,768 @@
+/*     $NetBSD: chfs.h,v 1.4 2011/11/28 12:50:07 ahoka Exp $   */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ *                   University of Szeged, Hungary
+ * Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu>
+ * Copyright (C) 2009 Zoltan Sogor <weth@inf.u-szeged.hu>
+ * Copyright (C) 2009 David Tengeri <dtengeri@inf.u-szeged.hu>
+ * Copyright (C) 2009 Tamas Toth <ttoth@inf.u-szeged.hu>
+ * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef __CHFS_H__
+#define __CHFS_H__
+
+#if 0
+#define DBG_MSG
+#define DBG_MSG_GC
+#endif
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/cdefs.h>
+#include <sys/stdint.h>
+#include <sys/types.h>
+#include <sys/tree.h>
+#include <sys/queue.h>
+#include <sys/kmem.h>
+#include <sys/endian.h>
+#include <sys/rwlock.h>
+#include <sys/condvar.h>
+#include <sys/mutex.h>
+#include <sys/kthread.h>
+#include <sys/rbtree.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/hash.h>
+#include <sys/module.h>
+#include <sys/dirent.h>
+
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/dir.h>
+
+/* XXX shouldnt be defined here, but needed by chfs_inode.h */
+TAILQ_HEAD(chfs_dirent_list, chfs_dirent);
+
+#include "chfs_pool.h"
+#include "ebh.h"
+#include "media.h"
+#include "chfs_inode.h"
+
+#ifndef MOUNT_CHFS
+#define MOUNT_CHFS "chfs"
+#endif
+
+#define CHFS_ROOTINO ROOTINO    /* ROOTINO == 2 */
+
+enum {
+       VNO_STATE_UNCHECKED,    /* CRC checks not yet done */
+       VNO_STATE_CHECKING,     /* CRC checks in progress */
+       VNO_STATE_PRESENT,      /* In core */
+       VNO_STATE_CHECKEDABSENT,/* Checked, cleared again */
+       VNO_STATE_GC,           /* GCing a 'pristine' node */
+       VNO_STATE_READING,      /* In read_inode() */
+       VNO_STATE_CLEARING      /* In clear_inode() */
+};
+
+#define VNODECACHE_SIZE 128
+
+#define MAX_READ_FREE(chmp) (((chmp)->chm_ebh)->eb_size / 8)
+/* an eraseblock will be clean if its dirty size is smaller than this */
+#define MAX_DIRTY_TO_CLEAN 255
+#define VERY_DIRTY(chmp, size) ((size) >= (((chmp)->chm_ebh)->eb_size / 2))
+
+#define CHFS_PAD(x) (((x)+3)&~3)
+
+enum {
+       CHFS_NODE_OK = 0,
+       CHFS_NODE_BADMAGIC,
+       CHFS_NODE_BADCRC,
+       CHFS_NODE_BADNAMECRC
+};
+
+enum {
+       CHFS_BLK_STATE_FREE = 100,
+       CHFS_BLK_STATE_CLEAN,
+       CHFS_BLK_STATE_PARTDIRTY,
+       CHFS_BLK_STATE_ALLDIRTY
+};
+
+extern struct pool chfs_inode_pool;
+extern const struct genfs_ops chfs_genfsops;
+
+/**
+ * struct chfs_node_ref - a reference to a node
+ * @lnr: logical identifier of the eraseblock where the node is
+ * @offset: offset int hte eraseblock where the node starts
+ * @next: used at data and dirent nodes, it points to the next data node which
+ *               belongs to the same vnode
+ */
+struct chfs_node_ref
+{
+       struct chfs_node_ref *nref_next;
+       uint32_t nref_lnr;
+       uint32_t nref_offset;
+};
+
+/* Constants  for allocating node refs */
+#define REFS_BLOCK_LEN (255/sizeof(struct chfs_node_ref))
+#define REF_EMPTY_NODE (UINT_MAX)
+#define REF_LINK_TO_NEXT (UINT_MAX - 1)
+
+enum {
+       CHFS_NORMAL_NODE_MASK,
+       CHFS_UNCHECKED_NODE_MASK,
+       CHFS_OBSOLETE_NODE_MASK,
+       CHFS_PRISTINE_NODE_MASK
+};
+
+#define CHFS_REF_FLAGS(ref)            ((ref)->nref_offset & 3)
+#define CHFS_REF_OBSOLETE(ref) (((ref)->nref_offset & 3) == CHFS_OBSOLETE_NODE_MASK)
+#define CHFS_MARK_REF_NORMAL(ref)                                            \
+       do {                                                                  \
+               (ref)->nref_offset = CHFS_GET_OFS((ref)->nref_offset) | CHFS_NORMAL_NODE_MASK; \
+       } while(0)
+
+#define CHFS_GET_OFS(ofs) (ofs & ~ 3)
+
+static inline struct chfs_node_ref *
+node_next(struct chfs_node_ref *nref)
+{
+       //dbg("node next: %u : %u\n", nref->nref_lnr, nref->nref_offset);
+       nref++;
+       //dbg("nref++: %u : %u\n", nref->nref_lnr, nref->nref_offset);
+
+       if (nref->nref_lnr == REF_LINK_TO_NEXT) {
+               //dbg("link to next\n");
+               nref = nref->nref_next;
+               if (!nref)
+                       return nref;
+       }
+
+       if (nref->nref_lnr == REF_EMPTY_NODE) {
+               //dbg("empty\n");
+               return NULL;
+       }
+
+       return nref;
+}
+
+/**
+ * struct chfs_dirent - full representation of a directory entry
+ */
+struct chfs_dirent
+{
+       struct chfs_node_ref *nref;
+//     struct chfs_dirent *next;
+       TAILQ_ENTRY(chfs_dirent) fds;
+       uint64_t version;
+       ino_t vno;
+       uint32_t nhash;
+       enum vtype type;
+       uint8_t  nsize;
+       uint8_t  name[0];
+
+       /* used by chfs_alloc_dirent and free counterpart */
+//     size_t alloc_size;
+};
+
+struct chfs_tmp_dnode {
+       struct chfs_full_dnode *node;
+       uint64_t version;
+       uint32_t data_crc;
+       //uint32_t partial_crc;
+       //uint16_t csize;
+       uint16_t overlapped;
+       struct chfs_tmp_dnode *next;
+};
+
+struct chfs_tmp_dnode_info {
+       struct rb_node rb_node;
+       struct chfs_tmp_dnode *tmpnode;
+};
+
+struct chfs_readinode_info {
+       struct rb_tree tdi_root;
+       struct chfs_tmp_dnode_info *mdata_tn;
+       uint64_t highest_version;
+       struct chfs_node_ref *latest_ref;
+};
+
+struct chfs_full_dnode {
+       struct chfs_node_ref *nref;
+       uint64_t ofs;
+       uint32_t size;
+       uint32_t frags;
+};
+
+struct chfs_node_frag {
+       struct rb_node rb_node;
+       struct chfs_full_dnode *node;
+       uint32_t size;
+       uint64_t ofs;
+};
+
+static inline struct chfs_node_frag *
+frag_first(struct rb_tree *tree)
+{
+       struct chfs_node_frag *frag;
+
+       frag = (struct chfs_node_frag *)RB_TREE_MIN(tree);
+
+       return frag;
+}
+
+static inline struct chfs_node_frag *
+frag_last(struct rb_tree *tree)
+{
+       struct chfs_node_frag *frag;
+
+       frag = (struct chfs_node_frag *)RB_TREE_MAX(tree);
+
+       return frag;
+}
+
+#define frag_next(tree, frag) (struct chfs_node_frag *)rb_tree_iterate(tree, frag, RB_DIR_RIGHT)
+#define frag_prev(tree, frag) (struct chfs_node_frag *)rb_tree_iterate(tree, frag, RB_DIR_LEFT)
+
+
+/* XXX hack
+   #ifndef CHFS_FRAG_TREE
+   #define CHFS_FRAG_TREE
+   RB_HEAD(chfs_frag_tree, chfs_node_frag);
+   #endif
+*/
+
+/* for prototypes, properly defined in chfs_inode.h */
+//struct chfs_inode_ext;
+
+/**
+ * struct chfs_vnode_cache - in memory representation of a vnode
+ * @v: pointer to the vnode info node
+ * @dnode: pointer to the list of data nodes
+ * @dirents: pointer to the list of directory entries
+ * @vno_version: used only during scan, holds the current version number of
+ *                              chfs_flash_vnode
+ * @scan_dirents: used only during scan, holds the full representation of
+ *                               directory entries of this vnode
+ * @pvno: parent vnode number
+ * @nlink: number of links to this vnode
+ */
+struct chfs_vnode_cache {
+//     struct chfs_dirent *scan_dirents;
+       void *p;
+       struct chfs_dirent_list scan_dirents;
+
+       struct chfs_node_ref *v;
+       struct chfs_node_ref *dnode;
+       struct chfs_node_ref *dirents;
+
+       uint64_t *vno_version;
+       uint64_t highest_version;
+
+       uint8_t flags;
+       uint16_t state;
+       ino_t vno;
+       ino_t pvno;
+       struct chfs_vnode_cache* next;
+       uint32_t nlink;
+};
+
+struct chfs_eraseblock
+{
+       uint32_t lnr;
+
+       TAILQ_ENTRY(chfs_eraseblock) queue;
+       //uint32_t bad_count;
+       uint32_t unchecked_size;
+       uint32_t used_size;
+       uint32_t dirty_size;
+       uint32_t free_size;
+       uint32_t wasted_size;
+
+       struct chfs_node_ref *first_node;
+       struct chfs_node_ref *last_node;
+
+       /* Next block to be garbage collected */
+       struct chfs_node_ref *gc_node;
+};
+
+TAILQ_HEAD(chfs_eraseblock_queue, chfs_eraseblock);
+
+#define ALLOC_NORMAL    0
+#define ALLOC_DELETION 1
+#define ALLOC_GC        2
+
+struct garbage_collector_thread {
+       lwp_t *gcth_thread;
+       kcondvar_t gcth_wakeup;
+       bool gcth_running;
+};
+
+#define CHFS_MP_FLAG_SCANNING 2
+#define CHFS_MP_FLAG_BUILDING 4
+
+/**
+ * struct chfs_mount - CHFS main descriptor structure
+ * @ebh: eraseblock handler
+ * @fl_index: index of flash device in the flash layer
+ * @fs_version: filesystem version descriptor
+ * @gbl_version: global version number
+ * @max_vno: max vnode id
+ * @chm_lock_mountfields:
+ * @vnocache_hash: hash table of vnode caches
+ * @vnocache_lock:
+ * @blocks: array of eraseblocks on flash
+ * @chm_root: used to protect all fields
+ * @free_size: free size on the flash
+ * @dirty_size: dirtied size on flash
+ * @unchecked_size: size of unchecked data on flash
+ * @free_queue: queue of free eraseblocks
+ * @clean_queue: queue of clean eraseblocks
+ * @dirty_queue: queue of dirty eraseblocks
+ * @very_dirty_queue: queue of very dirty eraseblocks
+ * @erase_pending_queue: queue of eraseblocks waiting for erasing
+ * @erasable_pending_wbuf_queue: queue of eraseblocks waiting for erasing and
+ *                              have data to write to them
+ * @nextblock: next eraseblock to write to
+ * @nr_free_blocks: number of free blocks on the free_queue
+ * @nr_erasable_blocks: number of blocks that can be erased and are on the
+ *                     erasable_queue
+ */
+struct chfs_mount {
+       struct mount *chm_fsmp;
+       struct chfs_ebh *chm_ebh;
+       int chm_fs_version;
+       uint64_t chm_gbl_version;
+       ino_t chm_max_vno;
+       ino_t chm_checked_vno;
+       unsigned int chm_flags;
+
+       /* chm_lock_mountfields:
+        * Used to protect all the following fields. */
+       kmutex_t chm_lock_mountfields;
+
+       struct chfs_vnode_cache **chm_vnocache_hash;
+       /* chm_lock_vnocache:
+        * Used to protect the vnode cache.
+        * If you have to lock chm_lock_mountfields and also chm_lock_vnocache,
+        * you must lock chm_lock_mountfields first. */
+       kmutex_t chm_lock_vnocache;
+
+       struct chfs_eraseblock *chm_blocks;
+
+       struct chfs_node *chm_root;
+
+       uint32_t chm_free_size;
+       uint32_t chm_dirty_size;
+       uint32_t chm_unchecked_size;
+       uint32_t chm_used_size;
+       uint32_t chm_wasted_size;
+       /* chm_lock_sizes:
+        * Used to protect the (free, used, etc.) sizes of the FS
+        * (and also the sizes of each eraseblock).
+        * If you have to lock chm_lock_mountfields and also chm_lock_sizes,
+        * you must lock chm_lock_mountfields first. */
+       kmutex_t chm_lock_sizes;
+
+       struct chfs_eraseblock_queue chm_free_queue;
+       struct chfs_eraseblock_queue chm_clean_queue;
+       struct chfs_eraseblock_queue chm_dirty_queue;
+       struct chfs_eraseblock_queue chm_very_dirty_queue;
+       struct chfs_eraseblock_queue chm_erasable_pending_wbuf_queue;
+       struct chfs_eraseblock_queue chm_erase_pending_queue;
+
+       uint8_t chm_resv_blocks_deletion;
+       uint8_t chm_resv_blocks_write;
+       uint8_t chm_resv_blocks_gctrigger;
+       uint8_t chm_resv_blocks_gcmerge;
+       uint8_t chm_nospc_dirty;
+
+       uint8_t chm_vdirty_blocks_gctrigger;
+
+       struct chfs_eraseblock *chm_nextblock;
+
+       struct garbage_collector_thread chm_gc_thread;
+       struct chfs_eraseblock *chm_gcblock;
+
+       int chm_nr_free_blocks;
+       int chm_nr_erasable_blocks;
+
+       int32_t chm_fs_bmask;
+       int32_t chm_fs_bsize;
+       int32_t chm_fs_qbmask;
+       int32_t chm_fs_bshift;
+       int32_t chm_fs_fmask;
+       int64_t chm_fs_qfmask;
+
+       /* TODO will we use these? */
+       unsigned int            chm_pages_max;
+       unsigned int            chm_pages_used;
+       unsigned int            chm_nodes_max;
+       unsigned int            chm_nodes_cnt;
+       struct chfs_pool        chm_dirent_pool;
+       struct chfs_pool        chm_node_pool;
+       struct chfs_str_pool    chm_str_pool;
+       /**/
+
+       size_t chm_wbuf_pagesize;
+       unsigned char* chm_wbuf;
+       size_t chm_wbuf_ofs;
+       size_t chm_wbuf_len;
+       /* chm_lock_wbuf:
+        * Used to protect the write buffer.
+        * If you have to lock chm_lock_mountfields and also chm_lock_wbuf,
+        * you must lock chm_lock_mountfields first. */
+       krwlock_t chm_lock_wbuf;
+};
+
+/*
+ * TODO we should move here all of these from the bottom of the file
+ * Macros/functions to convert from generic data structures to chfs
+ * specific ones.
+ */
+
+#define        CHFS_OFFSET_DOT         0
+#define        CHFS_OFFSET_DOTDOT      1
+#define CHFS_OFFSET_EOF                2
+#define CHFS_OFFSET_FIRST      3
+
+
+/*---------------------------------------------------------------------------*/
+
+/* chfs_build.c */
+void chfs_calc_trigger_levels(struct chfs_mount *);
+int chfs_build_filesystem(struct chfs_mount *);
+void chfs_build_set_vnodecache_nlink(struct chfs_mount *,
+    struct chfs_vnode_cache *);
+void chfs_build_remove_unlinked_vnode(struct chfs_mount *,
+    struct chfs_vnode_cache *, struct chfs_dirent_list *);
+
+/* chfs_scan.c */
+int chfs_scan_eraseblock(struct chfs_mount *, struct chfs_eraseblock *);
+struct chfs_vnode_cache *chfs_scan_make_vnode_cache(struct chfs_mount *,
+    ino_t);
+int chfs_scan_check_node_hdr(struct chfs_flash_node_hdr *);
+int chfs_scan_check_vnode(struct chfs_mount *,
+    struct chfs_eraseblock *, void *, off_t);
+int chfs_scan_mark_dirent_obsolete(struct chfs_mount *,
+    struct chfs_vnode_cache *, struct chfs_dirent *);
+void chfs_add_fd_to_list(struct chfs_mount *,
+    struct chfs_dirent *, struct chfs_vnode_cache *);
+int chfs_scan_check_dirent_node(struct chfs_mount *,
+    struct chfs_eraseblock *, void *, off_t);
+int chfs_scan_check_data_node(struct chfs_mount *,
+    struct chfs_eraseblock *, void *, off_t);
+int chfs_scan_classify_cheb(struct chfs_mount *,
+    struct chfs_eraseblock *);
+
+/* chfs_nodeops.c */
+int chfs_update_eb_dirty(struct chfs_mount *,
+    struct chfs_eraseblock *, uint32_t);
+void chfs_add_node_to_list(struct chfs_mount *, struct chfs_vnode_cache *,
+    struct chfs_node_ref *, struct chfs_node_ref **);
+void chfs_add_fd_to_inode(struct chfs_mount *,
+    struct chfs_inode *, struct chfs_dirent *);
+void chfs_add_vnode_ref_to_vc(struct chfs_mount *, struct chfs_vnode_cache *,
+    struct chfs_node_ref *);
+struct chfs_node_ref* chfs_nref_next(struct chfs_node_ref *);
+int chfs_nref_len(struct chfs_mount *,
+    struct chfs_eraseblock *, struct chfs_node_ref *);
+int chfs_close_eraseblock(struct chfs_mount *,
+    struct chfs_eraseblock *);
+int chfs_reserve_space_normal(struct chfs_mount *, uint32_t, int);
+int chfs_reserve_space_gc(struct chfs_mount *, uint32_t);
+int chfs_reserve_space(struct chfs_mount *, uint32_t);
+void chfs_mark_node_obsolete(struct chfs_mount *, struct chfs_node_ref *);
+
+static inline struct chfs_vnode_cache *
+chfs_nref_to_vc(struct chfs_node_ref *nref)
+{
+       while (nref->nref_next) {
+               nref = nref->nref_next;
+               //dbg("lnr: %u, ofs: %u\n", nref->nref_lnr, nref->nref_offset);
+               //dbg("vno: %llu\n", ((struct chfs_vnode_cache *)(nref))->vno);
+               //dbg("scan_dirents: %p\n", ((struct chfs_vnode_cache *)(nref))->scan_dirents);
+               if (nref->nref_lnr == REF_LINK_TO_NEXT) {
+                       dbg("Link to next!\n");
+               } else if (nref->nref_lnr == REF_EMPTY_NODE) {
+                       dbg("Empty!\n");
+               }
+       }
+       //dbg("vno: %llu\n", ((struct chfs_vnode_cache *)(nref))->vno);
+
+       //dbg("NREF_TO_VC: GET IT\n");
+       //dbg("nref_next: %p, lnr: %u, ofs: %u\n", nref->nref_next, nref->nref_lnr, nref->nref_offset);
+       struct chfs_vnode_cache *vc = (struct chfs_vnode_cache *) nref;
+       dbg("vno: %ju, pvno: %ju, hv: %ju, nlink: %u\n", (intmax_t )vc->vno,
+           (intmax_t )vc->pvno, (intmax_t )vc->highest_version, vc->nlink);
+       //return ((struct chfs_vnode_cache *)nref);
+       return vc;
+}
+
+
+/* chfs_malloc.c */
+int chfs_alloc_pool_caches(void);
+void chfs_destroy_pool_caches(void);
+struct chfs_vnode_cache* chfs_vnode_cache_alloc(ino_t);
+void chfs_vnode_cache_free(struct chfs_vnode_cache *);
+struct chfs_node_ref* chfs_alloc_node_ref(
+       struct chfs_eraseblock *);
+void chfs_free_node_refs(struct chfs_eraseblock *);
+struct chfs_dirent* chfs_alloc_dirent(int);
+void chfs_free_dirent(struct chfs_dirent *);
+struct chfs_flash_vnode* chfs_alloc_flash_vnode(void);
+void chfs_free_flash_vnode(struct chfs_flash_vnode *);
+struct chfs_flash_dirent_node* chfs_alloc_flash_dirent(void);
+void chfs_free_flash_dirent(struct chfs_flash_dirent_node *);
+struct chfs_flash_data_node* chfs_alloc_flash_dnode(void);
+void chfs_free_flash_dnode(struct chfs_flash_data_node *);
+struct chfs_node_frag* chfs_alloc_node_frag(void);
+void chfs_free_node_frag(struct chfs_node_frag *);
+struct chfs_node_ref* chfs_alloc_refblock(void);
+void chfs_free_refblock(struct chfs_node_ref *);
+struct chfs_full_dnode* chfs_alloc_full_dnode(void);
+void chfs_free_full_dnode(struct chfs_full_dnode *);
+struct chfs_tmp_dnode * chfs_alloc_tmp_dnode(void);
+void chfs_free_tmp_dnode(struct chfs_tmp_dnode *);
+struct chfs_tmp_dnode_info * chfs_alloc_tmp_dnode_info(void);
+void chfs_free_tmp_dnode_info(struct chfs_tmp_dnode_info *);
+
+/* chfs_readinode.c */
+int chfs_read_inode(struct chfs_mount *, struct chfs_inode *);
+int chfs_read_inode_internal(struct chfs_mount *, struct chfs_inode *);
+void chfs_kill_fragtree(struct rb_tree *);
+uint32_t chfs_truncate_fragtree(struct chfs_mount *,
+       struct rb_tree *, uint32_t);
+int chfs_add_full_dnode_to_inode(struct chfs_mount *,
+    struct chfs_inode *,
+    struct chfs_full_dnode *);
+int chfs_read_data(struct chfs_mount*, struct vnode *,
+    struct buf *);
+
+/* chfs_erase.c */
+int chfs_remap_leb(struct chfs_mount *);
+
+/* chfs_ihash.c */
+void chfs_ihashinit(void);
+void chfs_ihashreinit(void);
+void chfs_ihashdone(void);
+struct vnode *chfs_ihashlookup(dev_t, ino_t);
+struct vnode *chfs_ihashget(dev_t, ino_t, int);
+void chfs_ihashins(struct chfs_inode *);
+void chfs_ihashrem(struct chfs_inode *);
+
+extern kmutex_t        chfs_ihash_lock;
+extern kmutex_t        chfs_hashlock;
+
+/* chfs_gc.c */
+void chfs_gc_trigger(struct chfs_mount *);
+int chfs_gc_thread_should_wake(struct chfs_mount *);
+void chfs_gc_thread(void *);
+void chfs_gc_thread_start(struct chfs_mount *);
+void chfs_gc_thread_stop(struct chfs_mount *);
+int chfs_gcollect_pass(struct chfs_mount *);
+
+/* chfs_vfsops.c*/
+int chfs_gop_alloc(struct vnode *, off_t, off_t,  int, kauth_cred_t);
+int chfs_mountfs(struct vnode *, struct mount *);
+
+/* chfs_vnops.c */
+extern int (**chfs_vnodeop_p)(void *);
+extern int (**chfs_specop_p)(void *);
+extern int (**chfs_fifoop_p)(void *);
+int chfs_lookup(void *);
+int chfs_create(void *);
+int chfs_mknod(void *);
+int chfs_open(void *);
+int chfs_close(void *);
+int chfs_access(void *);
+int chfs_getattr(void *);
+int chfs_setattr(void *);
+int chfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t);
+int chfs_chmod(struct vnode *, int, kauth_cred_t);
+int chfs_read(void *);
+int chfs_write(void *);
+int chfs_fsync(void *);
+int chfs_remove(void *);
+int chfs_link(void *);
+int chfs_rename(void *);
+int chfs_mkdir(void *);
+int chfs_rmdir(void *);
+int chfs_symlink(void *);
+int chfs_readdir(void *);
+int chfs_readlink(void *);
+int chfs_inactive(void *);
+int chfs_reclaim(void *);
+int chfs_advlock(void *);
+int chfs_strategy(void *);
+int chfs_bmap(void *);
+
+/* chfs_vnode.c */
+struct vnode *chfs_vnode_lookup(struct chfs_mount *, ino_t);
+int chfs_readvnode(struct mount *, ino_t, struct vnode **);
+int chfs_readdirent(struct mount *, struct chfs_node_ref *,
+    struct chfs_inode *);
+int chfs_makeinode(int, struct vnode *, struct vnode **,
+    struct componentname *, int );
+void chfs_set_vnode_size(struct vnode *, size_t);
+void chfs_change_size_free(struct chfs_mount *,
+       struct chfs_eraseblock *, int);
+void chfs_change_size_dirty(struct chfs_mount *,
+       struct chfs_eraseblock *, int);
+void chfs_change_size_unchecked(struct chfs_mount *,
+       struct chfs_eraseblock *, int);
+void chfs_change_size_used(struct chfs_mount *,
+       struct chfs_eraseblock *, int);
+void chfs_change_size_wasted(struct chfs_mount *,
+       struct chfs_eraseblock *, int);
+
+/* chfs_vnode_cache.c */
+struct chfs_vnode_cache **chfs_vnocache_hash_init(void);
+void chfs_vnocache_hash_destroy(struct chfs_vnode_cache **);
+void chfs_vnode_cache_set_state(struct chfs_mount *,
+    struct chfs_vnode_cache *, int);
+struct chfs_vnode_cache* chfs_vnode_cache_get(struct chfs_mount *, ino_t);
+void chfs_vnode_cache_add(struct chfs_mount *, struct chfs_vnode_cache *);
+void chfs_vnode_cache_remove(struct chfs_mount *, struct chfs_vnode_cache *);
+
+/* chfs_wbuf.c */
+int chfs_write_wbuf(struct chfs_mount*,
+    const struct iovec *, long, off_t, size_t *);
+int chfs_flush_pending_wbuf(struct chfs_mount *);
+
+/* chfs_write.c */
+int chfs_write_flash_vnode(struct chfs_mount *, struct chfs_inode *, int);
+int chfs_write_flash_dirent(struct chfs_mount *, struct chfs_inode *,
+    struct chfs_inode *, struct chfs_dirent *, ino_t, int);
+int chfs_write_flash_dnode(struct chfs_mount *, struct vnode *,
+    struct buf *, struct chfs_full_dnode *);
+int chfs_do_link(struct chfs_inode *,
+    struct chfs_inode *, const char *, int, enum vtype);
+int chfs_do_unlink(struct chfs_inode *,
+    struct chfs_inode *, const char *, int);
+
+/* chfs_subr.c */
+size_t chfs_mem_info(bool);
+struct chfs_dirent * chfs_dir_lookup(struct chfs_inode *,
+    struct componentname *);
+int chfs_filldir (struct uio *, ino_t, const char *, int, enum vtype);
+int chfs_chsize(struct vnode *, u_quad_t, kauth_cred_t);
+int chfs_chflags(struct vnode *, int, kauth_cred_t);
+void chfs_itimes(struct chfs_inode *, const struct timespec *,
+    const struct timespec *, const struct timespec *);
+int    chfs_update(struct vnode *, const struct timespec *,
+    const struct timespec *, int);
+//int  chfs_truncate(struct vnode *, off_t);
+
+/*---------------------------------------------------------------------------*/
+
+/* Some inline functions temporarily placed here */
+static inline int
+chfs_map_leb(struct chfs_mount *chmp, int lnr)
+{
+       int err;
+
+       err = ebh_map_leb(chmp->chm_ebh, lnr);
+       if (err)
+               chfs_err("unmap leb %d failed, error: %d\n",lnr, err);
+
+       return err;
+
+}
+
+static inline int
+chfs_unmap_leb(struct chfs_mount *chmp, int lnr)
+{
+       int err;
+
+       err = ebh_unmap_leb(chmp->chm_ebh, lnr);
+       if (err)
+               chfs_err("unmap leb %d failed, error: %d\n",lnr, err);
+
+       return err;
+}
+
+static inline int
+chfs_read_leb(struct chfs_mount *chmp, int lnr, char *buf,
+    int offset, int len, size_t *retlen)
+{
+       int err;
+
+       err = ebh_read_leb(chmp->chm_ebh, lnr, buf, offset, len, retlen);
+       if (err)
+               chfs_err("read leb %d:%d failed, error: %d\n",
+                   lnr, offset, err);
+
+       return err;
+}
+
+static inline int chfs_write_leb(struct chfs_mount *chmp, int lnr, char *buf,
+    int offset, int len, size_t *retlen)
+{
+       int err;
+       err = ebh_write_leb(chmp->chm_ebh, lnr, buf, offset, len, retlen);
+       if (err)
+               chfs_err("write leb %d:%d failed, error: %d\n",
+                   lnr, offset, err);
+
+       return err;
+}
+
+/******************************************************************************/
+/* Code from dummyfs.h                                                                                                           */
+/******************************************************************************/
+/* --------------------------------------------------------------------- */
+
+#define CHFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE)
+
+static __inline size_t
+CHFS_PAGES_MAX(struct chfs_mount *chmp)
+{
+       size_t freepages;
+
+       freepages = chfs_mem_info(false);
+       if (freepages < CHFS_PAGES_RESERVED)
+               freepages = 0;
+       else
+               freepages -= CHFS_PAGES_RESERVED;
+
+       return MIN(chmp->chm_pages_max, freepages + chmp->chm_pages_used);
+}
+
+#define        CHFS_ITIMES(ip, acc, mod, cre)                                \
+       while ((ip)->iflag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY)) \
+               chfs_itimes(ip, acc, mod, cre)
+
+/* used for KASSERTs */
+#define IMPLIES(a, b) (!(a) || (b))
+#define IFF(a, b) (IMPLIES(a, b) && IMPLIES(b, a))
+
+#endif /* __CHFS_H__ */
diff --git a/nbsd_include/ufs/chfs/chfs_args.h b/nbsd_include/ufs/chfs/chfs_args.h
new file mode 100644 (file)
index 0000000..a222b4b
--- /dev/null
@@ -0,0 +1,53 @@
+/*     $NetBSD: chfs_args.h,v 1.1 2011/11/24 15:51:31 ahoka Exp $      */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ *                   University of Szeged, Hungary
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef _FS_CHFS_CHFS_ARGS_H_
+#define _FS_CHFS_CHFS_ARGS_H_
+
+#define CHFS_ARGS_VERSION      1
+
+/**
+ * struct chfs_args - arguments needed when mounting filesystem
+ * @fl_index: index of the flash device in the flash layer
+ */
+struct chfs_args {
+       //int   ca_version;
+       char *fspec;
+       int fl_index;
+
+       /* Root node attributes. */
+       /*uid_t                 ca_root_uid;
+         gid_t                 ca_root_gid;
+         mode_t                        ca_root_mode;*/
+};
+
+#endif /* _FS_CHFS_CHFS_ARGS_H_ */
diff --git a/nbsd_include/ufs/chfs/chfs_inode.h b/nbsd_include/ufs/chfs/chfs_inode.h
new file mode 100644 (file)
index 0000000..0661437
--- /dev/null
@@ -0,0 +1,136 @@
+/*     $NetBSD: chfs_inode.h,v 1.1 2011/11/24 15:51:31 ahoka Exp $     */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ *                   University of Szeged, Hungary
+ * Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
+ * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef __CHFS_INODE_H__
+#define __CHFS_INODE_H__
+
+#include <sys/vnode.h>
+#include <sys/stat.h>
+#include <ufs/ufs/ufsmount.h>
+#include <miscfs/genfs/genfs_node.h>
+
+struct chfs_inode
+{
+       kmutex_t inode_lock;    /* lock the fields of chfs_inode */
+
+       LIST_ENTRY(chfs_inode) hash_entry;      /* Hash chain. */
+
+       struct ufsmount *ump;                   /* ufs mount - TODO we should remove it */
+       struct chfs_mount *chmp;        /* chfs mount point - TODO we should remove it */
+
+       struct vnode *vp;       /* vnode associated with this inode */
+       ino_t ino;                      /* vnode identifier number */
+       
+       struct vnode *devvp;    /* vnode for block I/O */
+       dev_t dev;                              /* device associated with the inode */
+       
+       struct chfs_vnode_cache *chvc;  /* vnode cache of this node */
+
+       struct chfs_dirent *fd; /* full dirent of this node */
+//     struct chfs_dirent *dents;      /* directory entries */
+       struct chfs_dirent_list dents;
+
+       struct rb_tree fragtree;                /* fragtree of inode */
+
+       uint64_t version;                       /* version number */
+       //uint64_t highest_version;     /* highest vers. num. (used at data nodes) */
+       
+       uint32_t mode;          /* mode */
+       //int16_t nlink;                /* link count */
+       uint64_t size;          /* file byte count */
+       uint64_t write_size;    /* increasing while write the file out to the flash */
+       uint32_t uid;           /* file owner */
+       uint32_t gid;           /* file group */
+       uint32_t atime;         /* access time */
+       uint32_t mtime;         /* modify time */
+       uint32_t ctime;         /* creation time */
+       
+       uint32_t iflag;         /* flags, see below */
+       uint32_t flags;         /* status flags (chflags) */
+
+       dev_t rdev;                     /* used if type is VCHR or VBLK or VFIFO*/
+       char *target;           /* used if type is VLNK */
+};
+
+/* These flags are kept in chfs_inode->iflag. */
+#define        IN_ACCESS       0x0001          /* Access time update request. */
+#define        IN_CHANGE       0x0002          /* Inode change time update request. */
+#define        IN_UPDATE       0x0004          /* Inode was written to; update mtime. */
+#define        IN_MODIFY       0x2000          /* Modification time update request. */
+#define        IN_MODIFIED     0x0008          /* Inode has been modified. */
+#define        IN_ACCESSED     0x0010          /* Inode has been accessed. */
+#define        IN_RENAME       0x0020          /* Inode is being renamed. */
+#define        IN_SHLOCK       0x0040          /* File has shared lock. */
+#define        IN_EXLOCK       0x0080          /* File has exclusive lock. */
+#define        IN_CLEANING     0x0100          /* LFS: file is being cleaned */
+#define        IN_ADIROP       0x0200          /* LFS: dirop in progress */
+#define        IN_SPACECOUNTED 0x0400          /* Blocks to be freed in free count. */
+#define        IN_PAGING       0x1000          /* LFS: file is on paging queue */
+
+
+#ifdef VTOI
+# undef VTOI
+#endif
+#ifdef ITOV
+# undef ITOV
+#endif
+
+#define        VTOI(vp)        ((struct chfs_inode *)(vp)->v_data)
+#define        ITOV(ip)        ((ip)->vp)
+
+/* copied from ufs_dinode.h */
+#define        NDADDR  12                      /* Direct addresses in inode. */
+
+#define        ROOTINO ((ino_t)2)
+
+/* File permissions. */
+#define        IEXEC           0000100         /* Executable. */
+#define        IWRITE          0000200         /* Writable. */
+#define        IREAD           0000400         /* Readable. */
+#define        ISVTX           0001000         /* Sticky bit. */
+#define        ISGID           0002000         /* Set-gid. */
+#define        ISUID           0004000         /* Set-uid. */
+
+/* File types. */
+#define        IFMT            0170000         /* Mask of file type. */
+#define        IFIFO           0010000         /* Named pipe (fifo). */
+#define        IFCHR           0020000         /* Character device. */
+#define        IFDIR           0040000         /* Directory file. */
+#define        IFBLK           0060000         /* Block device. */
+#define        IFREG           0100000         /* Regular file. */
+#define        IFLNK           0120000         /* Symbolic link. */
+#define        IFSOCK          0140000         /* UNIX domain socket. */
+#define        IFWHT           0160000         /* Whiteout. */
+
+#endif /* __CHFS_INODE_H__ */
diff --git a/nbsd_include/ufs/chfs/chfs_pool.h b/nbsd_include/ufs/chfs/chfs_pool.h
new file mode 100644 (file)
index 0000000..78cb991
--- /dev/null
@@ -0,0 +1,84 @@
+/*     $NetBSD: chfs_pool.h,v 1.1 2011/11/24 15:51:31 ahoka Exp $      */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ *                   University of Szeged, Hungary
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef _FS_CHFS_CHFS_POOL_H_
+#define _FS_CHFS_CHFS_POOL_H_
+
+
+/* --------------------------------------------------------------------- */
+
+struct chfs_pool {
+       struct pool             chp_pool;
+       struct chfs_mount *     chp_mount;
+       char                    chp_name[64];
+};
+
+/* --------------------------------------------------------------------- */
+
+struct chfs_str_pool {
+       struct chfs_pool        chsp_pool_16;
+       struct chfs_pool        chsp_pool_32;
+       struct chfs_pool        chsp_pool_64;
+       struct chfs_pool        chsp_pool_128;
+       struct chfs_pool        chsp_pool_256;
+       struct chfs_pool        chsp_pool_512;
+       struct chfs_pool        chsp_pool_1024;
+};
+
+/* --------------------------------------------------------------------- */
+#ifdef _KERNEL
+
+/*
+ * Convenience functions and macros to manipulate a chfs_pool.
+ */
+
+void   chfs_pool_init(struct chfs_pool *chpp, size_t size,
+    const char *what, struct chfs_mount *chmp);
+void   chfs_pool_destroy(struct chfs_pool *chpp);
+
+#define        CHFS_POOL_GET(chpp, flags) pool_get((struct pool *)(chpp), flags)
+#define        CHFS_POOL_PUT(chpp, v) pool_put((struct pool *)(chpp), v)
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Functions to manipulate a chfs_str_pool.
+ */
+
+void   chfs_str_pool_init(struct chfs_str_pool *, struct chfs_mount *);
+void   chfs_str_pool_destroy(struct chfs_str_pool *);
+char * chfs_str_pool_get(struct chfs_str_pool *, size_t, int);
+void   chfs_str_pool_put(struct chfs_str_pool *, char *, size_t);
+
+#endif
+
+#endif /* _FS_CHFS_CHFS_POOL_H_ */
diff --git a/nbsd_include/ufs/chfs/debug.h b/nbsd_include/ufs/chfs/debug.h
new file mode 100644 (file)
index 0000000..6128f7f
--- /dev/null
@@ -0,0 +1,97 @@
+/*     $NetBSD: debug.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $  */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ *                   University of Szeged, Hungary
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * XipFFS -- Xip Flash File System
+ *
+ * Copyright (C) 2009  Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                     ...
+ *                     University of Szeged, Hungary
+ *
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ */
+
+#ifndef __CHFS_DEBUG_H__
+#define __CHFS_DEBUG_H__
+
+#define CHFS_ERROR_PREFIX      "[CHFS ERROR]"
+#define CHFS_WARNING_PREFIX    "[CHFS WARNING]"
+#define CHFS_NOTICE_PREFIX     "[CHFS NOTICE]"
+#define CHFS_DBG_PREFIX        "[CHFS DBG]"
+#define CHFS_DBG2_PREFIX       "[CHFS DBG2]"
+#define CHFS_DBG_EBH_PREFIX    "[CHFS DBG EBH]"
+#define CHFS_DBG_GC_PREFIX     "[CHFS_GC DBG]"
+
+#define unlikely(x) __builtin_expect ((x), 0)
+
+
+
+#define debug_msg(pref, fmt, ...)                                              \
+       do {                                                                   \
+               printf(pref                                                    \
+                       " %s: " fmt, __FUNCTION__ , ##__VA_ARGS__);            \
+       } while(0)
+
+#define chfs_assert(expr) do {                                               \
+       if (unlikely(!(expr))) {                                               \
+               printf("CHFS assert failed in %s at %u\n", \
+                       __func__, __LINE__);                     \
+               /*dump_stack();*/                                                  \
+       }                                                                      \
+} while (0)
+
+#ifdef DBG_MSG
+       #define chfs_err(fmt, ...) debug_msg(CHFS_ERROR_PREFIX, fmt, ##__VA_ARGS__)
+       #define chfs_warn(fmt, ...) debug_msg(CHFS_WARNING_PREFIX, fmt, ##__VA_ARGS__)
+       #define chfs_noti(fmt, ...) debug_msg(CHFS_NOTICE_PREFIX, fmt, ##__VA_ARGS__)
+       #define dbg(fmt, ...) debug_msg(CHFS_DBG_PREFIX, fmt, ##__VA_ARGS__)
+       #define dbg2(fmt, ...) debug_msg(CHFS_DBG2_PREFIX(fmt, ##__VA_ARGS__)
+       #define dbg_ebh(fmt, ...) debug_msg(CHFS_DBG_EBH_PREFIX, fmt, ##__VA_ARGS__)
+#else
+       #define chfs_err(fmt, ...) debug_msg(CHFS_ERROR_PREFIX, fmt, ##__VA_ARGS__)
+       #define chfs_warn(fmt, ...) debug_msg(CHFS_WARNING_PREFIX, fmt, ##__VA_ARGS__)
+       #define chfs_noti(fmt, ...) debug_msg(CHFS_NOTICE_PREFIX, fmt, ##__VA_ARGS__)
+       #define dbg(fmt, ...)
+       #define dbg2(fmt, ...)
+       #define dbg_ebh(fmt, ...)
+#endif
+
+#ifdef DBG_MSG_GC
+       #define dbg_gc(fmt, ...) debug_msg(CHFS_DBG_GC_PREFIX, fmt, ##__VA_ARGS__)
+#else
+       #define dbg_gc(fmt, ...)
+#endif
+
+#endif /* __CHFS_DEBUG_H__ */
diff --git a/nbsd_include/ufs/chfs/ebh.h b/nbsd_include/ufs/chfs/ebh.h
new file mode 100644 (file)
index 0000000..51e6999
--- /dev/null
@@ -0,0 +1,318 @@
+/*     $NetBSD: ebh.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $    */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ *                   University of Szeged, Hungary
+ * Copyright (c) 2010 David Tengeri <dtengeri@inf.u-szeged.hu>
+ * Copyright (c) 2010 Adam Hoka <ahoka@NetBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * ebh.h
+ *
+ *  Created on: 2009.11.03.
+ *      Author: dtengeri
+ */
+
+#ifndef EBH_H_
+#define EBH_H_
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/cdefs.h>
+#include <sys/stdint.h>
+#include <sys/types.h>
+#include <sys/tree.h>
+#include <sys/queue.h>
+#include <sys/kmem.h>
+#include <sys/endian.h>
+#include <sys/rwlock.h>
+#include <sys/condvar.h>
+#include <sys/mutex.h>
+#include <sys/kthread.h>
+
+#include <dev/flash/flash.h>
+#include <ufs/chfs/ebh_media.h>
+#include <ufs/chfs/debug.h>
+#include <ufs/chfs/ebh_misc.h>
+
+/* Maximum retries when getting new PEB before exit with failure */
+#define CHFS_MAX_GET_PEB_RETRIES 2
+
+/**
+ * LEB status
+ *
+ */
+enum {
+       EBH_LEB_UNMAPPED = -1,
+       EBH_LEB_MAPPED,
+       EBH_LEB_DIRTY,
+       EBH_LEB_INVALID,
+       EBH_LEB_ERASE,
+       EBH_LEB_ERASED,
+       EBH_LEB_FREE,
+};
+
+/**
+ * EB header status
+ */
+enum {
+       EBHDR_LEB_OK = 0,
+       EBHDR_LEB_DIRTY,
+       EBHDR_LEB_INVALIDATED,
+       EBHDR_LEB_BADMAGIC,
+       EBHDR_LEB_BADCRC,
+       EBHDR_LEB_FREE,
+       EBHDR_LEB_NO_HDR,
+};
+
+struct chfs_ebh;
+
+/**
+ * struct chfs_ltree_entry - an netry in the lock tree
+ * @rb: RB-node of the tree
+ * @lnr: logical eraseblock number
+ * @users: counts the tasks that are using or want to use the eraseblock
+ * @mutex: read/write mutex to lock the eraseblock
+ */
+struct chfs_ltree_entry {
+       RB_ENTRY(chfs_ltree_entry) rb;
+       int lnr;
+       int users;
+       krwlock_t mutex;
+};
+
+/* Generate structure for Lock tree's red-black tree */
+RB_HEAD(ltree_rbtree, chfs_ltree_entry);
+
+
+/**
+ * struct chfs_scan_leb - scanning infomration about a physical eraseblock
+ * @erase_cnt: erase counter
+ * @pebnr: physical eraseblock number
+ * @info: the status of the PEB's eraseblock header when NOR serial when NAND
+ * @u.list: link in one of the eraseblock list
+ * @u.rb: link in the used RB-tree of chfs_scan_info
+ */
+struct chfs_scan_leb {
+       int erase_cnt;
+       int pebnr;
+       int lnr;
+       uint64_t info;
+       union {
+               TAILQ_ENTRY(chfs_scan_leb) queue;
+               RB_ENTRY(chfs_scan_leb) rb;
+       } u;
+};
+
+TAILQ_HEAD(scan_leb_queue, chfs_scan_leb);
+RB_HEAD(scan_leb_used_rbtree, chfs_scan_leb);
+
+
+
+/**
+ * struct chfs_scan_info - chfs scanning information
+ * @corrupted: queue of corrupted physical eraseblocks
+ * @free: queue of free physical eraseblocks
+ * @erase: queue of the physical eraseblocks signed to erase
+ * @erased: queue of physical eraseblocks that contain no header
+ * @used: RB-tree of used PEBs describing by chfs_scan_leb
+ * @sum_of_ec: summary of erase counters
+ * @num_of_eb: number of free and used eraseblocks
+ * @bad_peb_cnt: counter of bad eraseblocks
+ *
+ * This structure contains information about the scanning for further
+ * processing.
+ */
+struct chfs_scan_info {
+       struct scan_leb_queue corrupted;
+       struct scan_leb_queue free;
+       struct scan_leb_queue erase;
+       struct scan_leb_queue erased;
+       struct scan_leb_used_rbtree used;
+       uint64_t sum_of_ec;
+       int num_of_eb;
+       int bad_peb_cnt;
+};
+
+/**
+ * struct chfs_peb - PEB information for erasing and wear leveling
+ * @erase_cnt: erase counter of the physical eraseblock
+ * @pebnr: physical eraseblock number
+ * @u.queue: link to the queue of the PEBs waiting for erase
+ * @u.rb: link to the RB-tree to the free PEBs
+ */
+struct chfs_peb {
+       int erase_cnt;
+       int pebnr;
+       union {
+               TAILQ_ENTRY(chfs_peb) queue;
+               RB_ENTRY(chfs_peb) rb;
+       } u;
+};
+
+/* Generate queue and rb-tree structures. */
+TAILQ_HEAD(peb_queue, chfs_peb);
+RB_HEAD(peb_free_rbtree, chfs_peb);
+RB_HEAD(peb_in_use_rbtree, chfs_peb);
+
+/**
+ * struct  chfs_eb_hdr - in-memory representation of eraseblock headers
+ * @ec_hdr: erase counter header ob eraseblock
+ * @u.nor_hdr: eraseblock header on NOR flash
+ * @u.nand_hdr: eraseblock header on NAND flash
+ */
+struct  chfs_eb_hdr {
+       struct chfs_eb_ec_hdr ec_hdr;
+       union {
+               struct chfs_nor_eb_hdr  nor_hdr;
+               struct chfs_nand_eb_hdr nand_hdr;
+       } u;
+};
+
+/*
+ * struct chfs_ebh_ops - collection of operations which
+ *                                                              depends on flash type
+ * *************************************************************************** *
+ * Direct flash operations:
+ *
+ * @read_eb_hdr: read eraseblock header from media
+ * @write_eb_hdr: write eraseblock header to media
+ * @check_eb_hdr: validates eraseblock header
+ * @mark_eb_hdr_dirty_flash: marks eraseblock dirty on flash
+ * @invalidate_eb_hdr: invalidates eraseblock header
+ * @mark_eb_hdr_free: marks eraseblock header free (after erase)
+ * *************************************************************************** *
+ * Scanning operations:
+ *
+ * @process_eb: process an eraseblock information at scan
+ * *************************************************************************** *
+ * Misc operations:
+ *
+ * @create_eb_hdr: creates an eraseblock header based on flash type
+ * @calc_data_offs: calculates where the data starts
+ */
+struct chfs_ebh_ops {
+       int (*read_eb_hdr)(struct chfs_ebh *ebh, int pebnr,
+           struct chfs_eb_hdr *ebhdr);
+       int (*write_eb_hdr)(struct chfs_ebh *ebh, int pebnr,
+           struct chfs_eb_hdr *ebhdr);
+       int (*check_eb_hdr)(struct chfs_ebh *ebh, void *buf);
+       int (*mark_eb_hdr_dirty_flash)(struct chfs_ebh *ebh, int pebnr, int lid);
+       int (*invalidate_eb_hdr)(struct chfs_ebh *ebh, int pebnr);
+       int (*mark_eb_hdr_free)(struct chfs_ebh *ebh, int pebnr, int ec);
+
+       int (*process_eb)(struct chfs_ebh *ebh, struct chfs_scan_info *si,
+           int pebnr, struct chfs_eb_hdr *ebhdr);
+
+       int (*create_eb_hdr)(struct chfs_eb_hdr *ebhdr, int lnr);
+       int (*calc_data_offs)(struct chfs_ebh *ebh, int pebnr, int offset);
+};
+
+/**
+ * struct erase_thread - background thread for erasing
+ * @thread: pointer to thread structure
+ * @wakeup: conditional variable for sleeping if there isn't any job to do
+ * @running: flag to signal a thread shutdown
+ */
+struct erase_thread {
+       lwp_t *eth_thread;
+       kcondvar_t eth_wakeup;
+       bool eth_running;
+};
+
+
+/**
+ * struct chfs_ebh - eraseblock handler descriptor
+ * @mtd: mtd device descriptor
+ * @eb_size: eraseblock size
+ * @peb_nr: number of PEBs
+ * @lmap: LEB to PEB mapping
+ * @layout_map: the LEBs layout (NOT USED YET)
+ * @ltree: the lock tree
+ * @ltree_lock: protects the tree
+ * @alc_mutex: serializes "atomic LEB change" operation
+ * @free: RB-tree of the free easeblocks
+ * @in_use: RB-tree of PEBs are in use
+ * @to_erase: list of the PEBs waiting for erase
+ * @fully_erased: list of PEBs that have been erased but don't have header
+ * @erase_lock: list and tree lock for fully_erased and to_erase lists and
+ *             for the free RB-tree
+ * @bg_erase: background thread for eraseing PEBs.
+ * @ops: collection of operations which depends on flash type
+ * @max_serial: max serial number of eraseblocks, only used on NAND
+ */
+struct chfs_ebh {
+       struct peb_free_rbtree free;
+       struct peb_in_use_rbtree in_use;
+       struct peb_queue to_erase;
+       struct peb_queue fully_erased;
+       struct erase_thread bg_erase;
+       device_t flash_dev;
+       const struct flash_interface *flash_if;
+       struct chfs_ebh_ops *ops;
+       uint64_t *max_serial;
+       int *lmap;
+       //int *layout_map;
+       struct ltree_rbtree ltree;
+       //struct mutex alc_mutex;
+       kmutex_t ltree_lock;
+       kmutex_t alc_mutex;
+       kmutex_t erase_lock;
+       size_t eb_size;
+       size_t peb_nr;
+       flash_size_t flash_size;
+};
+
+/**
+ * struct chfs_erase_info_priv - private information for erase
+ * @ebh: eraseblock handler
+ * @peb: physical eraseblock information
+ */
+struct chfs_erase_info_priv {
+       struct chfs_ebh *ebh;
+       struct chfs_peb *peb;
+};
+
+/* ebh.c */
+
+int ebh_open(struct chfs_ebh *ebh, dev_t dev);
+int ebh_close(struct chfs_ebh *ebh);
+int ebh_read_leb(struct chfs_ebh *ebh, int lnr, char *buf,
+    uint32_t offset, size_t len, size_t *retlen);
+int ebh_write_leb(struct chfs_ebh *ebh, int lnr, char *buf,
+    uint32_t offset, size_t len, size_t *retlen);
+int ebh_erase_leb(struct chfs_ebh *ebh, int lnr);
+int ebh_map_leb(struct chfs_ebh *ebh, int lnr);
+int ebh_unmap_leb(struct chfs_ebh *ebh, int lnr);
+int ebh_is_mapped(struct chfs_ebh *ebh, int lnr);
+int ebh_change_leb(struct chfs_ebh *ebh, int lnr, char *buf,
+    size_t len, size_t *retlen);
+
+
+#endif /* EBH_H_ */
diff --git a/nbsd_include/ufs/chfs/ebh_media.h b/nbsd_include/ufs/chfs/ebh_media.h
new file mode 100644 (file)
index 0000000..a1a9b11
--- /dev/null
@@ -0,0 +1,116 @@
+/*     $NetBSD: ebh_media.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $      */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ *                   University of Szeged, Hungary
+ * Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu>
+ * Copyright (C) 2009 Zoltan Sogor <weth@inf.u-szeged.hu>
+ * Copyright (C) 2009 David Tengeri <dtengeri@inf.u-szeged.hu>
+ * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef EBH_MEDIA_H_
+#define EBH_MEDIA_H_
+
+#ifndef _LE_TYPES
+#define _LE_TYPES
+typedef uint16_t le16;
+typedef uint32_t le32;
+typedef uint64_t le64;
+#endif
+
+/*****************************************************************************/
+/*                     EBH specific structures                              */
+/*****************************************************************************/
+#define CHFS_MAGIC_BITMASK 0x53454452
+
+#define CHFS_LID_NOT_DIRTY_BIT  0x80000000
+#define CHFS_LID_DIRTY_BIT_MASK 0x7fffffff
+
+/* sizeof(crc) + sizeof(lid) */
+#define CHFS_INVALIDATE_SIZE 8
+
+/* Size of magic + crc_ec +  erase_cnt */
+#define CHFS_EB_EC_HDR_SIZE sizeof(struct chfs_eb_ec_hdr)
+/* Size of NOR eraseblock header */
+#define CHFS_EB_HDR_NOR_SIZE sizeof(struct chfs_nor_eb_hdr)
+/* Size of NAND eraseblock header */
+#define CHFS_EB_HDR_NAND_SIZE sizeof(struct chfs_nand_eb_hdr)
+
+/*
+ * chfs_eb_ec_hdr - erase counter header of eraseblock
+ * @magic: filesystem magic
+ * @crc_ec: CRC32 sum of erase counter
+ * @erase_cnt: erase counter
+ *
+ * This structure holds the erasablock description information.
+ * This will be written to the beginning of the eraseblock.
+ *
+ */
+struct chfs_eb_ec_hdr {
+       le32 magic;
+       le32 crc_ec;
+       le32 erase_cnt;
+} __packed;
+
+/**
+ * struct chfs_nor_eb_hdr - eraseblock header on NOR flash
+ * @crc: CRC32 sum
+ * @lid: logical identifier
+ *
+ * @lid contains the logical block reference but only the first 31 bit (0-30) is
+ * used. The 32th bit is for marking a lid dirty (marked for recovery purposes).
+ * If a new eraseblock is succesfully assigned with the same lid then the lid of
+ * the old one is zeroed. If power failure happened during this operation then
+ * the recovery detects that there is two eraseblock with the same lid, but one
+ * of them is marked (the old one).
+ *
+ * Invalidated eraseblock header means that the @crc and @lid is set to 0.
+ */
+struct chfs_nor_eb_hdr {
+       le32 crc;
+       le32 lid;
+} __packed;
+
+/**
+ * struct chfs_nand_eb_hdr - eraseblock header on NAND flash
+ * @crc: CRC32 sum
+ * @lid: logical identifier
+ * @serial: layout of the lid
+ *
+ * @serial is an unique number. Every eraseblock header on NAND flash has its
+ * own serial. If there are two eraseblock on the flash referencing to the same
+ * logical eraseblock, the one with bigger serial is the newer.
+ */
+struct chfs_nand_eb_hdr {
+       le32 crc;
+       le32 lid;
+       le64 serial;
+} __packed;
+
+#endif /* EBH_MEDIA_H_ */
diff --git a/nbsd_include/ufs/chfs/ebh_misc.h b/nbsd_include/ufs/chfs/ebh_misc.h
new file mode 100644 (file)
index 0000000..75b09ae
--- /dev/null
@@ -0,0 +1,88 @@
+/*     $NetBSD: ebh_misc.h,v 1.1 2011/11/24 15:51:32 ahoka Exp $       */
+
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ *                   University of Szeged, Hungary
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef EBH_MISC_H_
+#define EBH_MISC_H_
+
+/******************************************************************************/
+/* EBH specific functions                                                                                                        */
+/******************************************************************************/
+
+#define CHFS_GET_MEMBER_POS(type, member)                                    \
+       ((unsigned long)(&((type *)0)->member))
+
+#define CHFS_GET_LID(lid) (le32toh(lid) & CHFS_LID_DIRTY_BIT_MASK)
+
+/**
+ * EBH_TREE_DESTROY - destroys an RB-tree and frees the memory of its elements.
+ * @name - the RB-tree structure's name
+ * @head - pointer to the RB-tree's head
+ * @type - type of the elements
+ */
+#define EBH_TREE_DESTROY(name, head, type)                                   \
+       {                                                                     \
+               type *var, *nxt;                                              \
+               for (var = RB_MIN(name, head); var != NULL; var = nxt) {      \
+                       nxt = RB_NEXT(name, head, var);                       \
+                       RB_REMOVE(name, head, var);                           \
+                       kmem_free(var, sizeof(type));                         \
+               }                                                             \
+       }
+
+/* XXX HACK! we need a clean solution for destroying mutexes in trees */
+#define EBH_TREE_DESTROY_MUTEX(name, head, type)                             \
+       {                                                                     \
+               type *var, *nxt;                                              \
+               for (var = RB_MIN(name, head); var != NULL; var = nxt) {      \
+                       nxt = RB_NEXT(name, head, var);                       \
+                       RB_REMOVE(name, head, var);                           \
+                       rw_destroy(&var->mutex);                              \
+                       kmem_free(var, sizeof(type));                         \
+               }                                                             \
+       }
+
+/**
+ * EBH_QUEUE_DESTROY - destroys a TAILQ and frees the memory of its elements.
+ * @head: pointer to the head of the queue
+ * @type: type of the elements
+ * @entry: name of TAILQ_ENTRY
+ */
+#define EBH_QUEUE_DESTROY(head, type, entry)                                 \
+       {                                                                     \
+               type *var;                                                    \
+               while ((var = TAILQ_FIRST(head))) {                           \
+                       TAILQ_REMOVE(head, var, entry);                       \
+                       kmem_free(var, sizeof(type));                         \
+               }                                                             \
+       }
+
+#endif /* EBH_MISC_H_ */
diff --git a/nbsd_include/ufs/chfs/media.h b/nbsd_include/ufs/chfs/media.h
new file mode 100644 (file)
index 0000000..1f94131
--- /dev/null
@@ -0,0 +1,200 @@
+/*-
+ * Copyright (c) 2010 Department of Software Engineering,
+ *                   University of Szeged, Hungary
+ * Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu>
+ * Copyright (C) 2009 Zoltan Sogor <weth@inf.u-szeged.hu>
+ * Copyright (C) 2009 David Tengeri <dtengeri@inf.u-szeged.hu>
+ * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by the Department of Software Engineering, University of Szeged, Hungary
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef __CHFS_MEDIA_H__
+#define __CHFS_MEDIA_H__
+
+#ifndef _LE_TYPES
+#define _LE_TYPES
+typedef uint16_t le16;
+typedef uint32_t le32;
+typedef uint64_t le64;
+#endif
+
+/*****************************************************************************/
+/*                     File system specific structures                      */
+/*****************************************************************************/
+
+enum {
+       CHFS_NODETYPE_VNODE = 1,
+       CHFS_NODETYPE_DATA,
+       CHFS_NODETYPE_DIRENT,
+       CHFS_NODETYPE_PADDING,
+};
+
+//#define CHFS_NODE_HDR_SIZE 12 /* magic + type + length + hdr_crc */
+#define CHFS_NODE_HDR_SIZE sizeof(struct chfs_flash_node_hdr)
+
+/* Max size we have to read to get all info.
+ * It is max size of chfs_flash_dirent_node with max name length.
+ */
+#define CHFS_MAX_NODE_SIZE 299
+
+/* This will identify CHfs nodes */
+#define CHFS_FS_MAGIC_BITMASK 0x4AF1
+
+/**
+ * struct chfs_flash_node_hdr - node header, its members are same for
+ *                                 all nodes, used at scan
+ * @magic: filesystem magic
+ * @type: node type
+ * @length: length of node
+ * @hdr_crc: crc of the first 3 members
+ */
+struct chfs_flash_node_hdr
+{
+       le16 magic;
+       le16 type;
+       le32 length;
+       le32 hdr_crc;
+} __packed;
+
+/**
+ * struct chfs_flash_vnode - vnode informations stored on flash
+ * @magic: filesystem magic
+ * @type: node type (CHFS_NODETYPE_VNODE)
+ * @length: length of node
+ * @hdr_crc: crc of the first 3 members
+ * @vno: vnode identifier id
+ * @version: vnode's version number
+ * @uid: owner of the file
+ * @gid: group of file
+ * @mode: permissions for vnode
+ * @dn_size: size of written out data nodes
+ * @atime: last access times
+ * @mtime: last modification time
+ * @ctime: change time
+ * @dsize: size of the node's data
+ * @node_crc: crc of full node
+ */
+struct chfs_flash_vnode
+{
+       le16 magic;             /*0 */
+       le16 type;              /*2 */
+       le32 length;            /*4 */
+       le32 hdr_crc;           /*8 */
+       le64 vno;               /*12*/
+       le64 version;           /*20*/
+       le32 uid;               /*28*/
+       le32 gid;               /*32*/
+       le32 mode;              /*36*/
+       le32 dn_size;           /*40*/
+       le32 atime;             /*44*/
+       le32 mtime;             /*48*/
+       le32 ctime;             /*52*/
+       le32 dsize;             /*56*/
+       le32 node_crc;          /*60*/
+} __packed;
+
+/**
+ * struct chfs_flash_data_node - node informations of data stored on flash
+ * @magic: filesystem magic
+ * @type: node type (CHFS_NODETYPE_DATA)
+ * @length: length of node with data
+ * @hdr_crc: crc of the first 3 members
+ * @vno: vnode identifier id
+ * @version: vnode's version number
+ * @offset: offset in the file where write begins
+ * @data_length: length of data
+ * @data_crc: crc of data
+ * @node_crc: crc of full node
+ * @data: array of data
+ */
+struct chfs_flash_data_node
+{
+       le16 magic;
+       le16 type;
+       le32 length;
+       le32 hdr_crc;
+       le64 vno;
+       le64 version;
+       le64 offset;
+       le32 data_length;
+       le32 data_crc;
+       le32 node_crc;
+       uint8_t  data[0];
+} __packed;
+
+/**
+ * struct chfs_flash_dirent_node - vnode informations stored on flash
+ * @magic: filesystem magic
+ * @type: node type (CHFS_NODETYPE_DIRENT)
+ * @length: length of node
+ * @hdr_crc: crc of the first 3 members
+ * @vno: vnode identifier id
+ * @pvno: vnode identifier id of parent vnode
+ * @version: vnode's version number
+ * @mctime:
+ * @nsize: length of name
+ * @dtype: file type
+ * @unused: just for padding
+ * @name_crc: crc of name
+ * @node_crc: crc of full node
+ * @name: name of the directory entry
+ */
+struct chfs_flash_dirent_node
+{
+       le16 magic;
+       le16 type;
+       le32 length;
+       le32 hdr_crc;
+       le64 vno;
+       le64 pvno;
+       le64 version;
+       le32 mctime;
+       uint8_t nsize;
+       uint8_t dtype;
+       uint8_t unused[2];
+       le32 name_crc;
+       le32 node_crc;
+       uint8_t  name[0];
+} __packed;
+
+/**
+ * struct chfs_flash_padding_node - node informations of data stored on
+ *                                     flash
+ * @magic: filesystem magic
+ * @type: node type (CHFS_NODETYPE_PADDING)
+ * @length: length of node
+ * @hdr_crc: crc of the first 3 members
+ */
+struct chfs_flash_padding_node
+{
+       le16 magic;
+       le16 type;
+       le32 length;
+       le32 hdr_crc;
+} __packed;
+
+#endif /* __CHFS_MEDIA_H__ */
diff --git a/nbsd_include/ufs/ext2fs/ext2fs.h b/nbsd_include/ufs/ext2fs/ext2fs.h
new file mode 100644 (file)
index 0000000..6b994a2
--- /dev/null
@@ -0,0 +1,372 @@
+/*     $NetBSD: ext2fs.h,v 1.29 2009/11/27 11:16:54 tsutsui Exp $      */
+
+/*
+ * Copyright (c) 1982, 1986, 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.
+ *
+ *     @(#)fs.h        8.10 (Berkeley) 10/27/94
+ *  Modified for ext2fs by Manuel Bouyer.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *     @(#)fs.h        8.10 (Berkeley) 10/27/94
+ *  Modified for ext2fs by Manuel Bouyer.
+ */
+
+#ifndef _UFS_EXT2FS_EXT2FS_H_
+#define _UFS_EXT2FS_EXT2FS_H_
+
+#include <sys/bswap.h>
+
+/*
+ * Each disk drive contains some number of file systems.
+ * A file system consists of a number of cylinder groups.
+ * Each cylinder group has inodes and data.
+ *
+ * A file system is described by its super-block, which in turn
+ * describes the cylinder groups.  The super-block is critical
+ * data and is replicated in each cylinder group to protect against
+ * catastrophic loss.  This is done at `newfs' time and the critical
+ * super-block data does not change, so the copies need not be
+ * referenced further unless disaster strikes.
+ *
+ * The first boot and super blocks are given in absolute disk addresses.
+ * The byte-offset forms are preferred, as they don't imply a sector size.
+ */
+#define BBSIZE         1024
+#define SBSIZE         1024
+#define        BBOFF           ((off_t)(0))
+#define        SBOFF           ((off_t)(BBOFF + BBSIZE))
+#define        BBLOCK          ((daddr_t)(0))
+#define        SBLOCK          ((daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE))
+
+/*
+ * Addresses stored in inodes are capable of addressing blocks
+ * XXX
+ */
+
+/*
+ * MINBSIZE is the smallest allowable block size.
+ * MINBSIZE must be big enough to hold a cylinder group block,
+ * thus changes to (struct cg) must keep its size within MINBSIZE.
+ * Note that super blocks are always of size SBSIZE,
+ * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
+ */
+#define LOG_MINBSIZE   10
+#define MINBSIZE       (1 << LOG_MINBSIZE)
+
+/*
+ * The path name on which the file system is mounted is maintained
+ * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
+ * the super block for this name.
+ */
+#define MAXMNTLEN      512
+
+/*
+ * MINFREE gives the minimum acceptable percentage of file system
+ * blocks which may be free. If the freelist drops below this level
+ * only the superuser may continue to allocate blocks. This may
+ * be set to 0 if no reserve of free blocks is deemed necessary,
+ * however throughput drops by fifty percent if the file system
+ * is run at between 95% and 100% full; thus the minimum default
+ * value of fs_minfree is 5%. However, to get good clustering
+ * performance, 10% is a better choice. hence we use 10% as our
+ * default value. With 10% free space, fragmentation is not a
+ * problem, so we choose to optimize for time.
+ */
+#define MINFREE                5
+
+/*
+ * Super block for an ext2fs file system.
+ */
+struct ext2fs {
+       uint32_t  e2fs_icount;          /* Inode count */
+       uint32_t  e2fs_bcount;          /* blocks count */
+       uint32_t  e2fs_rbcount;         /* reserved blocks count */
+       uint32_t  e2fs_fbcount;         /* free blocks count */
+       uint32_t  e2fs_ficount;         /* free inodes count */
+       uint32_t  e2fs_first_dblock;    /* first data block */
+       uint32_t  e2fs_log_bsize;       /* block size = 1024*(2^e2fs_log_bsize) */
+       uint32_t  e2fs_fsize;           /* fragment size */
+       uint32_t  e2fs_bpg;             /* blocks per group */
+       uint32_t  e2fs_fpg;             /* frags per group */
+       uint32_t  e2fs_ipg;             /* inodes per group */
+       uint32_t  e2fs_mtime;           /* mount time */
+       uint32_t  e2fs_wtime;           /* write time */
+       uint16_t  e2fs_mnt_count;       /* mount count */
+       uint16_t  e2fs_max_mnt_count;   /* max mount count */
+       uint16_t  e2fs_magic;           /* magic number */
+       uint16_t  e2fs_state;           /* file system state */
+       uint16_t  e2fs_beh;             /* behavior on errors */
+       uint16_t  e2fs_minrev;          /* minor revision level */
+       uint32_t  e2fs_lastfsck;        /* time of last fsck */
+       uint32_t  e2fs_fsckintv;        /* max time between fscks */
+       uint32_t  e2fs_creator;         /* creator OS */
+       uint32_t  e2fs_rev;             /* revision level */
+       uint16_t  e2fs_ruid;            /* default uid for reserved blocks */
+       uint16_t  e2fs_rgid;            /* default gid for reserved blocks */
+       /* EXT2_DYNAMIC_REV superblocks */
+       uint32_t  e2fs_first_ino;       /* first non-reserved inode */
+       uint16_t  e2fs_inode_size;      /* size of inode structure */
+       uint16_t  e2fs_block_group_nr;  /* block grp number of this sblk*/
+       uint32_t  e2fs_features_compat; /*  compatible feature set */
+       uint32_t  e2fs_features_incompat; /* incompatible feature set */
+       uint32_t  e2fs_features_rocompat; /* RO-compatible feature set */
+       uint8_t   e2fs_uuid[16];        /* 128-bit uuid for volume */
+       char      e2fs_vname[16];       /* volume name */
+       char      e2fs_fsmnt[64];       /* name mounted on */
+       uint32_t  e2fs_algo;            /* For compression */
+       uint8_t   e2fs_prealloc;        /* # of blocks to preallocate */
+       uint8_t   e2fs_dir_prealloc;    /* # of blocks to preallocate for dir */
+       uint16_t  e2fs_reserved_ngdb;   /* # of reserved gd blocks for resize */
+       uint32_t  reserved2[204];
+};
+
+
+/* in-memory data for ext2fs */
+struct m_ext2fs {
+       struct ext2fs e2fs;
+       u_char  e2fs_fsmnt[MAXMNTLEN];  /* name mounted on */
+       int8_t  e2fs_ronly;     /* mounted read-only flag */
+       int8_t  e2fs_fmod;      /* super block modified flag */
+       int32_t e2fs_bsize;     /* block size */
+       int32_t e2fs_bshift;    /* ``lblkno'' calc of logical blkno */
+       int32_t e2fs_bmask;     /* ``blkoff'' calc of blk offsets */
+       int64_t e2fs_qbmask;    /* ~fs_bmask - for use with quad size */
+       int32_t e2fs_fsbtodb;   /* fsbtodb and dbtofsb shift constant */
+       int32_t e2fs_ncg;       /* number of cylinder groups */
+       int32_t e2fs_ngdb;      /* number of group descriptor block */
+       int32_t e2fs_ipb;       /* number of inodes per block */
+       int32_t e2fs_itpg;      /* number of inode table per group */
+       struct  ext2_gd *e2fs_gd; /* group descripors */
+};
+
+
+
+/*
+ * Filesystem identification
+ */
+#define        E2FS_MAGIC      0xef53  /* the ext2fs magic number */
+#define E2FS_REV0      0       /* GOOD_OLD revision */
+#define E2FS_REV1      1       /* Support compat/incompat features */
+
+/* compatible/incompatible features */
+#define EXT2F_COMPAT_PREALLOC          0x0001
+#define EXT2F_COMPAT_HASJOURNAL                0x0004
+#define EXT2F_COMPAT_RESIZE            0x0010
+
+#define EXT2F_ROCOMPAT_SPARSESUPER     0x0001
+#define EXT2F_ROCOMPAT_LARGEFILE       0x0002
+#define EXT2F_ROCOMPAT_BTREE_DIR       0x0004
+
+#define EXT2F_INCOMPAT_COMP            0x0001
+#define EXT2F_INCOMPAT_FTYPE           0x0002
+
+/*
+ * Features supported in this implementation
+ *
+ * We support the following REV1 features:
+ * - EXT2F_ROCOMPAT_SPARSESUPER
+ *    superblock backups stored only in cg_has_sb(bno) groups
+ * - EXT2F_ROCOMPAT_LARGEFILE
+ *    use e2di_dacl in struct ext2fs_dinode to store 
+ *    upper 32bit of size for >2GB files
+ * - EXT2F_INCOMPAT_FTYPE
+ *    store file type to e2d_type in struct ext2fs_direct
+ *    (on REV0 e2d_namlen is uint16_t and no e2d_type, like ffs)
+ */
+#define EXT2F_COMPAT_SUPP              0x0000
+#define EXT2F_ROCOMPAT_SUPP            (EXT2F_ROCOMPAT_SPARSESUPER \
+                                        | EXT2F_ROCOMPAT_LARGEFILE)
+#define EXT2F_INCOMPAT_SUPP            EXT2F_INCOMPAT_FTYPE
+
+/*
+ * Definitions of behavior on errors
+ */
+#define E2FS_BEH_CONTINUE      1       /* continue operation */
+#define E2FS_BEH_READONLY      2       /* remount fs read only */
+#define E2FS_BEH_PANIC         3       /* cause panic */
+#define E2FS_BEH_DEFAULT       E2FS_BEH_CONTINUE
+
+/*
+ * OS identification
+ */
+#define E2FS_OS_LINUX  0
+#define E2FS_OS_HURD   1
+#define E2FS_OS_MASIX  2
+#define E2FS_OS_FREEBSD        3
+#define E2FS_OS_LITES  4
+
+/*
+ * Filesystem clean flags
+ */
+#define        E2FS_ISCLEAN    0x01
+#define        E2FS_ERRORS     0x02
+
+/* ext2 file system block group descriptor */
+
+struct ext2_gd {
+       uint32_t ext2bgd_b_bitmap;      /* blocks bitmap block */
+       uint32_t ext2bgd_i_bitmap;      /* inodes bitmap block */
+       uint32_t ext2bgd_i_tables;      /* inodes table block  */
+       uint16_t ext2bgd_nbfree;        /* number of free blocks */
+       uint16_t ext2bgd_nifree;        /* number of free inodes */
+       uint16_t ext2bgd_ndirs;         /* number of directories */
+       uint16_t reserved;
+       uint32_t reserved2[3];
+};
+
+
+/*
+ * If the EXT2F_ROCOMPAT_SPARSESUPER flag is set, the cylinder group has a
+ * copy of the super and cylinder group descriptors blocks only if it's
+ * 1, a power of 3, 5 or 7
+ */
+
+static __inline int cg_has_sb(int) __unused;
+static __inline int
+cg_has_sb(int i)
+{
+       int a3, a5, a7;
+
+       if (i == 0 || i == 1)
+               return 1;
+       for (a3 = 3, a5 = 5, a7 = 7;
+           a3 <= i || a5 <= i || a7 <= i;
+           a3 *= 3, a5 *= 5, a7 *= 7)
+               if (i == a3 || i == a5 || i == a7)
+                       return 1;
+       return 0;
+}
+
+/* EXT2FS metadatas are stored in little-endian byte order. These macros
+ * helps reading theses metadatas
+ */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#      define h2fs16(x) (x)
+#      define h2fs32(x) (x)
+#      define h2fs64(x) (x)
+#      define fs2h16(x) (x)
+#      define fs2h32(x) (x)
+#      define fs2h64(x) (x)
+#      define e2fs_sbload(old, new) memcpy((new), (old), SBSIZE);
+#      define e2fs_cgload(old, new, size) memcpy((new), (old), (size));
+#      define e2fs_sbsave(old, new) memcpy((new), (old), SBSIZE);
+#      define e2fs_cgsave(old, new, size) memcpy((new), (old), (size));
+#else
+void e2fs_sb_bswap(struct ext2fs *, struct ext2fs *);
+void e2fs_cg_bswap(struct ext2_gd *, struct ext2_gd *, int);
+#      define h2fs16(x) bswap16(x)
+#      define h2fs32(x) bswap32(x)
+#      define h2fs64(x) bswap64(x)
+#      define fs2h16(x) bswap16(x)
+#      define fs2h32(x) bswap32(x)
+#      define fs2h64(x) bswap64(x)
+#      define e2fs_sbload(old, new) e2fs_sb_bswap((old), (new))
+#      define e2fs_cgload(old, new, size) e2fs_cg_bswap((old), (new), (size));
+#      define e2fs_sbsave(old, new) e2fs_sb_bswap((old), (new))
+#      define e2fs_cgsave(old, new, size) e2fs_cg_bswap((old), (new), (size));
+#endif
+
+/*
+ * Turn file system block numbers into disk block addresses.
+ * This maps file system blocks to device size blocks.
+ */
+#define fsbtodb(fs, b) ((b) << (fs)->e2fs_fsbtodb)
+#define dbtofsb(fs, b) ((b) >> (fs)->e2fs_fsbtodb)
+
+/*
+ * Macros for handling inode numbers:
+ *      inode number to file system block offset.
+ *      inode number to cylinder group number.
+ *      inode number to file system block address.
+ */
+#define        ino_to_cg(fs, x)        (((x) - 1) / (fs)->e2fs.e2fs_ipg)
+#define        ino_to_fsba(fs, x)                                              \
+       ((fs)->e2fs_gd[ino_to_cg((fs), (x))].ext2bgd_i_tables +         \
+       (((x) - 1) % (fs)->e2fs.e2fs_ipg) / (fs)->e2fs_ipb)
+#define        ino_to_fsbo(fs, x)      (((x) - 1) % (fs)->e2fs_ipb)
+
+/*
+ * Give cylinder group number for a file system block.
+ * Give cylinder group block number for a file system block.
+ */
+#define        dtog(fs, d) (((d) - (fs)->e2fs.e2fs_first_dblock) / (fs)->e2fs.e2fs_fpg)
+#define        dtogd(fs, d) \
+       (((d) - (fs)->e2fs.e2fs_first_dblock) % (fs)->e2fs.e2fs_fpg)
+
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define blkoff(fs, loc)                /* calculates (loc % fs->e2fs_bsize) */ \
+       ((loc) & (fs)->e2fs_qbmask)
+#define lblktosize(fs, blk)    /* calculates (blk * fs->e2fs_bsize) */ \
+       ((blk) << (fs)->e2fs_bshift)
+#define lblkno(fs, loc)                /* calculates (loc / fs->e2fs_bsize) */ \
+       ((loc) >> (fs)->e2fs_bshift)
+#define blkroundup(fs, size)   /* calculates roundup(size, fs->e2fs_bsize) */ \
+       (((size) + (fs)->e2fs_qbmask) & (fs)->e2fs_bmask)
+#define fragroundup(fs, size)  /* calculates roundup(size, fs->e2fs_bsize) */ \
+       (((size) + (fs)->e2fs_qbmask) & (fs)->e2fs_bmask)
+/*
+ * Determine the number of available frags given a
+ * percentage to hold in reserve.
+ */
+#define freespace(fs) \
+   ((fs)->e2fs.e2fs_fbcount - (fs)->e2fs.e2fs_rbcount)
+
+/*
+ * Number of indirects in a file system block.
+ */
+#define        NINDIR(fs)      ((fs)->e2fs_bsize / sizeof(uint32_t))
+
+#endif /* !_UFS_EXT2FS_EXT2FS_H_ */
diff --git a/nbsd_include/ufs/ext2fs/ext2fs_dinode.h b/nbsd_include/ufs/ext2fs/ext2fs_dinode.h
new file mode 100644 (file)
index 0000000..0020e9a
--- /dev/null
@@ -0,0 +1,186 @@
+/*     $NetBSD: ext2fs_dinode.h,v 1.22 2009/11/27 11:16:54 tsutsui Exp $       */
+
+/*
+ * Copyright (c) 1982, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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.
+ *
+ *     @(#)dinode.h    8.6 (Berkeley) 9/13/94
+ *  Modified for ext2fs by Manuel Bouyer.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *     @(#)dinode.h    8.6 (Berkeley) 9/13/94
+ *  Modified for ext2fs by Manuel Bouyer.
+ */
+
+#ifndef _UFS_EXT2FS_EXT2FS_DINODE_H_
+#define _UFS_EXT2FS_EXT2FS_DINODE_H_
+
+#include <sys/stat.h>
+
+/*
+ * The root inode is the root of the file system.  Inode 0 can't be used for
+ * normal purposes and bad blocks are normally linked to inode 1, thus
+ * the root inode is 2.
+ * Inode 3 to 10 are reserved in ext2fs.
+ */
+#define        EXT2_BADBLKINO          ((ino_t)1)
+#define        EXT2_ROOTINO            ((ino_t)2)
+#define        EXT2_ACLIDXINO          ((ino_t)3)
+#define        EXT2_ACLDATAINO         ((ino_t)4)
+#define        EXT2_BOOTLOADERINO      ((ino_t)5)
+#define        EXT2_UNDELDIRINO        ((ino_t)6)
+#define        EXT2_RESIZEINO          ((ino_t)7)
+#define        EXT2_JOURNALINO         ((ino_t)8)
+#define        EXT2_FIRSTINO           ((ino_t)11)
+
+/*
+ * A dinode contains all the meta-data associated with a UFS file.
+ * This structure defines the on-disk format of a dinode. Since
+ * this structure describes an on-disk structure, all its fields
+ * are defined by types with precise widths.
+ */
+
+#define        NDADDR  12                      /* Direct addresses in inode. */
+#define        NIADDR  3                       /* Indirect addresses in inode. */
+
+#define EXT2_MAXSYMLINKLEN ((NDADDR+NIADDR) * sizeof (uint32_t))
+
+struct ext2fs_dinode {
+       uint16_t        e2di_mode;      /*   0: IFMT, permissions; see below. */
+       uint16_t        e2di_uid;       /*   2: Owner UID */
+       uint32_t        e2di_size;      /*       4: Size (in bytes) */
+       uint32_t        e2di_atime;     /*       8: Acces time */
+       uint32_t        e2di_ctime;     /*      12: Create time */
+       uint32_t        e2di_mtime;     /*      16: Modification time */
+       uint32_t        e2di_dtime;     /*      20: Deletion time */
+       uint16_t        e2di_gid;       /*  24: Owner GID */
+       uint16_t        e2di_nlink;     /*  26: File link count */
+       uint32_t        e2di_nblock;    /*  28: Blocks count */
+       uint32_t        e2di_flags;     /*  32: Status flags (chflags) */
+       uint32_t        e2di_linux_reserved1; /* 36 */
+       uint32_t        e2di_blocks[NDADDR+NIADDR]; /* 40: disk blocks */
+       uint32_t        e2di_gen;       /* 100: generation number */
+       uint32_t        e2di_facl;      /* 104: file ACL (not implemented) */
+       uint32_t        e2di_dacl;      /* 108: dir ACL (not implemented) */
+       uint32_t        e2di_faddr;     /* 112: fragment address */
+       uint8_t         e2di_nfrag;     /* 116: fragment number */
+       uint8_t         e2di_fsize;     /* 117: fragment size */
+       uint16_t        e2di_linux_reserved2; /* 118 */
+       uint16_t        e2di_uid_high;  /* 120: Owner UID top 16 bits */
+       uint16_t        e2di_gid_high;  /* 122: Owner GID top 16 bits */
+       uint32_t        e2di_linux_reserved3; /* 124 */
+};
+
+
+
+#define        E2MAXSYMLINKLEN ((NDADDR + NIADDR) * sizeof(uint32_t))
+
+/* File permissions. */
+#define        EXT2_IEXEC              0000100         /* Executable. */
+#define        EXT2_IWRITE             0000200         /* Writable. */
+#define        EXT2_IREAD              0000400         /* Readable. */
+#define        EXT2_ISVTX              0001000         /* Sticky bit. */
+#define        EXT2_ISGID              0002000         /* Set-gid. */
+#define        EXT2_ISUID              0004000         /* Set-uid. */
+
+/* File types. */
+#define        EXT2_IFMT               0170000         /* Mask of file type. */
+#define        EXT2_IFIFO              0010000         /* Named pipe (fifo). */
+#define        EXT2_IFCHR              0020000         /* Character device. */
+#define        EXT2_IFDIR              0040000         /* Directory file. */
+#define        EXT2_IFBLK              0060000         /* Block device. */
+#define        EXT2_IFREG              0100000         /* Regular file. */
+#define        EXT2_IFLNK              0120000         /* Symbolic link. */
+#define        EXT2_IFSOCK             0140000         /* UNIX domain socket. */
+
+/* file flags */
+#define EXT2_SECRM             0x00000001      /* Secure deletion */
+#define EXT2_UNRM              0x00000002      /* Undelete */
+#define EXT2_COMPR             0x00000004      /* Compress file */
+#define EXT2_SYNC              0x00000008      /* Synchronous updates */
+#define EXT2_IMMUTABLE         0x00000010      /* Immutable file */
+#define EXT2_APPEND            0x00000020 /* writes to file may only append */
+#define EXT2_NODUMP            0x00000040      /* do not dump file */
+
+/* Size of on-disk inode. */
+#define EXT2_REV0_DINODE_SIZE  sizeof(struct ext2fs_dinode)
+#define EXT2_DINODE_SIZE(fs)   ((fs)->e2fs.e2fs_rev > E2FS_REV0 ?      \
+                                   (fs)->e2fs.e2fs_inode_size :        \
+                                   EXT2_REV0_DINODE_SIZE)
+
+/*
+ * The e2di_blocks fields may be overlaid with other information for
+ * file types that do not have associated disk storage. Block
+ * and character devices overlay the first data block with their
+ * dev_t value. Short symbolic links place their path in the
+ * di_db area.
+ */
+
+#define e2di_rdev              e2di_blocks[0]
+#define e2di_shortlink         e2di_blocks
+
+/* e2fs needs byte swapping on big-endian systems */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#      define e2fs_iload(old, new)     \
+               memcpy((new),(old),sizeof(struct ext2fs_dinode))
+#      define e2fs_isave(old, new)     \
+               memcpy((new),(old),sizeof(struct ext2fs_dinode))
+#else
+void e2fs_i_bswap(struct ext2fs_dinode *, struct ext2fs_dinode *);
+#      define e2fs_iload(old, new) e2fs_i_bswap((old), (new))
+#      define e2fs_isave(old, new) e2fs_i_bswap((old), (new))
+#endif
+
+#endif /* !_UFS_EXT2FS_EXT2FS_DINODE_H_ */
diff --git a/nbsd_include/ufs/ext2fs/ext2fs_dir.h b/nbsd_include/ufs/ext2fs/ext2fs_dir.h
new file mode 100644 (file)
index 0000000..e1dc152
--- /dev/null
@@ -0,0 +1,180 @@
+/*     $NetBSD: ext2fs_dir.h,v 1.18 2009/10/19 18:41:17 bouyer Exp $   */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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.
+ *
+ *     @(#)dir.h       8.4 (Berkeley) 8/10/94
+ * Modified for ext2fs by Manuel Bouyer.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *     @(#)dir.h       8.4 (Berkeley) 8/10/94
+ * Modified for ext2fs by Manuel Bouyer.
+ */
+
+#ifndef _UFS_EXT2FS_EXT2FS_DIR_H_
+#define        _UFS_EXT2FS_EXT2FS_DIR_H_
+
+/*
+ * Theoretically, directories can be more than 2Gb in length, however, in
+ * practice this seems unlikely. So, we define the type doff_t as a 32-bit
+ * quantity to keep down the cost of doing lookup on a 32-bit machine.
+ */
+#define        doff_t                  int32_t
+#define        EXT2FS_MAXDIRSIZE       INT32_MAX
+
+/*
+ * A directory consists of some number of blocks of e2fs_bsize bytes.
+ *
+ * Each block contains some number of directory entry
+ * structures, which are of variable length.  Each directory entry has
+ * a struct direct at the front of it, containing its inode number,
+ * the length of the entry, and the length of the name contained in
+ * the entry.  These are followed by the name padded to a 4 byte boundary
+ * with null bytes.  All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is EXT2FS_MAXNAMLEN.
+ *
+ * The macro EXT2FS_DIRSIZ(fmt, dp) gives the amount of space required to
+ * represent a directory entry.  Free space in a directory is represented by
+ * entries which have dp->e2d_reclen > DIRSIZ(fmt, dp).  All d2fs_bsize bytes
+ * in a directory block are claimed by the directory entries.  This
+ * usually results in the last entry in a directory having a large
+ * dp->e2d_reclen.  When entries are deleted from a directory, the
+ * space is returned to the previous entry in the same directory
+ * block by increasing its dp->e2d_reclen.  If the first entry of
+ * a directory block is free, then its dp->e2d_ino is set to 0.
+ * Entries other than the first in a directory do not normally have
+ * dp->e2d_ino set to 0.
+ * Ext2 rev 0 has a 16 bits e2d_namlen. For Ext2 vev 1 this has been split
+ * into a 8 bits e2d_namlen and 8 bits e2d_type (looks like ffs, isnt't it ? :)
+ * It's safe to use this for rev 0 as well because all ext2 are little-endian.
+ */
+
+#define        EXT2FS_MAXNAMLEN        255
+
+struct ext2fs_direct {
+       uint32_t e2d_ino;               /* inode number of entry */
+       uint16_t e2d_reclen;            /* length of this record */
+       uint8_t e2d_namlen;             /* length of string in d_name */
+       uint8_t e2d_type;               /* file type */
+       char e2d_name[EXT2FS_MAXNAMLEN];/* name with length<=EXT2FS_MAXNAMLEN */
+};
+
+/* Ext2 directory file types (not the same as FFS. Sigh.) */
+#define EXT2_FT_UNKNOWN         0
+#define EXT2_FT_REG_FILE        1
+#define EXT2_FT_DIR             2
+#define EXT2_FT_CHRDEV          3
+#define EXT2_FT_BLKDEV          4
+#define EXT2_FT_FIFO            5
+#define EXT2_FT_SOCK            6
+#define EXT2_FT_SYMLINK         7
+
+#define EXT2_FT_MAX             8
+
+#define E2IFTODT(mode)    (((mode) & 0170000) >> 12)
+
+static __inline uint8_t inot2ext2dt(uint16_t) __unused;
+static __inline uint8_t
+inot2ext2dt(uint16_t type)
+{
+
+       switch (type) {
+       case E2IFTODT(EXT2_IFIFO):
+               return EXT2_FT_FIFO;
+       case E2IFTODT(EXT2_IFCHR):
+               return EXT2_FT_CHRDEV;
+       case E2IFTODT(EXT2_IFDIR):
+               return EXT2_FT_DIR;
+       case E2IFTODT(EXT2_IFBLK):
+               return EXT2_FT_BLKDEV;
+       case E2IFTODT(EXT2_IFREG):
+               return EXT2_FT_REG_FILE;
+       case E2IFTODT(EXT2_IFLNK):
+               return EXT2_FT_SYMLINK;
+       case E2IFTODT(EXT2_IFSOCK):
+               return EXT2_FT_SOCK;
+       default:
+               return 0;
+       }
+}
+
+/*
+ * The EXT2FS_DIRSIZ macro gives the minimum record length which will hold
+ * the directory entryfor a name len "len" (without the terminating null byte).
+ * This requires the amount of space in struct direct
+ * without the d_name field, plus enough space for the name without a
+ * terminating null byte, rounded up to a 4 byte boundary.
+ */
+#define EXT2FS_DIRSIZ(len)     roundup2(8 + len, 4)
+
+/*
+ * Template for manipulating directories.  Should use struct direct's,
+ * but the name field is EXT2FS_MAXNAMLEN - 1, and this just won't do.
+ */
+struct ext2fs_dirtemplate {
+       uint32_t        dot_ino;
+       int16_t         dot_reclen;
+       uint8_t         dot_namlen;
+       uint8_t         dot_type;
+       char            dot_name[4];    /* must be multiple of 4 */
+       uint32_t        dotdot_ino;
+       int16_t         dotdot_reclen;
+       uint8_t         dotdot_namlen;
+       uint8_t         dotdot_type;
+       char            dotdot_name[4]; /* ditto */
+};
+
+#endif /* !_UFS_EXT2FS_EXT2FS_DIR_H_ */
diff --git a/nbsd_include/ufs/ext2fs/ext2fs_extern.h b/nbsd_include/ufs/ext2fs/ext2fs_extern.h
new file mode 100644 (file)
index 0000000..aacff80
--- /dev/null
@@ -0,0 +1,179 @@
+/*     $NetBSD: ext2fs_extern.h,v 1.43 2011/07/12 16:59:48 dholland Exp $      */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *     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.
+ *
+ *     @(#)ffs_extern.h        8.3 (Berkeley) 4/16/94
+ * Modified for ext2fs by Manuel Bouyer.
+ */
+
+/*-
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *     @(#)ffs_extern.h        8.3 (Berkeley) 4/16/94
+ * Modified for ext2fs by Manuel Bouyer.
+ */
+
+#ifndef _UFS_EXT2FS_EXT2FS_EXTERN_H_
+#define _UFS_EXT2FS_EXT2FS_EXTERN_H_
+
+struct buf;
+struct fid;
+struct m_ext2fs;
+struct inode;
+struct mount;
+struct nameidata;
+struct lwp;
+struct proc;
+struct statvfs;
+struct timeval;
+struct ufsmount;
+struct uio;
+struct vnode;
+struct mbuf;
+struct componentname;
+
+extern struct pool ext2fs_inode_pool;          /* memory pool for inodes */
+extern struct pool ext2fs_dinode_pool;         /* memory pool for dinodes */
+
+#define        EXT2FS_ITIMES(ip, acc, mod, cre) \
+       while ((ip)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY)) \
+               ext2fs_itimes(ip, acc, mod, cre)
+
+__BEGIN_DECLS
+
+/* ext2fs_alloc.c */
+int ext2fs_alloc(struct inode *, daddr_t, daddr_t , kauth_cred_t,
+                  daddr_t *);
+int ext2fs_realloccg(struct inode *, daddr_t, daddr_t, int, int ,
+                         kauth_cred_t, struct buf **);
+int ext2fs_valloc(struct vnode *, int, kauth_cred_t, struct vnode **);
+/* XXX ondisk32 */
+daddr_t ext2fs_blkpref(struct inode *, daddr_t, int, int32_t *);
+void ext2fs_blkfree(struct inode *, daddr_t);
+int ext2fs_vfree(struct vnode *, ino_t, int);
+
+/* ext2fs_balloc.c */
+int ext2fs_balloc(struct inode *, daddr_t, int, kauth_cred_t,
+                       struct buf **, int);
+int ext2fs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
+
+/* ext2fs_bmap.c */
+int ext2fs_bmap(void *);
+
+/* ext2fs_inode.c */
+u_int64_t ext2fs_size(struct inode *);
+int ext2fs_setsize(struct inode *, u_int64_t);
+int ext2fs_update(struct vnode *, const struct timespec *,
+    const struct timespec *, int);
+int ext2fs_truncate(struct vnode *, off_t, int, kauth_cred_t);
+int ext2fs_inactive(void *);
+
+/* ext2fs_lookup.c */
+int ext2fs_readdir(void *);
+int ext2fs_lookup(void *);
+int ext2fs_direnter(struct inode *, struct vnode *,
+                        const struct ufs_lookup_results *,
+                        struct componentname *);
+int ext2fs_dirremove(struct vnode *, const struct ufs_lookup_results *,
+                    struct componentname *);
+int ext2fs_dirrewrite(struct inode *, const struct ufs_lookup_results *,
+                          struct inode *, struct componentname *);
+int ext2fs_dirempty(struct inode *, ino_t, kauth_cred_t);
+int ext2fs_checkpath(struct inode *, struct inode *, kauth_cred_t);
+
+/* ext2fs_subr.c */
+int ext2fs_blkatoff(struct vnode *, off_t, char **, struct buf **);
+void ext2fs_fragacct(struct m_ext2fs *, int, int32_t[], int);
+void ext2fs_itimes(struct inode *, const struct timespec *,
+    const struct timespec *, const struct timespec *);
+
+/* ext2fs_vfsops.c */
+VFS_PROTOS(ext2fs);
+int ext2fs_reload(struct mount *, kauth_cred_t, struct lwp *);
+int ext2fs_mountfs(struct vnode *, struct mount *);
+int ext2fs_flushfiles(struct mount *, int);
+int ext2fs_sbupdate(struct ufsmount *, int);
+int ext2fs_cgupdate(struct ufsmount *, int);
+void ext2fs_set_inode_guid(struct inode *);
+
+/* ext2fs_readwrite.c */
+int ext2fs_read(void *);
+int ext2fs_write(void *);
+
+/* ext2fs_vnops.c */
+int ext2fs_create(void *);
+int ext2fs_mknod(void *);
+int ext2fs_open(void *);
+int ext2fs_access(void *);
+int ext2fs_getattr(void *);
+int ext2fs_setattr(void *);
+int ext2fs_remove(void *);
+int ext2fs_link(void *);
+int ext2fs_rename(void *);
+int ext2fs_mkdir(void *);
+int ext2fs_rmdir(void *);
+int ext2fs_symlink(void *);
+int ext2fs_readlink(void *);
+int ext2fs_advlock(void *);
+int ext2fs_fsync(void *);
+int ext2fs_vinit(struct mount *, int (**specops)(void *),
+                     int (**fifoops)(void *), struct vnode **);
+int ext2fs_makeinode(int, struct vnode *, struct vnode **,
+                         struct componentname *cnp);
+int ext2fs_reclaim(void *);
+
+__END_DECLS
+
+#define IS_EXT2_VNODE(vp)   (vp->v_tag == VT_EXT2FS)
+
+extern int (**ext2fs_vnodeop_p)(void *);
+extern int (**ext2fs_specop_p)(void *);
+extern int (**ext2fs_fifoop_p)(void *);
+
+#endif /* !_UFS_EXT2FS_EXT2FS_EXTERN_H_ */
diff --git a/nbsd_include/ufs/ffs/ffs_extern.h b/nbsd_include/ufs/ffs/ffs_extern.h
new file mode 100644 (file)
index 0000000..c46631b
--- /dev/null
@@ -0,0 +1,211 @@
+/*     $NetBSD: ffs_extern.h,v 1.78 2011/06/17 14:23:52 manu Exp $     */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *     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.
+ *
+ *     @(#)ffs_extern.h        8.6 (Berkeley) 3/30/95
+ */
+
+#ifndef _UFS_FFS_FFS_EXTERN_H_
+#define _UFS_FFS_FFS_EXTERN_H_
+
+/*
+ * Sysctl values for the fast filesystem.
+ */
+#define FFS_CLUSTERREAD                1       /* cluster reading enabled */
+#define FFS_CLUSTERWRITE       2       /* cluster writing enabled */
+#define FFS_REALLOCBLKS                3       /* block reallocation enabled */
+#define FFS_ASYNCFREE          4       /* asynchronous block freeing enabled */
+#define FFS_LOG_CHANGEOPT      5       /* log optimalization strategy change */
+#define FFS_EXTATTR_AUTOCREATE 6       /* size for backing file autocreation */
+#define FFS_MAXID              7       /* number of valid ffs ids */
+
+struct buf;
+struct fid;
+struct fs;
+struct inode;
+struct ufs1_dinode;
+struct ufs2_dinode;
+struct mount;
+struct nameidata;
+struct lwp;
+struct statvfs;
+struct timeval;
+struct timespec;
+struct ufsmount;
+struct uio;
+struct vnode;
+struct mbuf;
+struct cg;
+
+#if defined(_KERNEL)
+
+#include <sys/pool.h>
+
+#define FFS_NOBLK              ((daddr_t)-1)
+
+#define        FFS_ITIMES(ip, acc, mod, cre) \
+       while ((ip)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY)) \
+               ffs_itimes(ip, acc, mod, cre)
+
+extern pool_cache_t ffs_inode_cache;   /* memory pool for inodes */
+extern pool_cache_t ffs_dinode1_cache; /* memory pool for UFS1 dinodes */
+extern pool_cache_t ffs_dinode2_cache; /* memory pool for UFS2 dinodes */
+
+#endif /* defined(_KERNEL) */
+
+__BEGIN_DECLS
+
+#if defined(_KERNEL)
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/wapbl.h>
+
+/* ffs_alloc.c */
+int    ffs_alloc(struct inode *, daddr_t, daddr_t , int, int, kauth_cred_t,
+                 daddr_t *);
+int    ffs_realloccg(struct inode *, daddr_t, daddr_t, int, int ,
+                     kauth_cred_t, struct buf **, daddr_t *);
+int    ffs_valloc(struct vnode *, int, kauth_cred_t, struct vnode **);
+daddr_t        ffs_blkpref_ufs1(struct inode *, daddr_t, int, int, int32_t *);
+daddr_t        ffs_blkpref_ufs2(struct inode *, daddr_t, int, int, int64_t *);
+int    ffs_blkalloc(struct inode *, daddr_t, long);
+int    ffs_blkalloc_ump(struct ufsmount *, daddr_t, long);
+void   ffs_blkfree(struct fs *, struct vnode *, daddr_t, long, ino_t);
+void   ffs_blkfree_snap(struct fs *, struct vnode *, daddr_t, long, ino_t);
+int    ffs_vfree(struct vnode *, ino_t, int);
+int    ffs_checkfreefile(struct fs *, struct vnode *, ino_t);
+int    ffs_freefile(struct mount *, ino_t, int);
+int    ffs_freefile_snap(struct fs *, struct vnode *, ino_t, int);
+
+/* ffs_balloc.c */
+int    ffs_balloc(struct vnode *, off_t, int, kauth_cred_t, int,
+    struct buf **);
+
+/* ffs_inode.c */
+int    ffs_update(struct vnode *, const struct timespec *,
+    const struct timespec *, int);
+int    ffs_truncate(struct vnode *, off_t, int, kauth_cred_t);
+
+/* ffs_vfsops.c */
+VFS_PROTOS(ffs);
+
+int     ffs_reload(struct mount *, kauth_cred_t, struct lwp *);
+int     ffs_mountfs(struct vnode *, struct mount *, struct lwp *);
+int    ffs_flushfiles(struct mount *, int, struct lwp *);
+int    ffs_sbupdate(struct ufsmount *, int);
+int    ffs_cgupdate(struct ufsmount *, int);
+
+/* ffs_vnops.c */
+int    ffs_read(void *);
+int    ffs_write(void *);
+int    ffs_fsync(void *);
+int    ffs_spec_fsync(void *);
+int    ffs_reclaim(void *);
+int    ffs_getpages(void *);
+void   ffs_gop_size(struct vnode *, off_t, off_t *, int);
+int    ffs_openextattr(void *);
+int    ffs_closeextattr(void *);
+int    ffs_getextattr(void *);
+int    ffs_setextattr(void *);
+int    ffs_listextattr(void *);
+int    ffs_deleteextattr(void *);
+int    ffs_lock(void *);
+int    ffs_unlock(void *);
+int    ffs_islocked(void *);
+int    ffs_full_fsync(struct vnode *, int);
+
+/*
+ * Snapshot function prototypes.
+ */
+int    ffs_snapshot_init(struct ufsmount *);
+void   ffs_snapshot_fini(struct ufsmount *);
+int    ffs_snapblkfree(struct fs *, struct vnode *, daddr_t, long, ino_t);
+void   ffs_snapremove(struct vnode *);
+int    ffs_snapshot(struct mount *, struct vnode *, struct timespec *);
+void   ffs_snapshot_mount(struct mount *);
+void   ffs_snapshot_unmount(struct mount *);
+void   ffs_snapgone(struct inode *);
+int    ffs_snapshot_read(struct vnode *, struct uio *, int);
+
+/* Write Ahead Physical Block Logging */
+void   ffs_wapbl_verify_inodes(struct mount *, const char *);
+void   ffs_wapbl_replay_finish(struct mount *);
+int    ffs_wapbl_start(struct mount *);
+int    ffs_wapbl_stop(struct mount *, int);
+int    ffs_wapbl_replay_start(struct mount *, struct fs *, struct vnode *);
+void   ffs_wapbl_blkalloc(struct fs *, struct vnode *, daddr_t, int);
+
+void   ffs_wapbl_sync_metadata(struct mount *, daddr_t *, int *, int);
+void   ffs_wapbl_abort_sync_metadata(struct mount *, daddr_t *, int *, int);
+
+extern int (**ffs_vnodeop_p)(void *);
+extern int (**ffs_specop_p)(void *);
+extern int (**ffs_fifoop_p)(void *);
+
+#endif /* defined(_KERNEL) */
+
+/* ffs_appleufs.c */
+struct appleufslabel;
+u_int16_t ffs_appleufs_cksum(const struct appleufslabel *);
+int    ffs_appleufs_validate(const char*, const struct appleufslabel *,
+                             struct appleufslabel *);
+void   ffs_appleufs_set(struct appleufslabel *, const char *, time_t,
+                        uint64_t);
+
+/* ffs_bswap.c */
+void   ffs_sb_swap(struct fs*, struct fs *);
+void   ffs_dinode1_swap(struct ufs1_dinode *, struct ufs1_dinode *);
+void   ffs_dinode2_swap(struct ufs2_dinode *, struct ufs2_dinode *);
+struct csum;
+void   ffs_csum_swap(struct csum *, struct csum *, int);
+struct csum_total;
+void   ffs_csumtotal_swap(struct csum_total *, struct csum_total *);
+void   ffs_cg_swap(struct cg *, struct cg *, struct fs *);
+
+/* ffs_subr.c */
+#if defined(_KERNEL)
+void   ffs_load_inode(struct buf *, struct inode *, struct fs *, ino_t);
+int    ffs_getblk(struct vnode *, daddr_t, daddr_t, int, bool, buf_t **);
+#endif /* defined(_KERNEL) */
+void   ffs_fragacct(struct fs *, int, int32_t[], int, int);
+int    ffs_isblock(struct fs *, u_char *, int32_t);
+int    ffs_isfreeblock(struct fs *, u_char *, int32_t);
+void   ffs_clrblock(struct fs *, u_char *, int32_t);
+void   ffs_setblock(struct fs *, u_char *, int32_t);
+void   ffs_itimes(struct inode *, const struct timespec *,
+    const struct timespec *, const struct timespec *);
+void   ffs_clusteracct(struct fs *, struct cg *, int32_t, int);
+
+/* ffs_quota2.c */
+int    ffs_quota2_mount(struct mount *);
+
+__END_DECLS
+
+#endif /* !_UFS_FFS_FFS_EXTERN_H_ */
diff --git a/nbsd_include/ufs/ffs/fs.h b/nbsd_include/ufs/ffs/fs.h
new file mode 100644 (file)
index 0000000..7e5af7c
--- /dev/null
@@ -0,0 +1,752 @@
+/*     $NetBSD: fs.h,v 1.56 2011/03/06 17:08:38 bouyer Exp $   */
+
+/*
+ * Copyright (c) 1982, 1986, 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.
+ *
+ *     @(#)fs.h        8.13 (Berkeley) 3/21/95
+ */
+
+/*
+ * NOTE: COORDINATE ON-DISK FORMAT CHANGES WITH THE FREEBSD PROJECT.
+ */
+
+#ifndef        _UFS_FFS_FS_H_
+#define        _UFS_FFS_FS_H_
+
+/*
+ * Each disk drive contains some number of file systems.
+ * A file system consists of a number of cylinder groups.
+ * Each cylinder group has inodes and data.
+ *
+ * A file system is described by its super-block, which in turn
+ * describes the cylinder groups.  The super-block is critical
+ * data and is replicated in each cylinder group to protect against
+ * catastrophic loss.  This is done at `newfs' time and the critical
+ * super-block data does not change, so the copies need not be
+ * referenced further unless disaster strikes.
+ *
+ * For file system fs, the offsets of the various blocks of interest
+ * are given in the super block as:
+ *     [fs->fs_sblkno]         Super-block
+ *     [fs->fs_cblkno]         Cylinder group block
+ *     [fs->fs_iblkno]         Inode blocks
+ *     [fs->fs_dblkno]         Data blocks
+ * The beginning of cylinder group cg in fs, is given by
+ * the ``cgbase(fs, cg)'' macro.
+ *
+ * Depending on the architecture and the media, the superblock may
+ * reside in any one of four places. For tiny media where every block
+ * counts, it is placed at the very front of the partition. Historically,
+ * UFS1 placed it 8K from the front to leave room for the disk label and
+ * a small bootstrap. For UFS2 it got moved to 64K from the front to leave
+ * room for the disk label and a bigger bootstrap, and for really piggy
+ * systems we check at 256K from the front if the first three fail. In
+ * all cases the size of the superblock will be SBLOCKSIZE. All values are
+ * given in byte-offset form, so they do not imply a sector size. The
+ * SBLOCKSEARCH specifies the order in which the locations should be searched.
+ *
+ * Unfortunately the UFS2/FFSv2 change was done without adequate consideration
+ * of backward compatibility.  In particular 'newfs' for a FFSv2 partition
+ * must overwrite any old FFSv1 superblock at 8k, and preferrably as many
+ * of the alternates as it can find - otherwise attempting to mount on a
+ * system that only supports FFSv1 is likely to succeed!.
+ * For a small FFSv1 filesystem, an old FFSv2 superblock can be left on
+ * the disk, and a system that tries to find an FFSv2 filesystem in preference
+ * to and FFSv1 one (as NetBSD does) can mount the old FFSv2 filesystem.
+ * As a added bonus, the 'first alternate' superblock of a FFSv1 filesystem
+ * with 64k blocks is at 64k - just where the code looks first when playing
+ * 'hunt the superblock'.
+ *
+ * The ffsv2 superblock layout (which might contain an ffsv1 filesystem)
+ * can be detected by checking for sb->fs_old_flags & FS_FLAGS_UPDATED.
+ * This is the default superblock type for NetBSD since ffsv2 support was added.
+ */
+#define        BBSIZE          8192
+#define        BBOFF           ((off_t)(0))
+#define        BBLOCK          ((daddr_t)(0))
+
+#define        SBLOCK_FLOPPY      0
+#define        SBLOCK_UFS1     8192
+#define        SBLOCK_UFS2    65536
+#define        SBLOCK_PIGGY  262144
+#define        SBLOCKSIZE      8192
+/*
+ * NB: Do not, under any circumstances, look for an ffsv1 filesystem at
+ * SBLOCK_UFS2.  Doing so will find the wrong superblock for filesystems
+ * with a 64k block size.
+ */
+#define        SBLOCKSEARCH \
+       { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 }
+
+/*
+ * Max number of fragments per block. This value is NOT tweakable.
+ */
+#define        MAXFRAG         8
+
+
+
+/*
+ * Addresses stored in inodes are capable of addressing fragments
+ * of `blocks'. File system blocks of at most size MAXBSIZE can
+ * be optionally broken into 2, 4, or 8 pieces, each of which is
+ * addressable; these pieces may be DEV_BSIZE, or some multiple of
+ * a DEV_BSIZE unit.
+ *
+ * Large files consist of exclusively large data blocks.  To avoid
+ * undue wasted disk space, the last data block of a small file may be
+ * allocated as only as many fragments of a large block as are
+ * necessary.  The file system format retains only a single pointer
+ * to such a fragment, which is a piece of a single large block that
+ * has been divided.  The size of such a fragment is determinable from
+ * information in the inode, using the ``blksize(fs, ip, lbn)'' macro.
+ *
+ * The file system records space availability at the fragment level;
+ * to determine block availability, aligned fragments are examined.
+ */
+
+/*
+ * MINBSIZE is the smallest allowable block size.
+ * In order to insure that it is possible to create files of size
+ * 2^32 with only two levels of indirection, MINBSIZE is set to 4096.
+ * MINBSIZE must be big enough to hold a cylinder group block,
+ * thus changes to (struct cg) must keep its size within MINBSIZE.
+ * Note that super blocks are always of size SBSIZE,
+ * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
+ */
+#define        MINBSIZE        4096
+
+/*
+ * The path name on which the file system is mounted is maintained
+ * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
+ * the super block for this name.
+ */
+#define        MAXMNTLEN       468
+
+/*
+ * The volume name for this filesystem is maintained in fs_volname.
+ * MAXVOLLEN defines the length of the buffer allocated.
+ * This space used to be part of of fs_fsmnt.
+ */
+#define        MAXVOLLEN       32
+
+/*
+ * There is a 128-byte region in the superblock reserved for in-core
+ * pointers to summary information. Originally this included an array
+ * of pointers to blocks of struct csum; now there are just four
+ * pointers and the remaining space is padded with fs_ocsp[].
+ * NOCSPTRS determines the size of this padding. One pointer (fs_csp)
+ * is taken away to point to a contiguous array of struct csum for
+ * all cylinder groups; a second (fs_maxcluster) points to an array
+ * of cluster sizes that is computed as cylinder groups are inspected;
+ * the third (fs_contigdirs) points to an array that tracks the
+ * creation of new directories; and the fourth (fs_active) is used
+ * by snapshots.
+ */
+#define        NOCSPTRS        ((128 / sizeof(void *)) - 4)
+
+/*
+ * A summary of contiguous blocks of various sizes is maintained
+ * in each cylinder group. Normally this is set by the initial
+ * value of fs_maxcontig. To conserve space, a maximum summary size
+ * is set by FS_MAXCONTIG.
+ */
+#define        FS_MAXCONTIG    16
+
+/*
+ * The maximum number of snapshot nodes that can be associated
+ * with each filesystem. This limit affects only the number of
+ * snapshot files that can be recorded within the superblock so
+ * that they can be found when the filesystem is mounted. However,
+ * maintaining too many will slow the filesystem performance, so
+ * having this limit is a good idea.
+ */
+#define        FSMAXSNAP 20
+
+/*
+ * Used to identify special blocks in snapshots:
+ *
+ * BLK_NOCOPY - A block that was unallocated at the time the snapshot
+ *      was taken, hence does not need to be copied when written.
+ * BLK_SNAP - A block held by another snapshot that is not needed by this
+ *      snapshot. When the other snapshot is freed, the BLK_SNAP entries
+ *      are converted to BLK_NOCOPY. These are needed to allow fsck to
+ *      identify blocks that are in use by other snapshots (which are
+ *      expunged from this snapshot).
+ */
+#define        BLK_NOCOPY      ((daddr_t)(1))
+#define        BLK_SNAP        ((daddr_t)(2))
+
+/*
+ * MINFREE gives the minimum acceptable percentage of file system
+ * blocks which may be free. If the freelist drops below this level
+ * only the superuser may continue to allocate blocks. This may
+ * be set to 0 if no reserve of free blocks is deemed necessary,
+ * however throughput drops by fifty percent if the file system
+ * is run at between 95% and 100% full; thus the minimum default
+ * value of fs_minfree is 5%. However, to get good clustering
+ * performance, 10% is a better choice. This value is used only
+ * when creating a file system and can be overriden from the
+ * command line. By default we choose to optimize for time.
+ */
+#define        MINFREE         5
+#define        DEFAULTOPT      FS_OPTTIME
+
+/*
+ * Grigoriy Orlov <gluk@ptci.ru> has done some extensive work to fine
+ * tune the layout preferences for directories within a filesystem.
+ * His algorithm can be tuned by adjusting the following parameters
+ * which tell the system the average file size and the average number
+ * of files per directory. These defaults are well selected for typical
+ * filesystems, but may need to be tuned for odd cases like filesystems
+ * being used for squid caches or news spools.
+ */
+#define        AVFILESIZ       16384   /* expected average file size */
+#define        AFPDIR          64      /* expected number of files per directory */
+
+/*
+ * Per cylinder group information; summarized in blocks allocated
+ * from first cylinder group data blocks.  These blocks have to be
+ * read in from fs_csaddr (size fs_cssize) in addition to the
+ * super block.
+ */
+struct csum {
+       int32_t cs_ndir;                /* number of directories */
+       int32_t cs_nbfree;              /* number of free blocks */
+       int32_t cs_nifree;              /* number of free inodes */
+       int32_t cs_nffree;              /* number of free frags */
+};
+
+struct csum_total {
+       int64_t cs_ndir;                /* number of directories */
+       int64_t cs_nbfree;              /* number of free blocks */
+       int64_t cs_nifree;              /* number of free inodes */
+       int64_t cs_nffree;              /* number of free frags */
+       int64_t cs_spare[4];            /* future expansion */
+};
+
+
+/*
+ * Super block for an FFS file system in memory.
+ */
+struct fs {
+       int32_t  fs_firstfield;         /* historic file system linked list, */
+       int32_t  fs_unused_1;           /*     used for incore super blocks */
+       int32_t  fs_sblkno;             /* addr of super-block in filesys */
+       int32_t  fs_cblkno;             /* offset of cyl-block in filesys */
+       int32_t  fs_iblkno;             /* offset of inode-blocks in filesys */
+       int32_t  fs_dblkno;             /* offset of first data after cg */
+       int32_t  fs_old_cgoffset;       /* cylinder group offset in cylinder */
+       int32_t  fs_old_cgmask;         /* used to calc mod fs_ntrak */
+       int32_t  fs_old_time;           /* last time written */
+       int32_t  fs_old_size;           /* number of blocks in fs */
+       int32_t  fs_old_dsize;          /* number of data blocks in fs */
+       int32_t  fs_ncg;                /* number of cylinder groups */
+       int32_t  fs_bsize;              /* size of basic blocks in fs */
+       int32_t  fs_fsize;              /* size of frag blocks in fs */
+       int32_t  fs_frag;               /* number of frags in a block in fs */
+/* these are configuration parameters */
+       int32_t  fs_minfree;            /* minimum percentage of free blocks */
+       int32_t  fs_old_rotdelay;       /* num of ms for optimal next block */
+       int32_t  fs_old_rps;            /* disk revolutions per second */
+/* these fields can be computed from the others */
+       int32_t  fs_bmask;              /* ``blkoff'' calc of blk offsets */
+       int32_t  fs_fmask;              /* ``fragoff'' calc of frag offsets */
+       int32_t  fs_bshift;             /* ``lblkno'' calc of logical blkno */
+       int32_t  fs_fshift;             /* ``numfrags'' calc number of frags */
+/* these are configuration parameters */
+       int32_t  fs_maxcontig;          /* max number of contiguous blks */
+       int32_t  fs_maxbpg;             /* max number of blks per cyl group */
+/* these fields can be computed from the others */
+       int32_t  fs_fragshift;          /* block to frag shift */
+       int32_t  fs_fsbtodb;            /* fsbtodb and dbtofsb shift constant */
+       int32_t  fs_sbsize;             /* actual size of super block */
+       int32_t  fs_spare1[2];          /* old fs_csmask */
+                                       /* old fs_csshift */
+       int32_t  fs_nindir;             /* value of NINDIR */
+       int32_t  fs_inopb;              /* value of INOPB */
+       int32_t  fs_old_nspf;           /* value of NSPF */
+/* yet another configuration parameter */
+       int32_t  fs_optim;              /* optimization preference, see below */
+/* these fields are derived from the hardware */
+       int32_t  fs_old_npsect;         /* # sectors/track including spares */
+       int32_t  fs_old_interleave;     /* hardware sector interleave */
+       int32_t  fs_old_trackskew;      /* sector 0 skew, per track */
+/* fs_id takes the space of the unused fs_headswitch and fs_trkseek fields */
+       int32_t  fs_id[2];              /* unique file system id */
+/* sizes determined by number of cylinder groups and their sizes */
+       int32_t  fs_old_csaddr;         /* blk addr of cyl grp summary area */
+       int32_t  fs_cssize;             /* size of cyl grp summary area */
+       int32_t  fs_cgsize;             /* cylinder group size */
+/* these fields are derived from the hardware */
+       int32_t  fs_spare2;             /* old fs_ntrak */
+       int32_t  fs_old_nsect;          /* sectors per track */
+       int32_t  fs_old_spc;            /* sectors per cylinder */
+       int32_t  fs_old_ncyl;           /* cylinders in file system */
+       int32_t  fs_old_cpg;            /* cylinders per group */
+       int32_t  fs_ipg;                /* inodes per group */
+       int32_t  fs_fpg;                /* blocks per group * fs_frag */
+/* this data must be re-computed after crashes */
+       struct  csum fs_old_cstotal;    /* cylinder summary information */
+/* these fields are cleared at mount time */
+       int8_t   fs_fmod;               /* super block modified flag */
+       uint8_t  fs_clean;              /* file system is clean flag */
+       int8_t   fs_ronly;              /* mounted read-only flag */
+       uint8_t  fs_old_flags;          /* see FS_ flags below */
+       u_char   fs_fsmnt[MAXMNTLEN];   /* name mounted on */
+       u_char   fs_volname[MAXVOLLEN]; /* volume name */
+       uint64_t fs_swuid;              /* system-wide uid */
+       int32_t  fs_pad;
+/* these fields retain the current block allocation info */
+       int32_t  fs_cgrotor;            /* last cg searched (UNUSED) */
+       void    *fs_ocsp[NOCSPTRS];     /* padding; was list of fs_cs buffers */
+       u_int8_t *fs_contigdirs;        /* # of contiguously allocated dirs */
+       struct csum *fs_csp;            /* cg summary info buffer for fs_cs */
+       int32_t *fs_maxcluster;         /* max cluster in each cyl group */
+       u_char  *fs_active;             /* used by snapshots to track fs */
+       int32_t  fs_old_cpc;            /* cyl per cycle in postbl */
+/* this area is otherwise allocated unless fs_old_flags & FS_FLAGS_UPDATED */
+       int32_t  fs_maxbsize;           /* maximum blocking factor permitted */
+       uint8_t  fs_journal_version;    /* journal format version */
+       uint8_t  fs_journal_location;   /* journal location type */
+       uint8_t  fs_journal_reserved[2];/* reserved for future use */
+       uint32_t fs_journal_flags;      /* journal flags */
+       uint64_t fs_journallocs[4];     /* location info for journal */
+       uint32_t fs_quota_magic;        /* see quota2.h */
+       uint8_t  fs_quota_flags;        /* see quota2.h */
+       uint8_t  fs_quota_reserved[3];  
+       uint64_t fs_quotafile[2];       /* pointer to quota inodes */
+       int64_t  fs_sparecon64[9];      /* reserved for future use */
+       int64_t  fs_sblockloc;          /* byte offset of standard superblock */
+       struct  csum_total fs_cstotal;  /* cylinder summary information */
+       int64_t  fs_time;               /* last time written */
+       int64_t  fs_size;               /* number of blocks in fs */
+       int64_t  fs_dsize;              /* number of data blocks in fs */
+       int64_t  fs_csaddr;             /* blk addr of cyl grp summary area */
+       int64_t  fs_pendingblocks;      /* blocks in process of being freed */
+       int32_t  fs_pendinginodes;      /* inodes in process of being freed */
+       int32_t  fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */
+/* back to stuff that has been around a while */
+       int32_t  fs_avgfilesize;        /* expected average file size */
+       int32_t  fs_avgfpdir;           /* expected # of files per directory */
+       int32_t  fs_save_cgsize;        /* save real cg size to use fs_bsize */
+       int32_t  fs_sparecon32[26];     /* reserved for future constants */
+       uint32_t fs_flags;              /* see FS_ flags below */
+/* back to stuff that has been around a while (again) */
+       int32_t  fs_contigsumsize;      /* size of cluster summary array */
+       int32_t  fs_maxsymlinklen;      /* max length of an internal symlink */
+       int32_t  fs_old_inodefmt;       /* format of on-disk inodes */
+       u_int64_t fs_maxfilesize;       /* maximum representable file size */
+       int64_t  fs_qbmask;             /* ~fs_bmask for use with 64-bit size */
+       int64_t  fs_qfmask;             /* ~fs_fmask for use with 64-bit size */
+       int32_t  fs_state;              /* validate fs_clean field (UNUSED) */
+       int32_t  fs_old_postblformat;   /* format of positional layout tables */
+       int32_t  fs_old_nrpos;          /* number of rotational positions */
+       int32_t  fs_spare5[2];          /* old fs_postbloff */
+                                       /* old fs_rotbloff */
+       int32_t  fs_magic;              /* magic number */
+};
+
+#define        fs_old_postbloff        fs_spare5[0]
+#define        fs_old_rotbloff         fs_spare5[1]
+#define        fs_old_postbl_start     fs_maxbsize
+#define        fs_old_headswitch       fs_id[0]
+#define        fs_old_trkseek  fs_id[1]
+#define        fs_old_csmask   fs_spare1[0]
+#define        fs_old_csshift  fs_spare1[1]
+
+#define        FS_42POSTBLFMT          -1      /* 4.2BSD rotational table format */
+#define        FS_DYNAMICPOSTBLFMT     1       /* dynamic rotational table format */
+
+#define        old_fs_postbl(fs_, cylno, opostblsave) \
+    ((((fs_)->fs_old_postblformat == FS_42POSTBLFMT) || \
+     ((fs_)->fs_old_postbloff == offsetof(struct fs, fs_old_postbl_start))) \
+    ? ((int16_t *)(opostblsave) + (cylno) * (fs_)->fs_old_nrpos) \
+    : ((int16_t *)((uint8_t *)(fs_) + \
+       (fs_)->fs_old_postbloff) + (cylno) * (fs_)->fs_old_nrpos))
+#define        old_fs_rotbl(fs) \
+    (((fs)->fs_old_postblformat == FS_42POSTBLFMT) \
+    ? ((uint8_t *)(&(fs)->fs_magic+1)) \
+    : ((uint8_t *)((uint8_t *)(fs) + (fs)->fs_old_rotbloff)))
+
+/*
+ * File system identification
+ */
+#define        FS_UFS1_MAGIC   0x011954        /* UFS1 fast file system magic number */
+#define        FS_UFS2_MAGIC   0x19540119      /* UFS2 fast file system magic number */
+#define        FS_UFS1_MAGIC_SWAPPED   0x54190100
+#define        FS_UFS2_MAGIC_SWAPPED   0x19015419
+#define        FS_OKAY         0x7c269d38      /* superblock checksum */
+#define        FS_42INODEFMT   -1              /* 4.2BSD inode format */
+#define        FS_44INODEFMT   2               /* 4.4BSD inode format */
+
+/*
+ * File system clean flags
+ */
+#define        FS_ISCLEAN      0x01
+#define        FS_WASCLEAN     0x02
+
+/*
+ * Preference for optimization.
+ */
+#define        FS_OPTTIME      0       /* minimize allocation time */
+#define        FS_OPTSPACE     1       /* minimize disk fragmentation */
+
+/*
+ * File system flags
+ */
+#define        FS_UNCLEAN      0x001   /* file system not clean at mount (unused) */
+#define        FS_DOSOFTDEP    0x002   /* file system using soft dependencies */
+#define        FS_NEEDSFSCK    0x004   /* needs sync fsck (FreeBSD compat, unused) */
+#define        FS_INDEXDIRS    0x008   /* kernel supports indexed directories */
+#define        FS_ACLS         0x010   /* file system has ACLs enabled */
+#define        FS_MULTILABEL   0x020   /* file system is MAC multi-label */
+#define        FS_GJOURNAL     0x40    /* gjournaled file system */
+#define        FS_FLAGS_UPDATED 0x80   /* flags have been moved to new location */
+#define        FS_DOWAPBL      0x100   /* Write ahead physical block logging */
+#define        FS_DOQUOTA2     0x200   /* in-filesystem quotas */
+
+/* File system flags that are ok for NetBSD if set in fs_flags */
+#define        FS_KNOWN_FLAGS  (FS_DOSOFTDEP | FS_DOWAPBL | FS_DOQUOTA2)
+
+/*
+ * File system internal flags, also in fs_flags.
+ * (Pick highest number to avoid conflicts with others)
+ */
+#define        FS_SWAPPED      0x80000000      /* file system is endian swapped */
+#define        FS_INTERNAL     0x80000000      /* mask for internal flags */
+
+/*
+ * Macros to access bits in the fs_active array.
+ */
+#define        ACTIVECG_SET(fs, cg)                            \
+       do {                                            \
+               if ((fs)->fs_active != NULL)            \
+                       setbit((fs)->fs_active, (cg));  \
+       } while (/*CONSTCOND*/ 0)
+#define        ACTIVECG_CLR(fs, cg)                            \
+       do {                                            \
+               if ((fs)->fs_active != NULL)            \
+                       clrbit((fs)->fs_active, (cg));  \
+       } while (/*CONSTCOND*/ 0)
+#define        ACTIVECG_ISSET(fs, cg)                          \
+       ((fs)->fs_active != NULL && isset((fs)->fs_active, (cg)))
+
+/*
+ * The size of a cylinder group is calculated by CGSIZE. The maximum size
+ * is limited by the fact that cylinder groups are at most one block.
+ * Its size is derived from the size of the maps maintained in the
+ * cylinder group and the (struct cg) size.
+ */
+#define        CGSIZE_IF(fs, ipg, fpg) \
+    /* base cg */      (sizeof(struct cg) + sizeof(int32_t) + \
+    /* old btotoff */  (fs)->fs_old_cpg * sizeof(int32_t) + \
+    /* old boff */     (fs)->fs_old_cpg * sizeof(u_int16_t) + \
+    /* inode map */    howmany((ipg), NBBY) + \
+    /* block map */    howmany((fpg), NBBY) +\
+    /* if present */   ((fs)->fs_contigsumsize <= 0 ? 0 : \
+    /* cluster sum */  (fs)->fs_contigsumsize * sizeof(int32_t) + \
+    /* cluster map */  howmany(fragstoblks(fs, (fpg)), NBBY)))
+
+#define        CGSIZE(fs) CGSIZE_IF((fs), (fs)->fs_ipg, (fs)->fs_fpg)
+
+/*
+ * The minimal number of cylinder groups that should be created.
+ */
+#define        MINCYLGRPS      4
+
+
+/*
+ * Convert cylinder group to base address of its global summary info.
+ */
+#define        fs_cs(fs, indx) fs_csp[indx]
+
+/*
+ * Cylinder group block for a file system.
+ */
+#define        CG_MAGIC        0x090255
+struct cg {
+       int32_t  cg_firstfield;         /* historic cyl groups linked list */
+       int32_t  cg_magic;              /* magic number */
+       int32_t  cg_old_time;           /* time last written */
+       int32_t  cg_cgx;                /* we are the cgx'th cylinder group */
+       int16_t  cg_old_ncyl;           /* number of cyl's this cg */
+       int16_t  cg_old_niblk;          /* number of inode blocks this cg */
+       int32_t  cg_ndblk;              /* number of data blocks this cg */
+       struct  csum cg_cs;             /* cylinder summary information */
+       int32_t  cg_rotor;              /* position of last used block */
+       int32_t  cg_frotor;             /* position of last used frag */
+       int32_t  cg_irotor;             /* position of last used inode */
+       int32_t  cg_frsum[MAXFRAG];     /* counts of available frags */
+       int32_t  cg_old_btotoff;        /* (int32) block totals per cylinder */
+       int32_t  cg_old_boff;           /* (u_int16) free block positions */
+       int32_t  cg_iusedoff;           /* (u_int8) used inode map */
+       int32_t  cg_freeoff;            /* (u_int8) free block map */
+       int32_t  cg_nextfreeoff;        /* (u_int8) next available space */
+       int32_t  cg_clustersumoff;      /* (u_int32) counts of avail clusters */
+       int32_t  cg_clusteroff;         /* (u_int8) free cluster map */
+       int32_t  cg_nclusterblks;       /* number of clusters this cg */
+       int32_t  cg_niblk;              /* number of inode blocks this cg */
+       int32_t  cg_initediblk;         /* last initialized inode */
+       int32_t  cg_sparecon32[3];      /* reserved for future use */
+       int64_t  cg_time;               /* time last written */
+       int64_t  cg_sparecon64[3];      /* reserved for future use */
+       u_int8_t cg_space[1];           /* space for cylinder group maps */
+/* actually longer */
+};
+
+/*
+ * The following structure is defined
+ * for compatibility with old file systems.
+ */
+struct ocg {
+       int32_t  cg_firstfield;         /* historic linked list of cyl groups */
+       int32_t  cg_unused_1;           /*     used for incore cyl groups */
+       int32_t  cg_time;               /* time last written */
+       int32_t  cg_cgx;                /* we are the cgx'th cylinder group */
+       int16_t  cg_ncyl;               /* number of cyl's this cg */
+       int16_t  cg_niblk;              /* number of inode blocks this cg */
+       int32_t  cg_ndblk;              /* number of data blocks this cg */
+       struct  csum cg_cs;             /* cylinder summary information */
+       int32_t  cg_rotor;              /* position of last used block */
+       int32_t  cg_frotor;             /* position of last used frag */
+       int32_t  cg_irotor;             /* position of last used inode */
+       int32_t  cg_frsum[8];           /* counts of available frags */
+       int32_t  cg_btot[32];           /* block totals per cylinder */
+       int16_t  cg_b[32][8];           /* positions of free blocks */
+       u_int8_t cg_iused[256];         /* used inode map */
+       int32_t  cg_magic;              /* magic number */
+       u_int8_t cg_free[1];            /* free block map */
+/* actually longer */
+};
+
+
+/*
+ * Macros for access to cylinder group array structures.
+ */
+#define        old_cg_blktot_old(cgp, ns) \
+    (((struct ocg *)(cgp))->cg_btot)
+#define        old_cg_blks_old(fs, cgp, cylno, ns) \
+    (((struct ocg *)(cgp))->cg_b[cylno])
+
+#define        old_cg_blktot_new(cgp, ns) \
+    ((int32_t *)((u_int8_t *)(cgp) + \
+       ufs_rw32((cgp)->cg_old_btotoff, (ns))))
+#define        old_cg_blks_new(fs, cgp, cylno, ns) \
+    ((int16_t *)((u_int8_t *)(cgp) + \
+       ufs_rw32((cgp)->cg_old_boff, (ns))) + (cylno) * (fs)->fs_old_nrpos)
+
+#define        old_cg_blktot(cgp, ns) \
+    ((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
+      old_cg_blktot_old(cgp, ns) : old_cg_blktot_new(cgp, ns))
+#define        old_cg_blks(fs, cgp, cylno, ns) \
+    ((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
+      old_cg_blks_old(fs, cgp, cylno, ns) : old_cg_blks_new(fs, cgp, cylno, ns))
+
+#define        cg_inosused_new(cgp, ns) \
+    ((u_int8_t *)((u_int8_t *)(cgp) + \
+       ufs_rw32((cgp)->cg_iusedoff, (ns))))
+#define        cg_blksfree_new(cgp, ns) \
+    ((u_int8_t *)((u_int8_t *)(cgp) + \
+       ufs_rw32((cgp)->cg_freeoff, (ns))))
+#define        cg_chkmagic_new(cgp, ns) \
+    (ufs_rw32((cgp)->cg_magic, (ns)) == CG_MAGIC)
+
+#define        cg_inosused_old(cgp, ns) \
+    (((struct ocg *)(cgp))->cg_iused)
+#define        cg_blksfree_old(cgp, ns) \
+    (((struct ocg *)(cgp))->cg_free)
+#define        cg_chkmagic_old(cgp, ns) \
+    (ufs_rw32(((struct ocg *)(cgp))->cg_magic, (ns)) == CG_MAGIC)
+
+#define        cg_inosused(cgp, ns) \
+    ((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
+      cg_inosused_old(cgp, ns) : cg_inosused_new(cgp, ns))
+#define        cg_blksfree(cgp, ns) \
+    ((ufs_rw32((cgp)->cg_magic, (ns)) != CG_MAGIC) ? \
+      cg_blksfree_old(cgp, ns) : cg_blksfree_new(cgp, ns))
+#define        cg_chkmagic(cgp, ns) \
+    (cg_chkmagic_new(cgp, ns) || cg_chkmagic_old(cgp, ns))
+
+#define        cg_clustersfree(cgp, ns) \
+    ((u_int8_t *)((u_int8_t *)(cgp) + \
+       ufs_rw32((cgp)->cg_clusteroff, (ns))))
+#define        cg_clustersum(cgp, ns) \
+    ((int32_t *)((u_int8_t *)(cgp) + \
+       ufs_rw32((cgp)->cg_clustersumoff, (ns))))
+
+
+/*
+ * Turn file system block numbers into disk block addresses.
+ * This maps file system blocks to device size blocks.
+ */
+#if defined (_KERNEL)
+#define        fsbtodb(fs, b)  ((b) << ((fs)->fs_fshift - DEV_BSHIFT))
+#define        dbtofsb(fs, b)  ((b) >> ((fs)->fs_fshift - DEV_BSHIFT))
+#else
+#define        fsbtodb(fs, b)  ((b) << (fs)->fs_fsbtodb)
+#define        dbtofsb(fs, b)  ((b) >> (fs)->fs_fsbtodb)
+#endif
+
+/*
+ * Cylinder group macros to locate things in cylinder groups.
+ * They calc file system addresses of cylinder group data structures.
+ */
+#define        cgbase(fs, c)   (((daddr_t)(fs)->fs_fpg) * (c))
+#define        cgstart_ufs1(fs, c) \
+    (cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask)))
+#define        cgstart_ufs2(fs, c) cgbase((fs), (c))
+#define        cgstart(fs, c) ((fs)->fs_magic == FS_UFS2_MAGIC \
+                           ? cgstart_ufs2((fs), (c)) : cgstart_ufs1((fs), (c)))
+#define        cgdmin(fs, c)   (cgstart(fs, c) + (fs)->fs_dblkno)      /* 1st data */
+#define        cgimin(fs, c)   (cgstart(fs, c) + (fs)->fs_iblkno)      /* inode blk */
+#define        cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno)      /* super blk */
+#define        cgtod(fs, c)    (cgstart(fs, c) + (fs)->fs_cblkno)      /* cg block */
+
+/*
+ * Macros for handling inode numbers:
+ *     inode number to file system block offset.
+ *     inode number to cylinder group number.
+ *     inode number to file system block address.
+ */
+#define        ino_to_cg(fs, x)        ((x) / (fs)->fs_ipg)
+#define        ino_to_fsba(fs, x)                                              \
+       ((daddr_t)(cgimin(fs, ino_to_cg(fs, x)) +                       \
+           (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
+#define        ino_to_fsbo(fs, x)      ((x) % INOPB(fs))
+
+/*
+ * Give cylinder group number for a file system block.
+ * Give cylinder group block number for a file system block.
+ */
+#define        dtog(fs, d)     ((d) / (fs)->fs_fpg)
+#define        dtogd(fs, d)    ((d) % (fs)->fs_fpg)
+
+/*
+ * Extract the bits for a block from a map.
+ * Compute the cylinder and rotational position of a cyl block addr.
+ */
+#define        blkmap(fs, map, loc) \
+    (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag)))
+#define        old_cbtocylno(fs, bno) \
+    (fsbtodb(fs, bno) / (fs)->fs_old_spc)
+#define        old_cbtorpos(fs, bno) \
+    ((fs)->fs_old_nrpos <= 1 ? 0 : \
+     (fsbtodb(fs, bno) % (fs)->fs_old_spc / (fs)->fs_old_nsect * (fs)->fs_old_trackskew + \
+      fsbtodb(fs, bno) % (fs)->fs_old_spc % (fs)->fs_old_nsect * (fs)->fs_old_interleave) % \
+     (fs)->fs_old_nsect * (fs)->fs_old_nrpos / (fs)->fs_old_npsect)
+
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define        blkoff(fs, loc)         /* calculates (loc % fs->fs_bsize) */ \
+       ((loc) & (fs)->fs_qbmask)
+#define        fragoff(fs, loc)        /* calculates (loc % fs->fs_fsize) */ \
+       ((loc) & (fs)->fs_qfmask)
+#define        lfragtosize(fs, frag)   /* calculates ((off_t)frag * fs->fs_fsize) */ \
+       (((off_t)(frag)) << (fs)->fs_fshift)
+#define        lblktosize(fs, blk)     /* calculates ((off_t)blk * fs->fs_bsize) */ \
+       (((off_t)(blk)) << (fs)->fs_bshift)
+#define        lblkno(fs, loc)         /* calculates (loc / fs->fs_bsize) */ \
+       ((loc) >> (fs)->fs_bshift)
+#define        numfrags(fs, loc)       /* calculates (loc / fs->fs_fsize) */ \
+       ((loc) >> (fs)->fs_fshift)
+#define        blkroundup(fs, size)    /* calculates roundup(size, fs->fs_bsize) */ \
+       (((size) + (fs)->fs_qbmask) & (fs)->fs_bmask)
+#define        fragroundup(fs, size)   /* calculates roundup(size, fs->fs_fsize) */ \
+       (((size) + (fs)->fs_qfmask) & (fs)->fs_fmask)
+#define        fragstoblks(fs, frags)  /* calculates (frags / fs->fs_frag) */ \
+       ((frags) >> (fs)->fs_fragshift)
+#define        blkstofrags(fs, blks)   /* calculates (blks * fs->fs_frag) */ \
+       ((blks) << (fs)->fs_fragshift)
+#define        fragnum(fs, fsb)        /* calculates (fsb % fs->fs_frag) */ \
+       ((fsb) & ((fs)->fs_frag - 1))
+#define        blknum(fs, fsb)         /* calculates rounddown(fsb, fs->fs_frag) */ \
+       ((fsb) &~ ((fs)->fs_frag - 1))
+
+/*
+ * Determine the number of available frags given a
+ * percentage to hold in reserve.
+ */
+#define        freespace(fs, percentreserved) \
+       (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \
+       (fs)->fs_cstotal.cs_nffree - \
+       (((off_t)((fs)->fs_dsize)) * (percentreserved) / 100))
+
+/*
+ * Determining the size of a file block in the file system.
+ */
+#define        blksize(fs, ip, lbn) \
+       (((lbn) >= NDADDR || (ip)->i_size >= lblktosize(fs, (lbn) + 1)) \
+           ? (fs)->fs_bsize \
+           : (fragroundup(fs, blkoff(fs, (ip)->i_size))))
+
+#define        sblksize(fs, size, lbn) \
+       (((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \
+         ? (fs)->fs_bsize \
+         : (fragroundup(fs, blkoff(fs, (size)))))
+
+
+/*
+ * Number of inodes in a secondary storage block/fragment.
+ */
+#define        INOPB(fs)       ((fs)->fs_inopb)
+#define        INOPF(fs)       ((fs)->fs_inopb >> (fs)->fs_fragshift)
+
+/*
+ * Number of indirects in a file system block.
+ */
+#define        NINDIR(fs)      ((fs)->fs_nindir)
+
+/*
+ * Apple UFS Label:
+ *  We check for this to decide to use APPLEUFS_DIRBLKSIZ
+ */
+#define        APPLEUFS_LABEL_MAGIC            0x4c41424c /* LABL */
+#define        APPLEUFS_LABEL_SIZE             1024
+#define        APPLEUFS_LABEL_OFFSET   (BBSIZE - APPLEUFS_LABEL_SIZE) /* located at 7k */
+#define        APPLEUFS_LABEL_VERSION  1
+#define        APPLEUFS_MAX_LABEL_NAME 512
+
+struct appleufslabel {
+       u_int32_t       ul_magic;
+       u_int16_t       ul_checksum;
+       u_int16_t       ul_unused0;
+       u_int32_t       ul_version;
+       u_int32_t       ul_time;
+       u_int16_t       ul_namelen;
+       u_char  ul_name[APPLEUFS_MAX_LABEL_NAME]; /* Warning: may not be null terminated */
+       u_int16_t       ul_unused1;
+       u_int64_t       ul_uuid;        /* Note this is only 4 byte aligned */
+       u_char  ul_reserved[24];
+       u_char  ul_unused[460];
+} __packed;
+
+
+#endif /* !_UFS_FFS_FS_H_ */
diff --git a/nbsd_include/ufs/lfs/lfs.h b/nbsd_include/ufs/lfs/lfs.h
new file mode 100644 (file)
index 0000000..9f6ae8d
--- /dev/null
@@ -0,0 +1,1156 @@
+/*     $NetBSD: lfs.h,v 1.134 2011/07/11 08:27:40 hannken Exp $        */
+
+/*-
+ * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Konrad E. Schroder <perseant@hhhh.org>.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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) 1991, 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.
+ *
+ *     @(#)lfs.h       8.9 (Berkeley) 5/8/95
+ */
+
+#ifndef _UFS_LFS_LFS_H_
+#define _UFS_LFS_LFS_H_
+
+#include <sys/rwlock.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/condvar.h>
+
+/*
+ * Compile-time options for LFS.
+ */
+#define LFS_IFIND_RETRIES  16
+#define LFS_LOGLENGTH      1024 /* size of debugging log */
+#define LFS_MAX_ACTIVE    10   /* Dirty segments before ckp forced */
+
+/*
+ * Fixed filesystem layout parameters
+ */
+#define        LFS_LABELPAD    8192            /* LFS label size */
+#define        LFS_SBPAD       8192            /* LFS superblock size */
+
+#define        LFS_UNUSED_INUM 0               /* 0: out of band inode number */
+#define        LFS_IFILE_INUM  1               /* 1: IFILE inode number */
+                                       /* 2: Root inode number */
+#define        LOSTFOUNDINO    3               /* 3: lost+found inode number */
+#define        LFS_FIRST_INUM  4               /* 4: first free inode number */
+
+#define        LFS_V1_SUMMARY_SIZE     512     /* V1 fixed summary size */
+#define        LFS_DFL_SUMMARY_SIZE    512     /* Default summary size */
+
+#define LFS_MAX_DADDR  0x7fffffff      /* Highest addressable fsb */
+
+#define LFS_MAXNAMLEN  255             /* maximum name length in a dir */
+
+/* Adjustable filesystem parameters */
+#define MIN_FREE_SEGS  20
+#define MIN_RESV_SEGS  15
+#ifndef LFS_ATIME_IFILE
+# define LFS_ATIME_IFILE 0 /* Store atime info in ifile (optional in LFSv1) */
+#endif
+#define LFS_MARKV_MAXBLKCNT    65536   /* Max block count for lfs_markv() */
+
+/* Misc. definitions */
+#define BW_CLEAN       1               /* Flag for lfs_bwrite_ext() */
+#define PG_DELWRI      PG_PAGER1       /* Local def for delayed pageout */
+
+/* Resource limits */
+#define        LFS_MAX_RESOURCE(x, u)  (((x) >> 2) - 10 * (u))
+#define        LFS_WAIT_RESOURCE(x, u) (((x) >> 1) - ((x) >> 3) - 10 * (u))
+#define        LFS_INVERSE_MAX_RESOURCE(x, u)  (((x) + 10 * (u)) << 2)
+#define LFS_MAX_BUFS       LFS_MAX_RESOURCE(nbuf, 1)
+#define LFS_WAIT_BUFS      LFS_WAIT_RESOURCE(nbuf, 1)
+#define LFS_INVERSE_MAX_BUFS(n)        LFS_INVERSE_MAX_RESOURCE(n, 1)
+#define LFS_MAX_BYTES      LFS_MAX_RESOURCE(bufmem_lowater, PAGE_SIZE)
+#define LFS_INVERSE_MAX_BYTES(n) LFS_INVERSE_MAX_RESOURCE(n, PAGE_SIZE)
+#define LFS_WAIT_BYTES     LFS_WAIT_RESOURCE(bufmem_lowater, PAGE_SIZE)
+#define LFS_MAX_DIROP      ((desiredvnodes >> 2) + (desiredvnodes >> 3))
+#define SIZEOF_DIROP(fs)       (2 * ((fs)->lfs_bsize + DINODE1_SIZE))
+#define LFS_MAX_FSDIROP(fs)                                            \
+       ((fs)->lfs_nclean <= (fs)->lfs_resvseg ? 0 :                    \
+        (((fs)->lfs_nclean - (fs)->lfs_resvseg) * (fs)->lfs_ssize) /   \
+          (2 * SIZEOF_DIROP(fs)))
+#define LFS_MAX_PAGES  lfs_max_pages()
+#define LFS_WAIT_PAGES lfs_wait_pages()
+#define LFS_BUFWAIT        2   /* How long to wait if over *_WAIT_* */
+
+#ifdef _KERNEL
+int lfs_wait_pages(void);
+int lfs_max_pages(void);
+#endif /* _KERNEL */
+
+/* How starved can we be before we start holding back page writes */
+#define LFS_STARVED_FOR_SEGS(fs) ((fs)->lfs_nclean < (fs)->lfs_resvseg)
+
+/*
+ * Reserved blocks for lfs_malloc
+ */
+
+/* Structure to keep reserved blocks */
+typedef struct lfs_res_blk {
+       void *p;
+       LIST_ENTRY(lfs_res_blk) res;
+       int size;
+       char inuse;
+} res_t;
+
+/* Types for lfs_newbuf and lfs_malloc */
+#define LFS_NB_UNKNOWN -1
+#define LFS_NB_SUMMARY 0
+#define LFS_NB_SBLOCK  1
+#define LFS_NB_IBLOCK  2
+#define LFS_NB_CLUSTER 3
+#define LFS_NB_CLEAN   4
+#define LFS_NB_BLKIOV  5
+#define LFS_NB_COUNT   6 /* always last */
+
+/* Number of reserved memory blocks of each type */
+#define LFS_N_SUMMARIES 2
+#define LFS_N_SBLOCKS  1   /* Always 1, to throttle superblock writes */
+#define LFS_N_IBLOCKS  16  /* In theory ssize/bsize; in practice around 2 */
+#define LFS_N_CLUSTERS 16  /* In theory ssize/MAXPHYS */
+#define LFS_N_CLEAN    0
+#define LFS_N_BLKIOV   1
+
+/* Total count of "large" (non-pool) types */
+#define LFS_N_TOTAL (LFS_N_SUMMARIES + LFS_N_SBLOCKS + LFS_N_IBLOCKS + \
+                    LFS_N_CLUSTERS + LFS_N_CLEAN + LFS_N_BLKIOV)
+
+/* Counts for pool types */
+#define LFS_N_CL       LFS_N_CLUSTERS
+#define LFS_N_BPP      2
+#define LFS_N_SEG      2
+
+/*
+ * "struct buf" associated definitions
+ */
+
+/* Unassigned disk addresses. */
+#define        UNASSIGNED      -1
+#define UNWRITTEN      -2
+
+/* Unused logical block number */
+#define LFS_UNUSED_LBN -1
+
+/* Determine if a buffer belongs to the ifile */
+#define IS_IFILE(bp)   (VTOI(bp->b_vp)->i_number == LFS_IFILE_INUM)
+
+# define LFS_LOCK_BUF(bp) do {                                         \
+       if (((bp)->b_flags & B_LOCKED) == 0 && bp->b_iodone == NULL) {  \
+               mutex_enter(&lfs_lock);                                 \
+               ++locked_queue_count;                                   \
+               locked_queue_bytes += bp->b_bufsize;                    \
+               mutex_exit(&lfs_lock);                                  \
+       }                                                               \
+       (bp)->b_flags |= B_LOCKED;                                      \
+} while (0)
+
+# define LFS_UNLOCK_BUF(bp) do {                                       \
+       if (((bp)->b_flags & B_LOCKED) != 0 && bp->b_iodone == NULL) {  \
+               mutex_enter(&lfs_lock);                                 \
+               --locked_queue_count;                                   \
+               locked_queue_bytes -= bp->b_bufsize;                    \
+               if (locked_queue_count < LFS_WAIT_BUFS &&               \
+                   locked_queue_bytes < LFS_WAIT_BYTES)                \
+                       cv_broadcast(&locked_queue_cv);                 \
+               mutex_exit(&lfs_lock);                                  \
+       }                                                               \
+       (bp)->b_flags &= ~B_LOCKED;                                     \
+} while (0)
+
+#ifdef _KERNEL
+
+extern u_long bufmem_lowater, bufmem_hiwater; /* XXX */
+
+# define LFS_IS_MALLOC_BUF(bp) ((bp)->b_iodone == lfs_callback)
+
+# ifdef DEBUG
+#  define LFS_DEBUG_COUNTLOCKED(m) do {                                        \
+       if (lfs_debug_log_subsys[DLOG_LLIST]) {                         \
+               lfs_countlocked(&locked_queue_count, &locked_queue_bytes, (m)); \
+               cv_broadcast(&locked_queue_cv);                         \
+       }                                                               \
+} while (0)
+# else
+#  define LFS_DEBUG_COUNTLOCKED(m)
+# endif
+
+/* log for debugging writes to the Ifile */
+# ifdef DEBUG
+struct lfs_log_entry {
+       const char *op;
+       const char *file;
+       int pid;
+       int line;
+       daddr_t block;
+       unsigned long flags;
+};
+extern int lfs_lognum;
+extern struct lfs_log_entry lfs_log[LFS_LOGLENGTH];
+#  define LFS_BWRITE_LOG(bp) lfs_bwrite_log((bp), __FILE__, __LINE__)
+#  define LFS_ENTER_LOG(theop, thefile, theline, lbn, theflags, thepid) do {\
+       int _s;                                                         \
+                                                                       \
+       mutex_enter(&lfs_lock);                                         \
+       _s = splbio();                                                  \
+       lfs_log[lfs_lognum].op = theop;                                 \
+       lfs_log[lfs_lognum].file = thefile;                             \
+       lfs_log[lfs_lognum].line = (theline);                           \
+       lfs_log[lfs_lognum].pid = (thepid);                             \
+       lfs_log[lfs_lognum].block = (lbn);                              \
+       lfs_log[lfs_lognum].flags = (theflags);                         \
+       lfs_lognum = (lfs_lognum + 1) % LFS_LOGLENGTH;                  \
+       splx(_s);                                                       \
+       mutex_exit(&lfs_lock);                                          \
+} while (0)
+
+#  define LFS_BCLEAN_LOG(fs, bp) do {                                  \
+       if ((bp)->b_vp == (fs)->lfs_ivnode)                             \
+               LFS_ENTER_LOG("clear", __FILE__, __LINE__,              \
+                             bp->b_lblkno, bp->b_flags, curproc->p_pid);\
+} while (0)
+
+/* Must match list in lfs_vfsops.c ! */
+#  define DLOG_RF     0  /* roll forward */
+#  define DLOG_ALLOC  1  /* inode alloc */
+#  define DLOG_AVAIL  2  /* lfs_{,r,f}avail */
+#  define DLOG_FLUSH  3  /* flush */
+#  define DLOG_LLIST  4  /* locked list accounting */
+#  define DLOG_WVNODE 5  /* vflush/writevnodes verbose */
+#  define DLOG_VNODE  6  /* vflush/writevnodes */
+#  define DLOG_SEG    7  /* segwrite */
+#  define DLOG_SU     8  /* seguse accounting */
+#  define DLOG_CLEAN  9  /* cleaner routines */
+#  define DLOG_MOUNT  10 /* mount/unmount */
+#  define DLOG_PAGE   11 /* putpages/gop_write */
+#  define DLOG_DIROP  12 /* dirop accounting */
+#  define DLOG_MALLOC 13 /* lfs_malloc accounting */
+#  define DLOG_MAX    14 /* The terminator */
+#  define DLOG(a) lfs_debug_log a
+# else /* ! DEBUG */
+#  define LFS_BCLEAN_LOG(fs, bp)
+#  define LFS_BWRITE_LOG(bp)           VOP_BWRITE((bp)->b_vp, (bp))
+#  define DLOG(a)
+# endif /* ! DEBUG */
+#else /* ! _KERNEL */
+# define LFS_BWRITE_LOG(bp)            VOP_BWRITE((bp))
+#endif /* _KERNEL */
+
+#ifdef _KERNEL
+/* Filehandle structure for exported LFSes */
+struct lfid {
+       struct ufid lfid_ufid;
+#define lfid_len lfid_ufid.ufid_len
+#define lfid_ino lfid_ufid.ufid_ino
+#define lfid_gen lfid_ufid.ufid_gen
+       uint32_t lfid_ident;
+};
+#endif /* _KERNEL */
+
+/*
+ * "struct inode" associated definitions
+ */
+
+/* Address calculations for metadata located in the inode */
+#define        S_INDIR(fs)     -NDADDR
+#define        D_INDIR(fs)     (S_INDIR(fs) - NINDIR(fs) - 1)
+#define        T_INDIR(fs)     (D_INDIR(fs) - NINDIR(fs) * NINDIR(fs) - 1)
+
+/* For convenience */
+#define IN_ALLMOD (IN_MODIFIED|IN_ACCESS|IN_CHANGE|IN_UPDATE|IN_MODIFY|IN_ACCESSED|IN_CLEANING)
+
+#define LFS_SET_UINO(ip, flags) do {                                   \
+       if (((flags) & IN_ACCESSED) && !((ip)->i_flag & IN_ACCESSED))   \
+               ++(ip)->i_lfs->lfs_uinodes;                             \
+       if (((flags) & IN_CLEANING) && !((ip)->i_flag & IN_CLEANING))   \
+               ++(ip)->i_lfs->lfs_uinodes;                             \
+       if (((flags) & IN_MODIFIED) && !((ip)->i_flag & IN_MODIFIED))   \
+               ++(ip)->i_lfs->lfs_uinodes;                             \
+       (ip)->i_flag |= (flags);                                        \
+} while (0)
+
+#define LFS_CLR_UINO(ip, flags) do {                                   \
+       if (((flags) & IN_ACCESSED) && ((ip)->i_flag & IN_ACCESSED))    \
+               --(ip)->i_lfs->lfs_uinodes;                             \
+       if (((flags) & IN_CLEANING) && ((ip)->i_flag & IN_CLEANING))    \
+               --(ip)->i_lfs->lfs_uinodes;                             \
+       if (((flags) & IN_MODIFIED) && ((ip)->i_flag & IN_MODIFIED))    \
+               --(ip)->i_lfs->lfs_uinodes;                             \
+       (ip)->i_flag &= ~(flags);                                       \
+       if ((ip)->i_lfs->lfs_uinodes < 0) {                             \
+               panic("lfs_uinodes < 0");                               \
+       }                                                               \
+} while (0)
+
+#define LFS_ITIMES(ip, acc, mod, cre) \
+       while ((ip)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY)) \
+               lfs_itimes(ip, acc, mod, cre)
+
+/*
+ * "struct vnode" associated definitions
+ */
+
+/* Heuristic emptiness measure */
+#define VPISEMPTY(vp)   (LIST_EMPTY(&(vp)->v_dirtyblkhd) &&            \
+                         !(vp->v_type == VREG && (vp)->v_iflag & VI_ONWORKLST) &&\
+                         VTOI(vp)->i_lfs_nbtree == 0)
+
+#define WRITEINPROG(vp) ((vp)->v_numoutput > 0 ||                      \
+       (!LIST_EMPTY(&(vp)->v_dirtyblkhd) &&                            \
+        !(VTOI(vp)->i_flag & (IN_MODIFIED | IN_ACCESSED | IN_CLEANING))))
+
+
+/*
+ * On-disk and in-memory checkpoint segment usage structure.
+ */
+typedef struct segusage SEGUSE;
+struct segusage {
+       u_int32_t su_nbytes;            /* 0: number of live bytes */
+       u_int32_t su_olastmod;          /* 4: SEGUSE last modified timestamp */
+       u_int16_t su_nsums;             /* 8: number of summaries in segment */
+       u_int16_t su_ninos;             /* 10: number of inode blocks in seg */
+
+#define        SEGUSE_ACTIVE           0x01    /*  segment currently being written */
+#define        SEGUSE_DIRTY            0x02    /*  segment has data in it */
+#define        SEGUSE_SUPERBLOCK       0x04    /*  segment contains a superblock */
+#define SEGUSE_ERROR           0x08    /*  cleaner: do not clean segment */
+#define SEGUSE_EMPTY           0x10    /*  segment is empty */
+#define SEGUSE_INVAL           0x20    /*  segment is invalid */
+       u_int32_t su_flags;             /* 12: segment flags */
+       u_int64_t su_lastmod;           /* 16: last modified timestamp */
+};
+
+typedef struct segusage_v1 SEGUSE_V1;
+struct segusage_v1 {
+       u_int32_t su_nbytes;            /* 0: number of live bytes */
+       u_int32_t su_lastmod;           /* 4: SEGUSE last modified timestamp */
+       u_int16_t su_nsums;             /* 8: number of summaries in segment */
+       u_int16_t su_ninos;             /* 10: number of inode blocks in seg */
+       u_int32_t su_flags;             /* 12: segment flags  */
+};
+
+#define        SEGUPB(fs)      (fs->lfs_sepb)
+#define        SEGTABSIZE_SU(fs)                                               \
+       (((fs)->lfs_nseg + SEGUPB(fs) - 1) / (fs)->lfs_sepb)
+
+#ifdef _KERNEL
+# define SHARE_IFLOCK(F)                                               \
+  do {                                                                 \
+       rw_enter(&(F)->lfs_iflock, RW_READER);                          \
+  } while(0)
+# define UNSHARE_IFLOCK(F)                                             \
+  do {                                                                 \
+       rw_exit(&(F)->lfs_iflock);                                      \
+  } while(0)
+#else /* ! _KERNEL */
+# define SHARE_IFLOCK(F)
+# define UNSHARE_IFLOCK(F)
+#endif /* ! _KERNEL */
+
+/* Read in the block with a specific segment usage entry from the ifile. */
+#define        LFS_SEGENTRY(SP, F, IN, BP) do {                                \
+       int _e;                                                         \
+       SHARE_IFLOCK(F);                                                \
+       VTOI((F)->lfs_ivnode)->i_flag |= IN_ACCESS;                     \
+       if ((_e = bread((F)->lfs_ivnode,                                \
+           ((IN) / (F)->lfs_sepb) + (F)->lfs_cleansz,                  \
+           (F)->lfs_bsize, NOCRED, 0, &(BP))) != 0)                    \
+               panic("lfs: ifile read: %d", _e);                       \
+       if ((F)->lfs_version == 1)                                      \
+               (SP) = (SEGUSE *)((SEGUSE_V1 *)(BP)->b_data +           \
+                       ((IN) & ((F)->lfs_sepb - 1)));                  \
+       else                                                            \
+               (SP) = (SEGUSE *)(BP)->b_data + ((IN) % (F)->lfs_sepb); \
+       UNSHARE_IFLOCK(F);                                              \
+} while (0)
+
+#define LFS_WRITESEGENTRY(SP, F, IN, BP) do {                          \
+       if ((SP)->su_nbytes == 0)                                       \
+               (SP)->su_flags |= SEGUSE_EMPTY;                         \
+       else                                                            \
+               (SP)->su_flags &= ~SEGUSE_EMPTY;                        \
+       (F)->lfs_suflags[(F)->lfs_activesb][(IN)] = (SP)->su_flags;     \
+       LFS_BWRITE_LOG(BP);                                             \
+} while (0)
+
+/*
+ * On-disk file information.  One per file with data blocks in the segment.
+ */
+typedef struct finfo FINFO;
+struct finfo {
+       u_int32_t fi_nblocks;           /* number of blocks */
+       u_int32_t fi_version;           /* version number */
+       u_int32_t fi_ino;               /* inode number */
+       u_int32_t fi_lastlength;        /* length of last block in array */
+       int32_t   fi_blocks[1];         /* array of logical block numbers */
+};
+/* sizeof FINFO except fi_blocks */
+#define        FINFOSIZE       (sizeof(FINFO) - sizeof(int32_t))
+
+/*
+ * Index file inode entries.
+ */
+typedef struct ifile IFILE;
+struct ifile {
+       u_int32_t if_version;           /* inode version number */
+#define        LFS_UNUSED_DADDR        0       /* out-of-band daddr */
+       int32_t   if_daddr;             /* inode disk address */
+#define LFS_ORPHAN_NEXTFREE    (~(u_int32_t)0) /* indicate orphaned file */
+       u_int32_t if_nextfree;          /* next-unallocated inode */
+       u_int32_t if_atime_sec;         /* Last access time, seconds */
+       u_int32_t if_atime_nsec;        /* and nanoseconds */
+};
+
+typedef struct ifile_v1 IFILE_V1;
+struct ifile_v1 {
+       u_int32_t if_version;           /* inode version number */
+       int32_t   if_daddr;             /* inode disk address */
+       u_int32_t if_nextfree;          /* next-unallocated inode */
+#if LFS_ATIME_IFILE
+       struct timespec if_atime;       /* Last access time */
+#endif
+};
+
+/*
+ * LFSv1 compatibility code is not allowed to touch if_atime, since it
+ * may not be mapped!
+ */
+/* Read in the block with a specific inode from the ifile. */
+#define        LFS_IENTRY(IP, F, IN, BP) do {                                  \
+       int _e;                                                         \
+       SHARE_IFLOCK(F);                                                \
+       VTOI((F)->lfs_ivnode)->i_flag |= IN_ACCESS;                     \
+       if ((_e = bread((F)->lfs_ivnode,                                \
+       (IN) / (F)->lfs_ifpb + (F)->lfs_cleansz + (F)->lfs_segtabsz,    \
+       (F)->lfs_bsize, NOCRED, 0, &(BP))) != 0)                        \
+               panic("lfs: ifile ino %d read %d", (int)(IN), _e);      \
+       if ((F)->lfs_version == 1)                                      \
+               (IP) = (IFILE *)((IFILE_V1 *)(BP)->b_data +             \
+                                (IN) % (F)->lfs_ifpb);                 \
+       else                                                            \
+               (IP) = (IFILE *)(BP)->b_data + (IN) % (F)->lfs_ifpb;    \
+       UNSHARE_IFLOCK(F);                                              \
+} while (0)
+
+/*
+ * Cleaner information structure.  This resides in the ifile and is used
+ * to pass information from the kernel to the cleaner.
+ */
+typedef struct _cleanerinfo {
+       u_int32_t clean;                /* number of clean segments */
+       u_int32_t dirty;                /* number of dirty segments */
+       int32_t   bfree;                /* disk blocks free */
+       int32_t   avail;                /* disk blocks available */
+       u_int32_t free_head;            /* head of the inode free list */
+       u_int32_t free_tail;            /* tail of the inode free list */
+#define LFS_CLEANER_MUST_CLEAN 0x01
+       u_int32_t flags;                /* status word from the kernel */
+} CLEANERINFO;
+
+#define        CLEANSIZE_SU(fs)                                                \
+       ((sizeof(CLEANERINFO) + (fs)->lfs_bsize - 1) >> (fs)->lfs_bshift)
+
+/* Read in the block with the cleaner info from the ifile. */
+#define LFS_CLEANERINFO(CP, F, BP) do {                                        \
+       SHARE_IFLOCK(F);                                                \
+       VTOI((F)->lfs_ivnode)->i_flag |= IN_ACCESS;                     \
+       if (bread((F)->lfs_ivnode,                                      \
+           (daddr_t)0, (F)->lfs_bsize, NOCRED, 0, &(BP)))              \
+               panic("lfs: ifile read");                               \
+       (CP) = (CLEANERINFO *)(BP)->b_data;                             \
+       UNSHARE_IFLOCK(F);                                              \
+} while (0)
+
+/*
+ * Synchronize the Ifile cleaner info with current avail and bfree.
+ */
+#define LFS_SYNC_CLEANERINFO(cip, fs, bp, w) do {                      \
+    mutex_enter(&lfs_lock);                                            \
+    if ((w) || (cip)->bfree != (fs)->lfs_bfree ||                      \
+       (cip)->avail != (fs)->lfs_avail - (fs)->lfs_ravail -            \
+       (fs)->lfs_favail) {                                             \
+       (cip)->bfree = (fs)->lfs_bfree;                                 \
+       (cip)->avail = (fs)->lfs_avail - (fs)->lfs_ravail -             \
+               (fs)->lfs_favail;                                       \
+       if (((bp)->b_flags & B_GATHERED) == 0) {                        \
+               (fs)->lfs_flags |= LFS_IFDIRTY;                         \
+       }                                                               \
+       mutex_exit(&lfs_lock);                                          \
+       (void) LFS_BWRITE_LOG(bp); /* Ifile */                          \
+    } else {                                                           \
+       mutex_exit(&lfs_lock);                                          \
+       brelse(bp, 0);                                                  \
+    }                                                                  \
+} while (0)
+
+/*
+ * Get the head of the inode free list.
+ * Always called with the segment lock held.
+ */
+#define LFS_GET_HEADFREE(FS, CIP, BP, FREEP) do {                      \
+       if ((FS)->lfs_version > 1) {                                    \
+               LFS_CLEANERINFO((CIP), (FS), (BP));                     \
+               (FS)->lfs_freehd = (CIP)->free_head;                    \
+               brelse(BP, 0);                                          \
+       }                                                               \
+       *(FREEP) = (FS)->lfs_freehd;                                    \
+} while (0)
+
+#define LFS_PUT_HEADFREE(FS, CIP, BP, VAL) do {                                \
+       (FS)->lfs_freehd = (VAL);                                       \
+       if ((FS)->lfs_version > 1) {                                    \
+               LFS_CLEANERINFO((CIP), (FS), (BP));                     \
+               (CIP)->free_head = (VAL);                               \
+               LFS_BWRITE_LOG(BP);                                     \
+               mutex_enter(&lfs_lock);                                 \
+               (FS)->lfs_flags |= LFS_IFDIRTY;                         \
+               mutex_exit(&lfs_lock);                                  \
+       }                                                               \
+} while (0)
+
+#define LFS_GET_TAILFREE(FS, CIP, BP, FREEP) do {                      \
+       LFS_CLEANERINFO((CIP), (FS), (BP));                             \
+       *(FREEP) = (CIP)->free_tail;                                    \
+       brelse(BP, 0);                                                  \
+} while (0)
+
+#define LFS_PUT_TAILFREE(FS, CIP, BP, VAL) do {                                \
+       LFS_CLEANERINFO((CIP), (FS), (BP));                             \
+       (CIP)->free_tail = (VAL);                                       \
+       LFS_BWRITE_LOG(BP);                                             \
+       mutex_enter(&lfs_lock);                                         \
+       (FS)->lfs_flags |= LFS_IFDIRTY;                                 \
+       mutex_exit(&lfs_lock);                                          \
+} while (0)
+
+/*
+ * On-disk segment summary information
+ */
+typedef struct segsum_v1 SEGSUM_V1;
+struct segsum_v1 {
+       u_int32_t ss_sumsum;            /* 0: check sum of summary block */
+       u_int32_t ss_datasum;           /* 4: check sum of data */
+       u_int32_t ss_magic;             /* 8: segment summary magic number */
+#define SS_MAGIC       0x061561
+       int32_t   ss_next;              /* 12: next segment */
+       u_int32_t ss_create;            /* 16: creation time stamp */
+       u_int16_t ss_nfinfo;            /* 20: number of file info structures */
+       u_int16_t ss_ninos;             /* 22: number of inodes in summary */
+
+#define        SS_DIROP        0x01            /* segment begins a dirop */
+#define        SS_CONT         0x02            /* more partials to finish this write*/
+#define        SS_CLEAN        0x04            /* written by the cleaner */
+#define        SS_RFW          0x08            /* written by the roll-forward agent */
+       u_int16_t ss_flags;             /* 24: used for directory operations */
+       u_int16_t ss_pad;               /* 26: extra space */
+       /* FINFO's and inode daddr's... */
+};
+
+typedef struct segsum SEGSUM;
+struct segsum {
+       u_int32_t ss_sumsum;            /* 0: check sum of summary block */
+       u_int32_t ss_datasum;           /* 4: check sum of data */
+       u_int32_t ss_magic;             /* 8: segment summary magic number */
+       int32_t   ss_next;              /* 12: next segment */
+       u_int32_t ss_ident;             /* 16: roll-forward fsid */
+#define ss_ocreate ss_ident /* ident is where create was in v1 */
+       u_int16_t ss_nfinfo;            /* 20: number of file info structures */
+       u_int16_t ss_ninos;             /* 22: number of inodes in summary */
+       u_int16_t ss_flags;             /* 24: used for directory operations */
+       u_int8_t  ss_pad[6];            /* 26: extra space */
+       u_int64_t ss_serial;            /* 32: serial number */
+       u_int64_t ss_create;            /* 40: time stamp */
+       /* FINFO's and inode daddr's... */
+};
+
+#define SEGSUM_SIZE(fs) ((fs)->lfs_version == 1 ? sizeof(SEGSUM_V1) : sizeof(SEGSUM))
+
+
+/*
+ * On-disk super block.
+ */
+struct dlfs {
+#define               LFS_MAGIC       0x070162
+       u_int32_t dlfs_magic;     /* 0: magic number */
+#define               LFS_VERSION     2
+       u_int32_t dlfs_version;   /* 4: version number */
+
+       u_int32_t dlfs_size;      /* 8: number of blocks in fs (v1) */
+                                 /*    number of frags in fs (v2) */
+       u_int32_t dlfs_ssize;     /* 12: number of blocks per segment (v1) */
+                                 /*     number of bytes per segment (v2) */
+       u_int32_t dlfs_dsize;     /* 16: number of disk blocks in fs */
+       u_int32_t dlfs_bsize;     /* 20: file system block size */
+       u_int32_t dlfs_fsize;     /* 24: size of frag blocks in fs */
+       u_int32_t dlfs_frag;      /* 28: number of frags in a block in fs */
+
+/* Checkpoint region. */
+       u_int32_t dlfs_freehd;    /* 32: start of the free list */
+       int32_t   dlfs_bfree;     /* 36: number of free disk blocks */
+       u_int32_t dlfs_nfiles;    /* 40: number of allocated inodes */
+       int32_t   dlfs_avail;     /* 44: blocks available for writing */
+       int32_t   dlfs_uinodes;   /* 48: inodes in cache not yet on disk */
+       int32_t   dlfs_idaddr;    /* 52: inode file disk address */
+       u_int32_t dlfs_ifile;     /* 56: inode file inode number */
+       int32_t   dlfs_lastseg;   /* 60: address of last segment written */
+       int32_t   dlfs_nextseg;   /* 64: address of next segment to write */
+       int32_t   dlfs_curseg;    /* 68: current segment being written */
+       int32_t   dlfs_offset;    /* 72: offset in curseg for next partial */
+       int32_t   dlfs_lastpseg;  /* 76: address of last partial written */
+       u_int32_t dlfs_inopf;     /* 80: v1: time stamp; v2: inodes per frag */
+#define dlfs_otstamp dlfs_inopf
+
+/* These are configuration parameters. */
+       u_int32_t dlfs_minfree;   /* 84: minimum percentage of free blocks */
+
+/* These fields can be computed from the others. */
+       u_int64_t dlfs_maxfilesize; /* 88: maximum representable file size */
+       u_int32_t dlfs_fsbpseg;     /* 96: fsb per segment */
+       u_int32_t dlfs_inopb;     /* 100: inodes per block */
+       u_int32_t dlfs_ifpb;      /* 104: IFILE entries per block */
+       u_int32_t dlfs_sepb;      /* 108: SEGUSE entries per block */
+       u_int32_t dlfs_nindir;    /* 112: indirect pointers per block */
+       u_int32_t dlfs_nseg;      /* 116: number of segments */
+       u_int32_t dlfs_nspf;      /* 120: number of sectors per fragment */
+       u_int32_t dlfs_cleansz;   /* 124: cleaner info size in blocks */
+       u_int32_t dlfs_segtabsz;  /* 128: segment table size in blocks */
+       u_int32_t dlfs_segmask;   /* 132: calculate offset within a segment */
+       u_int32_t dlfs_segshift;  /* 136: fast mult/div for segments */
+       u_int32_t dlfs_bshift;    /* 140: calc block number from file offset */
+       u_int32_t dlfs_ffshift;   /* 144: fast mult/div for frag from file */
+       u_int32_t dlfs_fbshift;   /* 148: fast mult/div for frag from block */
+       u_int64_t dlfs_bmask;     /* 152: calc block offset from file offset */
+       u_int64_t dlfs_ffmask;    /* 160: calc frag offset from file offset */
+       u_int64_t dlfs_fbmask;    /* 168: calc frag offset from block offset */
+       u_int32_t dlfs_blktodb;   /* 176: blktodb and dbtoblk shift constant */
+       u_int32_t dlfs_sushift;   /* 180: fast mult/div for segusage table */
+
+       int32_t   dlfs_maxsymlinklen; /* 184: max length of an internal symlink */
+#define LFS_MIN_SBINTERVAL     5  /* minimum superblock segment spacing */
+#define LFS_MAXNUMSB          10 /* 188: superblock disk offsets */
+       int32_t    dlfs_sboffs[LFS_MAXNUMSB];
+
+       u_int32_t dlfs_nclean;    /* 228: Number of clean segments */
+       u_char    dlfs_fsmnt[MNAMELEN];  /* 232: name mounted on */
+#define LFS_PF_CLEAN 0x1
+       u_int16_t dlfs_pflags;    /* 322: file system persistent flags */
+       int32_t   dlfs_dmeta;     /* 324: total number of dirty summaries */
+       u_int32_t dlfs_minfreeseg; /* 328: segments not counted in bfree */
+       u_int32_t dlfs_sumsize;   /* 332: size of summary blocks */
+       u_int64_t dlfs_serial;    /* 336: serial number */
+       u_int32_t dlfs_ibsize;    /* 344: size of inode blocks */
+       int32_t   dlfs_start;     /* 348: start of segment 0 */
+       u_int64_t dlfs_tstamp;    /* 352: time stamp */
+#define LFS_44INODEFMT 0
+#define LFS_MAXINODEFMT 0
+       u_int32_t dlfs_inodefmt;  /* 360: inode format version */
+       u_int32_t dlfs_interleave; /* 364: segment interleave */
+       u_int32_t dlfs_ident;     /* 368: per-fs identifier */
+       u_int32_t dlfs_fsbtodb;   /* 372: fsbtodb abd dbtodsb shift constant */
+       u_int32_t dlfs_resvseg;   /* 376: segments reserved for the cleaner */
+       int8_t    dlfs_pad[128];  /* 380: round to 512 bytes */
+/* Checksum -- last valid disk field. */
+       u_int32_t dlfs_cksum;     /* 508: checksum for superblock checking */
+};
+
+/* Type used for the inode bitmap */
+typedef u_int32_t lfs_bm_t;
+
+/*
+ * Linked list of segments whose byte count needs updating following a
+ * file truncation.
+ */
+struct segdelta {
+       long segnum;
+       size_t num;
+       LIST_ENTRY(segdelta) list;
+};
+
+/*
+ * In-memory super block.
+ */
+struct lfs {
+       struct dlfs lfs_dlfs;           /* on-disk parameters */
+#define lfs_magic lfs_dlfs.dlfs_magic
+#define lfs_version lfs_dlfs.dlfs_version
+#define lfs_size lfs_dlfs.dlfs_size
+#define lfs_ssize lfs_dlfs.dlfs_ssize
+#define lfs_dsize lfs_dlfs.dlfs_dsize
+#define lfs_bsize lfs_dlfs.dlfs_bsize
+#define lfs_fsize lfs_dlfs.dlfs_fsize
+#define lfs_frag lfs_dlfs.dlfs_frag
+#define lfs_freehd lfs_dlfs.dlfs_freehd
+#define lfs_bfree lfs_dlfs.dlfs_bfree
+#define lfs_nfiles lfs_dlfs.dlfs_nfiles
+#define lfs_avail lfs_dlfs.dlfs_avail
+#define lfs_uinodes lfs_dlfs.dlfs_uinodes
+#define lfs_idaddr lfs_dlfs.dlfs_idaddr
+#define lfs_ifile lfs_dlfs.dlfs_ifile
+#define lfs_lastseg lfs_dlfs.dlfs_lastseg
+#define lfs_nextseg lfs_dlfs.dlfs_nextseg
+#define lfs_curseg lfs_dlfs.dlfs_curseg
+#define lfs_offset lfs_dlfs.dlfs_offset
+#define lfs_lastpseg lfs_dlfs.dlfs_lastpseg
+#define lfs_otstamp lfs_dlfs.dlfs_inopf
+#define lfs_inopf lfs_dlfs.dlfs_inopf
+#define lfs_minfree lfs_dlfs.dlfs_minfree
+#define lfs_maxfilesize lfs_dlfs.dlfs_maxfilesize
+#define lfs_fsbpseg lfs_dlfs.dlfs_fsbpseg
+#define lfs_inopb lfs_dlfs.dlfs_inopb
+#define lfs_ifpb lfs_dlfs.dlfs_ifpb
+#define lfs_sepb lfs_dlfs.dlfs_sepb
+#define lfs_nindir lfs_dlfs.dlfs_nindir
+#define lfs_nseg lfs_dlfs.dlfs_nseg
+#define lfs_nspf lfs_dlfs.dlfs_nspf
+#define lfs_cleansz lfs_dlfs.dlfs_cleansz
+#define lfs_segtabsz lfs_dlfs.dlfs_segtabsz
+#define lfs_segmask lfs_dlfs.dlfs_segmask
+#define lfs_segshift lfs_dlfs.dlfs_segshift
+#define lfs_bmask lfs_dlfs.dlfs_bmask
+#define lfs_bshift lfs_dlfs.dlfs_bshift
+#define lfs_ffmask lfs_dlfs.dlfs_ffmask
+#define lfs_ffshift lfs_dlfs.dlfs_ffshift
+#define lfs_fbmask lfs_dlfs.dlfs_fbmask
+#define lfs_fbshift lfs_dlfs.dlfs_fbshift
+#define lfs_blktodb lfs_dlfs.dlfs_blktodb
+#define lfs_fsbtodb lfs_dlfs.dlfs_fsbtodb
+#define lfs_sushift lfs_dlfs.dlfs_sushift
+#define lfs_maxsymlinklen lfs_dlfs.dlfs_maxsymlinklen
+#define lfs_sboffs lfs_dlfs.dlfs_sboffs
+#define lfs_cksum lfs_dlfs.dlfs_cksum
+#define lfs_pflags lfs_dlfs.dlfs_pflags
+#define lfs_fsmnt lfs_dlfs.dlfs_fsmnt
+#define lfs_nclean lfs_dlfs.dlfs_nclean
+#define lfs_dmeta lfs_dlfs.dlfs_dmeta
+#define lfs_minfreeseg lfs_dlfs.dlfs_minfreeseg
+#define lfs_sumsize lfs_dlfs.dlfs_sumsize
+#define lfs_serial lfs_dlfs.dlfs_serial
+#define lfs_ibsize lfs_dlfs.dlfs_ibsize
+#define lfs_start lfs_dlfs.dlfs_start
+#define lfs_tstamp lfs_dlfs.dlfs_tstamp
+#define lfs_inodefmt lfs_dlfs.dlfs_inodefmt
+#define lfs_interleave lfs_dlfs.dlfs_interleave
+#define lfs_ident lfs_dlfs.dlfs_ident
+#define lfs_resvseg lfs_dlfs.dlfs_resvseg
+
+/* These fields are set at mount time and are meaningless on disk. */
+       struct segment *lfs_sp;         /* current segment being written */
+       struct vnode *lfs_ivnode;       /* vnode for the ifile */
+       u_int32_t  lfs_seglock;         /* single-thread the segment writer */
+       pid_t     lfs_lockpid;          /* pid of lock holder */
+       lwpid_t   lfs_locklwp;          /* lwp of lock holder */
+       u_int32_t lfs_iocount;          /* number of ios pending */
+       u_int32_t lfs_writer;           /* don't allow any dirops to start */
+       u_int32_t lfs_dirops;           /* count of active directory ops */
+       u_int32_t lfs_dirvcount;        /* count of VDIROP nodes in this fs */
+       u_int32_t lfs_doifile;          /* Write ifile blocks on next write */
+       u_int32_t lfs_nactive;          /* Number of segments since last ckp */
+       int8_t    lfs_fmod;             /* super block modified flag */
+       int8_t    lfs_ronly;            /* mounted read-only flag */
+#define LFS_NOTYET  0x01
+#define LFS_IFDIRTY 0x02
+#define LFS_WARNED  0x04
+#define LFS_UNDIROP 0x08
+       int8_t    lfs_flags;            /* currently unused flag */
+       u_int16_t lfs_activesb;         /* toggle between superblocks */
+       daddr_t   lfs_sbactive;         /* disk address of current sb write */
+       struct vnode *lfs_flushvp;      /* vnode being flushed */
+       int lfs_flushvp_fakevref;       /* fake vref count for flushvp */
+       struct vnode *lfs_unlockvp;     /* being inactivated in lfs_segunlock */
+       u_int32_t lfs_diropwait;        /* # procs waiting on dirop flush */
+       size_t lfs_devbsize;            /* Device block size */
+       size_t lfs_devbshift;           /* Device block shift */
+       krwlock_t lfs_fraglock;
+       krwlock_t lfs_iflock;           /* Ifile lock */
+       kcondvar_t lfs_stopcv;          /* Wrap lock */
+       struct lwp *lfs_stoplwp;
+       pid_t lfs_rfpid;                /* Process ID of roll-forward agent */
+       int       lfs_nadirop;          /* number of active dirop nodes */
+       long      lfs_ravail;           /* blocks pre-reserved for writing */
+       long      lfs_favail;           /* blocks pre-reserved for writing */
+       res_t *lfs_resblk;              /* Reserved memory for pageout */
+       TAILQ_HEAD(, inode) lfs_dchainhd; /* dirop vnodes */
+       TAILQ_HEAD(, inode) lfs_pchainhd; /* paging vnodes */
+#define LFS_RESHASH_WIDTH 17
+       LIST_HEAD(, lfs_res_blk) lfs_reshash[LFS_RESHASH_WIDTH];
+       int       lfs_pdflush;           /* pagedaemon wants us to flush */
+       u_int32_t **lfs_suflags;        /* Segment use flags */
+#ifdef _KERNEL
+       struct pool lfs_clpool;         /* Pool for struct lfs_cluster */
+       struct pool lfs_bpppool;        /* Pool for bpp */
+       struct pool lfs_segpool;        /* Pool for struct segment */
+#endif /* _KERNEL */
+#define LFS_MAX_CLEANIND 64
+       int32_t  lfs_cleanint[LFS_MAX_CLEANIND]; /* Active cleaning intervals */
+       int      lfs_cleanind;          /* Index into intervals */
+       int lfs_sleepers;               /* # procs sleeping this fs */
+       int lfs_pages;                  /* dirty pages blaming this fs */
+       lfs_bm_t *lfs_ino_bitmap;       /* Inuse inodes bitmap */
+       int lfs_nowrap;                 /* Suspend log wrap */
+       int lfs_wrappass;               /* Allow first log wrap requester to pass */
+       int lfs_wrapstatus;             /* Wrap status */
+       LIST_HEAD(, segdelta) lfs_segdhd;       /* List of pending trunc accounting events */
+};
+
+/* NINDIR is the number of indirects in a file system block. */
+#define        NINDIR(fs)      ((fs)->lfs_nindir)
+
+/* INOPB is the number of inodes in a secondary storage block. */
+#define        INOPB(fs)       ((fs)->lfs_inopb)
+/* INOPF is the number of inodes in a fragment. */
+#define INOPF(fs)      ((fs)->lfs_inopf)
+
+#define        blksize(fs, ip, lbn) \
+       (((lbn) >= NDADDR || (ip)->i_ffs1_size >= ((lbn) + 1) << (fs)->lfs_bshift) \
+           ? (fs)->lfs_bsize \
+           : (fragroundup(fs, blkoff(fs, (ip)->i_ffs1_size))))
+#define        blkoff(fs, loc)         ((int)((loc) & (fs)->lfs_bmask))
+#define fragoff(fs, loc)    /* calculates (loc % fs->lfs_fsize) */ \
+    ((int)((loc) & (fs)->lfs_ffmask))
+
+#if defined (_KERNEL)
+#define        fsbtodb(fs, b)          ((b) << ((fs)->lfs_ffshift - DEV_BSHIFT))
+#define        dbtofsb(fs, b)          ((b) >> ((fs)->lfs_ffshift - DEV_BSHIFT))
+#else
+#define        fsbtodb(fs, b)          ((b) << (fs)->lfs_fsbtodb)
+#define        dbtofsb(fs, b)          ((b) >> (fs)->lfs_fsbtodb)
+#endif
+
+#define        lblkno(fs, loc)         ((loc) >> (fs)->lfs_bshift)
+#define        lblktosize(fs, blk)     ((blk) << (fs)->lfs_bshift)
+
+#define fsbtob(fs, b)          ((b) << (fs)->lfs_ffshift)
+#define btofsb(fs, b)          ((b) >> (fs)->lfs_ffshift)
+
+#define numfrags(fs, loc)      /* calculates (loc / fs->lfs_fsize) */  \
+       ((loc) >> (fs)->lfs_ffshift)
+#define blkroundup(fs, size)   /* calculates roundup(size, fs->lfs_bsize) */ \
+       ((off_t)(((size) + (fs)->lfs_bmask) & (~(fs)->lfs_bmask)))
+#define fragroundup(fs, size)  /* calculates roundup(size, fs->lfs_fsize) */ \
+       ((off_t)(((size) + (fs)->lfs_ffmask) & (~(fs)->lfs_ffmask)))
+#define fragstoblks(fs, frags)/* calculates (frags / fs->fs_frag) */ \
+       ((frags) >> (fs)->lfs_fbshift)
+#define blkstofrags(fs, blks)  /* calculates (blks * fs->fs_frag) */ \
+       ((blks) << (fs)->lfs_fbshift)
+#define fragnum(fs, fsb)       /* calculates (fsb % fs->lfs_frag) */   \
+       ((fsb) & ((fs)->lfs_frag - 1))
+#define blknum(fs, fsb)                /* calculates rounddown(fsb, fs->lfs_frag) */ \
+       ((fsb) &~ ((fs)->lfs_frag - 1))
+#define dblksize(fs, dp, lbn) \
+       (((lbn) >= NDADDR || (dp)->di_size >= ((lbn) + 1) << (fs)->lfs_bshift)\
+           ? (fs)->lfs_bsize \
+           : (fragroundup(fs, blkoff(fs, (dp)->di_size))))
+
+#define        segsize(fs)     ((fs)->lfs_version == 1 ?                       \
+                          lblktosize((fs), (fs)->lfs_ssize) :          \
+                          (fs)->lfs_ssize)
+#define segtod(fs, seg) (((fs)->lfs_version == 1     ?                 \
+                          (fs)->lfs_ssize << (fs)->lfs_blktodb :       \
+                          btofsb((fs), (fs)->lfs_ssize)) * (seg))
+#define        dtosn(fs, daddr)        /* block address to segment number */   \
+       ((uint32_t)(((daddr) - (fs)->lfs_start) / segtod((fs), 1)))
+#define sntod(fs, sn)          /* segment number to disk address */    \
+       ((daddr_t)(segtod((fs), (sn)) + (fs)->lfs_start))
+
+/*
+ * Structures used by lfs_bmapv and lfs_markv to communicate information
+ * about inodes and data blocks.
+ */
+typedef struct block_info {
+       u_int32_t bi_inode;             /* inode # */
+       int32_t bi_lbn;                 /* logical block w/in file */
+       int32_t bi_daddr;               /* disk address of block */
+       u_int64_t bi_segcreate;         /* origin segment create time */
+       int     bi_version;             /* file version number */
+       void    *bi_bp;                 /* data buffer */
+       int     bi_size;                /* size of the block (if fragment) */
+} BLOCK_INFO;
+
+/* Compatibility for 1.5 binaries */
+typedef struct block_info_15 {
+       u_int32_t bi_inode;             /* inode # */
+       int32_t bi_lbn;                 /* logical block w/in file */
+       int32_t bi_daddr;               /* disk address of block */
+       u_int32_t bi_segcreate;         /* origin segment create time */
+       int     bi_version;             /* file version number */
+       void    *bi_bp;                 /* data buffer */
+       int     bi_size;                /* size of the block (if fragment) */
+} BLOCK_INFO_15;
+
+/* In-memory description of a segment about to be written. */
+struct segment {
+       struct lfs       *fs;           /* file system pointer */
+       struct buf      **bpp;          /* pointer to buffer array */
+       struct buf      **cbpp;         /* pointer to next available bp */
+       struct buf      **start_bpp;    /* pointer to first bp in this set */
+       struct buf       *ibp;          /* buffer pointer to inode page */
+       struct ufs1_dinode    *idp;          /* pointer to ifile dinode */
+       struct finfo     *fip;          /* current fileinfo pointer */
+       struct vnode     *vp;           /* vnode being gathered */
+       void     *segsum;               /* segment summary info */
+       u_int32_t ninodes;              /* number of inodes in this segment */
+       int32_t seg_bytes_left;         /* bytes left in segment */
+       int32_t sum_bytes_left;         /* bytes left in summary block */
+       u_int32_t seg_number;           /* number of this segment */
+       int32_t *start_lbp;             /* beginning lbn for this set */
+
+#define        SEGM_CKP        0x01            /* doing a checkpoint */
+#define        SEGM_CLEAN      0x02            /* cleaner call; don't sort */
+#define        SEGM_SYNC       0x04            /* wait for segment */
+#define        SEGM_PROT       0x08            /* don't inactivate at segunlock */
+#define SEGM_PAGEDAEMON        0x10            /* pagedaemon called us */
+#define SEGM_WRITERD   0x20            /* LFS writed called us */
+#define SEGM_FORCE_CKP 0x40            /* Force checkpoint right away */
+       u_int16_t seg_flags;            /* run-time flags for this segment */
+       u_int32_t seg_iocount;          /* number of ios pending */
+       int       ndupino;              /* number of duplicate inodes */
+};
+
+#ifdef _KERNEL
+struct lfs_cluster {
+       size_t bufsize;        /* Size of kept data */
+       struct buf **bpp;      /* Array of kept buffers */
+       int bufcount;          /* Number of kept buffers */
+#define LFS_CL_MALLOC  0x00000001
+#define LFS_CL_SHIFT   0x00000002
+#define LFS_CL_SYNC    0x00000004
+       u_int32_t flags;       /* Flags */
+       struct lfs *fs;        /* LFS that this belongs to */
+       struct segment *seg;   /* Segment structure, for LFS_CL_SYNC */
+};
+
+/*
+ * Splay tree containing block numbers allocated through lfs_balloc.
+ */
+struct lbnentry {
+       SPLAY_ENTRY(lbnentry) entry;
+       daddr_t lbn;
+};
+#endif /* _KERNEL */
+
+/*
+ * LFS inode extensions.
+ */
+struct lfs_inode_ext {
+       off_t     lfs_osize;            /* size of file on disk */
+       u_int32_t lfs_effnblocks;  /* number of blocks when i/o completes */
+       size_t    lfs_fragsize[NDADDR]; /* size of on-disk direct blocks */
+       TAILQ_ENTRY(inode) lfs_dchain;  /* Dirop chain. */
+       TAILQ_ENTRY(inode) lfs_pchain;  /* Paging chain. */
+#define LFSI_NO_GOP_WRITE 0x01
+#define LFSI_DELETED      0x02
+#define LFSI_WRAPBLOCK    0x04
+#define LFSI_WRAPWAIT     0x08
+       u_int32_t lfs_iflags;           /* Inode flags */
+       daddr_t   lfs_hiblk;            /* Highest lbn held by inode */
+#ifdef _KERNEL
+       SPLAY_HEAD(lfs_splay, lbnentry) lfs_lbtree; /* Tree of balloc'd lbns */
+       int       lfs_nbtree;           /* Size of tree */
+       LIST_HEAD(, segdelta) lfs_segdhd;
+#endif
+       int16_t   lfs_odnlink;          /* on-disk nlink count for cleaner */
+};
+#define i_lfs_osize            inode_ext.lfs->lfs_osize
+#define i_lfs_effnblks         inode_ext.lfs->lfs_effnblocks
+#define i_lfs_fragsize         inode_ext.lfs->lfs_fragsize
+#define i_lfs_dchain           inode_ext.lfs->lfs_dchain
+#define i_lfs_pchain           inode_ext.lfs->lfs_pchain
+#define i_lfs_iflags           inode_ext.lfs->lfs_iflags
+#define i_lfs_hiblk            inode_ext.lfs->lfs_hiblk
+#define i_lfs_lbtree           inode_ext.lfs->lfs_lbtree
+#define i_lfs_nbtree           inode_ext.lfs->lfs_nbtree
+#define i_lfs_segdhd           inode_ext.lfs->lfs_segdhd
+#define i_lfs_odnlink          inode_ext.lfs->lfs_odnlink
+
+/*
+ * Macros for determining free space on the disk, with the variable metadata
+ * of segment summaries and inode blocks taken into account.
+ */
+/* Estimate number of clean blocks not available for writing */
+#define LFS_EST_CMETA(F) (int32_t)((((F)->lfs_dmeta *                       \
+                                    (int64_t)(F)->lfs_nclean) /             \
+                                     ((F)->lfs_nseg - (F)->lfs_nclean)))
+
+/* Estimate total size of the disk not including metadata */
+#define LFS_EST_NONMETA(F) ((F)->lfs_dsize - (F)->lfs_dmeta - LFS_EST_CMETA(F))
+
+/* Estimate number of blocks actually available for writing */
+#define LFS_EST_BFREE(F) ((F)->lfs_bfree > LFS_EST_CMETA(F) ?               \
+                         (F)->lfs_bfree - LFS_EST_CMETA(F) : 0)
+
+/* Amount of non-meta space not available to mortal man */
+#define LFS_EST_RSVD(F) (int32_t)((LFS_EST_NONMETA(F) *                             \
+                                  (u_int64_t)(F)->lfs_minfree) /            \
+                                 100)
+
+/* Can credential C write BB blocks */
+#define ISSPACE(F, BB, C)                                              \
+       ((((C) == NOCRED || kauth_cred_geteuid(C) == 0) &&              \
+         LFS_EST_BFREE(F) >= (BB)) ||                                  \
+        (kauth_cred_geteuid(C) != 0 && IS_FREESPACE(F, BB)))
+
+/* Can an ordinary user write BB blocks */
+#define IS_FREESPACE(F, BB)                                            \
+         (LFS_EST_BFREE(F) >= (BB) + LFS_EST_RSVD(F))
+
+/*
+ * The minimum number of blocks to create a new inode.  This is:
+ * directory direct block (1) + NIADDR indirect blocks + inode block (1) +
+ * ifile direct block (1) + NIADDR indirect blocks = 3 + 2 * NIADDR blocks.
+ */
+#define LFS_NRESERVE(F) (btofsb((F), (2 * NIADDR + 3) << (F)->lfs_bshift))
+
+/* Statistics Counters */
+struct lfs_stats {     /* Must match sysctl list in lfs_vfsops.h ! */
+       u_int   segsused;
+       u_int   psegwrites;
+       u_int   psyncwrites;
+       u_int   pcleanwrites;
+       u_int   blocktot;
+       u_int   cleanblocks;
+       u_int   ncheckpoints;
+       u_int   nwrites;
+       u_int   nsync_writes;
+       u_int   wait_exceeded;
+       u_int   write_exceeded;
+       u_int   flush_invoked;
+       u_int   vflush_invoked;
+       u_int   clean_inlocked;
+       u_int   clean_vnlocked;
+       u_int   segs_reclaimed;
+};
+#ifdef _KERNEL
+extern struct lfs_stats lfs_stats;
+#endif
+
+/* Fcntls to take the place of the lfs syscalls */
+struct lfs_fcntl_markv {
+       BLOCK_INFO *blkiov;     /* blocks to relocate */
+       int blkcnt;             /* number of blocks */
+};
+
+#define LFCNSEGWAITALL _FCNR_FSPRIV('L', 14, struct timeval)
+#define LFCNSEGWAIT    _FCNR_FSPRIV('L', 15, struct timeval)
+#define LFCNBMAPV      _FCNRW_FSPRIV('L', 2, struct lfs_fcntl_markv)
+#define LFCNMARKV      _FCNRW_FSPRIV('L', 3, struct lfs_fcntl_markv)
+#define LFCNRECLAIM     _FCNO_FSPRIV('L', 4)
+
+struct lfs_fhandle {
+       char space[28]; /* FHANDLE_SIZE_COMPAT (but used from userland too) */
+};
+#define LFCNREWIND       _FCNR_FSPRIV('L', 6, int)
+#define LFCNINVAL        _FCNR_FSPRIV('L', 7, int)
+#define LFCNRESIZE       _FCNR_FSPRIV('L', 8, int)
+#define LFCNWRAPSTOP    _FCNR_FSPRIV('L', 9, int)
+#define LFCNWRAPGO      _FCNR_FSPRIV('L', 10, int)
+#define LFCNIFILEFH     _FCNW_FSPRIV('L', 11, struct lfs_fhandle)
+#define LFCNWRAPPASS    _FCNR_FSPRIV('L', 12, int)
+# define LFS_WRAP_GOING   0x0
+# define LFS_WRAP_WAITING 0x1
+#define LFCNWRAPSTATUS  _FCNW_FSPRIV('L', 13, int)
+
+/*
+ * Compat.  Defined for kernel only.  Userland always uses
+ * "the one true version".
+ */
+#ifdef _KERNEL
+#include <compat/sys/time_types.h>
+
+#define LFCNSEGWAITALL_COMPAT   _FCNW_FSPRIV('L', 0, struct timeval50)
+#define LFCNSEGWAIT_COMPAT      _FCNW_FSPRIV('L', 1, struct timeval50)
+#define LFCNIFILEFH_COMPAT      _FCNW_FSPRIV('L', 5, struct lfs_fhandle)
+#define LFCNIFILEFH_COMPAT2     _FCN_FSPRIV(F_FSOUT, 'L', 11, 32)
+#define LFCNWRAPSTOP_COMPAT     _FCNO_FSPRIV('L', 9)
+#define LFCNWRAPGO_COMPAT       _FCNO_FSPRIV('L', 10)
+#define LFCNSEGWAITALL_COMPAT_50 _FCNR_FSPRIV('L', 0, struct timeval50)
+#define LFCNSEGWAIT_COMPAT_50   _FCNR_FSPRIV('L', 1, struct timeval50)
+#endif
+
+#ifdef _KERNEL
+/* XXX MP */
+#define        LFS_SEGLOCK_HELD(fs) \
+       ((fs)->lfs_seglock != 0 &&                                      \
+        (fs)->lfs_lockpid == curproc->p_pid &&                         \
+        (fs)->lfs_locklwp == curlwp->l_lid)
+#endif /* _KERNEL */
+
+/* Debug segment lock */
+#ifdef notyet
+# define ASSERT_SEGLOCK(fs) KASSERT(LFS_SEGLOCK_HELD(fs))
+# define ASSERT_NO_SEGLOCK(fs) KASSERT(!LFS_SEGLOCK_HELD(fs))
+# define ASSERT_DUNNO_SEGLOCK(fs)
+# define ASSERT_MAYBE_SEGLOCK(fs)
+#else /* !notyet */
+# define ASSERT_DUNNO_SEGLOCK(fs) \
+       DLOG((DLOG_SEG, "lfs func %s seglock wrong (%d)\n", __func__, \
+               LFS_SEGLOCK_HELD(fs)))
+# define ASSERT_SEGLOCK(fs) do {                                       \
+       if (!LFS_SEGLOCK_HELD(fs)) {                                    \
+               DLOG((DLOG_SEG, "lfs func %s seglock wrong (0)\n", __func__)); \
+       }                                                               \
+} while(0)
+# define ASSERT_NO_SEGLOCK(fs) do {                                    \
+       if (LFS_SEGLOCK_HELD(fs)) {                                     \
+               DLOG((DLOG_SEG, "lfs func %s seglock wrong (1)\n", __func__)); \
+       }                                                               \
+} while(0)
+# define ASSERT_MAYBE_SEGLOCK(x)
+#endif /* !notyet */
+
+__BEGIN_DECLS
+void lfs_itimes(struct inode *, const struct timespec *,
+    const struct timespec *, const struct timespec *);
+__END_DECLS
+
+#endif /* !_UFS_LFS_LFS_H_ */
diff --git a/nbsd_include/ufs/lfs/lfs_extern.h b/nbsd_include/ufs/lfs/lfs_extern.h
new file mode 100644 (file)
index 0000000..46a9555
--- /dev/null
@@ -0,0 +1,287 @@
+/*     $NetBSD: lfs_extern.h,v 1.96 2008/06/28 01:34:05 rumble Exp $   */
+
+/*-
+ * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Konrad E. Schroder <perseant@hhhh.org>.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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) 1991, 1993, 1994
+ *     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.
+ *
+ *     @(#)lfs_extern.h        8.6 (Berkeley) 5/8/95
+ */
+
+#ifndef _UFS_LFS_LFS_EXTERN_H_
+#define _UFS_LFS_LFS_EXTERN_H_
+
+#ifdef _KERNEL
+#include <sys/mallocvar.h>
+
+MALLOC_DECLARE(M_SEGMENT);
+#endif
+
+/* Copied from ext2fs for ITIMES.  XXX This is a bogus use of v_tag. */
+#define IS_LFS_VNODE(vp)   (vp->v_tag == VT_LFS)
+
+/*
+ * Sysctl values for LFS.
+ */
+#define LFS_WRITEINDIR  1 /* flush indirect blocks on non-checkpoint writes */
+#define LFS_CLEAN_VNHEAD 2 /* put prev unrefed cleaned vnodes on head of free list */
+#define LFS_DOSTATS     3
+#define LFS_MAXPAGES    4
+#define LFS_FS_PAGETRIP         5
+#define LFS_STATS       6
+#define LFS_DO_RFW      7
+#define LFS_DEBUGLOG    8
+#define LFS_IGNORE_LAZY_SYNC   9
+#define LFS_MAXID       10
+
+struct fid;
+struct mount;
+struct nameidata;
+struct proc;
+struct statvfs;
+struct timeval;
+struct inode;
+struct uio;
+struct mbuf;
+struct ufs1_dinode;
+struct buf;
+struct vnode;
+struct dlfs;
+struct lfs;
+struct segment;
+struct block_info;
+
+#if defined(_KERNEL)
+
+extern int lfs_allclean_wakeup;
+extern struct pool lfs_inode_pool;             /* memory pool for inodes */
+extern struct pool lfs_dinode_pool;            /* memory pool for dinodes */
+extern struct pool lfs_inoext_pool;    /* memory pool for inode extension */
+extern struct pool lfs_lbnentry_pool;   /* memory pool for balloc accounting */
+
+extern int locked_queue_count;
+extern long locked_queue_bytes;
+extern int lfs_subsys_pages;
+extern int lfs_dirvcount;
+extern kmutex_t lfs_lock;
+extern int lfs_debug_log_subsys[];
+extern kcondvar_t lfs_writing_cv;
+extern kcondvar_t locked_queue_cv;
+
+__BEGIN_DECLS
+/* lfs_alloc.c */
+void lfs_vcreate(struct mount *, ino_t, struct vnode *);
+int lfs_valloc(struct vnode *, int, kauth_cred_t, struct vnode **);
+int lfs_vfree(struct vnode *, ino_t, int);
+void lfs_order_freelist(struct lfs *);
+int lfs_extend_ifile(struct lfs *, kauth_cred_t);
+int lfs_ialloc(struct lfs *, struct vnode *, ino_t, int, struct vnode **);
+void lfs_orphan(struct lfs *, ino_t);
+
+/* lfs_balloc.c */
+int lfs_balloc(struct vnode *, off_t, int, kauth_cred_t, int, struct buf **);
+void lfs_register_block(struct vnode *, daddr_t);
+void lfs_deregister_block(struct vnode *, daddr_t);
+void lfs_deregister_all(struct vnode *);
+
+/* lfs_bio.c */
+int lfs_availwait(struct lfs *, int);
+int lfs_bwrite_ext(struct buf *, int);
+int lfs_fits(struct lfs *, int);
+void lfs_flush_fs(struct lfs *, int);
+void lfs_flush(struct lfs *, int, int);
+int lfs_check(struct vnode *, daddr_t, int);
+void lfs_freebuf(struct lfs *, struct buf *);
+struct buf *lfs_newbuf(struct lfs *, struct vnode *, daddr_t, size_t, int);
+void lfs_countlocked(int *, long *, const char *);
+int lfs_reserve(struct lfs *, struct vnode *, struct vnode *, int);
+
+/* lfs_debug.c */
+#ifdef DEBUG
+int lfs_bwrite_log(struct buf *, const char *, int);
+void lfs_dumplog(void);
+void lfs_dump_super(struct lfs *);
+void lfs_dump_dinode(struct ufs1_dinode *);
+void lfs_check_bpp(struct lfs *, struct segment *, char *, int);
+void lfs_check_segsum(struct lfs *, struct segment *, char *, int);
+void lfs_debug_log(int, const char *, ...);
+#endif /* DEBUG */
+
+/* lfs_inode.c */
+int lfs_update(struct vnode *, const struct timespec *, const struct timespec *,
+    int);
+int lfs_truncate(struct vnode *, off_t, int, kauth_cred_t);
+struct ufs1_dinode *lfs_ifind(struct lfs *, ino_t, struct buf *);
+void lfs_finalize_ino_seguse(struct lfs *, struct inode *);
+void lfs_finalize_fs_seguse(struct lfs *);
+
+/* lfs_rfw.c */
+int lfs_rf_valloc(struct lfs *, ino_t, int, struct lwp *, struct vnode **);
+void lfs_roll_forward(struct lfs *, struct mount *, struct lwp *);
+
+/* lfs_segment.c */
+void lfs_imtime(struct lfs *);
+int lfs_vflush(struct vnode *);
+int lfs_segwrite(struct mount *, int);
+int lfs_writefile(struct lfs *, struct segment *, struct vnode *);
+int lfs_writeinode(struct lfs *, struct segment *, struct inode *);
+int lfs_gatherblock(struct segment *, struct buf *, kmutex_t *);
+int lfs_gather(struct lfs *, struct segment *, struct vnode *, int (*match )(struct lfs *, struct buf *));
+void lfs_update_single(struct lfs *, struct segment *, struct vnode *,
+    daddr_t, int32_t, int);
+void lfs_updatemeta(struct segment *);
+int lfs_rewind(struct lfs *, int);
+void lfs_unset_inval_all(struct lfs *);
+int lfs_initseg(struct lfs *);
+int lfs_writeseg(struct lfs *, struct segment *);
+void lfs_writesuper(struct lfs *, daddr_t);
+int lfs_match_data(struct lfs *, struct buf *);
+int lfs_match_indir(struct lfs *, struct buf *);
+int lfs_match_dindir(struct lfs *, struct buf *);
+int lfs_match_tindir(struct lfs *, struct buf *);
+void lfs_callback(struct buf *);
+int lfs_vref(struct vnode *);
+void lfs_vunref(struct vnode *);
+void lfs_vunref_head(struct vnode *);
+void lfs_acquire_finfo(struct lfs *fs, ino_t, int);
+void lfs_release_finfo(struct lfs *fs);
+
+/* lfs_subr.c */
+void lfs_setup_resblks(struct lfs *);
+void lfs_pad_check(unsigned char *, int, char *, int);
+void lfs_free_resblks(struct lfs *);
+void *lfs_malloc(struct lfs *, size_t, int);
+void lfs_free(struct lfs *, void *, int);
+int lfs_seglock(struct lfs *, unsigned long);
+void lfs_segunlock(struct lfs *);
+void lfs_segunlock_relock(struct lfs *);
+int lfs_writer_enter(struct lfs *, const char *);
+void lfs_writer_leave(struct lfs *);
+void lfs_wakeup_cleaner(struct lfs *);
+
+/* lfs_syscalls.c */
+int lfs_fastvget(struct mount *, ino_t, daddr_t, struct vnode **, struct ufs1_dinode *);
+struct buf *lfs_fakebuf(struct lfs *, struct vnode *, int, size_t, void *);
+int lfs_do_segclean(struct lfs *, unsigned long);
+int lfs_segwait(fsid_t *, struct timeval *);
+int lfs_bmapv(struct proc *, fsid_t *, struct block_info *, int);
+int lfs_markv(struct proc *, fsid_t *, struct block_info *, int);
+
+/* lfs_vfsops.c */
+void lfs_init(void);
+void lfs_reinit(void);
+void lfs_done(void);
+int lfs_mountroot(void);
+int lfs_mount(struct mount *, const char *, void *, size_t *);
+int lfs_unmount(struct mount *, int);
+int lfs_statvfs(struct mount *, struct statvfs *);
+int lfs_sync(struct mount *, int, kauth_cred_t);
+int lfs_vget(struct mount *, ino_t, struct vnode **);
+int lfs_fhtovp(struct mount *, struct fid *, struct vnode **);
+int lfs_vptofh(struct vnode *, struct fid *, size_t *);
+void lfs_vinit(struct mount *, struct vnode **);
+int lfs_resize_fs(struct lfs *, int);
+
+/* lfs_vnops.c */
+void lfs_mark_vnode(struct vnode *);
+void lfs_unmark_vnode(struct vnode *);
+int lfs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
+void lfs_gop_size(struct vnode *, off_t, off_t *, int);
+int lfs_putpages_ext(void *, int);
+int lfs_gatherpages(struct vnode *);
+void lfs_flush_dirops(struct lfs *);
+void lfs_flush_pchain(struct lfs *);
+
+int lfs_bwrite  (void *);
+int lfs_fsync   (void *);
+int lfs_symlink         (void *);
+int lfs_mknod   (void *);
+int lfs_create  (void *);
+int lfs_mkdir   (void *);
+int lfs_read    (void *);
+int lfs_remove  (void *);
+int lfs_rmdir   (void *);
+int lfs_link    (void *);
+int lfs_mmap    (void *);
+int lfs_rename  (void *);
+int lfs_getattr         (void *);
+int lfs_setattr         (void *);
+int lfs_close   (void *);
+int lfsspec_close(void *);
+int lfsfifo_close(void *);
+int lfs_fcntl   (void *);
+int lfs_inactive (void *);
+int lfs_reclaim         (void *);
+int lfs_strategy (void *);
+int lfs_write   (void *);
+int lfs_getpages (void *);
+int lfs_putpages (void *);
+
+extern int lfs_mount_type;
+extern int (**lfs_vnodeop_p)(void *);
+extern int (**lfs_specop_p)(void *);
+extern int (**lfs_fifoop_p)(void *);
+extern const struct genfs_ops lfs_genfsops;
+
+#endif /* defined(_KERNEL) */
+
+/* lfs_cksum.c */
+u_int32_t cksum(void *, size_t);
+u_int32_t lfs_cksum_part(void *, size_t, u_int32_t);
+#define lfs_cksum_fold(sum)    (sum)
+u_int32_t lfs_sb_cksum(struct dlfs *);
+
+__END_DECLS
+
+#endif /* !_UFS_LFS_LFS_EXTERN_H_ */
diff --git a/nbsd_include/ufs/mfs/mfs_extern.h b/nbsd_include/ufs/mfs/mfs_extern.h
new file mode 100644 (file)
index 0000000..b644499
--- /dev/null
@@ -0,0 +1,79 @@
+/*     $NetBSD: mfs_extern.h,v 1.31 2010/03/02 17:20:02 pooka Exp $    */
+
+/*-
+ * Copyright (c) 1991, 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.
+ *
+ *     @(#)mfs_extern.h        8.4 (Berkeley) 3/30/95
+ */
+
+#ifndef _UFS_MFS_MFS_EXTERN_H_
+#define _UFS_MFS_MFS_EXTERN_H_
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/mallocvar.h>
+
+struct buf;
+struct mount;
+struct nameidata;
+struct proc;
+struct statvfs;
+struct vnode;
+
+__BEGIN_DECLS
+#define        mfs_ioctl       genfs_enoioctl
+
+/* mfs_vfsops.c */
+VFS_PROTOS(mfs);
+
+int    mfs_initminiroot(void *);
+
+/* mfs_vnops.c */
+int    mfs_open(void *);
+int    mfs_strategy(void *);
+void   mfs_doio(struct buf *, void *);
+int    mfs_bmap(void *);
+int    mfs_close(void *);
+int    mfs_inactive(void *);
+int    mfs_reclaim(void *);
+int    mfs_print(void *);
+int    mfs_fsync(void *);
+
+#ifdef _KERNEL
+
+#include <sys/mutex.h>
+
+extern kmutex_t        mfs_lock;
+extern void *mfs_rootbase;
+extern u_long mfs_rootsize;
+
+#endif
+
+__END_DECLS
+
+#endif /* !_UFS_MFS_MFS_EXTERN_H_ */
diff --git a/nbsd_include/ufs/mfs/mfsnode.h b/nbsd_include/ufs/mfs/mfsnode.h
new file mode 100644 (file)
index 0000000..c1ed9c3
--- /dev/null
@@ -0,0 +1,91 @@
+/*     $NetBSD: mfsnode.h,v 1.21 2008/03/26 14:19:43 ad Exp $  */
+
+/*
+ * Copyright (c) 1989, 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.
+ *
+ *     @(#)mfsnode.h   8.3 (Berkeley) 5/19/95
+ */
+
+#ifndef _UFS_MFS_MFSNODE_H_
+#define _UFS_MFS_MFSNODE_H_
+
+/*
+ * This structure defines the control data for the memory based file system.
+ */
+
+struct mfsnode {
+       struct vnode *mfs_vnode;        /* vnode associated with this mfsnode */
+       void    *mfs_baseoff;           /* base of file system in memory */
+       long    mfs_size;               /* size of memory file system */
+       struct proc *mfs_proc;          /* supporting process */
+       int     mfs_shutdown;           /* shutdown this mfsnode */
+#if defined(_KERNEL)
+       kcondvar_t mfs_cv;              /* notifier */
+       int     mfs_refcnt;             /* number of references */
+       struct  bufq_state *mfs_buflist;/* list of I/O requests */
+#endif /* defined(_KERNEL) */
+};
+
+#if defined(_KERNEL)
+/*
+ * Convert between mfsnode pointers and vnode pointers
+ */
+#define VTOMFS(vp)     ((struct mfsnode *)(vp)->v_data)
+#define MFSTOV(mfsp)   ((mfsp)->mfs_vnode)
+
+/* Prototypes for MFS operations on vnodes. */
+#define        mfs_lookup      genfs_badop
+#define        mfs_create      genfs_badop
+#define        mfs_mknod       genfs_badop
+#define        mfs_access      genfs_badop
+#define        mfs_getattr     genfs_badop
+#define        mfs_setattr     genfs_badop
+#define        mfs_read        genfs_badop
+#define        mfs_write       genfs_badop
+#define        mfs_poll        genfs_badop
+#define        mfs_mmap        genfs_badop
+#define        mfs_seek        genfs_badop
+#define        mfs_remove      genfs_badop
+#define        mfs_link        genfs_badop
+#define        mfs_rename      genfs_badop
+#define        mfs_mkdir       genfs_badop
+#define        mfs_rmdir       genfs_badop
+#define        mfs_symlink     genfs_badop
+#define        mfs_readdir     genfs_badop
+#define        mfs_readlink    genfs_badop
+#define        mfs_abortop     genfs_badop
+#define        mfs_islocked    genfs_noislocked
+#define        mfs_pathconf    genfs_badop
+#define        mfs_advlock     genfs_badop
+#define        mfs_bwrite      vn_bwrite
+#define        mfs_revoke      genfs_revoke
+#define        mfs_putpages    genfs_null_putpages
+
+#endif /* defined(_KERNEL) */
+
+#endif /* !_UFS_MFS_MFSNODE_H_ */
diff --git a/nbsd_include/ufs/ufs/dinode.h b/nbsd_include/ufs/ufs/dinode.h
new file mode 100644 (file)
index 0000000..af0dabb
--- /dev/null
@@ -0,0 +1,180 @@
+/*     $NetBSD: dinode.h,v 1.21 2009/06/28 09:26:18 ad Exp $   */
+
+/*
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by Marshall
+ * Kirk McKusick and Network Associates Laboratories, the Security
+ * Research Division of Network Associates, Inc. under DARPA/SPAWAR
+ * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
+ * research program
+ *
+ * Copyright (c) 1982, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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.
+ *
+ *     @(#)dinode.h    8.9 (Berkeley) 3/29/95
+ */
+
+/*
+ * NOTE: COORDINATE ON-DISK FORMAT CHANGES WITH THE FREEBSD PROJECT.
+ */
+
+#ifndef        _UFS_UFS_DINODE_H_
+#define        _UFS_UFS_DINODE_H_
+
+/*
+ * The root inode is the root of the file system.  Inode 0 can't be used for
+ * normal purposes and historically bad blocks were linked to inode 1, thus
+ * the root inode is 2.  (Inode 1 is no longer used for this purpose, however
+ * numerous dump tapes make this assumption, so we are stuck with it).
+ */
+#define        ROOTINO ((ino_t)2)
+
+/*
+ * The Whiteout inode# is a dummy non-zero inode number which will
+ * never be allocated to a real file.  It is used as a place holder
+ * in the directory entry which has been tagged as a DT_W entry.
+ * See the comments about ROOTINO above.
+ */
+#define        WINO    ((ino_t)1)
+
+/*
+ * A dinode contains all the meta-data associated with a UFS file.
+ * This structure defines the on-disk format of a dinode. Since
+ * this structure describes an on-disk structure, all its fields
+ * are defined by types with precise widths.
+ */
+
+#define NXADDR 2
+#define        NDADDR  12                      /* Direct addresses in inode. */
+#define        NIADDR  3                       /* Indirect addresses in inode. */
+
+struct ufs1_dinode {
+       u_int16_t       di_mode;        /*   0: IFMT, permissions; see below. */
+       int16_t         di_nlink;       /*   2: File link count. */
+       union {
+               u_int16_t oldids[2];    /*   4: Ffs: old user and group ids. */
+               u_int32_t inumber;      /*   4: Lfs: inode number. */
+       } di_u;
+       u_int64_t       di_size;        /*   8: File byte count. */
+       int32_t         di_atime;       /*  16: Last access time. */
+       int32_t         di_atimensec;   /*  20: Last access time. */
+       int32_t         di_mtime;       /*  24: Last modified time. */
+       int32_t         di_mtimensec;   /*  28: Last modified time. */
+       int32_t         di_ctime;       /*  32: Last inode change time. */
+       int32_t         di_ctimensec;   /*  36: Last inode change time. */
+       int32_t         di_db[NDADDR];  /*  40: Direct disk blocks. */
+       int32_t         di_ib[NIADDR];  /*  88: Indirect disk blocks. */
+       u_int32_t       di_flags;       /* 100: Status flags (chflags). */
+       u_int32_t       di_blocks;      /* 104: Blocks actually held. */
+       int32_t         di_gen;         /* 108: Generation number. */
+       u_int32_t       di_uid;         /* 112: File owner. */
+       u_int32_t       di_gid;         /* 116: File group. */
+       u_int64_t       di_modrev;      /* 120: i_modrev for NFSv4 */
+};
+
+struct ufs2_dinode {
+       u_int16_t       di_mode;        /*   0: IFMT, permissions; see below. */
+       int16_t         di_nlink;       /*   2: File link count. */
+       u_int32_t       di_uid;         /*   4: File owner. */
+       u_int32_t       di_gid;         /*   8: File group. */
+       u_int32_t       di_blksize;     /*  12: Inode blocksize. */
+       u_int64_t       di_size;        /*  16: File byte count. */
+       u_int64_t       di_blocks;      /*  24: Bytes actually held. */
+       int64_t         di_atime;       /*  32: Last access time. */
+       int64_t         di_mtime;       /*  40: Last modified time. */
+       int64_t         di_ctime;       /*  48: Last inode change time. */
+       int64_t         di_birthtime;   /*  56: Inode creation time. */
+       int32_t         di_mtimensec;   /*  64: Last modified time. */
+       int32_t         di_atimensec;   /*  68: Last access time. */
+       int32_t         di_ctimensec;   /*  72: Last inode change time. */
+       int32_t         di_birthnsec;   /*  76: Inode creation time. */
+       int32_t         di_gen;         /*  80: Generation number. */
+       u_int32_t       di_kernflags;   /*  84: Kernel flags. */
+       u_int32_t       di_flags;       /*  88: Status flags (chflags). */
+       int32_t         di_extsize;     /*  92: External attributes block. */
+       int64_t         di_extb[NXADDR];/*  96: External attributes block. */
+       int64_t         di_db[NDADDR];  /* 112: Direct disk blocks. */
+       int64_t         di_ib[NIADDR];  /* 208: Indirect disk blocks. */
+       u_int64_t       di_modrev;      /* 232: i_modrev for NFSv4 */
+       int64_t         di_spare[2];    /* 240: Reserved; currently unused */
+};
+
+/*
+ * The di_db fields may be overlaid with other information for
+ * file types that do not have associated disk storage. Block
+ * and character devices overlay the first data block with their
+ * dev_t value. Short symbolic links place their path in the
+ * di_db area.
+ */
+#define        di_inumber      di_u.inumber
+#define        di_ogid         di_u.oldids[1]
+#define        di_ouid         di_u.oldids[0]
+#define        di_rdev         di_db[0]
+#define MAXSYMLINKLEN_UFS1     ((NDADDR + NIADDR) * sizeof(int32_t))
+#define MAXSYMLINKLEN_UFS2     ((NDADDR + NIADDR) * sizeof(int64_t))
+
+#define MAXSYMLINKLEN(ip) \
+       ((ip)->i_ump->um_fstype == UFS1) ? \
+       MAXSYMLINKLEN_UFS1 : MAXSYMLINKLEN_UFS2
+
+/* NeXT used to keep short symlinks in the inode even when using
+ * FS_42INODEFMT.  In that case fs->fs_maxsymlinklen is probably -1,
+ * but short symlinks were stored in inodes shorter than this:
+ */
+#define        APPLEUFS_MAXSYMLINKLEN 60
+
+/* File permissions. */
+#define        IEXEC           0000100         /* Executable. */
+#define        IWRITE          0000200         /* Writable. */
+#define        IREAD           0000400         /* Readable. */
+#define        ISVTX           0001000         /* Sticky bit. */
+#define        ISGID           0002000         /* Set-gid. */
+#define        ISUID           0004000         /* Set-uid. */
+
+/* File types. */
+#define        IFMT            0170000         /* Mask of file type. */
+#define        IFIFO           0010000         /* Named pipe (fifo). */
+#define        IFCHR           0020000         /* Character device. */
+#define        IFDIR           0040000         /* Directory file. */
+#define        IFBLK           0060000         /* Block device. */
+#define        IFREG           0100000         /* Regular file. */
+#define        IFLNK           0120000         /* Symbolic link. */
+#define        IFSOCK          0140000         /* UNIX domain socket. */
+#define        IFWHT           0160000         /* Whiteout. */
+
+/* Size of the on-disk inode. */
+#define        DINODE1_SIZE    (sizeof(struct ufs1_dinode))            /* 128 */
+#define        DINODE2_SIZE    (sizeof(struct ufs2_dinode))
+
+#endif /* !_UFS_UFS_DINODE_H_ */
diff --git a/nbsd_include/ufs/ufs/dir.h b/nbsd_include/ufs/ufs/dir.h
new file mode 100644 (file)
index 0000000..74cf7e7
--- /dev/null
@@ -0,0 +1,160 @@
+/*     $NetBSD: dir.h,v 1.21 2009/07/22 04:49:19 dholland Exp $        */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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.
+ *
+ *     @(#)dir.h       8.5 (Berkeley) 4/27/95
+ */
+
+#ifndef _UFS_UFS_DIR_H_
+#define        _UFS_UFS_DIR_H_
+
+/*
+ * Theoretically, directories can be more than 2Gb in length; however, in
+ * practice this seems unlikely. So, we define the type doff_t as a 32-bit
+ * quantity to keep down the cost of doing lookup on a 32-bit machine.
+ */
+#define        doff_t          int32_t
+#define        MAXDIRSIZE      (0x7fffffff)
+
+/*
+ * A directory consists of some number of blocks of DIRBLKSIZ
+ * bytes, where DIRBLKSIZ is chosen such that it can be transferred
+ * to disk in a single atomic operation (e.g. 512 bytes on most machines).
+ *
+ * Each DIRBLKSIZ byte block contains some number of directory entry
+ * structures, which are of variable length.  Each directory entry has
+ * a struct direct at the front of it, containing its inode number,
+ * the length of the entry, and the length of the name contained in
+ * the entry.  These are followed by the name padded to a 4 byte boundary.
+ * All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is FFS_MAXNAMLEN.
+ *
+ * The macro DIRSIZ(fmt, dp) gives the amount of space required to represent
+ * a directory entry.  Free space in a directory is represented by
+ * entries which have dp->d_reclen > DIRSIZ(fmt, dp).  All DIRBLKSIZ bytes
+ * in a directory block are claimed by the directory entries.  This
+ * usually results in the last entry in a directory having a large
+ * dp->d_reclen.  When entries are deleted from a directory, the
+ * space is returned to the previous entry in the same directory
+ * block by increasing its dp->d_reclen.  If the first entry of
+ * a directory block is free, then its dp->d_ino is set to 0.
+ * Entries other than the first in a directory do not normally have
+ * dp->d_ino set to 0.
+ */
+#undef DIRBLKSIZ
+#define        DIRBLKSIZ       DEV_BSIZE
+#define        FFS_MAXNAMLEN   255
+#define APPLEUFS_DIRBLKSIZ 1024
+
+#define d_ino d_fileno
+struct direct {
+       u_int32_t d_fileno;             /* inode number of entry */
+       u_int16_t d_reclen;             /* length of this record */
+       u_int8_t  d_type;               /* file type, see below */
+       u_int8_t  d_namlen;             /* length of string in d_name */
+       char      d_name[FFS_MAXNAMLEN + 1];/* name with length <= FFS_MAXNAMLEN */
+};
+
+/*
+ * File types
+ */
+#define        DT_UNKNOWN       0
+#define        DT_FIFO          1
+#define        DT_CHR           2
+#define        DT_DIR           4
+#define        DT_BLK           6
+#define        DT_REG           8
+#define        DT_LNK          10
+#define        DT_SOCK         12
+#define        DT_WHT          14
+
+/*
+ * Convert between stat structure types and directory types.
+ */
+#define        IFTODT(mode)    (((mode) & 0170000) >> 12)
+#define        DTTOIF(dirtype) ((dirtype) << 12)
+
+/*
+ * The DIRSIZ macro gives the minimum record length which will hold
+ * the directory entry.  This requires the amount of space in struct direct
+ * without the d_name field, plus enough space for the name with a terminating
+ * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+ */
+#define        DIRECTSIZ(namlen) \
+       ((sizeof(struct direct) - (FFS_MAXNAMLEN+1)) + (((namlen)+1 + 3) &~ 3))
+
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+#define DIRSIZ(oldfmt, dp, needswap)   \
+    (((oldfmt) && !(needswap)) ?       \
+    DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
+#else
+#define DIRSIZ(oldfmt, dp, needswap)   \
+    (((oldfmt) && (needswap)) ?                \
+    DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
+#endif
+
+#define OLDDIRFMT      1
+#define NEWDIRFMT      0
+
+/*
+ * Template for manipulating directories.  Should use struct direct's,
+ * but the name field is FFS_MAXNAMLEN - 1, and this just won't do.
+ */
+struct dirtemplate {
+       u_int32_t       dot_ino;
+       int16_t         dot_reclen;
+       u_int8_t        dot_type;
+       u_int8_t        dot_namlen;
+       char            dot_name[4];    /* must be multiple of 4 */
+       u_int32_t       dotdot_ino;
+       int16_t         dotdot_reclen;
+       u_int8_t        dotdot_type;
+       u_int8_t        dotdot_namlen;
+       char            dotdot_name[4]; /* ditto */
+};
+
+/*
+ * This is the old format of directories, sanz type element.
+ */
+struct odirtemplate {
+       u_int32_t       dot_ino;
+       int16_t         dot_reclen;
+       u_int16_t       dot_namlen;
+       char            dot_name[4];    /* must be multiple of 4 */
+       u_int32_t       dotdot_ino;
+       int16_t         dotdot_reclen;
+       u_int16_t       dotdot_namlen;
+       char            dotdot_name[4]; /* ditto */
+};
+#endif /* !_UFS_UFS_DIR_H_ */
diff --git a/nbsd_include/ufs/ufs/dirhash.h b/nbsd_include/ufs/ufs/dirhash.h
new file mode 100644 (file)
index 0000000..914eeca
--- /dev/null
@@ -0,0 +1,129 @@
+/*     $NetBSD: dirhash.h,v 1.6 2008/06/04 11:33:19 ad Exp $   */
+
+/*
+ * Copyright (c) 2001 Ian Dowse.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/sys/ufs/ufs/dirhash.h,v 1.2.2.2 2004/12/08 11:54:13 dwmalone Exp $
+ */
+
+#ifndef _UFS_UFS_DIRHASH_H_
+#define _UFS_UFS_DIRHASH_H_
+
+/*
+ * For fast operations on large directories, we maintain a hash
+ * that maps the file name to the offset of the directory entry within
+ * the directory file.
+ *
+ * The hashing uses a dumb spillover to the next free slot on
+ * collisions, so we must keep the utilisation low to avoid
+ * long linear searches. Deleted entries that are not the last
+ * in a chain must be marked DIRHASH_DEL.
+ *
+ * We also maintain information about free space in each block
+ * to speed up creations.
+ */
+#define DIRHASH_EMPTY  (-1)    /* entry unused */
+#define DIRHASH_DEL    (-2)    /* deleted entry; may be part of chain */
+
+#define DIRALIGN       4
+#define DH_NFSTATS     (DIRECTSIZ(FFS_MAXNAMLEN + 1) / DIRALIGN)
+                                /* max DIRALIGN words in a directory entry */
+
+/*
+ * Dirhash uses a score mechanism to achieve a hybrid between a
+ * least-recently-used and a least-often-used algorithm for entry
+ * recycling. The score is incremented when a directory is used, and
+ * decremented when the directory is a candidate for recycling. When
+ * the score reaches zero, the hash is recycled. Hashes are linked
+ * together on a TAILQ list, and hashes with higher scores filter
+ * towards the tail (most recently used) end of the list.
+ *
+ * New hash entries are given an inital score of DH_SCOREINIT and are
+ * placed at the most-recently-used end of the list. This helps a lot
+ * in the worst-case case scenario where every directory access is
+ * to a directory that is not hashed (i.e. the working set of hash
+ * candidates is much larger than the configured memry limit). In this
+ * case it limits the number of hash builds to 1/DH_SCOREINIT of the
+ * number of accesses.
+ */
+#define DH_SCOREINIT   8       /* initial dh_score when dirhash built */
+#define DH_SCOREMAX    64      /* max dh_score value */
+
+/*
+ * The main hash table has 2 levels. It is an array of pointers to
+ * blocks of DH_NBLKOFF offsets.
+ */
+#define DH_BLKOFFSHIFT 8
+#define DH_NBLKOFF     (1 << DH_BLKOFFSHIFT)
+#define DH_BLKOFFMASK  (DH_NBLKOFF - 1)
+
+#define DH_ENTRY(dh, slot) \
+    ((dh)->dh_hash[(slot) >> DH_BLKOFFSHIFT][(slot) & DH_BLKOFFMASK])
+
+struct dirhash {
+       kmutex_t dh_lock;       /* protects all fields except dh_list */
+
+       doff_t  **dh_hash;      /* the hash array (2-level) */
+       size_t  dh_hashsz;
+       int     dh_narrays;     /* number of entries in dh_hash */
+       int     dh_hlen;        /* total slots in the 2-level hash array */
+       int     dh_hused;       /* entries in use */
+
+       u_int8_t *dh_blkfree;   /* free DIRALIGN words in each dir block */
+       size_t  dh_blkfreesz;
+       int     dh_nblk;        /* size of dh_blkfree array */
+       int     dh_dirblks;     /* number of DIRBLKSIZ blocks in dir */
+       int     dh_firstfree[DH_NFSTATS + 1]; /* first blk with N words free */
+
+       int     dh_seqopt;      /* sequential access optimisation enabled */
+       doff_t  dh_seqoff;      /* sequential access optimisation offset */
+
+       int     dh_score;       /* access count for this dirhash */
+
+       int     dh_onlist;      /* true if on the ufsdirhash_list chain */
+
+       /* Protected by ufsdirhash_lock. */
+       TAILQ_ENTRY(dirhash) dh_list;   /* chain of all dirhashes */
+};
+
+
+/*
+ * Dirhash functions.
+ */
+int    ufsdirhash_build(struct inode *);
+doff_t ufsdirhash_findfree(struct inode *, int, int *);
+doff_t ufsdirhash_enduseful(struct inode *);
+int    ufsdirhash_lookup(struct inode *, const char *, int, doff_t *,
+           struct buf **, doff_t *);
+void   ufsdirhash_newblk(struct inode *, doff_t);
+void   ufsdirhash_add(struct inode *, struct direct *, doff_t);
+void   ufsdirhash_remove(struct inode *, struct direct *, doff_t);
+void   ufsdirhash_move(struct inode *, struct direct *, doff_t, doff_t);
+void   ufsdirhash_dirtrunc(struct inode *, doff_t);
+void   ufsdirhash_free(struct inode *);
+void   ufsdirhash_checkblock(struct inode *, char *, doff_t);
+void   ufsdirhash_init(void);
+void   ufsdirhash_done(void);
+
+#endif /* !_UFS_UFS_DIRHASH_H_ */
diff --git a/nbsd_include/ufs/ufs/extattr.h b/nbsd_include/ufs/ufs/extattr.h
new file mode 100644 (file)
index 0000000..e87d063
--- /dev/null
@@ -0,0 +1,128 @@
+/*     $NetBSD: extattr.h,v 1.10 2011/10/09 21:15:34 chs Exp $ */
+
+/*-
+ * Copyright (c) 1999-2001 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/sys/ufs/ufs/extattr.h,v 1.20 2005/01/31 08:16:45 imp Exp $
+ */
+
+/*
+ * Support for file system extended attributes on the UFS1 file system.
+ * Developed by the TrustedBSD Project.
+ */
+
+#ifndef _UFS_UFS_EXTATTR_H_
+#define        _UFS_UFS_EXTATTR_H_
+
+#define        UFS_EXTATTR_MAGIC               0x00b5d5ec
+#define        UFS_EXTATTR_VERSION             0x00000003
+#define        UFS_EXTATTR_FSROOTSUBDIR        ".attribute"
+#define        UFS_EXTATTR_SUBDIR_SYSTEM       "system"
+#define        UFS_EXTATTR_SUBDIR_USER         "user"
+#define        UFS_EXTATTR_MAXEXTATTRNAME      65      /* including null */
+
+#define        UFS_EXTATTR_ATTR_FLAG_INUSE     0x00000001      /* attr has been set */
+#define        UFS_EXTATTR_PERM_KERNEL         0x00000000
+#define        UFS_EXTATTR_PERM_ROOT           0x00000001
+#define        UFS_EXTATTR_PERM_OWNER          0x00000002
+#define        UFS_EXTATTR_PERM_ANYONE         0x00000003
+
+#define        UFS_EXTATTR_UEPM_INITIALIZED    0x00000001
+#define        UFS_EXTATTR_UEPM_STARTED        0x00000002
+
+#define        UFS_EXTATTR_CMD_START           EXTATTR_CMD_START
+#define        UFS_EXTATTR_CMD_STOP            EXTATTR_CMD_STOP
+#define        UFS_EXTATTR_CMD_ENABLE          0x00000003
+#define        UFS_EXTATTR_CMD_DISABLE         0x00000004
+
+struct ufs_extattr_fileheader {
+       uint32_t        uef_magic;      /* magic number for sanity checking */
+       uint32_t        uef_version;    /* version of attribute file */
+       uint32_t        uef_size;       /* size of attributes, w/o header */
+};
+
+struct ufs_extattr_header {
+       uint32_t        ueh_flags;      /* flags for attribute */
+       uint32_t        ueh_len;        /* local defined length; <= uef_size */
+       uint32_t        ueh_i_gen;      /* generation number for sanity */
+       /* data follows the header */
+};
+
+#ifdef _KERNEL
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_EXTATTR);
+#endif
+
+struct vnode;
+LIST_HEAD(ufs_extattr_list_head, ufs_extattr_list_entry);
+struct ufs_extattr_list_entry {
+       LIST_ENTRY(ufs_extattr_list_entry)      uele_entries;
+       struct ufs_extattr_fileheader           uele_fileheader;
+       int             uele_attrnamespace;
+       char            uele_attrname[UFS_EXTATTR_MAXEXTATTRNAME];
+       struct vnode    *uele_backing_vnode;
+       int             uele_flags;
+};
+
+/* uele_flags */
+#define        UELE_F_NEEDSWAP         0x01    /* needs byte swap */
+
+#define        UELE_NEEDSWAP(uele)     ((uele)->uele_flags & UELE_F_NEEDSWAP)
+
+struct lock;
+struct ufs_extattr_per_mount {
+       kmutex_t                        uepm_lock;
+       struct ufs_extattr_list_head    uepm_list;
+       kauth_cred_t                    uepm_ucred;
+       int                             uepm_lockcnt;
+       int                             uepm_flags;
+};
+
+void   ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm);
+void   ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm);
+int    ufs_extattr_start(struct mount *mp, struct lwp *l);
+int    ufs_extattr_autostart(struct mount *mp, struct lwp *l);
+void   ufs_extattr_stop(struct mount *mp, struct lwp *l);
+int    ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename,
+           int attrnamespace, const char *attrname);
+struct vop_getextattr_args;
+int    ufs_getextattr(struct vop_getextattr_args *ap);
+struct vop_deleteextattr_args;
+int    ufs_deleteextattr(struct vop_deleteextattr_args *ap);
+struct vop_setextattr_args;
+int    ufs_setextattr(struct vop_setextattr_args *ap);
+struct vop_listextattr_args;
+int    ufs_listextattr(struct vop_listextattr_args *ap);
+void   ufs_extattr_vnode_inactive(struct vnode *vp, struct lwp *l);
+
+void   ufs_extattr_init(void);
+void   ufs_extattr_done(void);
+
+#endif /* !_KERNEL */
+
+#endif /* !_UFS_UFS_EXTATTR_H_ */
diff --git a/nbsd_include/ufs/ufs/inode.h b/nbsd_include/ufs/ufs/inode.h
new file mode 100644 (file)
index 0000000..a904ef9
--- /dev/null
@@ -0,0 +1,300 @@
+/*     $NetBSD: inode.h,v 1.58 2011/07/12 02:22:13 dholland Exp $      */
+
+/*
+ * Copyright (c) 1982, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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.
+ *
+ *     @(#)inode.h     8.9 (Berkeley) 5/14/95
+ */
+
+#ifndef _UFS_UFS_INODE_H_
+#define        _UFS_UFS_INODE_H_
+
+#include <sys/vnode.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <miscfs/genfs/genfs_node.h>
+
+/*
+ * Lookup result state (other than the result inode). This is
+ * currently stashed in the vnode between VOP_LOOKUP and directory
+ * operation VOPs, which is gross.
+ */
+struct ufs_lookup_results {
+       int32_t   ulr_count;    /* Size of free slot in directory. */
+       doff_t    ulr_endoff;   /* End of useful stuff in directory. */
+       doff_t    ulr_diroff;   /* Offset in dir, where we found last entry. */
+       doff_t    ulr_offset;   /* Offset of free space in directory. */
+       u_int32_t ulr_reclen;   /* Size of found directory entry. */
+};
+
+/* notyet XXX */
+#define UFS_CHECK_CRAPCOUNTER(dp) ((void)(dp)->i_crapcounter)
+
+/*
+ * Per-filesystem inode extensions.
+ */
+struct ffs_inode_ext {
+       daddr_t *ffs_snapblklist;       /* Collect expunged snapshot blocks. */
+       /* follow two fields are used by contiguous allocation code only. */
+       daddr_t ffs_first_data_blk;     /* first data block on disk. */
+       daddr_t ffs_first_indir_blk;    /* first indirect block on disk. */
+};
+
+struct ext2fs_inode_ext {
+       daddr_t ext2fs_last_lblk;       /* last logical block allocated */
+       daddr_t ext2fs_last_blk;        /* last block allocated on disk */
+};
+
+struct lfs_inode_ext;
+
+/*
+ * The inode is used to describe each active (or recently active) file in the
+ * UFS filesystem. It is composed of two types of information. The first part
+ * is the information that is needed only while the file is active (such as
+ * the identity of the file and linkage to speed its lookup). The second part
+ * is the permanent meta-data associated with the file which is read in
+ * from the permanent dinode from long term storage when the file becomes
+ * active, and is put back when the file is no longer being used.
+ */
+struct inode {
+       struct genfs_node i_gnode;
+       LIST_ENTRY(inode) i_hash;/* Hash chain. */
+       TAILQ_ENTRY(inode) i_nextsnap; /* snapshot file list. */
+       struct  vnode *i_vnode; /* Vnode associated with this inode. */
+       struct  ufsmount *i_ump; /* Mount point associated with this inode. */
+       struct  vnode *i_devvp; /* Vnode for block I/O. */
+       u_int32_t i_flag;       /* flags, see below */
+       dev_t     i_dev;        /* Device associated with the inode. */
+       ino_t     i_number;     /* The identity of the inode. */
+
+       union {                 /* Associated filesystem. */
+               struct  fs *fs;         /* FFS */
+               struct  lfs *lfs;       /* LFS */
+               struct  m_ext2fs *e2fs; /* EXT2FS */
+       } inode_u;
+#define        i_fs    inode_u.fs
+#define        i_lfs   inode_u.lfs
+#define        i_e2fs  inode_u.e2fs
+
+       void    *i_unused1;     /* Unused. */
+       struct   dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
+       u_quad_t i_modrev;      /* Revision level for NFS lease. */
+       struct   lockf *i_lockf;/* Head of byte-level lock list. */
+
+       /*
+        * Side effects; used during (and after) directory lookup.
+        * XXX should not be here.
+        */
+       struct ufs_lookup_results i_crap;
+       unsigned i_crapcounter; /* serial number for i_crap */
+
+       /*
+        * Inode extensions
+        */
+       union {
+               /* Other extensions could go here... */
+               struct  ffs_inode_ext ffs;
+               struct  ext2fs_inode_ext e2fs;
+               struct  lfs_inode_ext *lfs;
+       } inode_ext;
+#define        i_snapblklist           inode_ext.ffs.ffs_snapblklist
+#define        i_ffs_first_data_blk    inode_ext.ffs.ffs_first_data_blk
+#define        i_ffs_first_indir_blk   inode_ext.ffs.ffs_first_indir_blk
+#define        i_e2fs_last_lblk        inode_ext.e2fs.ext2fs_last_lblk
+#define        i_e2fs_last_blk         inode_ext.e2fs.ext2fs_last_blk
+       /*
+        * Copies from the on-disk dinode itself.
+        *
+        * These fields are currently only used by FFS and LFS,
+        * do NOT use them with ext2fs.
+        */
+       u_int16_t i_mode;       /* IFMT, permissions; see below. */
+       int16_t   i_nlink;      /* File link count. */
+       u_int64_t i_size;       /* File byte count. */
+       u_int32_t i_flags;      /* Status flags (chflags). */
+       int32_t   i_gen;        /* Generation number. */
+       u_int32_t i_uid;        /* File owner. */
+       u_int32_t i_gid;        /* File group. */
+       u_int16_t i_omode;      /* Old mode, for ufs_reclaim. */
+
+       struct dirhash *i_dirhash;      /* Hashing for large directories */
+
+       /*
+        * The on-disk dinode itself.
+        */
+       union {
+               struct  ufs1_dinode *ffs1_din;  /* 128 bytes of the on-disk dinode. */
+               struct  ufs2_dinode *ffs2_din;
+               struct  ext2fs_dinode *e2fs_din; /* 128 bytes of the on-disk
+                                                  dinode. */
+       } i_din;
+};
+
+#define        i_ffs1_atime            i_din.ffs1_din->di_atime
+#define        i_ffs1_atimensec        i_din.ffs1_din->di_atimensec
+#define        i_ffs1_blocks           i_din.ffs1_din->di_blocks
+#define        i_ffs1_ctime            i_din.ffs1_din->di_ctime
+#define        i_ffs1_ctimensec        i_din.ffs1_din->di_ctimensec
+#define        i_ffs1_db               i_din.ffs1_din->di_db
+#define        i_ffs1_flags            i_din.ffs1_din->di_flags
+#define        i_ffs1_gen              i_din.ffs1_din->di_gen
+#define        i_ffs1_gid              i_din.ffs1_din->di_gid
+#define        i_ffs1_ib               i_din.ffs1_din->di_ib
+#define        i_ffs1_mode             i_din.ffs1_din->di_mode
+#define        i_ffs1_mtime            i_din.ffs1_din->di_mtime
+#define        i_ffs1_mtimensec        i_din.ffs1_din->di_mtimensec
+#define        i_ffs1_nlink            i_din.ffs1_din->di_nlink
+#define        i_ffs1_rdev             i_din.ffs1_din->di_rdev
+#define        i_ffs1_size             i_din.ffs1_din->di_size
+#define        i_ffs1_uid              i_din.ffs1_din->di_uid
+#define        i_ffs1_ouid             i_din.ffs1_din->di_u.oldids[0]
+#define        i_ffs1_ogid             i_din.ffs1_din->di_u.oldids[1]
+
+#define        i_ffs2_atime            i_din.ffs2_din->di_atime
+#define        i_ffs2_atimensec        i_din.ffs2_din->di_atimensec
+#define        i_ffs2_birthtime        i_din.ffs2_din->di_birthtime
+#define        i_ffs2_birthnsec        i_din.ffs2_din->di_birthnsec
+#define        i_ffs2_blocks           i_din.ffs2_din->di_blocks
+#define        i_ffs2_blksize          i_din.ffs2_din->di_blksize
+#define        i_ffs2_ctime            i_din.ffs2_din->di_ctime
+#define        i_ffs2_ctimensec        i_din.ffs2_din->di_ctimensec
+#define        i_ffs2_db               i_din.ffs2_din->di_db
+#define        i_ffs2_flags            i_din.ffs2_din->di_flags
+#define        i_ffs2_gen              i_din.ffs2_din->di_gen
+#define        i_ffs2_gid              i_din.ffs2_din->di_gid
+#define        i_ffs2_ib               i_din.ffs2_din->di_ib
+#define        i_ffs2_mode             i_din.ffs2_din->di_mode
+#define        i_ffs2_mtime            i_din.ffs2_din->di_mtime
+#define        i_ffs2_mtimensec        i_din.ffs2_din->di_mtimensec
+#define        i_ffs2_nlink            i_din.ffs2_din->di_nlink
+#define        i_ffs2_rdev             i_din.ffs2_din->di_rdev
+#define        i_ffs2_size             i_din.ffs2_din->di_size
+#define        i_ffs2_uid              i_din.ffs2_din->di_uid
+#define        i_ffs2_kernflags        i_din.ffs2_din->di_kernflags
+#define        i_ffs2_extsize          i_din.ffs2_din->di_extsize
+#define        i_ffs2_extb             i_din.ffs2_din->di_extb
+
+#define        i_e2fs_mode             i_din.e2fs_din->e2di_mode
+#define        i_e2fs_uid              i_din.e2fs_din->e2di_uid
+#define        i_e2fs_size             i_din.e2fs_din->e2di_size
+#define        i_e2fs_atime            i_din.e2fs_din->e2di_atime
+#define        i_e2fs_ctime            i_din.e2fs_din->e2di_ctime
+#define        i_e2fs_mtime            i_din.e2fs_din->e2di_mtime
+#define        i_e2fs_dtime            i_din.e2fs_din->e2di_dtime
+#define        i_e2fs_gid              i_din.e2fs_din->e2di_gid
+#define        i_e2fs_nlink            i_din.e2fs_din->e2di_nlink
+#define        i_e2fs_nblock           i_din.e2fs_din->e2di_nblock
+#define        i_e2fs_flags            i_din.e2fs_din->e2di_flags
+#define        i_e2fs_blocks           i_din.e2fs_din->e2di_blocks
+#define        i_e2fs_gen              i_din.e2fs_din->e2di_gen
+#define        i_e2fs_facl             i_din.e2fs_din->e2di_facl
+#define        i_e2fs_dacl             i_din.e2fs_din->e2di_dacl
+#define        i_e2fs_faddr            i_din.e2fs_din->e2di_faddr
+#define        i_e2fs_nfrag            i_din.e2fs_din->e2di_nfrag
+#define        i_e2fs_fsize            i_din.e2fs_din->e2di_fsize
+#define        i_e2fs_rdev             i_din.e2fs_din->e2di_rdev
+#define        i_e2fs_uid_high         i_din.e2fs_din->e2di_uid_high
+#define        i_e2fs_gid_high         i_din.e2fs_din->e2di_gid_high
+
+/* These flags are kept in i_flag. */
+#define        IN_ACCESS       0x0001          /* Access time update request. */
+#define        IN_CHANGE       0x0002          /* Inode change time update request. */
+#define        IN_UPDATE       0x0004          /* Inode was written to; update mtime. */
+#define        IN_MODIFY       0x2000          /* Modification time update request. */
+#define        IN_MODIFIED     0x0008          /* Inode has been modified. */
+#define        IN_ACCESSED     0x0010          /* Inode has been accessed. */
+#define        IN_RENAME       0x0020          /* Inode is being renamed. */
+#define        IN_SHLOCK       0x0040          /* File has shared lock. */
+#define        IN_EXLOCK       0x0080          /* File has exclusive lock. */
+#define        IN_CLEANING     0x0100          /* LFS: file is being cleaned */
+#define        IN_ADIROP       0x0200          /* LFS: dirop in progress */
+#define        IN_SPACECOUNTED 0x0400          /* Blocks to be freed in free count. */
+#define        IN_PAGING       0x1000          /* LFS: file is on paging queue */
+
+#if defined(_KERNEL)
+
+/*
+ * The DIP macro is used to access fields in the dinode that are
+ * not cached in the inode itself.
+ */
+#define        DIP(ip, field) \
+       (((ip)->i_ump->um_fstype == UFS1) ? \
+       (ip)->i_ffs1_##field : (ip)->i_ffs2_##field)
+
+#define        DIP_ASSIGN(ip, field, value)                                    \
+       do {                                                            \
+               if ((ip)->i_ump->um_fstype == UFS1)                     \
+                       (ip)->i_ffs1_##field = (value);                 \
+               else                                                    \
+                       (ip)->i_ffs2_##field = (value);                 \
+       } while(0)
+
+#define        DIP_ADD(ip, field, value)                                       \
+       do {                                                            \
+               if ((ip)->i_ump->um_fstype == UFS1)                     \
+                       (ip)->i_ffs1_##field += (value);                \
+               else                                                    \
+                       (ip)->i_ffs2_##field += (value);                \
+       } while(0)
+
+#define         SHORTLINK(ip) \
+       (((ip)->i_ump->um_fstype == UFS1) ? \
+       (void *)(ip)->i_ffs1_db : (void *)(ip)->i_ffs2_db)
+
+
+/*
+ * Structure used to pass around logical block paths generated by
+ * ufs_getlbns and used by truncate and bmap code.
+ */
+struct indir {
+       daddr_t in_lbn;         /* Logical block number. */
+       int     in_off;                 /* Offset in buffer. */
+       int     in_exists;              /* Flag if the block exists. */
+};
+
+/* Convert between inode pointers and vnode pointers. */
+#define        VTOI(vp)        ((struct inode *)(vp)->v_data)
+#define        ITOV(ip)        ((ip)->i_vnode)
+
+/* This overlays the fid structure (see fstypes.h). */
+struct ufid {
+       u_int16_t ufid_len;     /* Length of structure. */
+       u_int16_t ufid_pad;     /* Force 32-bit alignment. */
+       u_int32_t ufid_ino;     /* File number (ino). */
+       int32_t   ufid_gen;     /* Generation number. */
+};
+#endif /* _KERNEL */
+
+#endif /* !_UFS_UFS_INODE_H_ */
diff --git a/nbsd_include/ufs/ufs/quota.h b/nbsd_include/ufs/ufs/quota.h
new file mode 100644 (file)
index 0000000..58b1452
--- /dev/null
@@ -0,0 +1,97 @@
+/*     $NetBSD: quota.h,v 1.28 2011/03/25 10:25:17 bouyer Exp $        */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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.
+ *
+ *     @(#)quota.h     8.3 (Berkeley) 8/19/94
+ */
+
+#ifndef        _UFS_UFS_QUOTA_H_
+#define        _UFS_UFS_QUOTA_H_
+
+/*
+ * These definitions are common to the original disk quota implementation
+ * (quota1) and the newer implementation (quota2)
+ */
+
+/*
+ * The following constants define the usage of the quota file array in the
+ * ufsmount structure and dquot array in the inode structure.  The semantics
+ * of the elements of these arrays are defined in the routine getinoquota;
+ * the remainder of the quota code treats them generically and need not be
+ * inspected when changing the size of the array.
+ */
+#define        MAXQUOTAS       2
+#define        USRQUOTA        0       /* element used for user quotas */
+#define        GRPQUOTA        1       /* element used for group quotas */
+
+
+#if !defined(HAVE_NBTOOL_CONFIG_H)
+#include <quota/quotaprop.h>
+__inline static int __unused
+ufsclass2qtype(int class)
+{
+       switch(class) {
+       case QUOTA_CLASS_USER:
+               return USRQUOTA;
+       case QUOTA_CLASS_GROUP:
+               return GRPQUOTA;
+       default:
+               return -1;
+       }
+}
+
+static __inline int __unused
+qtype2ufsclass(int type)
+{
+       switch(type) {
+       case USRQUOTA:
+               return QUOTA_CLASS_USER;
+       case GRPQUOTA:
+               return QUOTA_CLASS_GROUP;
+       default:
+               return -1;
+       }
+}
+#endif /* !defined(HAVE_NBTOOL_CONFIG_H) */
+
+#ifdef _KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+void   dqinit(void);
+void   dqreinit(void);
+void   dqdone(void);
+__END_DECLS
+#endif /* _KERNEL */
+
+#endif /* !_UFS_UFS_QUOTA_H_ */
diff --git a/nbsd_include/ufs/ufs/quota1.h b/nbsd_include/ufs/ufs/quota1.h
new file mode 100644 (file)
index 0000000..3fdf137
--- /dev/null
@@ -0,0 +1,111 @@
+/*     $NetBSD: quota1.h,v 1.5 2011/11/25 16:55:05 dholland Exp $      */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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.
+ *
+ *     @(#)quota.h     8.3 (Berkeley) 8/19/94
+ */
+
+#ifndef        _UFS_UFS_QUOTA1_H_
+#define        _UFS_UFS_QUOTA1_H_
+
+#include <sys/quota.h>
+#include <ufs/ufs/quota.h>
+
+/*
+ * These definitions are for the original disk quota implementation, which
+ * is deprecated. the newer implementation is defined in quota2.h
+ * and friends
+ */
+
+/*
+ * Definitions for the default names of the quotas files/quota types.
+ */
+#define INITQFNAMES { \
+       "user",         /* USRQUOTA */ \
+       "group",        /* GRPQUOTA */ \
+}
+
+/*
+ * Definitions for disk quotas imposed on the average user
+ * (big brother finally hits UNIX).
+ *
+ * The following constants define the amount of time given a user before the
+ * soft limits are treated as hard limits (usually resulting in an allocation
+ * failure). The timer is started when the user crosses their soft limit, it
+ * is reset when they go below their soft limit.
+ */
+#define        MAX_IQ_TIME     (7*24*60*60)    /* seconds in 1 week */
+#define        MAX_DQ_TIME     (7*24*60*60)    /* seconds in 1 week */
+
+#define        QUOTAFILENAME   "quota"
+#define        QUOTAGROUP      "operator"
+
+/*
+ * Command definitions for the 'compat_50_quotactl' system call.  The commands
+ * are broken into a main command defined below and a subcommand that is used
+ * to convey the type of quota that is being manipulated (see above).
+ */
+#define SUBCMDMASK     0x00ff
+#define SUBCMDSHIFT    8
+#define        QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
+
+#define        Q_QUOTAON       0x0100  /* enable quotas */
+#define        Q_QUOTAOFF      0x0200  /* disable quotas */
+#define        Q_GETQUOTA      0x0300  /* get limits and usage */
+#define        Q_SETQUOTA      0x0400  /* set limits and usage */
+#define        Q_SETUSE        0x0500  /* set usage */
+#define        Q_SYNC          0x0600  /* sync disk copy of a filesystems quotas */
+
+/*
+ * The following structure defines the format of the disk quota file
+ * (as it appears on disk) - the file is an array of these structures
+ * indexed by user or group number.  The setquota system call establishes
+ * the vnode for each quota file (a pointer is retained in the ufsmount
+ * structure).
+ */
+struct dqblk {
+       u_int32_t dqb_bhardlimit;       /* absolute limit on disk blks alloc */
+       u_int32_t dqb_bsoftlimit;       /* preferred limit on disk blks */
+       u_int32_t dqb_curblocks;        /* current block count */
+       u_int32_t dqb_ihardlimit;       /* maximum # allocated inodes + 1 */
+       u_int32_t dqb_isoftlimit;       /* preferred inode limit */
+       u_int32_t dqb_curinodes;        /* current # allocated inodes */
+       int32_t   dqb_btime;            /* time limit for excessive disk use */
+       int32_t   dqb_itime;            /* time limit for excessive files */
+};
+
+/* quota1_subr.c */
+struct quota2_entry;
+void dqblk_to_quotaval(const struct dqblk *, struct quotaval *);
+void quotaval_to_dqblk(const struct quotaval *, struct dqblk *);
+
+#endif /* !_UFS_UFS_QUOTA1_H_ */
diff --git a/nbsd_include/ufs/ufs/quota2.h b/nbsd_include/ufs/ufs/quota2.h
new file mode 100644 (file)
index 0000000..f2456a2
--- /dev/null
@@ -0,0 +1,131 @@
+/* $NetBSD: quota2.h,v 1.5 2011/06/07 14:56:13 bouyer Exp $ */
+/*-
+  * Copyright (c) 2010 Manuel Bouyer
+  * 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.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+  */
+
+#ifndef _UFS_UFS_QUOTA2_H_
+#define _UFS_UFS_QUOTA2_H_
+#include <ufs/ufs/quota.h>
+#include <quota/quota.h>
+
+
+/* New disk quota implementation. In this implementation, the quota datas
+ * (default values, user limits and current usage) are part of the filesystem
+ * metadata. On FFS, this will be in a hidden, unlinked inode. fsck_ffs is
+ * responsible for checking quotas with the rest of the filesystem integrity,
+ * and quotas metadata are also covered by the filesystem journal if any.
+ * quota enable/disable is done on a filesystem basis via flags in the
+ * superblock
+ */
+
+/*
+ * The quota file is comprised of 2 parts, the header and the entries.
+ * The header contains global informations, and head of list of quota entries.
+ * A quota entry can either be in the free list, or one of the hash lists.
+ */
+
+/* description of a block or inode quota */
+struct quota2_val {
+       uint64_t q2v_hardlimit; /* absolute limit */
+       uint64_t q2v_softlimit; /* overflowable limit */
+       uint64_t q2v_cur; /* current usage */
+       int64_t q2v_time; /* grace expiration date for softlimit overflow */
+       int64_t q2v_grace; /* allowed time for softlimit overflow */
+};
+
+/* NAMES for the above in the plist */
+#define INITQVNAMES_ALL { \
+    QUOTADICT_LIMIT_HARD, \
+    QUOTADICT_LIMIT_SOFT, \
+    QUOTADICT_LIMIT_USAGE, \
+    QUOTADICT_LIMIT_ETIME, \
+    QUOTADICT_LIMIT_GTIME \
+    }
+#define INITQVNAMES_LIMITSONLY { \
+    QUOTADICT_LIMIT_HARD, \
+    QUOTADICT_LIMIT_SOFT, \
+    NULL, \
+    NULL, \
+    QUOTADICT_LIMIT_GTIME \
+    }
+
+#define N_QV 5
+/*
+ * On-disk description of a user or group quota
+ * These entries are keept as linked list, either in one of the hash HEAD,
+ * or in the free list.
+ */
+
+#define N_QL 2
+#define QL_BLOCK 0
+#define QL_FILE 1
+#define INITQLNAMES {QUOTADICT_LTYPE_BLOCK, QUOTADICT_LTYPE_FILE}
+
+struct quota2_entry {
+       /* block & inode limits and status */
+       struct quota2_val q2e_val[N_QL];
+       /* pointer to next entry for this list (offset in the file) */
+       uint64_t q2e_next;
+       /* ownership information */
+       uint32_t q2e_uid;
+       uint32_t q2e_pad;
+};
+
+/* header present at the start of the quota file */
+struct quota2_header {
+       uint32_t q2h_magic_number;
+       uint8_t  q2h_type; /* quota type, see below */
+       uint8_t  q2h_hash_shift; /* bytes used for hash index */
+       uint16_t q2h_hash_size; /* size of hash table */
+       /* default values applied to new entries */
+       struct quota2_entry q2h_defentry;
+       /* head of free quota2_entry list */
+       uint64_t q2h_free;
+       /* variable-sized hash table */
+       uint64_t q2h_entries[0];
+};
+
+#define Q2_HEAD_MAGIC  0xb746915e
+
+/* superblock flags */
+#define FS_Q2_DO_TYPE(type)    (0x01 << (type))
+
+#define off2qindex(hsize, off) (((off) - (hsize)) / sizeof(struct quota2_entry))
+#define qindex2off(hsize, idx) \
+       ((daddr_t)(idx) * sizeof(struct quota2_entry) + (hsize))
+
+/* quota2_subr.c */
+void quota2_addfreeq2e(struct quota2_header *, void *, uint64_t, uint64_t, int);
+void quota2_create_blk0(uint64_t, void *bp, int, int, int);
+void quota2_ufs_rwq2v(const struct quota2_val *, struct quota2_val *, int);
+void quota2_ufs_rwq2e(const struct quota2_entry *, struct quota2_entry *, int);
+
+__inline static int __unused
+quota2_check_limit(struct quota2_val *q2v, uint64_t change, time_t now)
+{
+       return quota_check_limit(q2v->q2v_cur, change, q2v->q2v_softlimit,
+           q2v->q2v_hardlimit, q2v->q2v_time, now);
+}
+#endif /*  _UFS_UFS_QUOTA2_H_ */
diff --git a/nbsd_include/ufs/ufs/ufs_bswap.h b/nbsd_include/ufs/ufs/ufs_bswap.h
new file mode 100644 (file)
index 0000000..c793e55
--- /dev/null
@@ -0,0 +1,80 @@
+/*     $NetBSD: ufs_bswap.h,v 1.19 2009/10/19 18:41:17 bouyer Exp $    */
+
+/*
+ * Copyright (c) 1998 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ */
+
+#ifndef _UFS_UFS_BSWAP_H_
+#define _UFS_UFS_BSWAP_H_
+
+#if defined(_KERNEL_OPT)
+#include "opt_ffs.h"
+#endif
+
+#include <sys/bswap.h>
+
+/* Macros to access UFS flags */
+#ifdef FFS_EI
+#define        UFS_MPNEEDSWAP(ump)     ((ump)->um_flags & UFS_NEEDSWAP)
+#define UFS_FSNEEDSWAP(fs)     ((fs)->fs_flags & FS_SWAPPED)
+#define        UFS_IPNEEDSWAP(ip)      UFS_MPNEEDSWAP((ip)->i_ump)
+#else
+#define        UFS_MPNEEDSWAP(ump)     (0)
+#define UFS_FSNEEDSWAP(fs)     (0)
+#define        UFS_IPNEEDSWAP(ip)      (0)
+#endif
+
+#if !defined(_KERNEL) || defined(FFS_EI)
+/* inlines for access to swapped data */
+static inline u_int16_t
+ufs_rw16(uint16_t a, int ns)
+{
+       return ((ns) ? bswap16(a) : (a));
+}
+
+static inline u_int32_t
+ufs_rw32(uint32_t a, int ns)
+{
+       return ((ns) ? bswap32(a) : (a));
+}
+
+static inline u_int64_t
+ufs_rw64(uint64_t a, int ns)
+{
+       return ((ns) ? bswap64(a) : (a));
+}
+#else
+#define ufs_rw16(a, ns) ((uint16_t)(a))
+#define ufs_rw32(a, ns) ((uint32_t)(a))
+#define ufs_rw64(a, ns) ((uint64_t)(a))
+#endif
+
+#define ufs_add16(a, b, ns) \
+       (a) = ufs_rw16(ufs_rw16((a), (ns)) + (b), (ns))
+#define ufs_add32(a, b, ns) \
+       (a) = ufs_rw32(ufs_rw32((a), (ns)) + (b), (ns))
+#define ufs_add64(a, b, ns) \
+       (a) = ufs_rw64(ufs_rw64((a), (ns)) + (b), (ns))
+
+#endif /* !_UFS_UFS_BSWAP_H_ */
diff --git a/nbsd_include/ufs/ufs/ufs_extern.h b/nbsd_include/ufs/ufs/ufs_extern.h
new file mode 100644 (file)
index 0000000..61e42ee
--- /dev/null
@@ -0,0 +1,188 @@
+/*     $NetBSD: ufs_extern.h,v 1.66 2011/07/17 22:07:59 dholland Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *     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_extern.h        8.10 (Berkeley) 5/14/95
+ */
+
+#ifndef _UFS_UFS_EXTERN_H_
+#define _UFS_UFS_EXTERN_H_
+
+#include <sys/mutex.h>
+
+struct buf;
+struct componentname;
+struct direct;
+struct disklabel;
+struct dquot;
+struct fid;
+struct flock;
+struct indir;
+struct inode;
+struct mbuf;
+struct mount;
+struct nameidata;
+struct lwp;
+struct ufid;
+struct ufs_args;
+struct ufs_lookup_results;
+struct ufsmount;
+struct uio;
+struct vattr;
+struct vnode;
+
+extern pool_cache_t ufs_direct_cache;  /* memory pool for directs */
+
+__BEGIN_DECLS
+#define        ufs_abortop     genfs_abortop
+int    ufs_access(void *);
+int    ufs_advlock(void *);
+int    ufs_bmap(void *);
+int    ufs_close(void *);
+int    ufs_create(void *);
+int    ufs_getattr(void *);
+int    ufs_inactive(void *);
+#define        ufs_fcntl       genfs_fcntl
+#define        ufs_ioctl       genfs_enoioctl
+#define        ufs_islocked    genfs_islocked
+int    ufs_link(void *);
+#define        ufs_lock        genfs_lock
+int    ufs_lookup(void *);
+int    ufs_mkdir(void *);
+int    ufs_mknod(void *);
+#define        ufs_mmap        genfs_mmap
+#define        ufs_revoke      genfs_revoke
+int    ufs_open(void *);
+int    ufs_pathconf(void *);
+int    ufs_print(void *);
+int    ufs_readdir(void *);
+int    ufs_readlink(void *);
+int    ufs_remove(void *);
+int    ufs_rename(void *);
+int    ufs_rmdir(void *);
+#define        ufs_seek        genfs_seek
+#define        ufs_poll        genfs_poll
+int    ufs_setattr(void *);
+int    ufs_strategy(void *);
+int    ufs_symlink(void *);
+#define        ufs_unlock      genfs_unlock
+int    ufs_whiteout(void *);
+int    ufsspec_close(void *);
+int    ufsspec_read(void *);
+int    ufsspec_write(void *);
+
+int    ufsfifo_read(void *);
+int    ufsfifo_write(void *);
+int    ufsfifo_close(void *);
+
+/* ufs_bmap.c */
+typedef        bool (*ufs_issequential_callback_t)(const struct ufsmount *,
+                                                daddr_t, daddr_t);
+int    ufs_bmaparray(struct vnode *, daddr_t, daddr_t *, struct indir *,
+                     int *, int *, ufs_issequential_callback_t);
+int    ufs_getlbns(struct vnode *, daddr_t, struct indir *, int *);
+
+/* ufs_ihash.c */
+void   ufs_ihashinit(void);
+void   ufs_ihashreinit(void);
+void   ufs_ihashdone(void);
+struct vnode *ufs_ihashlookup(dev_t, ino_t);
+struct vnode *ufs_ihashget(dev_t, ino_t, int);
+void   ufs_ihashins(struct inode *);
+void   ufs_ihashrem(struct inode *);
+
+/* ufs_inode.c */
+int    ufs_reclaim(struct vnode *);
+int    ufs_balloc_range(struct vnode *, off_t, off_t, kauth_cred_t, int);
+
+/* ufs_lookup.c */
+void   ufs_dirbad(struct inode *, doff_t, const char *);
+int    ufs_dirbadentry(struct vnode *, struct direct *, int);
+void   ufs_makedirentry(struct inode *, struct componentname *,
+                        struct direct *);
+int    ufs_direnter(struct vnode *, const struct ufs_lookup_results *,
+                    struct vnode *, struct direct *,
+                    struct componentname *, struct buf *);
+int    ufs_dirremove(struct vnode *, const struct ufs_lookup_results *,
+                     struct inode *, int, int);
+int    ufs_dirrewrite(struct inode *, off_t,
+                      struct inode *, ino_t, int, int, int);
+int    ufs_dirempty(struct inode *, ino_t, kauth_cred_t);
+int    ufs_checkpath(struct inode *, struct inode *, kauth_cred_t);
+int    ufs_parentcheck(struct vnode *, struct vnode *, kauth_cred_t,
+                       int *, struct vnode **);
+int    ufs_blkatoff(struct vnode *, off_t, char **, struct buf **, bool);
+
+/* ufs_quota.c */
+/*
+ * Flags to chkdq() and chkiq()
+ */
+#define        FORCE   0x01    /* force usage changes independent of limits */
+void   ufsquota_init(struct inode *);
+void   ufsquota_free(struct inode *);
+int    chkdq(struct inode *, int64_t, kauth_cred_t, int);
+int    chkiq(struct inode *, int32_t, kauth_cred_t, int);
+int    quota_handle_cmd(struct mount *, struct lwp *, prop_dictionary_t);
+int    qsync(struct mount *);
+
+/* ufs_quota1.c */
+int    quota1_umount(struct mount *, int);
+
+/* ufs_quota2.c */
+int    quota2_umount(struct mount *, int);
+
+/* ufs_vfsops.c */
+void   ufs_init(void);
+void   ufs_reinit(void);
+void   ufs_done(void);
+int    ufs_start(struct mount *, int);
+int    ufs_root(struct mount *, struct vnode **);
+int    ufs_quotactl(struct mount *, prop_dictionary_t);
+int    ufs_fhtovp(struct mount *, struct ufid *, struct vnode **);
+
+/* ufs_vnops.c */
+void   ufs_vinit(struct mount *, int (**)(void *),
+                 int (**)(void *), struct vnode **);
+int    ufs_makeinode(int, struct vnode *, const struct ufs_lookup_results *,
+                     struct vnode **, struct componentname *);
+int    ufs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
+void   ufs_gop_markupdate(struct vnode *, int);
+
+/*
+ * Snapshot function prototypes.
+ */
+
+void   ffs_snapgone(struct inode *);
+
+__END_DECLS
+
+extern kmutex_t ufs_ihash_lock;
+extern kmutex_t ufs_hashlock;
+
+#endif /* !_UFS_UFS_EXTERN_H_ */
diff --git a/nbsd_include/ufs/ufs/ufs_quota.h b/nbsd_include/ufs/ufs/ufs_quota.h
new file mode 100644 (file)
index 0000000..efc87f1
--- /dev/null
@@ -0,0 +1,130 @@
+/*     $NetBSD: ufs_quota.h,v 1.2 2011/03/06 17:08:39 bouyer Exp $     */
+
+/*
+ * Copyright (c) 1982, 1986, 1990, 1993, 1995
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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_quota.c 8.5 (Berkeley) 5/20/95
+ */
+#include <ufs/ufs/quota1.h>
+#include <ufs/ufs/quota2.h>
+
+/* link to this quota in the quota inode (for QUOTA2) */
+struct dq2_desc {
+       uint64_t dq2_lblkno; /* logical disk block holding this quota */
+       u_int    dq2_blkoff; /* offset in disk block holding this quota */
+};
+
+/*
+ * The following structure records disk usage for a user or group on a
+ * filesystem. There is one allocated for each quota that exists on any
+ * filesystem for the current user or group. A cache is kept of recently
+ * used entries.
+ * Field markings and the corresponding locks:
+ * h:  dqlock
+ * d:  dq_interlock
+ *
+ * Lock order is: dq_interlock -> dqlock
+ *                dq_interlock -> dqvp
+ */
+struct dquot {
+       LIST_ENTRY(dquot) dq_hash;      /* h: hash list */
+       u_int16_t dq_flags;             /* d: flags, see below */
+       u_int16_t dq_type;              /* d: quota type of this dquot */
+       u_int32_t dq_cnt;               /* h: count of active references */
+       u_int32_t dq_id;                /* d: identifier this applies to */
+       struct  ufsmount *dq_ump;       /* d: filesystem this is taken from */
+       kmutex_t dq_interlock;          /* d: lock this dquot */
+       union {
+               struct dqblk dq1_dqb;   /* d: actual usage & quotas */
+               struct dq2_desc dq2_desc; /* d: pointer to quota data */
+       } dq_un;
+};
+
+/*
+ * Flag values.
+ */
+#define        DQ_MOD          0x04            /* this quota modified since read */
+#define        DQ_FAKE         0x08            /* no limits here, just usage */
+#define        DQ_WARN(ltype)  (0x10 << ltype) /* has been warned about "type" limit */
+/*
+ * Shorthand notation.
+ */
+#define        dq_bhardlimit   dq_un.dq1_dqb.dqb_bhardlimit
+#define        dq_bsoftlimit   dq_un.dq1_dqb.dqb_bsoftlimit
+#define        dq_curblocks    dq_un.dq1_dqb.dqb_curblocks
+#define        dq_ihardlimit   dq_un.dq1_dqb.dqb_ihardlimit
+#define        dq_isoftlimit   dq_un.dq1_dqb.dqb_isoftlimit
+#define        dq_curinodes    dq_un.dq1_dqb.dqb_curinodes
+#define        dq_btime        dq_un.dq1_dqb.dqb_btime
+#define        dq_itime        dq_un.dq1_dqb.dqb_itime
+
+#define dq2_lblkno     dq_un.dq2_desc.dq2_lblkno
+#define dq2_blkoff     dq_un.dq2_desc.dq2_blkoff
+/*
+ * If the system has never checked for a quota for this file, then it is
+ * set to NODQUOT.  Once a write attempt is made the inode pointer is set
+ * to reference a dquot structure.
+ */
+#define        NODQUOT         NULL
+
+extern kmutex_t dqlock;
+extern kcondvar_t dqcv;
+/*
+ * Quota name to error message mapping.
+ */
+const char *quotatypes[MAXQUOTAS];
+
+int  getinoquota(struct inode *);
+int  dqget(struct vnode *, u_long, struct ufsmount *, int, struct dquot **);
+void dqref(struct dquot *);
+void dqrele(struct vnode *, struct dquot *);
+void dqflush(struct vnode *);
+
+int chkdq1(struct inode *, int64_t, kauth_cred_t, int);
+int chkiq1(struct inode *, int32_t, kauth_cred_t, int);
+int q1sync(struct mount *);
+int dq1get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *);
+int dq1sync(struct vnode *, struct dquot *);
+int quota1_handle_cmd_get(struct ufsmount *, int, int, int, prop_array_t);
+int quota1_handle_cmd_set(struct ufsmount *, int, int, int, prop_dictionary_t);
+int quota1_handle_cmd_quotaon(struct lwp *, struct ufsmount *, int,
+    const char *);
+int quota1_handle_cmd_quotaoff(struct lwp *, struct ufsmount *, int);
+
+int chkdq2(struct inode *, int64_t, kauth_cred_t, int);
+int chkiq2(struct inode *, int32_t, kauth_cred_t, int);
+int quota2_handle_cmd_get(struct ufsmount *, int, int, int, prop_array_t);
+int quota2_handle_cmd_set(struct ufsmount *, int, int, int, prop_dictionary_t);
+int quota2_handle_cmd_clear(struct ufsmount *, int, int, int, prop_dictionary_t);
+int quota2_handle_cmd_getall(struct ufsmount *, int, prop_array_t);
+int q2sync(struct mount *);
+int dq2get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *);
+int dq2sync(struct vnode *, struct dquot *);
diff --git a/nbsd_include/ufs/ufs/ufs_wapbl.h b/nbsd_include/ufs/ufs/ufs_wapbl.h
new file mode 100644 (file)
index 0000000..6dc878c
--- /dev/null
@@ -0,0 +1,178 @@
+/*     $NetBSD: ufs_wapbl.h,v 1.7 2011/09/19 11:18:01 gdt Exp $        */
+
+/*-
+ * Copyright (c) 2003,2006,2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Wasabi Systems, Inc.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+
+#ifndef _UFS_UFS_UFS_WAPBL_H_
+#define        _UFS_UFS_UFS_WAPBL_H_
+
+#if defined(_KERNEL_OPT)
+#include "opt_wapbl.h"
+#endif
+
+/*
+ * Information for the journal location stored in the superblock.
+ * We store the journal version, some flags, the journal location
+ * type, and some location specific "locators" that identify where
+ * the log itself is located.
+ */
+
+/* fs->fs_journal_version */
+#define        UFS_WAPBL_VERSION                       1
+
+/* fs->fs_journal_location */
+#define        UFS_WAPBL_JOURNALLOC_NONE               0
+
+#define        UFS_WAPBL_JOURNALLOC_END_PARTITION      1
+#define         UFS_WAPBL_EPART_ADDR                     0 /* locator slots */
+#define         UFS_WAPBL_EPART_COUNT                    1
+#define         UFS_WAPBL_EPART_BLKSZ                    2
+#define         UFS_WAPBL_EPART_UNUSED                   3
+
+#define        UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM      2
+#define         UFS_WAPBL_INFS_ADDR                      0 /* locator slots */
+#define         UFS_WAPBL_INFS_COUNT                     1
+#define         UFS_WAPBL_INFS_BLKSZ                     2
+#define         UFS_WAPBL_INFS_INO                       3
+
+/* fs->fs_journal_flags */
+#define        UFS_WAPBL_FLAGS_CREATE_LOG              0x1
+#define        UFS_WAPBL_FLAGS_CLEAR_LOG               0x2
+
+
+/*
+ * The journal size is limited to between 1MB and 64MB.
+ * The default journal size is the filesystem size divided by
+ * the scale factor - this is 1M of journal per 1GB of filesystem
+ * space.
+ *
+ * XXX: Is 64MB too limiting?  If user explicitly asks for more, allow it?
+ */
+#define        UFS_WAPBL_JOURNAL_SCALE                 1024
+#define        UFS_WAPBL_MIN_JOURNAL_SIZE              (1024 * 1024)
+#define        UFS_WAPBL_MAX_JOURNAL_SIZE              (64 * 1024 * 1024)
+
+
+#if defined(WAPBL)
+
+#if defined(WAPBL_DEBUG)
+#define        WAPBL_DEBUG_INODES
+#endif
+
+#ifdef WAPBL_DEBUG_INODES
+#error Undefine WAPBL_DEBUG_INODES or update the code.  Have a nice day.
+#endif
+
+#ifdef WAPBL_DEBUG_INODES
+void   ufs_wapbl_verify_inodes(struct mount *, const char *);
+#endif
+
+static __inline int
+ufs_wapbl_begin2(struct mount *mp, struct vnode *vp1, struct vnode *vp2,
+                const char *file, int line)
+{
+       if (mp->mnt_wapbl) {
+               int error;
+
+               if (vp1)
+                       vref(vp1);
+               if (vp2)
+                       vref(vp2);
+               error = wapbl_begin(mp->mnt_wapbl, file, line);
+               if (error)
+                       return error;
+#ifdef WAPBL_DEBUG_INODES
+               if (mp->mnt_wapbl->wl_lock.lk_exclusivecount == 1)
+                       ufs_wapbl_verify_inodes(mp, "wapbl_begin");
+#endif
+       }
+       return 0;
+}
+
+static __inline void
+ufs_wapbl_end2(struct mount *mp, struct vnode *vp1, struct vnode *vp2)
+{
+       if (mp->mnt_wapbl) {
+#ifdef WAPBL_DEBUG_INODES
+               if (mp->mnt_wapbl->wl_lock.lk_exclusivecount == 1)
+                       ufs_wapbl_verify_inodes(mp, "wapbl_end");
+#endif
+               wapbl_end(mp->mnt_wapbl);
+               if (vp2)
+                       vrele(vp2);
+               if (vp1)
+                       vrele(vp1);
+       }
+}
+
+#define        UFS_WAPBL_BEGIN(mp)                                             \
+       ufs_wapbl_begin2(mp, NULL, NULL, __FUNCTION__, __LINE__)
+#define        UFS_WAPBL_BEGIN1(mp, v1)                                        \
+       ufs_wapbl_begin2(mp, v1, NULL, __FUNCTION__, __LINE__)
+#define        UFS_WAPBL_END(mp)       ufs_wapbl_end2(mp, NULL, NULL)
+#define        UFS_WAPBL_END1(mp, v1)  ufs_wapbl_end2(mp, v1, NULL)
+
+#define        UFS_WAPBL_UPDATE(vp, access, modify, flags)                     \
+       if ((vp)->v_mount->mnt_wapbl) {                                 \
+               UFS_UPDATE(vp, access, modify, flags);                  \
+       }
+
+#ifdef UFS_WAPBL_DEBUG_JLOCK
+#define        UFS_WAPBL_JLOCK_ASSERT(mp)                                      \
+       if (mp->mnt_wapbl) wapbl_jlock_assert(mp->mnt_wapbl)
+#define        UFS_WAPBL_JUNLOCK_ASSERT(mp)                                    \
+       if (mp->mnt_wapbl) wapbl_junlock_assert(mp->mnt_wapbl)
+#else
+#define        UFS_WAPBL_JLOCK_ASSERT(mp)
+#define        UFS_WAPBL_JUNLOCK_ASSERT(mp)
+#endif
+
+#define        UFS_WAPBL_REGISTER_INODE(mp, ino, mode)                         \
+       if (mp->mnt_wapbl) wapbl_register_inode(mp->mnt_wapbl, ino, mode)
+#define        UFS_WAPBL_UNREGISTER_INODE(mp, ino, mode)                       \
+       if (mp->mnt_wapbl) wapbl_unregister_inode(mp->mnt_wapbl, ino, mode)
+
+#define        UFS_WAPBL_REGISTER_DEALLOCATION(mp, blk, len)                   \
+       if (mp->mnt_wapbl) wapbl_register_deallocation(mp->mnt_wapbl, blk, len)
+
+#else /* ! WAPBL */
+#define        UFS_WAPBL_BEGIN(mp) 0
+#define        UFS_WAPBL_BEGIN1(mp, v1) 0
+#define        UFS_WAPBL_END(mp)       do { } while (0)
+#define        UFS_WAPBL_END1(mp, v1)
+#define        UFS_WAPBL_UPDATE(vp, access, modify, flags)     do { } while (0)
+#define        UFS_WAPBL_JLOCK_ASSERT(mp)
+#define        UFS_WAPBL_JUNLOCK_ASSERT(mp)
+#define        UFS_WAPBL_REGISTER_INODE(mp, ino, mode)         do { } while (0)
+#define        UFS_WAPBL_UNREGISTER_INODE(mp, ino, mode)       do { } while (0)
+#define        UFS_WAPBL_REGISTER_DEALLOCATION(mp, blk, len)
+#endif
+
+#endif /* !_UFS_UFS_UFS_WAPBL_H_ */
diff --git a/nbsd_include/ufs/ufs/ufsmount.h b/nbsd_include/ufs/ufs/ufsmount.h
new file mode 100644 (file)
index 0000000..9fcc897
--- /dev/null
@@ -0,0 +1,197 @@
+/*     $NetBSD: ufsmount.h,v 1.37 2011/11/24 15:51:32 ahoka Exp $      */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 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.
+ *
+ *     @(#)ufsmount.h  8.6 (Berkeley) 3/30/95
+ */
+
+#ifndef _UFS_UFS_UFSMOUNT_H_
+#define _UFS_UFS_UFSMOUNT_H_
+
+#include <sys/mount.h> /* struct export_args30 */
+
+/*
+ * Arguments to mount UFS-based filesystems
+ */
+struct ufs_args {
+       char    *fspec;                 /* block special device to mount */
+};
+
+#ifndef __minix
+/*
+ * Arguments to mount MFS
+ */
+struct mfs_args {
+       char    *fspec;                 /* name to export for statfs */
+       struct  export_args30 _pad1; /* compat with old userland tools */
+       void *  base;                   /* base of file system in memory */
+       u_long  size;                   /* size of file system */
+};
+#endif
+
+#ifdef _KERNEL
+
+#if defined(_KERNEL_OPT)
+#include "opt_ffs.h"
+#endif
+
+#include <sys/mutex.h>
+
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
+
+struct buf;
+struct inode;
+struct nameidata;
+struct timeval;
+struct uio;
+struct vnode;
+
+/* This structure describes the UFS specific mount structure data. */
+struct ufsmount {
+       struct  mount *um_mountp;               /* filesystem vfs structure */
+       dev_t   um_dev;                         /* device mounted */
+       struct  vnode *um_devvp;                /* block device mounted vnode */
+       u_long  um_fstype;
+       u_int32_t um_flags;                     /* UFS-specific flags - see below */
+       union {                                 /* pointer to superblock */
+               struct  fs *fs;                 /* FFS */
+               struct  lfs *lfs;               /* LFS */
+               struct  m_ext2fs *e2fs;         /* EXT2FS */
+               struct  chfs_mount *chfs;       /* CHFS */
+       } ufsmount_u;
+#define        um_fs   ufsmount_u.fs
+#define        um_lfs  ufsmount_u.lfs
+#define um_e2fs        ufsmount_u.e2fs
+#define um_e2fsb ufsmount_u.e2fs->s_es
+#define um_chfs        ufsmount_u.chfs
+
+       /* Extended attribute information. */
+       struct ufs_extattr_per_mount um_extattr;
+
+       struct  vnode *um_quotas[MAXQUOTAS];    /* pointer to quota files */
+       kauth_cred_t   um_cred[MAXQUOTAS];      /* quota file access cred */
+       u_long  um_nindir;                      /* indirect ptrs per block */
+       u_long  um_lognindir;                   /* log2 of um_nindir */
+       u_long  um_bptrtodb;                    /* indir ptr to disk block */
+       u_long  um_seqinc;                      /* inc between seq blocks */
+       kmutex_t um_lock;                       /* lock on global data */
+       union {
+           struct um_q1 {
+               time_t  q1_btime[MAXQUOTAS];    /* block quota time limit */
+               time_t  q1_itime[MAXQUOTAS];    /* inode quota time limit */
+               char    q1_qflags[MAXQUOTAS];   /* quota specific flags */
+           } um_q1;
+           struct um_q2 {
+               uint64_t q2_bsize;              /* block size of quota file */
+               uint64_t q2_bmask;              /* mask for above */
+           } um_q2;
+       } um_q;
+#define umq1_btime  um_q.um_q1.q1_btime
+#define umq1_itime  um_q.um_q1.q1_itime
+#define umq1_qflags um_q.um_q1.q1_qflags
+#define umq2_bsize  um_q.um_q2.q2_bsize
+#define umq2_bmask  um_q.um_q2.q2_bmask
+
+       void    *um_oldfscompat;                /* save 4.2 rotbl */
+       int     um_maxsymlinklen;
+       int     um_dirblksiz;
+       u_int64_t um_maxfilesize;
+       void    *um_snapinfo;                   /* snapshot private data */
+
+       const struct ufs_ops *um_ops;
+};
+
+struct ufs_ops {
+       void (*uo_itimes)(struct inode *ip, const struct timespec *,
+           const struct timespec *, const struct timespec *);
+       int (*uo_update)(struct vnode *, const struct timespec *,
+           const struct timespec *, int);
+       int (*uo_truncate)(struct vnode *, off_t, int, kauth_cred_t);
+       int (*uo_valloc)(struct vnode *, int, kauth_cred_t, struct vnode **);
+       int (*uo_vfree)(struct vnode *, ino_t, int);
+       int (*uo_balloc)(struct vnode *, off_t, int, kauth_cred_t, int,
+           struct buf **);
+        void (*uo_unmark_vnode)(struct vnode *);
+};
+
+#define        UFS_OPS(vp)     (VFSTOUFS((vp)->v_mount)->um_ops)
+
+#define        UFS_ITIMES(vp, acc, mod, cre) \
+       (*UFS_OPS(vp)->uo_itimes)(VTOI(vp), (acc), (mod), (cre))
+#define        UFS_UPDATE(vp, acc, mod, flags) \
+       (*UFS_OPS(vp)->uo_update)((vp), (acc), (mod), (flags))
+#define        UFS_TRUNCATE(vp, off, flags, cr) \
+       (*UFS_OPS(vp)->uo_truncate)((vp), (off), (flags), (cr))
+#define        UFS_VALLOC(vp, mode, cr, vpp) \
+       (*UFS_OPS(vp)->uo_valloc)((vp), (mode), (cr), (vpp))
+#define        UFS_VFREE(vp, ino, mode) \
+       (*UFS_OPS(vp)->uo_vfree)((vp), (ino), (mode))
+#define        UFS_BALLOC(vp, off, size, cr, flags, bpp) \
+       (*UFS_OPS(vp)->uo_balloc)((vp), (off), (size), (cr), (flags), (bpp))
+#define        UFS_UNMARK_VNODE(vp) \
+       (*UFS_OPS(vp)->uo_unmark_vnode)((vp))
+
+/* UFS-specific flags */
+#define UFS_NEEDSWAP   0x01    /* filesystem metadata need byte-swapping */
+#define UFS_ISAPPLEUFS 0x02    /* filesystem is Apple UFS */
+#define UFS_QUOTA      0x04    /* filesystem has QUOTA (v1) */
+#define UFS_QUOTA2     0x08    /* filesystem has QUOTA2 */
+
+/*
+ * Filesystem types
+ */
+#define UFS1  1
+#define UFS2  2
+
+
+/*
+ * Flags describing the state of quotas.
+ */
+#define        QTF_OPENING     0x01                    /* Q_QUOTAON in progress */
+#define        QTF_CLOSING     0x02                    /* Q_QUOTAOFF in progress */
+
+/* Convert mount ptr to ufsmount ptr. */
+#define VFSTOUFS(mp)   ((struct ufsmount *)((mp)->mnt_data))
+
+#ifdef APPLE_UFS
+#define UFS_MPISAPPLEUFS(ump)  ((ump)->um_flags & UFS_ISAPPLEUFS)
+#else
+#define UFS_MPISAPPLEUFS(ump)  (0)
+#endif
+
+/*
+ * Macros to access file system parameters in the ufsmount structure.
+ * Used by ufs_bmap.
+ */
+#define MNINDIR(ump)                   ((ump)->um_nindir)
+#define        blkptrtodb(ump, b)              ((b) << (ump)->um_bptrtodb)
+#endif /* _KERNEL */
+
+#endif /* !_UFS_UFS_UFSMOUNT_H_ */
index 0b8c6276a390cbd636b1268e2204b85d018210ae..220ff19f36dff568e05d5324eef47fb928678f43 100644 (file)
@@ -2,6 +2,6 @@
 
 .include <bsd.own.mk>
 
-SUBDIR= fsck 
+SUBDIR= fsck fsck_ext2fs newfs_ext2fs
 
 .include <bsd.subdir.mk>
index 4bf0296e0c3040fcb950b9dd258bb805b30d5ef1..e57ec3065706f5ce5c8d8404f6e62a0969ccdabb 100644 (file)
@@ -183,6 +183,11 @@ main(int argc, char *argv[])
        if (flags & CHECK_PROGRESS)
                maxrun = 1;
 
+#ifdef __minix
+       /* parallel checking heuristic doesn't work for minix currently */
+       maxrun = 1;
+#endif
+
        argc -= optind;
        argv += optind;
 
@@ -552,6 +557,9 @@ mangle(char *opts, int *argcp, const char ** volatile *argvp, int *maxargcp)
 static const char *
 getfslab(const char *str)
 {
+#ifdef __minix
+       errx(1, "cannot determine vfstype under minix");
+#else
        static struct dkwedge_info dkw;
        struct disklabel dl;
        int fd;
@@ -589,6 +597,7 @@ getfslab(const char *str)
                    fstypenames[t], str);
 
        return vfstype;
+#endif
 }
 
 
index 4d626619abab114ff3edfc1f34ddae8ab8b59ad9..88cf59d9e36dbea2398cc1ecc57045b8132fcea7 100644 (file)
@@ -92,6 +92,9 @@ dict2geom(struct disk_geom *geo, prop_dictionary_t dict)
 static void
 part2wedge(struct dkwedge_info *dkw, const struct disklabel *lp, const char *s)
 {
+#ifdef __minix
+       errx(1, "minix doesn't know about wedges");
+#else
        struct stat sb;
        const struct partition *pp;
        int ptn;
@@ -150,6 +153,7 @@ part2wedge(struct dkwedge_info *dkw, const struct disklabel *lp, const char *s)
                (void)strcpy(dkw->dkw_ptype, DKW_PTYPE_NTFS);
                break;
        }
+#endif
 }
 
 int
diff --git a/sbin/fsck_ext2fs/Makefile b/sbin/fsck_ext2fs/Makefile
new file mode 100644 (file)
index 0000000..c93408a
--- /dev/null
@@ -0,0 +1,19 @@
+#      $NetBSD: Makefile,v 1.16 2011/08/06 16:42:41 dholland Exp $
+#      @(#)Makefile    8.1 (Berkeley) 6/5/93
+
+.include <bsd.own.mk>
+
+PROG=  fsck_ext2fs
+MAN=    fsck_ext2fs.8
+SRCS=  dir.c inode.c main.c pass1.c pass1b.c pass2.c pass3.c pass4.c \
+       pass5.c fsutil.c setup.c utilities.c ext2fs_bswap.c
+FSCK=  ${NETBSDSRCDIR}/sbin/fsck
+CPPFLAGS+= -I${FSCK}
+.PATH: -I/usr/nbsdsrc/src/sys/ufs/ext2fs ${FSCK}
+
+SYMLINKS+= $(BINDIR)/$(PROG) $(BINDIR)/fsck.ext2
+
+.include <bsd.prog.mk>
+
+LDADD+=-lutil
+DPADD+=${LIBUTIL}
diff --git a/sbin/fsck_ext2fs/dir.c b/sbin/fsck_ext2fs/dir.c
new file mode 100644 (file)
index 0000000..8036f52
--- /dev/null
@@ -0,0 +1,723 @@
+/*     $NetBSD: dir.c,v 1.23 2009/10/19 18:41:07 bouyer Exp $  */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)dir.c      8.5 (Berkeley) 12/8/94";
+#else
+__RCSID("$NetBSD: dir.c,v 1.23 2009/10/19 18:41:07 bouyer Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs_dir.h>
+#include <ufs/ext2fs/ext2fs.h>
+
+#include <ufs/ufs/dinode.h> /* for IFMT & friends */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+
+#include "fsck.h"
+#include "fsutil.h"
+#include "extern.h"
+
+const char     *lfname = "lost+found";
+int    lfmode = 01700;
+struct ext2fs_dirtemplate emptydir = {
+       .dot_ino = 0,
+       .dot_reclen = DIRBLKSIZ,
+}; 
+struct ext2fs_dirtemplate dirhead = {
+       .dot_ino = 0,
+       .dot_reclen = 12,
+       .dot_namlen = 1,
+       .dot_type = EXT2_FT_DIR,
+       .dot_name = ".",
+       .dotdot_ino = 0,
+       .dotdot_reclen = DIRBLKSIZ - 12,
+       .dotdot_namlen = 2,
+       .dotdot_type = EXT2_FT_DIR,
+       .dotdot_name = "..",
+};
+#undef DIRBLKSIZ
+
+static int expanddir(struct ext2fs_dinode *, char *);
+static void freedir(ino_t, ino_t);
+static struct ext2fs_direct *fsck_readdir(struct inodesc *);
+static struct bufarea *getdirblk(daddr_t, long);
+static int lftempname(char *, ino_t);
+static int mkentry(struct inodesc *);
+static int chgino(struct  inodesc *);
+
+/*
+ * Propagate connected state through the tree.
+ */
+void
+propagate(void)
+{
+       struct inoinfo **inpp, *inp, *pinp;
+       struct inoinfo **inpend;
+
+       /*
+        * Create a list of children for each directory.
+        */
+       inpend = &inpsort[inplast];
+       for (inpp = inpsort; inpp < inpend; inpp++) {
+               inp = *inpp;
+               if (inp->i_parent == 0 ||
+                   inp->i_number == EXT2_ROOTINO)
+                       continue;
+               pinp = getinoinfo(inp->i_parent);
+               inp->i_parentp = pinp;
+               inp->i_sibling = pinp->i_child;
+               pinp->i_child = inp;
+       }
+       inp = getinoinfo(EXT2_ROOTINO);
+       while (inp) {
+               statemap[inp->i_number] = DFOUND;
+               if (inp->i_child &&
+                   statemap[inp->i_child->i_number] == DSTATE)
+                       inp = inp->i_child;
+               else if (inp->i_sibling)
+                       inp = inp->i_sibling;
+               else
+                       inp = inp->i_parentp;
+       }
+}
+
+/*
+ * Scan each entry in a directory block.
+ */
+int
+dirscan(struct inodesc *idesc)
+{
+       struct ext2fs_direct *dp;
+       struct bufarea *bp;
+       int dsize, n;
+       long blksiz;
+       char *dbuf = NULL;
+
+       if ((dbuf = malloc(sblock.e2fs_bsize)) == NULL)
+               err(8, "Can't allocate directory block");
+
+       if (idesc->id_type != DATA)
+               errexit("wrong type to dirscan %d", idesc->id_type);
+       if (idesc->id_entryno == 0 &&
+           (idesc->id_filesize & (sblock.e2fs_bsize - 1)) != 0)
+               idesc->id_filesize = roundup(idesc->id_filesize, sblock.e2fs_bsize);
+       blksiz = idesc->id_numfrags * sblock.e2fs_bsize;
+       if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
+               idesc->id_filesize -= blksiz;
+               free(dbuf);
+               return (SKIP);
+       }
+       idesc->id_loc = 0;
+       for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
+               dsize = fs2h16(dp->e2d_reclen);
+               memcpy(dbuf, dp, (size_t)dsize);
+               idesc->id_dirp = (struct ext2fs_direct *)dbuf;
+               if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
+                       bp = getdirblk(idesc->id_blkno, blksiz);
+                       memcpy(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf,
+                           (size_t)dsize);
+                       dirty(bp);
+                       sbdirty();
+               }
+               if (n & STOP) {
+                       free(dbuf);
+                       return (n);
+               }
+       }
+       free(dbuf);
+       return (idesc->id_filesize > 0 ? KEEPON : STOP);
+}
+
+/*
+ * get next entry in a directory.
+ */
+static struct ext2fs_direct *
+fsck_readdir(struct inodesc *idesc)
+{
+       struct ext2fs_direct *dp, *ndp;
+       struct bufarea *bp;
+       long size, blksiz, fix, dploc;
+
+       blksiz = idesc->id_numfrags * sblock.e2fs_bsize;
+       bp = getdirblk(idesc->id_blkno, blksiz);
+       if (idesc->id_loc % sblock.e2fs_bsize == 0 && idesc->id_filesize > 0 &&
+           idesc->id_loc < blksiz) {
+               dp = (struct ext2fs_direct *)(bp->b_un.b_buf + idesc->id_loc);
+               if (dircheck(idesc, dp))
+                       goto dpok;
+               if (idesc->id_fix == IGNORE)
+                       return (0);
+               fix = dofix(idesc, "DIRECTORY CORRUPTED");
+               bp = getdirblk(idesc->id_blkno, blksiz);
+               dp = (struct ext2fs_direct *)(bp->b_un.b_buf + idesc->id_loc);
+               dp->e2d_reclen = h2fs16(sblock.e2fs_bsize);
+               dp->e2d_ino = 0;
+               dp->e2d_namlen = 0;
+               dp->e2d_type = 0;
+               dp->e2d_name[0] = '\0';
+               if (fix)
+                       dirty(bp);
+               idesc->id_loc += sblock.e2fs_bsize;
+               idesc->id_filesize -= sblock.e2fs_bsize;
+               return (dp);
+       }
+dpok:
+       if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
+               return NULL;
+       dploc = idesc->id_loc;
+       dp = (struct ext2fs_direct *)(bp->b_un.b_buf + dploc);
+       idesc->id_loc += fs2h16(dp->e2d_reclen);
+       idesc->id_filesize -= fs2h16(dp->e2d_reclen);
+       if ((idesc->id_loc % sblock.e2fs_bsize) == 0)
+               return (dp);
+       ndp = (struct ext2fs_direct *)(bp->b_un.b_buf + idesc->id_loc);
+       if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
+           dircheck(idesc, ndp) == 0) {
+               size = sblock.e2fs_bsize - (idesc->id_loc % sblock.e2fs_bsize);
+               idesc->id_loc += size;
+               idesc->id_filesize -= size;
+               if (idesc->id_fix == IGNORE)
+                       return (0);
+               fix = dofix(idesc, "DIRECTORY CORRUPTED");
+               bp = getdirblk(idesc->id_blkno, blksiz);
+               dp = (struct ext2fs_direct *)(bp->b_un.b_buf + dploc);
+               dp->e2d_reclen = h2fs16(fs2h16(dp->e2d_reclen) + size);
+               if (fix)
+                       dirty(bp);
+       }
+       return (dp);
+}
+
+/*
+ * Verify that a directory entry is valid.
+ * This is a superset of the checks made in the kernel.
+ */
+int
+dircheck(struct inodesc *idesc, struct ext2fs_direct *dp)
+{
+       int size;
+       char *cp;
+       int spaceleft;
+       u_int16_t reclen = fs2h16(dp->e2d_reclen);
+
+       spaceleft = sblock.e2fs_bsize - (idesc->id_loc % sblock.e2fs_bsize);
+       if (fs2h32(dp->e2d_ino) > maxino ||
+           reclen == 0 ||
+           reclen > spaceleft ||
+           (reclen & 0x3) != 0)
+               return (0);
+       if (dp->e2d_ino == 0)
+               return (1);
+       if (sblock.e2fs.e2fs_rev < E2FS_REV1 ||
+           (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE) == 0)
+               if (dp->e2d_type != 0)
+                       return (1);
+       size = EXT2FS_DIRSIZ(dp->e2d_namlen);
+       if (reclen < size ||
+           idesc->id_filesize < size /* ||
+           dp->e2d_namlen > EXT2FS_MAXNAMLEN */)
+               return (0);
+       for (cp = dp->e2d_name, size = 0; size < dp->e2d_namlen; size++)
+               if (*cp == '\0' || (*cp++ == '/'))
+                       return (0);
+       return (1);
+}
+
+void
+direrror(ino_t ino, const char *errmesg)
+{
+
+       fileerror(ino, ino, errmesg);
+}
+
+void
+fileerror(ino_t cwd, ino_t ino, const char *errmesg)
+{
+       struct ext2fs_dinode *dp;
+       char pathbuf[MAXPATHLEN + 1];
+
+       pwarn("%s ", errmesg);
+       pinode(ino);
+       printf("\n");
+       getpathname(pathbuf, sizeof(pathbuf), cwd, ino);
+       if ((ino < EXT2_FIRSTINO && ino != EXT2_ROOTINO) || ino > maxino) {
+               pfatal("NAME=%s\n", pathbuf);
+               return;
+       }
+       dp = ginode(ino);
+       if (ftypeok(dp))
+               pfatal("%s=%s\n",
+                   (fs2h16(dp->e2di_mode) & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf);
+       else
+               pfatal("NAME=%s\n", pathbuf);
+}
+
+void
+adjust(struct inodesc *idesc, short lcnt)
+{
+       struct ext2fs_dinode *dp;
+
+       dp = ginode(idesc->id_number);
+       if (fs2h16(dp->e2di_nlink) == lcnt) {
+               if (linkup(idesc->id_number, (ino_t)0) == 0)
+                       clri(idesc, "UNREF", 0);
+       } else {
+               pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
+                       ((fs2h16(dp->e2di_mode) & IFMT) == IFDIR ? "DIR" : "FILE"));
+               pinode(idesc->id_number);
+               printf(" COUNT %d SHOULD BE %d",
+                       fs2h16(dp->e2di_nlink), fs2h16(dp->e2di_nlink) - lcnt);
+               if (preen) {
+                       if (lcnt < 0) {
+                               printf("\n");
+                               pfatal("LINK COUNT INCREASING");
+                       }
+                       printf(" (ADJUSTED)\n");
+               }
+               if (preen || reply("ADJUST") == 1) {
+                       dp->e2di_nlink = h2fs16(fs2h16(dp->e2di_nlink) - lcnt);
+                       inodirty();
+               }
+       }
+}
+
+static int
+mkentry(struct inodesc *idesc)
+{
+       struct ext2fs_direct *dirp = idesc->id_dirp;
+       struct ext2fs_direct newent;
+       int newlen, oldlen;
+
+       newent.e2d_type = 0;    /* XXX gcc */
+       newent.e2d_namlen = strlen(idesc->id_name);
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+           (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE))
+               newent.e2d_type = inot2ext2dt(typemap[idesc->id_parent]);
+       newlen = EXT2FS_DIRSIZ(newent.e2d_namlen);
+       if (dirp->e2d_ino != 0)
+               oldlen = EXT2FS_DIRSIZ(dirp->e2d_namlen);
+       else
+               oldlen = 0;
+       if (fs2h16(dirp->e2d_reclen) - oldlen < newlen)
+               return (KEEPON);
+       newent.e2d_reclen = h2fs16(fs2h16(dirp->e2d_reclen) - oldlen);
+       dirp->e2d_reclen = h2fs16(oldlen);
+       dirp = (struct ext2fs_direct *)(((char *)dirp) + oldlen);
+       dirp->e2d_ino = h2fs32(idesc->id_parent); /* ino to be entered is in id_parent */
+       dirp->e2d_reclen = newent.e2d_reclen;
+       dirp->e2d_namlen = newent.e2d_namlen;
+       dirp->e2d_type = newent.e2d_type;
+       memcpy(dirp->e2d_name, idesc->id_name, (size_t)(dirp->e2d_namlen));
+       return (ALTERED|STOP);
+}
+
+static int
+chgino(struct inodesc *idesc)
+{
+       struct ext2fs_direct *dirp = idesc->id_dirp;
+       u_int16_t namlen = dirp->e2d_namlen;
+
+       if (strlen(idesc->id_name) != namlen ||
+               strncmp(dirp->e2d_name, idesc->id_name, (int)namlen))
+               return (KEEPON);
+       dirp->e2d_ino = h2fs32(idesc->id_parent);
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+           (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE))
+               dirp->e2d_type = inot2ext2dt(typemap[idesc->id_parent]);
+       else
+               dirp->e2d_type = 0;
+       return (ALTERED|STOP);
+}
+
+int
+linkup(ino_t orphan, ino_t parentdir)
+{
+       struct ext2fs_dinode *dp;
+       int lostdir;
+       ino_t oldlfdir;
+       struct inodesc idesc;
+       char tempname[BUFSIZ];
+
+       memset(&idesc, 0, sizeof(struct inodesc));
+       dp = ginode(orphan);
+       lostdir = (fs2h16(dp->e2di_mode) & IFMT) == IFDIR;
+       pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
+       pinode(orphan);
+       if (preen && inosize(dp) == 0)
+               return (0);
+       if (preen)
+               printf(" (RECONNECTED)\n");
+       else
+               if (reply("RECONNECT") == 0)
+                       return (0);
+       if (lfdir == 0) {
+               dp = ginode(EXT2_ROOTINO);
+               idesc.id_name = lfname;
+               idesc.id_type = DATA;
+               idesc.id_func = findino;
+               idesc.id_number = EXT2_ROOTINO;
+               if ((ckinode(dp, &idesc) & FOUND) != 0) {
+                       lfdir = idesc.id_parent;
+               } else {
+                       pwarn("NO lost+found DIRECTORY");
+                       if (preen || reply("CREATE")) {
+                               lfdir = allocdir(EXT2_ROOTINO, (ino_t)0, lfmode);
+                               if (lfdir != 0) {
+                                       if (makeentry(EXT2_ROOTINO, lfdir, lfname) != 0) {
+                                               if (preen)
+                                                       printf(" (CREATED)\n");
+                                       } else {
+                                               freedir(lfdir, EXT2_ROOTINO);
+                                               lfdir = 0;
+                                               if (preen)
+                                                       printf("\n");
+                                       }
+                               }
+                       }
+               }
+               if (lfdir == 0) {
+                       pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
+                       printf("\n\n");
+                       return (0);
+               }
+       }
+       dp = ginode(lfdir);
+       if ((fs2h16(dp->e2di_mode) & IFMT) != IFDIR) {
+               pfatal("lost+found IS NOT A DIRECTORY");
+               if (reply("REALLOCATE") == 0)
+                       return (0);
+               oldlfdir = lfdir;
+               if ((lfdir = allocdir(EXT2_ROOTINO, (ino_t)0, lfmode)) == 0) {
+                       pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
+                       return (0);
+               }
+               if ((changeino(EXT2_ROOTINO, lfname, lfdir) & ALTERED) == 0) {
+                       pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
+                       return (0);
+               }
+               inodirty();
+               idesc.id_type = ADDR;
+               idesc.id_func = pass4check;
+               idesc.id_number = oldlfdir;
+               adjust(&idesc, lncntp[oldlfdir] + 1);
+               lncntp[oldlfdir] = 0;
+               dp = ginode(lfdir);
+       }
+       if (statemap[lfdir] != DFOUND) {
+               pfatal("SORRY. NO lost+found DIRECTORY\n\n");
+               return (0);
+       }
+       (void)lftempname(tempname, orphan);
+       if (makeentry(lfdir, orphan, tempname) == 0) {
+               pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
+               printf("\n\n");
+               return (0);
+       }
+       lncntp[orphan]--;
+       if (lostdir) {
+               if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
+                   parentdir != (ino_t)-1)
+                       (void)makeentry(orphan, lfdir, "..");
+               dp = ginode(lfdir);
+               dp->e2di_nlink = h2fs16(fs2h16(dp->e2di_nlink) +1);
+               inodirty();
+               lncntp[lfdir]++;
+               pwarn("DIR I=%llu CONNECTED. ", (unsigned long long)orphan);
+               if (parentdir != (ino_t)-1)
+                       printf("PARENT WAS I=%llu\n",
+                           (unsigned long long)parentdir);
+               if (preen == 0)
+                       printf("\n");
+       }
+       return (1);
+}
+
+/*
+ * fix an entry in a directory.
+ */
+int
+changeino(ino_t dir, const char *name, ino_t newnum)
+{
+       struct inodesc idesc;
+
+       memset(&idesc, 0, sizeof(struct inodesc));
+       idesc.id_type = DATA;
+       idesc.id_func = chgino;
+       idesc.id_number = dir;
+       idesc.id_fix = DONTKNOW;
+       idesc.id_name = name;
+       idesc.id_parent = newnum;       /* new value for name */
+       return (ckinode(ginode(dir), &idesc));
+}
+
+/*
+ * make an entry in a directory
+ */
+int
+makeentry(ino_t parent, ino_t ino, const char *name)
+{
+       struct ext2fs_dinode *dp;
+       struct inodesc idesc;
+       char pathbuf[MAXPATHLEN + 1];
+       
+       if ((parent < EXT2_FIRSTINO && parent != EXT2_ROOTINO)
+               || parent >= maxino ||
+           (ino < EXT2_FIRSTINO && ino < EXT2_ROOTINO) || ino >= maxino)
+               return (0);
+       memset(&idesc, 0, sizeof(struct inodesc));
+       idesc.id_type = DATA;
+       idesc.id_func = mkentry;
+       idesc.id_number = parent;
+       idesc.id_parent = ino;  /* this is the inode to enter */
+       idesc.id_fix = DONTKNOW;
+       idesc.id_name = name;
+       dp = ginode(parent);
+       if (inosize(dp) % sblock.e2fs_bsize) {
+               inossize(dp, roundup(inosize(dp), sblock.e2fs_bsize));
+               inodirty();
+       }
+       if ((ckinode(dp, &idesc) & ALTERED) != 0)
+               return (1);
+       getpathname(pathbuf, sizeof(pathbuf), parent, parent);
+       dp = ginode(parent);
+       if (expanddir(dp, pathbuf) == 0)
+               return (0);
+       return (ckinode(dp, &idesc) & ALTERED);
+}
+
+/*
+ * Attempt to expand the size of a directory
+ */
+static int
+expanddir(struct ext2fs_dinode *dp, char *name)
+{
+       daddr_t lastbn, newblk;
+       struct bufarea *bp;
+       char *firstblk;
+
+       lastbn = lblkno(&sblock, inosize(dp));
+       if (lastbn >= NDADDR - 1 || fs2h32(dp->e2di_blocks[lastbn]) == 0 ||
+               inosize(dp) == 0) {
+               return (0);
+       }
+       if ((newblk = allocblk()) == 0) {
+               return (0);
+       }
+       dp->e2di_blocks[lastbn + 1] = dp->e2di_blocks[lastbn];
+       dp->e2di_blocks[lastbn] = h2fs32(newblk);
+       inossize(dp, inosize(dp) + sblock.e2fs_bsize);
+       dp->e2di_nblock = h2fs32(fs2h32(dp->e2di_nblock) + 1);
+       bp = getdirblk(fs2h32(dp->e2di_blocks[lastbn + 1]),
+               sblock.e2fs_bsize);
+       if (bp->b_errs)
+               goto bad;
+       if ((firstblk = malloc(sblock.e2fs_bsize)) == NULL)
+               err(8, "cannot allocate first block");
+       memcpy(firstblk, bp->b_un.b_buf, sblock.e2fs_bsize);
+       bp = getdirblk(newblk, sblock.e2fs_bsize);
+       if (bp->b_errs) {
+               free(firstblk);
+               goto bad;
+       }
+       memcpy(bp->b_un.b_buf, firstblk, sblock.e2fs_bsize);
+       free(firstblk);
+       dirty(bp);
+       bp = getdirblk(fs2h32(dp->e2di_blocks[lastbn + 1]),
+               sblock.e2fs_bsize);
+       if (bp->b_errs)
+               goto bad;
+       emptydir.dot_reclen = h2fs16(sblock.e2fs_bsize);
+       memcpy(bp->b_un.b_buf, &emptydir, sizeof emptydir);
+       pwarn("NO SPACE LEFT IN %s", name);
+       if (preen)
+               printf(" (EXPANDED)\n");
+       else if (reply("EXPAND") == 0)
+               goto bad;
+       dirty(bp);
+       inodirty();
+       return (1);
+bad:
+       dp->e2di_blocks[lastbn] = dp->e2di_blocks[lastbn + 1];
+       dp->e2di_blocks[lastbn + 1] = 0;
+       inossize(dp, inosize(dp) - sblock.e2fs_bsize);
+       dp->e2di_nblock = h2fs32(fs2h32(dp->e2di_nblock) - 1);
+       freeblk(newblk);
+       return (0);
+}
+
+/*
+ * allocate a new directory
+ */
+int
+allocdir(ino_t parent, ino_t request, int mode)
+{
+       ino_t ino;
+       struct ext2fs_dinode *dp;
+       struct bufarea *bp;
+       struct ext2fs_dirtemplate *dirp;
+
+       ino = allocino(request, IFDIR|mode);
+       dirhead.dot_reclen = h2fs16(12); /* XXX */
+       dirhead.dotdot_reclen = h2fs16(sblock.e2fs_bsize - 12); /* XXX */
+       dirhead.dot_namlen = 1;
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+           (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE))
+               dirhead.dot_type = EXT2_FT_DIR;
+       else
+               dirhead.dot_type = 0;
+       dirhead.dotdot_namlen = 2;
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+           (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE))
+               dirhead.dotdot_type = EXT2_FT_DIR;
+       else
+               dirhead.dotdot_type = 0;
+       dirp = &dirhead;
+       dirp->dot_ino = h2fs32(ino);
+       dirp->dotdot_ino = h2fs32(parent);
+       dp = ginode(ino);
+       bp = getdirblk(fs2h32(dp->e2di_blocks[0]), sblock.e2fs_bsize);
+       if (bp->b_errs) {
+               freeino(ino);
+               return (0);
+       }
+       memcpy(bp->b_un.b_buf, dirp, sizeof(struct ext2fs_dirtemplate));
+       dirty(bp);
+       dp->e2di_nlink = h2fs16(2);
+       inodirty();
+       if (ino == EXT2_ROOTINO) {
+               lncntp[ino] = fs2h16(dp->e2di_nlink);
+               cacheino(dp, ino);
+               return(ino);
+       }
+       if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
+               freeino(ino);
+               return (0);
+       }
+       cacheino(dp, ino);
+       statemap[ino] = statemap[parent];
+       if (statemap[ino] == DSTATE) {
+               lncntp[ino] = fs2h16(dp->e2di_nlink);
+               lncntp[parent]++;
+       }
+       dp = ginode(parent);
+       dp->e2di_nlink = h2fs16(fs2h16(dp->e2di_nlink) + 1);
+       inodirty();
+       return (ino);
+}
+
+/*
+ * free a directory inode
+ */
+static void
+freedir(ino_t ino, ino_t parent)
+{
+       struct ext2fs_dinode *dp;
+
+       if (ino != parent) {
+               dp = ginode(parent);
+               dp->e2di_nlink = h2fs16(fs2h16(dp->e2di_nlink) - 1);
+               inodirty();
+       }
+       freeino(ino);
+}
+
+/*
+ * generate a temporary name for the lost+found directory.
+ */
+static int
+lftempname(char *bufp, ino_t ino)
+{
+       ino_t in;
+       char *cp;
+       int namlen;
+
+       cp = bufp + 2;
+       for (in = maxino; in > 0; in /= 10)
+               cp++;
+       *--cp = 0;
+       namlen = cp - bufp;
+       in = ino;
+       while (cp > bufp) {
+               *--cp = (in % 10) + '0';
+               in /= 10;
+       }
+       *cp = '#';
+       return (namlen);
+}
+
+/*
+ * Get a directory block.
+ * Insure that it is held until another is requested.
+ */
+static struct bufarea *
+getdirblk(daddr_t blkno, long size)
+{
+
+       if (pdirbp != 0)
+               pdirbp->b_flags &= ~B_INUSE;
+       pdirbp = getdatablk(blkno, size);
+       return (pdirbp);
+}
diff --git a/sbin/fsck_ext2fs/ext2fs_bswap.c b/sbin/fsck_ext2fs/ext2fs_bswap.c
new file mode 100644 (file)
index 0000000..ba0ddc4
--- /dev/null
@@ -0,0 +1,121 @@
+/*     $NetBSD: ext2fs_bswap.c,v 1.16 2009/10/19 18:41:17 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_bswap.c,v 1.16 2009/10/19 18:41:17 bouyer Exp $");
+
+#include <sys/types.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#else
+#include <string.h>
+#endif
+
+/* These functions are only needed if native byte order is not big endian */
+#if BYTE_ORDER == BIG_ENDIAN
+void
+e2fs_sb_bswap(struct ext2fs *old, struct ext2fs *new)
+{
+
+       /* preserve unused fields */
+       memcpy(new, old, sizeof(struct ext2fs));
+       new->e2fs_icount        =       bswap32(old->e2fs_icount);
+       new->e2fs_bcount        =       bswap32(old->e2fs_bcount);
+       new->e2fs_rbcount       =       bswap32(old->e2fs_rbcount);
+       new->e2fs_fbcount       =       bswap32(old->e2fs_fbcount);
+       new->e2fs_ficount       =       bswap32(old->e2fs_ficount);
+       new->e2fs_first_dblock  =       bswap32(old->e2fs_first_dblock);
+       new->e2fs_log_bsize     =       bswap32(old->e2fs_log_bsize);
+       new->e2fs_fsize         =       bswap32(old->e2fs_fsize);
+       new->e2fs_bpg           =       bswap32(old->e2fs_bpg);
+       new->e2fs_fpg           =       bswap32(old->e2fs_fpg);
+       new->e2fs_ipg           =       bswap32(old->e2fs_ipg);
+       new->e2fs_mtime         =       bswap32(old->e2fs_mtime);
+       new->e2fs_wtime         =       bswap32(old->e2fs_wtime);
+       new->e2fs_mnt_count     =       bswap16(old->e2fs_mnt_count);
+       new->e2fs_max_mnt_count =       bswap16(old->e2fs_max_mnt_count);
+       new->e2fs_magic         =       bswap16(old->e2fs_magic);
+       new->e2fs_state         =       bswap16(old->e2fs_state);
+       new->e2fs_beh           =       bswap16(old->e2fs_beh);
+       new->e2fs_minrev        =       bswap16(old->e2fs_minrev);
+       new->e2fs_lastfsck      =       bswap32(old->e2fs_lastfsck);
+       new->e2fs_fsckintv      =       bswap32(old->e2fs_fsckintv);
+       new->e2fs_creator       =       bswap32(old->e2fs_creator);
+       new->e2fs_rev           =       bswap32(old->e2fs_rev);
+       new->e2fs_ruid          =       bswap16(old->e2fs_ruid);
+       new->e2fs_rgid          =       bswap16(old->e2fs_rgid);
+       new->e2fs_first_ino     =       bswap32(old->e2fs_first_ino);
+       new->e2fs_inode_size    =       bswap16(old->e2fs_inode_size);
+       new->e2fs_block_group_nr =      bswap16(old->e2fs_block_group_nr);
+       new->e2fs_features_compat =     bswap32(old->e2fs_features_compat);
+       new->e2fs_features_incompat =   bswap32(old->e2fs_features_incompat);
+       new->e2fs_features_rocompat =   bswap32(old->e2fs_features_rocompat);
+       new->e2fs_algo          =       bswap32(old->e2fs_algo);
+       new->e2fs_reserved_ngdb =       bswap16(old->e2fs_reserved_ngdb);
+}
+
+void e2fs_cg_bswap(struct ext2_gd *old, struct ext2_gd *new, int size)
+{
+       int i;
+
+       for (i = 0; i < (size / (int)sizeof(struct  ext2_gd)); i++) {
+               new[i].ext2bgd_b_bitmap = bswap32(old[i].ext2bgd_b_bitmap);
+               new[i].ext2bgd_i_bitmap = bswap32(old[i].ext2bgd_i_bitmap);
+               new[i].ext2bgd_i_tables = bswap32(old[i].ext2bgd_i_tables);
+               new[i].ext2bgd_nbfree   = bswap16(old[i].ext2bgd_nbfree);
+               new[i].ext2bgd_nifree   = bswap16(old[i].ext2bgd_nifree);
+               new[i].ext2bgd_ndirs    = bswap16(old[i].ext2bgd_ndirs);
+       }
+}
+
+void e2fs_i_bswap(struct ext2fs_dinode *old, struct ext2fs_dinode *new)
+{
+
+       new->e2di_mode          =       bswap16(old->e2di_mode);
+       new->e2di_uid           =       bswap16(old->e2di_uid);
+       new->e2di_gid           =       bswap16(old->e2di_gid);
+       new->e2di_nlink         =       bswap16(old->e2di_nlink);
+       new->e2di_size          =       bswap32(old->e2di_size);
+       new->e2di_atime         =       bswap32(old->e2di_atime);
+       new->e2di_ctime         =       bswap32(old->e2di_ctime);
+       new->e2di_mtime         =       bswap32(old->e2di_mtime);
+       new->e2di_dtime         =       bswap32(old->e2di_dtime);
+       new->e2di_nblock        =       bswap32(old->e2di_nblock);
+       new->e2di_flags         =       bswap32(old->e2di_flags);
+       new->e2di_gen           =       bswap32(old->e2di_gen);
+       new->e2di_facl          =       bswap32(old->e2di_facl);
+       new->e2di_dacl          =       bswap32(old->e2di_dacl);
+       new->e2di_faddr         =       bswap32(old->e2di_faddr);
+       new->e2di_uid_high      =       bswap16(old->e2di_uid_high);
+       new->e2di_gid_high      =       bswap16(old->e2di_gid_high);
+       memcpy(&new->e2di_blocks[0], &old->e2di_blocks[0],
+           (NDADDR + NIADDR) * sizeof(uint32_t));
+}
+#endif
diff --git a/sbin/fsck_ext2fs/extern.h b/sbin/fsck_ext2fs/extern.h
new file mode 100644 (file)
index 0000000..fdaca8e
--- /dev/null
@@ -0,0 +1,73 @@
+/*     $NetBSD: extern.h,v 1.7 2011/06/09 19:57:50 christos Exp $      */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ * Copyright (c) 1994 James A. Jegers
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+void   adjust(struct inodesc *, short);
+int    allocblk(void);
+int    allocdir(ino_t, ino_t, int);
+void   blkerror(ino_t, const char *, daddr_t);
+int    bread(int, char *, daddr_t, long);
+void   bufinit(void);
+void   bwrite(int, char *, daddr_t, long);
+void   cacheino(struct ext2fs_dinode *, ino_t);
+int    changeino(ino_t, const char *, ino_t);
+int    chkrange(daddr_t, int);
+void   ckfini(int);
+int    ckinode(struct ext2fs_dinode *, struct inodesc *);
+void   clri(struct inodesc *, const char *, int);
+int    dircheck(struct inodesc *, struct ext2fs_direct *);
+void   direrror(ino_t, const char *);
+int    dirscan(struct inodesc *);
+int    dofix(struct inodesc *, const char *);
+void   fileerror(ino_t, ino_t, const char *);
+int    findino(struct inodesc *);
+int    findname(struct inodesc *);
+void   flush(int, struct bufarea *);
+void   freeblk(daddr_t);
+void   freeino(ino_t);
+void   freeinodebuf(void);
+int    ftypeok(struct ext2fs_dinode *);
+void   getpathname(char *, size_t, ino_t, ino_t);
+void   inocleanup(void);
+void   inodirty(void);
+u_int64_t inosize(struct ext2fs_dinode *);
+void   inossize(struct ext2fs_dinode *, u_int64_t);
+int    linkup(ino_t, ino_t);
+int    makeentry(ino_t, ino_t, const char *);
+void   pass1(void);
+void   pass1b(void);
+void   pass2(void);
+void   pass3(void);
+void   pass4(void);
+int    pass1check(struct inodesc *);
+int    pass4check(struct inodesc *);
+void   pass5(void);
+void   pinode(ino_t);
+void   propagate(void);
+int    reply(const char *);
+void   resetinodebuf(void);
+int    setup(const char *);
+struct ext2fs_dinode * getnextinode(ino_t);
diff --git a/sbin/fsck_ext2fs/fsck.h b/sbin/fsck_ext2fs/fsck.h
new file mode 100644 (file)
index 0000000..cd02016
--- /dev/null
@@ -0,0 +1,238 @@
+/*     $NetBSD: fsck.h,v 1.15 2009/10/19 18:41:08 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ *
+ *     @(#)fsck.h      8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *     @(#)fsck.h      8.1 (Berkeley) 6/5/93
+ */
+
+#define        MAXDUP          10      /* limit on dup blks (per inode) */
+#define        MAXBAD          10      /* limit on bad blks (per inode) */
+#define        MAXBUFSPACE     80*1024 /* maximum space to allocate to buffers */
+#define        INOBUFSIZE      128*1024        /* size of buffer to read inodes in pass1 */
+
+#ifndef BUFSIZ
+#define BUFSIZ 1024
+#endif
+
+#define        USTATE  01              /* inode not allocated */
+#define        FSTATE  02              /* inode is file */
+#define        DSTATE  03              /* inode is directory */
+#define        DFOUND  04              /* directory found during descent */
+#define        DCLEAR  05              /* directory is to be cleared */
+#define        FCLEAR  06              /* file is to be cleared */
+
+/*
+ * buffer cache structure.
+ */
+struct bufarea {
+       struct bufarea  *b_next;                /* free list queue */
+       struct bufarea  *b_prev;                /* free list queue */
+       daddr_t b_bno;
+       int     b_size;
+       int     b_errs;
+       int     b_flags;
+       union {
+               char    *b_buf;                 /* buffer space */
+               /* XXX ondisk32 */
+               int32_t *b_indir;               /* indirect block */
+               struct  ext2fs *b_fs;           /* super block */
+               struct  ext2_gd *b_cgd;         /* cylinder group descriptor */
+               struct  ext2fs_dinode *b_dinode;        /* inode block */
+       } b_un;
+       char    b_dirty;
+};
+
+#define        B_INUSE 1
+
+#define        MINBUFS         5       /* minimum number of buffers required */
+struct bufarea bufhead;                /* head of list of other blks in filesys */
+struct bufarea sblk;           /* file system superblock */
+struct bufarea asblk;          /* first alternate superblock */
+struct bufarea *pdirbp;                /* current directory contents */
+struct bufarea *pbp;           /* current inode block */
+struct bufarea *getdatablk(daddr_t, long);
+struct m_ext2fs sblock;
+
+#define        dirty(bp)       (bp)->b_dirty = 1
+#define        initbarea(bp) \
+       (bp)->b_dirty = 0; \
+       (bp)->b_bno = (daddr_t)-1; \
+       (bp)->b_flags = 0;
+
+#define        sbdirty()       copyback_sb(&sblk); sblk.b_dirty = 1
+
+enum fixstate {DONTKNOW, NOFIX, FIX, IGNORE};
+
+struct inodesc {
+       enum fixstate id_fix;   /* policy on fixing errors */
+       int (*id_func)          /* function to be applied to blocks of inode */
+           (struct inodesc *);
+       ino_t id_number;        /* inode number described */
+       ino_t id_parent;        /* for DATA nodes, their parent */
+       daddr_t id_blkno;       /* current block number being examined */
+       int id_numfrags;        /* number of frags contained in block */
+       quad_t id_filesize;     /* for DATA nodes, the size of the directory */
+       int id_loc;             /* for DATA nodes, current location in dir */
+       int id_entryno;         /* for DATA nodes, current entry number */
+       struct ext2fs_direct *id_dirp;  /* for DATA nodes, ptr to current entry */
+       const char *id_name;    /* for DATA nodes, name to find or enter */
+       char id_type;           /* type of descriptor, DATA or ADDR */
+};
+/* file types */
+#define        DATA    1
+#define        ADDR    2
+
+/*
+ * Linked list of duplicate blocks.
+ * 
+ * The list is composed of two parts. The first part of the
+ * list (from duplist through the node pointed to by muldup)
+ * contains a single copy of each duplicate block that has been 
+ * found. The second part of the list (from muldup to the end)
+ * contains duplicate blocks that have been found more than once.
+ * To check if a block has been found as a duplicate it is only
+ * necessary to search from duplist through muldup. To find the 
+ * total number of times that a block has been found as a duplicate
+ * the entire list must be searched for occurrences of the block
+ * in question. The following diagram shows a sample list where
+ * w (found twice), x (found once), y (found three times), and z
+ * (found once) are duplicate block numbers:
+ *
+ *    w -> y -> x -> z -> y -> w -> y
+ *    ^                     ^
+ *    |                     |
+ * duplist       muldup
+ */
+struct dups {
+       struct dups *next;
+       daddr_t dup;
+};
+struct dups *duplist;          /* head of dup list */
+struct dups *muldup;           /* end of unique duplicate dup block numbers */
+
+/*
+ * Linked list of inodes with zero link counts.
+ */
+struct zlncnt {
+       struct zlncnt *next;
+       ino_t zlncnt;
+};
+struct zlncnt *zlnhead;                /* head of zero link count list */
+
+/*
+ * Inode cache data structures.
+ */
+struct inoinfo {
+       struct  inoinfo *i_nexthash;    /* next entry in hash chain */
+       struct  inoinfo *i_child, *i_sibling, *i_parentp;
+       ino_t   i_number;               /* inode number of this entry */
+       ino_t   i_parent;               /* inode number of parent */
+       ino_t   i_dotdot;               /* inode number of `..' */
+       u_int64_t i_isize;              /* size of inode */
+       u_int   i_numblks;              /* size of block array in bytes */
+       /* XXX ondisk32 */
+       int32_t i_blks[1];              /* actually longer */
+} **inphead, **inpsort;
+long numdirs, listmax, inplast;
+
+long   dev_bsize;              /* computed value of DEV_BSIZE */
+long   secsize;                /* actual disk sector size */
+char   nflag;                  /* assume a no response */
+char   yflag;                  /* assume a yes response */
+int    bflag;                  /* location of alternate super block */
+int    Uflag;                  /* resolve user names */
+int    debug;                  /* output debugging info */
+int    preen;                  /* just fix normal inconsistencies */
+char   havesb;                 /* superblock has been read */
+char   skipclean;              /* skip clean file systems if preening */
+int    fsmodified;             /* 1 => write done to file system */
+int    fsreadfd;               /* file descriptor for reading file system */
+int    fswritefd;              /* file descriptor for writing file system */
+int    rerun;                  /* rerun fsck.  Only used in non-preen mode */
+
+daddr_t        maxfsblock;             /* number of blocks in the file system */
+char   *blockmap;              /* ptr to primary blk allocation map */
+ino_t  maxino;                 /* number of inodes in file system */
+ino_t  lastino;                /* last inode in use */
+char   *statemap;              /* ptr to inode state table */
+u_char *typemap;               /* ptr to inode type table */
+int16_t        *lncntp;                /* ptr to link count table */
+
+ino_t  lfdir;                  /* lost & found directory inode number */
+extern const char *lfname;     /* lost & found directory name */
+extern int     lfmode;         /* lost & found directory creation mode */
+
+daddr_t        n_blks;                 /* number of blocks in use */
+daddr_t        n_files;                /* number of files in use */
+
+#define        clearinode(dp)  (*(dp) = zino)
+struct ext2fs_dinode zino;
+
+#define        setbmap(blkno)  setbit(blockmap, blkno)
+#define        testbmap(blkno) isset(blockmap, blkno)
+#define        clrbmap(blkno)  clrbit(blockmap, blkno)
+
+#define        STOP    0x01
+#define        SKIP    0x02
+#define        KEEPON  0x04
+#define        ALTERED 0x08
+#define        FOUND   0x10
+
+struct ext2fs_dinode *ginode(ino_t);
+struct inoinfo *getinoinfo(ino_t);
+void getblk(struct bufarea *, daddr_t, long);
+ino_t allocino(ino_t, int);
+void copyback_sb(struct bufarea*);
+daddr_t cgoverhead(int);       /* overhead per cg */
diff --git a/sbin/fsck_ext2fs/fsck_ext2fs.8 b/sbin/fsck_ext2fs/fsck_ext2fs.8
new file mode 100644 (file)
index 0000000..4dcefa8
--- /dev/null
@@ -0,0 +1,253 @@
+.\"    $NetBSD: fsck_ext2fs.8,v 1.19 2010/02/21 13:26:45 wiz Exp $
+.\"
+.\" Copyright (c) 1980, 1989, 1991, 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.
+.\"
+.\" Copyright (c) 1997 Manuel Bouyer.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+.\"
+.\"    @(#)fsck.8      8.3 (Berkeley) 11/29/94
+.\"
+.Dd October 9, 2008
+.Dt FSCK_EXT2FS 8
+.Os
+.Sh NAME
+.Nm fsck_ext2fs
+.Nd ext2 File System consistency check and interactive repair
+.Sh SYNOPSIS
+.Nm
+.Op Fl dfnpUy
+.Op Fl b Ar block#
+.Op Fl c Ar level
+.Op Fl m Ar mode
+.Ar filesystem ...
+.Sh DESCRIPTION
+.Nm
+performs interactive filesystem consistency checks and repair for each of
+the filesystems specified on the command line.
+It is normally invoked from
+.Xr fsck 8 .
+.Pp
+The kernel takes care that only a restricted class of innocuous filesystem
+inconsistencies can happen unless hardware or software failures intervene.
+These are limited to the following:
+.Pp
+.Bl -item -compact
+.It
+Unreferenced inodes
+.It
+Link counts in inodes too large
+.It
+Missing blocks in the free map
+.It
+Blocks in the free map also in files
+.It
+Counts in the super-block wrong
+.El
+.Pp
+These are the only inconsistencies that
+.Nm
+in
+.Dq preen
+mode (with the
+.Fl p
+option) will correct; if it encounters other inconsistencies, it exits
+with an abnormal return status.
+For each corrected inconsistency one or more lines will be printed
+identifying the filesystem on which the correction will take place,
+and the nature of the correction.
+After successfully correcting a filesystem,
+.Nm
+will print the number of files on that filesystem
+and the number of used and free blocks.
+.Pp
+If sent a
+.Dv QUIT
+signal,
+.Nm
+will finish the filesystem checks, then exit with an abnormal return status.
+.Pp
+Without the
+.Fl p
+option,
+.Nm
+audits and interactively repairs inconsistent conditions for filesystems.
+If the filesystem is inconsistent the operator is prompted for concurrence
+before each correction is attempted.
+It should be noted that some of the corrective actions which are not
+correctable under the
+.Fl p
+option will result in some loss of data.
+The amount and severity of data lost may be determined from the diagnostic
+output.
+The default action for each consistency correction
+is to wait for the operator to respond
+.Li yes
+or
+.Li no .
+If the operator does not have write permission on the filesystem
+.Nm
+will default to a
+.Fl n
+action.
+.Pp
+The following flags are interpreted by
+.Nm .
+.Bl -tag -width indent
+.It Fl b
+Use the block specified immediately after the flag as
+the super block for the filesystem.
+Block 8193 is usually an alternate super block.
+.It Fl d
+Print debugging output.
+.It Fl f
+Force checking of file systems.
+Normally, if a file system is cleanly unmounted, the kernel will set a
+.Dq clean flag
+in the file system superblock, and
+.Nm
+will not check the file system.
+This option forces
+.Nm
+to check the file system, regardless of the state of the clean flag.
+.It Fl m
+Use the mode specified in octal immediately after the flag as the
+permission bits to use when creating the
+.Pa lost+found
+directory rather than the default 1777.
+In particular, systems that do not wish to have lost files accessible
+by all users on the system should use a more restrictive
+set of permissions such as 700.
+.It Fl n
+Assume a no response to all questions asked by
+.Nm
+except for
+.Ql CONTINUE? ,
+which is assumed to be affirmative;
+do not open the filesystem for writing.
+.It Fl p
+Specify
+.Dq preen
+mode, described above.
+.It Fl U
+Resolve numeric userids to usernames.
+.It Fl y
+Assume a yes response to all questions asked by
+.Nm ;
+this should be used with great caution as this is a free license
+to continue after essentially unlimited trouble has been encountered.
+.El
+.Pp
+Inconsistencies checked are as follows:
+.Bl -enum -offset indent -compact
+.It
+Blocks claimed by more than one inode or the free map.
+.It
+Blocks claimed by an inode outside the range of the filesystem.
+.It
+Incorrect link counts.
+.It
+Size checks:
+.Bl -item -offset indent -compact
+.It
+Directory size not a multiple of filesystem block size.
+.It
+Partially truncated file.
+.El
+.It
+Bad inode format.
+.It
+Blocks not accounted for anywhere.
+.It
+Directory checks:
+.Bl -item -offset indent -compact
+.It
+File pointing to unallocated inode.
+.It
+Inode number out of range.
+.It
+Dot or dot-dot not the first two entries of a directory
+or having the wrong inode number.
+.El
+.It
+Super Block checks:
+.Bl -item -offset indent -compact
+.It
+More blocks for inodes than there are in the filesystem.
+.It
+Bad free block map format.
+.It
+Total free block and/or free inode count incorrect.
+.El
+.El
+.Pp
+Orphaned files and directories (allocated but unreferenced) are,
+with the operator's concurrence, reconnected by
+placing them in the
+.Pa lost+found
+directory.
+The name assigned is the inode number.
+If the
+.Pa lost+found
+directory does not exist, it is created.
+If there is insufficient space its size is increased.
+.Pp
+Because of inconsistencies between the block device and the buffer cache,
+the raw device should always be used.
+.Sh DIAGNOSTICS
+The diagnostics produced by
+.Nm
+are fully enumerated and explained in Appendix A of
+.Rs
+.%T "Fsck \- The UNIX File System Check Program"
+.Re
+.Sh SEE ALSO
+.Xr fs 5 ,
+.Xr fstab 5 ,
+.Xr fsck 8 ,
+.Xr fsdb 8 ,
+.Xr newfs 8 ,
+.Xr reboot 8
diff --git a/sbin/fsck_ext2fs/inode.c b/sbin/fsck_ext2fs/inode.c
new file mode 100644 (file)
index 0000000..3c0f88f
--- /dev/null
@@ -0,0 +1,736 @@
+/*     $NetBSD: inode.c,v 1.31 2010/02/04 23:55:42 christos Exp $      */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)inode.c    8.5 (Berkeley) 2/8/95";
+#else
+__RCSID("$NetBSD: inode.c,v 1.31 2010/02/04 23:55:42 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs_dir.h>
+#include <ufs/ext2fs/ext2fs.h>
+
+#include <ufs/ufs/dinode.h> /* for IFMT & friends */
+#ifndef SMALL
+#include <pwd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "fsck.h"
+#include "fsutil.h"
+#include "extern.h"
+
+/*
+ * CG is stored in fs byte order in memory, so we can't use ino_to_fsba
+ * here.
+ */
+
+#define fsck_ino_to_fsba(fs, x)                      \
+       (fs2h32((fs)->e2fs_gd[ino_to_cg(fs, x)].ext2bgd_i_tables) + \
+       (((x)-1) % (fs)->e2fs.e2fs_ipg)/(fs)->e2fs_ipb)
+
+
+static ino_t startinum;
+
+static int iblock(struct inodesc *, long, u_int64_t);
+
+static int setlarge(void);
+
+static int
+setlarge(void)
+{
+       if (sblock.e2fs.e2fs_rev < E2FS_REV1) {
+               pfatal("LARGE FILES UNSUPPORTED ON REVISION 0 FILESYSTEMS");
+               return 0;
+       }
+       if (!(sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE)) {
+               if (preen)
+                       pwarn("SETTING LARGE FILE INDICATOR\n");
+               else if (!reply("SET LARGE FILE INDICATOR"))
+                       return 0;
+               sblock.e2fs.e2fs_features_rocompat |= EXT2F_ROCOMPAT_LARGEFILE;
+               sbdirty();
+       }
+       return 1;
+}
+
+u_int64_t
+inosize(struct ext2fs_dinode *dp)
+{
+       u_int64_t size = fs2h32(dp->e2di_size);
+
+       if ((fs2h16(dp->e2di_mode) & IFMT) == IFREG)
+               size |= (u_int64_t)fs2h32(dp->e2di_dacl) << 32;
+       if (size > INT32_MAX)
+               (void)setlarge();
+       return size;
+}
+
+void
+inossize(struct ext2fs_dinode *dp, u_int64_t size)
+{
+       if ((fs2h16(dp->e2di_mode) & IFMT) == IFREG) {
+               dp->e2di_dacl = h2fs32(size >> 32);
+               if (size > INT32_MAX)
+                       if (!setlarge())
+                               return;
+       } else if (size > INT32_MAX) {
+               pfatal("TRYING TO SET FILESIZE TO %llu ON MODE %x FILE\n",
+                   (unsigned long long)size, fs2h16(dp->e2di_mode) & IFMT);
+               return;
+       }
+       dp->e2di_size = h2fs32(size);
+}
+
+int
+ckinode(struct ext2fs_dinode *dp, struct inodesc *idesc)
+{
+       u_int32_t *ap;
+       long ret, n, ndb;
+       struct ext2fs_dinode dino;
+       u_int64_t remsize, sizepb;
+       mode_t mode;
+       char pathbuf[MAXPATHLEN + 1];
+
+       if (idesc->id_fix != IGNORE)
+               idesc->id_fix = DONTKNOW;
+       idesc->id_entryno = 0;
+       idesc->id_filesize = inosize(dp);
+       mode = fs2h16(dp->e2di_mode) & IFMT;
+       if (mode == IFBLK || mode == IFCHR || mode == IFIFO ||
+           (mode == IFLNK && (inosize(dp) < EXT2_MAXSYMLINKLEN)))
+               return (KEEPON);
+       dino = *dp;
+       ndb = howmany(inosize(&dino), sblock.e2fs_bsize);
+       for (ap = &dino.e2di_blocks[0]; ap < &dino.e2di_blocks[NDADDR];
+           ap++,ndb--) {
+               idesc->id_numfrags = 1;
+               if (*ap == 0) {
+                       if (idesc->id_type == DATA && ndb > 0) {
+                               /* An empty block in a directory XXX */
+                               getpathname(pathbuf, sizeof(pathbuf),
+                                   idesc->id_number, idesc->id_number);
+                               pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
+                                   pathbuf);
+                               if (reply("ADJUST LENGTH") == 1) {
+                                       dp = ginode(idesc->id_number);
+                                       inossize(dp,
+                                           (ap - &dino.e2di_blocks[0]) *
+                                           sblock.e2fs_bsize);
+                                       printf(
+                                           "YOU MUST RERUN FSCK AFTERWARDS\n");
+                                       rerun = 1;
+                                       inodirty();
+                               }
+                       }
+                       continue;
+               }
+               idesc->id_blkno = fs2h32(*ap);
+               if (idesc->id_type == ADDR)
+                       ret = (*idesc->id_func)(idesc);
+               else
+                       ret = dirscan(idesc);
+               if (ret & STOP)
+                       return (ret);
+       }
+       idesc->id_numfrags = 1;
+       remsize = inosize(&dino) - sblock.e2fs_bsize * NDADDR;
+       sizepb = sblock.e2fs_bsize;
+       for (ap = &dino.e2di_blocks[NDADDR], n = 1; n <= NIADDR; ap++, n++) {
+               if (*ap) {
+                       idesc->id_blkno = fs2h32(*ap);
+                       ret = iblock(idesc, n, remsize);
+                       if (ret & STOP)
+                               return (ret);
+               } else {
+                       if (idesc->id_type == DATA && remsize > 0) {
+                               /* An empty block in a directory XXX */
+                               getpathname(pathbuf, sizeof(pathbuf),
+                                   idesc->id_number, idesc->id_number);
+                               pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
+                                   pathbuf);
+                               if (reply("ADJUST LENGTH") == 1) {
+                                       dp = ginode(idesc->id_number);
+                                       inossize(dp, inosize(dp) - remsize);
+                                       remsize = 0;
+                                       printf(
+                                           "YOU MUST RERUN FSCK AFTERWARDS\n");
+                                       rerun = 1;
+                                       inodirty();
+                                       break;
+                               }
+                       }
+               }
+               sizepb *= NINDIR(&sblock);
+               remsize -= sizepb;
+       }
+       return (KEEPON);
+}
+
+static int
+iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
+{
+       /* XXX ondisk32 */
+       int32_t *ap;
+       int32_t *aplim;
+       struct bufarea *bp;
+       int i, n, (*func)(struct inodesc *);
+       size_t nif;
+       u_int64_t sizepb;
+       char buf[BUFSIZ];
+       char pathbuf[MAXPATHLEN + 1];
+       struct ext2fs_dinode *dp;
+
+       if (idesc->id_type == ADDR) {
+               func = idesc->id_func;
+               if (((n = (*func)(idesc)) & KEEPON) == 0)
+                       return (n);
+       } else
+               func = dirscan;
+       if (chkrange(idesc->id_blkno, idesc->id_numfrags))
+               return (SKIP);
+       bp = getdatablk(idesc->id_blkno, sblock.e2fs_bsize);
+       ilevel--;
+       for (sizepb = sblock.e2fs_bsize, i = 0; i < ilevel; i++)
+               sizepb *= NINDIR(&sblock);
+       if (isize > sizepb * NINDIR(&sblock))
+               nif = NINDIR(&sblock);
+       else
+               nif = howmany(isize, sizepb);
+       if (idesc->id_func == pass1check &&
+               nif < NINDIR(&sblock)) {
+               aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
+               for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
+                       if (*ap == 0)
+                               continue;
+                       (void)snprintf(buf, sizeof(buf),
+                           "PARTIALLY TRUNCATED INODE I=%llu",
+                           (unsigned long long)idesc->id_number);
+                       if (dofix(idesc, buf)) {
+                               *ap = 0;
+                               dirty(bp);
+                       }
+               }
+               flush(fswritefd, bp);
+       }
+       aplim = &bp->b_un.b_indir[nif];
+       for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
+               if (*ap) {
+                       idesc->id_blkno = fs2h32(*ap);
+                       if (ilevel == 0)
+                               n = (*func)(idesc);
+                       else
+                               n = iblock(idesc, ilevel, isize);
+                       if (n & STOP) {
+                               bp->b_flags &= ~B_INUSE;
+                               return (n);
+                       }
+               } else {
+                       if (idesc->id_type == DATA && isize > 0) {
+                               /* An empty block in a directory XXX */
+                               getpathname(pathbuf, sizeof(pathbuf),
+                                   idesc->id_number, idesc->id_number);
+                               pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
+                                   pathbuf);
+                               if (reply("ADJUST LENGTH") == 1) {
+                                       dp = ginode(idesc->id_number);
+                                       inossize(dp, inosize(dp) - isize);
+                                       isize = 0;
+                                       printf(
+                                           "YOU MUST RERUN FSCK AFTERWARDS\n");
+                                       rerun = 1;
+                                       inodirty();
+                                       bp->b_flags &= ~B_INUSE;
+                                       return(STOP);
+                               }
+                       }
+               }
+               isize -= sizepb;
+       }
+       bp->b_flags &= ~B_INUSE;
+       return (KEEPON);
+}
+
+/*
+ * Check that a block in a legal block number.
+ * Return 0 if in range, 1 if out of range.
+ */
+int
+chkrange(daddr_t blk, int cnt)
+{
+       int c, overh;
+
+       if ((unsigned int)(blk + cnt) > maxfsblock)
+               return (1);
+       c = dtog(&sblock, blk);
+       overh = cgoverhead(c);
+       if (blk < sblock.e2fs.e2fs_bpg * c + overh +
+           sblock.e2fs.e2fs_first_dblock) {
+               if ((blk + cnt) > sblock.e2fs.e2fs_bpg * c + overh +
+                   sblock.e2fs.e2fs_first_dblock) {
+                       if (debug) {
+                               printf("blk %lld < cgdmin %d;",
+                                   (long long)blk,
+                                   sblock.e2fs.e2fs_bpg * c + overh +
+                                   sblock.e2fs.e2fs_first_dblock);
+                               printf(" blk + cnt %lld > cgsbase %d\n",
+                                   (long long)(blk + cnt),
+                                   sblock.e2fs.e2fs_bpg * c +
+                                   overh + sblock.e2fs.e2fs_first_dblock);
+                       }
+                       return (1);
+               }
+       } else {
+               if ((blk + cnt) > sblock.e2fs.e2fs_bpg * (c + 1) + overh +
+                   sblock.e2fs.e2fs_first_dblock) {
+                       if (debug)  {
+                               printf("blk %lld >= cgdmin %d;",
+                                   (long long)blk,
+                                   sblock.e2fs.e2fs_bpg * c + overh +
+                                   sblock.e2fs.e2fs_first_dblock);
+                               printf(" blk + cnt %lld > cgdmax %d\n",
+                                   (long long)(blk+cnt),
+                                   sblock.e2fs.e2fs_bpg * (c + 1) +
+                                   overh + sblock.e2fs.e2fs_first_dblock);
+                       }
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+/*
+ * General purpose interface for reading inodes.
+ */
+struct ext2fs_dinode *
+ginode(ino_t inumber)
+{
+       daddr_t iblk;
+       struct ext2fs_dinode *dp;
+
+       if ((inumber < EXT2_FIRSTINO &&
+            inumber != EXT2_ROOTINO &&
+            !(inumber == EXT2_RESIZEINO &&
+              (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0))
+               || inumber > maxino)
+               errexit("bad inode number %llu to ginode",
+                   (unsigned long long)inumber);
+       if (startinum == 0 ||
+           inumber < startinum || inumber >= startinum + sblock.e2fs_ipb) {
+               iblk = fsck_ino_to_fsba(&sblock, inumber);
+               if (pbp != 0)
+                       pbp->b_flags &= ~B_INUSE;
+               pbp = getdatablk(iblk, sblock.e2fs_bsize);
+               startinum =
+                   ((inumber - 1) / sblock.e2fs_ipb) * sblock.e2fs_ipb + 1;
+       }
+       dp = (struct ext2fs_dinode *)(pbp->b_un.b_buf +
+           EXT2_DINODE_SIZE(&sblock) * ino_to_fsbo(&sblock, inumber));
+
+       return dp;
+}
+
+/*
+ * Special purpose version of ginode used to optimize first pass
+ * over all the inodes in numerical order.
+ */
+ino_t nextino, lastinum;
+long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
+char *inodebuf;
+
+struct ext2fs_dinode *
+getnextinode(ino_t inumber)
+{
+       long size;
+       daddr_t dblk;
+       struct ext2fs_dinode *dp;
+       static char *bp;
+
+       if (inumber != nextino++ || inumber > maxino)
+               errexit("bad inode number %llu to nextinode",
+                   (unsigned long long)inumber);
+       if (inumber >= lastinum) {
+               readcnt++;
+               dblk = fsbtodb(&sblock, fsck_ino_to_fsba(&sblock, lastinum));
+               if (readcnt % readpercg == 0) {
+                       size = partialsize;
+                       lastinum += partialcnt;
+               } else {
+                       size = inobufsize;
+                       lastinum += fullcnt;
+               }
+               (void)bread(fsreadfd, inodebuf, dblk, size);
+               bp = inodebuf;
+       }
+       dp = (struct ext2fs_dinode *)bp;
+       bp += EXT2_DINODE_SIZE(&sblock);
+
+       return dp;
+}
+
+void
+resetinodebuf(void)
+{
+
+       startinum = 0;
+       nextino = 1;
+       lastinum = 1;
+       readcnt = 0;
+       inobufsize = blkroundup(&sblock, INOBUFSIZE);
+       fullcnt = inobufsize / EXT2_DINODE_SIZE(&sblock);
+       readpercg = sblock.e2fs.e2fs_ipg / fullcnt;
+       partialcnt = sblock.e2fs.e2fs_ipg % fullcnt;
+       partialsize = partialcnt * EXT2_DINODE_SIZE(&sblock);
+       if (partialcnt != 0) {
+               readpercg++;
+       } else {
+               partialcnt = fullcnt;
+               partialsize = inobufsize;
+       }
+       if (inodebuf == NULL &&
+           (inodebuf = malloc((unsigned int)inobufsize)) == NULL)
+               errexit("Cannot allocate space for inode buffer");
+       while (nextino < EXT2_ROOTINO)
+               (void)getnextinode(nextino);
+}
+
+void
+freeinodebuf(void)
+{
+
+       if (inodebuf != NULL)
+               free(inodebuf);
+       inodebuf = NULL;
+}
+
+/*
+ * Routines to maintain information about directory inodes.
+ * This is built during the first pass and used during the
+ * second and third passes.
+ *
+ * Enter inodes into the cache.
+ */
+void
+cacheino(struct ext2fs_dinode *dp, ino_t inumber)
+{
+       struct inoinfo *inp;
+       struct inoinfo **inpp;
+       unsigned int blks;
+
+       blks = howmany(inosize(dp), sblock.e2fs_bsize);
+       if (blks > NDADDR)
+               blks = NDADDR + NIADDR;
+       /* XXX ondisk32 */
+       inp = malloc(sizeof(*inp) + (blks - 1) * sizeof(int32_t));
+       if (inp == NULL)
+               return;
+       inpp = &inphead[inumber % numdirs];
+       inp->i_nexthash = *inpp;
+       *inpp = inp;
+       inp->i_child = inp->i_sibling = inp->i_parentp = 0;
+       if (inumber == EXT2_ROOTINO)
+               inp->i_parent = EXT2_ROOTINO;
+       else
+               inp->i_parent = (ino_t)0;
+       inp->i_dotdot = (ino_t)0;
+       inp->i_number = inumber;
+       inp->i_isize = inosize(dp);
+       /* XXX ondisk32 */
+       inp->i_numblks = blks * sizeof(int32_t);
+       memcpy(&inp->i_blks[0], &dp->e2di_blocks[0], (size_t)inp->i_numblks);
+       if (inplast == listmax) {
+               listmax += 100;
+               inpsort = (struct inoinfo **)realloc((char *)inpsort,
+                   (unsigned int)listmax * sizeof(struct inoinfo *));
+               if (inpsort == NULL)
+                       errexit("cannot increase directory list");
+       }
+       inpsort[inplast++] = inp;
+}
+
+/*
+ * Look up an inode cache structure.
+ */
+struct inoinfo *
+getinoinfo(ino_t inumber)
+{
+       struct inoinfo *inp;
+
+       for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
+               if (inp->i_number != inumber)
+                       continue;
+               return (inp);
+       }
+       errexit("cannot find inode %llu", (unsigned long long)inumber);
+       return ((struct inoinfo *)0);
+}
+
+/*
+ * Clean up all the inode cache structure.
+ */
+void
+inocleanup(void)
+{
+       struct inoinfo **inpp;
+
+       if (inphead == NULL)
+               return;
+       for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
+               free(*inpp);
+       free(inphead);
+       free(inpsort);
+       inphead = inpsort = NULL;
+}
+       
+void
+inodirty(void)
+{
+       
+       dirty(pbp);
+}
+
+void
+clri(struct inodesc *idesc, const char *type, int flag)
+{
+       struct ext2fs_dinode *dp;
+
+       dp = ginode(idesc->id_number);
+       if (flag == 1) {
+               pwarn("%s %s", type,
+                   (fs2h16(dp->e2di_mode) & IFMT) == IFDIR ? "DIR" : "FILE");
+               pinode(idesc->id_number);
+       }
+       if (preen || reply("CLEAR") == 1) {
+               if (preen)
+                       printf(" (CLEARED)\n");
+               n_files--;
+               (void)ckinode(dp, idesc);
+               clearinode(dp);
+               statemap[idesc->id_number] = USTATE;
+               inodirty();
+       }
+}
+
+int
+findname(struct inodesc *idesc)
+{
+       struct ext2fs_direct *dirp = idesc->id_dirp;
+       u_int16_t namlen = dirp->e2d_namlen;
+       /* from utilities.c namebuf[] variable */
+       char *buf = __UNCONST(idesc->id_name);
+       if (namlen > MAXPATHLEN) {
+               /* XXX: Prevent overflow but don't fix */
+               namlen = MAXPATHLEN;
+       }
+
+       if (fs2h32(dirp->e2d_ino) != idesc->id_parent)
+               return (KEEPON);
+       (void)memcpy(buf, dirp->e2d_name, (size_t)namlen);
+       buf[namlen] = '\0';
+       return (STOP|FOUND);
+}
+
+int
+findino(struct inodesc *idesc)
+{
+       struct ext2fs_direct *dirp = idesc->id_dirp;
+       u_int32_t ino = fs2h32(dirp->e2d_ino);
+
+       if (ino == 0)
+               return (KEEPON);
+       if (strcmp(dirp->e2d_name, idesc->id_name) == 0 &&
+           (ino == EXT2_ROOTINO || ino >= EXT2_FIRSTINO) 
+               && ino <= maxino) {
+               idesc->id_parent = ino;
+               return (STOP|FOUND);
+       }
+       return (KEEPON);
+}
+
+void
+pinode(ino_t ino)
+{
+       struct ext2fs_dinode *dp;
+       struct passwd *pw;
+       uid_t uid;
+
+       printf(" I=%llu ", (unsigned long long)ino);
+       if ((ino < EXT2_FIRSTINO && ino != EXT2_ROOTINO) || ino > maxino)
+               return;
+       dp = ginode(ino);
+       uid = fs2h16(dp->e2di_uid);
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0)
+               uid |= fs2h16(dp->e2di_uid_high) << 16;
+       printf(" OWNER=");
+#ifndef SMALL
+       if (Uflag && (pw = getpwuid(uid)) != 0)
+               printf("%s ", pw->pw_name);
+       else
+#endif
+               printf("%u ", (unsigned int)uid);
+       printf("MODE=%o\n", fs2h16(dp->e2di_mode));
+       if (preen)
+               printf("%s: ", cdevname());
+       printf("SIZE=%llu ", (long long)inosize(dp));
+       printf("MTIME=%s ", print_mtime(fs2h32(dp->e2di_mtime)));
+}
+
+void
+blkerror(ino_t ino, const char *type, daddr_t blk)
+{
+
+       pfatal("%lld %s I=%llu", (long long)blk, type, (unsigned long long)ino);
+       printf("\n");
+       switch (statemap[ino]) {
+
+       case FSTATE:
+               statemap[ino] = FCLEAR;
+               return;
+
+       case DSTATE:
+               statemap[ino] = DCLEAR;
+               return;
+
+       case FCLEAR:
+       case DCLEAR:
+               return;
+
+       default:
+               errexit("BAD STATE %d TO BLKERR", statemap[ino]);
+               /* NOTREACHED */
+       }
+}
+
+/*
+ * allocate an unused inode
+ */
+ino_t
+allocino(ino_t request, int type)
+{
+       ino_t ino;
+       struct ext2fs_dinode *dp;
+       time_t t;
+
+       if (request == 0)
+               request = EXT2_ROOTINO;
+       else if (statemap[request] != USTATE)
+               return (0);
+       for (ino = request; ino < maxino; ino++) {
+               if ((ino > EXT2_ROOTINO) && (ino < EXT2_FIRSTINO))
+                       continue;
+               if (statemap[ino] == USTATE)
+                       break;
+       }
+       if (ino == maxino)
+               return (0);
+       switch (type & IFMT) {
+       case IFDIR:
+               statemap[ino] = DSTATE;
+               break;
+       case IFREG:
+       case IFLNK:
+               statemap[ino] = FSTATE;
+               break;
+       default:
+               return (0);
+       }
+       dp = ginode(ino);
+       dp->e2di_blocks[0] = h2fs32(allocblk());
+       if (dp->e2di_blocks[0] == 0) {
+               statemap[ino] = USTATE;
+               return (0);
+       }
+       dp->e2di_mode = h2fs16(type);
+       (void)time(&t);
+       dp->e2di_atime = h2fs32(t);
+       dp->e2di_mtime = dp->e2di_ctime = dp->e2di_atime;
+       dp->e2di_dtime = 0;
+       inossize(dp, sblock.e2fs_bsize);
+       dp->e2di_nblock = h2fs32(btodb(sblock.e2fs_bsize));
+       n_files++;
+       inodirty();
+       typemap[ino] = E2IFTODT(type);
+       return (ino);
+}
+
+/*
+ * deallocate an inode
+ */
+void
+freeino(ino_t ino)
+{
+       struct inodesc idesc;
+       struct ext2fs_dinode *dp;
+
+       memset(&idesc, 0, sizeof(struct inodesc));
+       idesc.id_type = ADDR;
+       idesc.id_func = pass4check;
+       idesc.id_number = ino;
+       dp = ginode(ino);
+       (void)ckinode(dp, &idesc);
+       clearinode(dp);
+       inodirty();
+       statemap[ino] = USTATE;
+       n_files--;
+}
diff --git a/sbin/fsck_ext2fs/main.c b/sbin/fsck_ext2fs/main.c
new file mode 100644 (file)
index 0000000..2160e90
--- /dev/null
@@ -0,0 +1,358 @@
+/*     $NetBSD: main.c,v 1.37 2011/06/09 19:57:51 christos Exp $       */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1993\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)main.c     8.2 (Berkeley) 1/23/94";
+#else
+__RCSID("$NetBSD: main.c,v 1.37 2011/06/09 19:57:51 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <fstab.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "fsck.h"
+#include "extern.h"
+#include "fsutil.h"
+#include "exitvalues.h"
+
+volatile sig_atomic_t  returntosingle = 0;
+
+
+static int     argtoi(int, const char *, const char *, int);
+static int     checkfilesys(const char *, char *, long, int);
+static void    usage(void) __dead;
+
+int
+main(int argc, char *argv[])
+{
+       int ch;
+       int ret = FSCK_EXIT_OK;
+
+       ckfinish = ckfini;
+       sync();
+       skipclean = 1;
+       while ((ch = getopt(argc, argv, "b:dfm:npPqUy")) != -1) {
+               switch (ch) {
+               case 'b':
+                       skipclean = 0;
+                       bflag = argtoi('b', "number", optarg, 10);
+                       printf("Alternate super block location: %d\n", bflag);
+                       break;
+
+               case 'd':
+                       debug++;
+                       break;
+
+               case 'f':
+                       skipclean = 0;
+                       break;
+
+               case 'm':
+                       lfmode = argtoi('m', "mode", optarg, 8);
+                       if (lfmode &~ 07777)
+                               errexit("bad mode to -m: %o", lfmode);
+                       printf("** lost+found creation mode %o\n", lfmode);
+                       break;
+
+               case 'n':
+                       nflag++;
+                       yflag = 0;
+                       break;
+
+               case 'p':
+                       preen++;
+                       break;
+
+               case 'P':
+                       /* Progress meter not implemented. */
+                       break;
+
+               case 'q':               /* Quiet not implemented */
+                       break;
+
+#ifndef SMALL
+               case 'U':
+                       Uflag++;
+                       break;
+#endif
+
+               case 'y':
+                       yflag++;
+                       nflag = 0;
+                       break;
+
+               default:
+                       usage();
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (!argc)
+               usage();
+
+       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+               (void)signal(SIGINT, catch);
+       if (preen)
+               (void)signal(SIGQUIT, catchquit);
+
+       while (argc-- > 0) {
+               int nret = checkfilesys(blockcheck(*argv++), 0, 0L, 0);
+               if (ret < nret)
+                       ret = nret;
+       }
+
+       return returntosingle ? FSCK_EXIT_UNRESOLVED : ret;
+}
+
+static int
+argtoi(int flag, const char *req, const char *str, int base)
+{
+       char *cp;
+       int ret;
+
+       ret = (int)strtol(str, &cp, base);
+       if (cp == str || *cp)
+               errexit("-%c flag requires a %s", flag, req);
+       return (ret);
+}
+
+/*
+ * Check the specified filesystem.
+ */
+/* ARGSUSED */
+static int
+checkfilesys(const char *filesys, char *mntpt, long auxdata, int child)
+{
+       daddr_t n_bfree;
+       struct dups *dp;
+       struct zlncnt *zlnp;
+       int i;
+
+       if (preen && child)
+               (void)signal(SIGQUIT, voidquit);
+       setcdevname(filesys, preen);
+       if (debug && preen)
+               pwarn("starting\n");
+       switch (setup(filesys)) {
+       case 0:
+               if (preen)
+                       pfatal("CAN'T CHECK FILE SYSTEM.");
+       case -1:
+               return FSCK_EXIT_OK;
+       }
+       /*
+        * 1: scan inodes tallying blocks used
+        */
+       if (preen == 0) {
+               if (sblock.e2fs.e2fs_rev > E2FS_REV0) {
+                       printf("** Last Mounted on %s\n",
+                           sblock.e2fs.e2fs_fsmnt);
+               }
+               if (hotroot())
+                       printf("** Root file system\n");
+               printf("** Phase 1 - Check Blocks and Sizes\n");
+       }
+       pass1();
+
+       /*
+        * 1b: locate first references to duplicates, if any
+        */
+       if (duplist) {
+               if (preen)
+                       pfatal("INTERNAL ERROR: dups with -p");
+               printf("** Phase 1b - Rescan For More DUPS\n");
+               pass1b();
+       }
+
+       /*
+        * 2: traverse directories from root to mark all connected directories
+        */
+       if (preen == 0)
+               printf("** Phase 2 - Check Pathnames\n");
+       pass2();
+
+       /*
+        * 3: scan inodes looking for disconnected directories
+        */
+       if (preen == 0)
+               printf("** Phase 3 - Check Connectivity\n");
+       pass3();
+
+       /*
+        * 4: scan inodes looking for disconnected files; check reference counts
+        */
+       if (preen == 0)
+               printf("** Phase 4 - Check Reference Counts\n");
+       pass4();
+
+       /*
+        * 5: check and repair resource counts in cylinder groups
+        */
+       if (preen == 0)
+               printf("** Phase 5 - Check Cyl groups\n");
+       pass5();
+
+       /*
+        * print out summary statistics
+        */
+       n_bfree = sblock.e2fs.e2fs_fbcount;
+               
+       pwarn("%lld files, %lld used, %lld free\n",
+           (long long)n_files, (long long)n_blks, (long long)n_bfree);
+       if (debug &&
+               /* 9 reserved and unused inodes in FS */
+           (n_files -= maxino - 9 - sblock.e2fs.e2fs_ficount))
+               printf("%lld files missing\n", (long long)n_files);
+       if (debug) {
+               for (i = 0; i < sblock.e2fs_ncg; i++)
+                       n_blks +=  cgoverhead(i);
+               n_blks += sblock.e2fs.e2fs_first_dblock;
+               if (n_blks -= maxfsblock - n_bfree)
+                       printf("%lld blocks missing\n", (long long)n_blks);
+               if (duplist != NULL) {
+                       printf("The following duplicate blocks remain:");
+                       for (dp = duplist; dp; dp = dp->next)
+                               printf(" %lld,", (long long)dp->dup);
+                       printf("\n");
+               }
+               if (zlnhead != NULL) {
+                       printf("The following zero link count inodes remain:");
+                       for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
+                               printf(" %llu,",
+                                   (unsigned long long)zlnp->zlncnt);
+                       printf("\n");
+               }
+       }
+       zlnhead = (struct zlncnt *)0;
+       duplist = (struct dups *)0;
+       muldup = (struct dups *)0;
+       inocleanup();
+       if (fsmodified) {
+               time_t t;
+               (void)time(&t);
+               sblock.e2fs.e2fs_wtime = t;
+               sblock.e2fs.e2fs_lastfsck = t;
+               sbdirty();
+       }
+       ckfini(1);
+       free(blockmap);
+       free(statemap);
+       free((char *)lncntp);
+       if (!fsmodified)
+               return FSCK_EXIT_OK;
+       if (!preen)
+               printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
+       if (rerun)
+               printf("\n***** PLEASE RERUN FSCK *****\n");
+#ifndef __minix
+       if (hotroot()) {
+               struct statvfs stfs_buf;
+               /*
+                * We modified the root.  Do a mount update on
+                * it, unless it is read-write, so we can continue.
+                */
+               if (statvfs("/", &stfs_buf) == 0) {
+                       long flags = stfs_buf.f_flag;
+                       struct ufs_args args;
+
+                       if (flags & MNT_RDONLY) {
+                               args.fspec = 0;
+                               flags |= MNT_UPDATE | MNT_RELOAD;
+                               if (mount(MOUNT_EXT2FS, "/", flags,
+                                   &args, sizeof args) == 0)
+                                       return FSCK_EXIT_OK;
+                       }
+               }
+               if (!preen)
+                       printf("\n***** REBOOT NOW *****\n");
+               sync();
+               return FSCK_EXIT_ROOT_CHANGED;
+       }
+#endif
+       return FSCK_EXIT_OK;
+}
+
+static void
+usage(void)
+{
+
+       (void) fprintf(stderr,
+           "usage: %s [-dfnpUy] [-b block] [-c level] [-m mode] filesystem ...\n",
+           getprogname());
+       exit(FSCK_EXIT_USAGE);
+}
+
diff --git a/sbin/fsck_ext2fs/pass1.c b/sbin/fsck_ext2fs/pass1.c
new file mode 100644 (file)
index 0000000..12fe784
--- /dev/null
@@ -0,0 +1,394 @@
+/*     $NetBSD: pass1.c,v 1.21 2010/02/04 23:55:42 christos Exp $      */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pass1.c    8.1 (Berkeley) 6/5/93";
+#else
+__RCSID("$NetBSD: pass1.c,v 1.21 2010/02/04 23:55:42 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs_dir.h>
+#include <ufs/ext2fs/ext2fs.h>
+
+#include <ufs/ufs/dinode.h> /* for IFMT & friends */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "fsck.h"
+#include "extern.h"
+#include "fsutil.h"
+#include "exitvalues.h"
+
+static daddr_t badblk;
+static daddr_t dupblk;
+static void checkinode(ino_t, struct inodesc *);
+
+void
+pass1(void)
+{
+       ino_t inumber;
+       int c, i;
+       size_t j;
+       daddr_t dbase;
+       struct inodesc idesc;
+
+       /*
+        * Set file system reserved blocks in used block map.
+        */
+       for (c = 0; c < sblock.e2fs_ncg; c++) {
+               dbase = c * sblock.e2fs.e2fs_bpg +
+                   sblock.e2fs.e2fs_first_dblock;
+               /* Mark the blocks used for the inode table */
+               if (fs2h32(sblock.e2fs_gd[c].ext2bgd_i_tables) >= dbase) {
+                       for (i = 0; i < sblock.e2fs_itpg; i++)
+                               setbmap(
+                                   fs2h32(sblock.e2fs_gd[c].ext2bgd_i_tables)
+                                   + i);
+               }
+               /* Mark the blocks used for the block bitmap */
+               if (fs2h32(sblock.e2fs_gd[c].ext2bgd_b_bitmap) >= dbase)
+                       setbmap(fs2h32(sblock.e2fs_gd[c].ext2bgd_b_bitmap));
+               /* Mark the blocks used for the inode bitmap */
+               if (fs2h32(sblock.e2fs_gd[c].ext2bgd_i_bitmap) >= dbase)
+                       setbmap(fs2h32(sblock.e2fs_gd[c].ext2bgd_i_bitmap));
+
+               if (sblock.e2fs.e2fs_rev == E2FS_REV0 ||
+                   (sblock.e2fs.e2fs_features_rocompat &
+                       EXT2F_ROCOMPAT_SPARSESUPER) == 0 ||
+                   cg_has_sb(c)) {
+                       /* Mark copuy of SB and descriptors */
+                       setbmap(dbase);
+                       for (i = 1; i <= sblock.e2fs_ngdb; i++)
+                               setbmap(dbase+i);
+               }
+
+
+               if (c == 0) {
+                       for(i = 0; i < dbase; i++)
+                               setbmap(i);
+               }
+       }
+
+       /*
+        * Find all allocated blocks.
+        */
+       memset(&idesc, 0, sizeof(struct inodesc));
+       idesc.id_type = ADDR;
+       idesc.id_func = pass1check;
+       inumber = 1;
+       n_files = n_blks = 0;
+       resetinodebuf();
+       for (c = 0; c < sblock.e2fs_ncg; c++) {
+               for (j = 0;
+                       j < sblock.e2fs.e2fs_ipg && inumber <= sblock.e2fs.e2fs_icount;
+                       j++, inumber++) {
+                       if (inumber < EXT2_ROOTINO) /* XXX */
+                               continue;
+                       checkinode(inumber, &idesc);
+               }
+       }
+       freeinodebuf();
+}
+
+static void
+checkinode(ino_t inumber, struct inodesc *idesc)
+{
+       struct ext2fs_dinode *dp;
+       struct zlncnt *zlnp;
+       int ndb, j;
+       mode_t mode;
+
+       dp = getnextinode(inumber);
+       if (inumber < EXT2_FIRSTINO &&
+           inumber != EXT2_ROOTINO &&
+           !(inumber == EXT2_RESIZEINO &&
+             (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0))
+               return;
+
+       mode = fs2h16(dp->e2di_mode) & IFMT;
+       if (mode == 0 || (dp->e2di_dtime != 0 && dp->e2di_nlink == 0)) {
+               if (mode == 0 && (
+                   memcmp(dp->e2di_blocks, zino.e2di_blocks,
+                   (NDADDR + NIADDR) * sizeof(u_int32_t)) ||
+                   dp->e2di_mode || inosize(dp))) {
+                       pfatal("PARTIALLY ALLOCATED INODE I=%llu",
+                           (unsigned long long)inumber);
+                       if (reply("CLEAR") == 1) {
+                               dp = ginode(inumber);
+                               clearinode(dp);
+                               inodirty();
+                       }
+               }
+#ifdef notyet /* it seems that dtime == 0 is valid for a unallocated inode */
+               if (dp->e2di_dtime == 0) {
+                       pwarn("DELETED INODE I=%llu HAS A NULL DTIME",
+                           (unsigned long long)inumber);
+                       if (preen) {
+                               printf(" (CORRECTED)\n");
+                       }
+                       if (preen || reply("CORRECT")) {
+                               time_t t;
+                               time(&t);
+                               dp->e2di_dtime = h2fs32(t);
+                               dp = ginode(inumber);
+                               inodirty();
+                       }
+               }
+#endif
+               statemap[inumber] = USTATE;
+               return;
+       }
+       lastino = inumber;
+       if (dp->e2di_dtime != 0) {
+               pwarn("INODE I=%llu HAS DTIME=%s",
+                   (unsigned long long)inumber,
+                   print_mtime(fs2h32(dp->e2di_dtime)));
+               if (preen) {
+                       printf(" (CORRECTED)\n");
+               }
+               if (preen || reply("CORRECT")) {
+                       dp = ginode(inumber);
+                       dp->e2di_dtime = 0;
+                       inodirty();
+               }
+       }
+       if (inosize(dp) + sblock.e2fs_bsize - 1 < inosize(dp)) {
+               if (debug)
+                       printf("bad size %llu:", (unsigned long long)inosize(dp));
+               goto unknown;
+       }
+       if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
+               dp = ginode(inumber);
+               dp->e2di_mode = h2fs16(IFREG|0600);
+               inossize(dp, sblock.e2fs_bsize);
+               inodirty();
+       }
+       ndb = howmany(inosize(dp), sblock.e2fs_bsize);
+       if (ndb < 0) {
+               if (debug)
+                       printf("bad size %llu ndb %d:",
+                           (unsigned long long)inosize(dp), ndb);
+               goto unknown;
+       }
+       if (mode == IFBLK || mode == IFCHR)
+               ndb++;
+       if (mode == IFLNK) {
+               /*
+                * Fake ndb value so direct/indirect block checks below
+                * will detect any garbage after symlink string.
+                */
+               if (inosize(dp) < EXT2_MAXSYMLINKLEN ||
+                   (EXT2_MAXSYMLINKLEN == 0 && dp->e2di_blocks == 0)) {
+                       ndb = howmany(inosize(dp), sizeof(u_int32_t));
+                       if (ndb > NDADDR) {
+                               j = ndb - NDADDR;
+                               for (ndb = 1; j > 1; j--)
+                                       ndb *= NINDIR(&sblock);
+                               ndb += NDADDR;
+                       }
+               }
+       }
+       /* Linux puts things in blocks for FIFO, so skip this check */
+       if (mode != IFIFO) {
+               for (j = ndb; j < NDADDR; j++)
+                       if (dp->e2di_blocks[j] != 0) {
+                               if (debug)
+                                       printf("bad direct addr: %d\n",
+                                           fs2h32(dp->e2di_blocks[j]));
+                               goto unknown;
+                       }
+               for (j = 0, ndb -= NDADDR; ndb > 0; j++)
+                       ndb /= NINDIR(&sblock);
+               for (; j < NIADDR; j++) {
+                       if (dp->e2di_blocks[j+NDADDR] != 0) {
+                               if (debug)
+                                       printf("bad indirect addr: %d\n",
+                                           fs2h32(dp->e2di_blocks[j+NDADDR]));
+                               goto unknown;
+                       }
+               }
+       }
+       if (ftypeok(dp) == 0)
+               goto unknown;
+       if (inumber >= EXT2_FIRSTINO || inumber == EXT2_ROOTINO) {
+               /* Don't count reserved inodes except root */
+               n_files++;
+       }
+       lncntp[inumber] = fs2h16(dp->e2di_nlink);
+       if (dp->e2di_nlink == 0) {
+               zlnp = malloc(sizeof *zlnp);
+               if (zlnp == NULL) {
+                       pfatal("LINK COUNT TABLE OVERFLOW");
+                       if (reply("CONTINUE") == 0)
+                               exit(FSCK_EXIT_CHECK_FAILED);
+               } else {
+                       zlnp->zlncnt = inumber;
+                       zlnp->next = zlnhead;
+                       zlnhead = zlnp;
+               }
+       }
+       if (mode == IFDIR) {
+               if (inosize(dp) == 0)
+                       statemap[inumber] = DCLEAR;
+               else
+                       statemap[inumber] = DSTATE;
+               cacheino(dp, inumber);
+       } else {
+               statemap[inumber] = FSTATE;
+       }
+       typemap[inumber] = E2IFTODT(mode);
+       badblk = dupblk = 0;
+       idesc->id_number = inumber;
+       (void)ckinode(dp, idesc);
+       idesc->id_entryno *= btodb(sblock.e2fs_bsize);
+       if (fs2h32(dp->e2di_nblock) != (uint32_t)idesc->id_entryno) {
+               pwarn("INCORRECT BLOCK COUNT I=%llu (%d should be %d)",
+                   (unsigned long long)inumber, fs2h32(dp->e2di_nblock),
+                   idesc->id_entryno);
+               if (preen)
+                       printf(" (CORRECTED)\n");
+               else if (reply("CORRECT") == 0)
+                       return;
+               dp = ginode(inumber);
+               dp->e2di_nblock = h2fs32(idesc->id_entryno);
+               inodirty();
+       }
+       return;
+unknown:
+       pfatal("UNKNOWN FILE TYPE I=%llu", (unsigned long long)inumber);
+       statemap[inumber] = FCLEAR;
+       if (reply("CLEAR") == 1) {
+               statemap[inumber] = USTATE;
+               dp = ginode(inumber);
+               clearinode(dp);
+               inodirty();
+       }
+}
+
+int
+pass1check(struct inodesc *idesc)
+{
+       int res = KEEPON;
+       int anyout, nfrags;
+       daddr_t blkno = idesc->id_blkno;
+       struct dups *dlp;
+       struct dups *new;
+
+       if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
+               blkerror(idesc->id_number, "BAD", blkno);
+               if (badblk++ >= MAXBAD) {
+                       pwarn("EXCESSIVE BAD BLKS I=%llu",
+                           (unsigned long long)idesc->id_number);
+                       if (preen)
+                               printf(" (SKIPPING)\n");
+                       else if (reply("CONTINUE") == 0)
+                               exit(FSCK_EXIT_CHECK_FAILED);
+                       return (STOP);
+               }
+       }
+       for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
+               if (anyout && chkrange(blkno, 1)) {
+                       res = SKIP;
+               } else if (!testbmap(blkno)) {
+                       n_blks++;
+                       setbmap(blkno);
+               } else {
+                       blkerror(idesc->id_number, "DUP", blkno);
+                       if (dupblk++ >= MAXDUP) {
+                               pwarn("EXCESSIVE DUP BLKS I=%llu",
+                                   (unsigned long long)idesc->id_number);
+                               if (preen)
+                                       printf(" (SKIPPING)\n");
+                               else if (reply("CONTINUE") == 0)
+                                       exit(FSCK_EXIT_CHECK_FAILED);
+                               return (STOP);
+                       }
+                       new = malloc(sizeof(struct dups));
+                       if (new == NULL) {
+                               pfatal("DUP TABLE OVERFLOW.");
+                               if (reply("CONTINUE") == 0)
+                                       exit(FSCK_EXIT_CHECK_FAILED);
+                               return (STOP);
+                       }
+                       new->dup = blkno;
+                       if (muldup == 0) {
+                               duplist = muldup = new;
+                               new->next = 0;
+                       } else {
+                               new->next = muldup->next;
+                               muldup->next = new;
+                       }
+                       for (dlp = duplist; dlp != muldup; dlp = dlp->next)
+                               if (dlp->dup == blkno)
+                                       break;
+                       if (dlp == muldup && dlp->dup != blkno)
+                               muldup = new;
+               }
+               /*
+                * count the number of blocks found in id_entryno
+                */
+               idesc->id_entryno++;
+       }
+       return (res);
+}
diff --git a/sbin/fsck_ext2fs/pass1b.c b/sbin/fsck_ext2fs/pass1b.c
new file mode 100644 (file)
index 0000000..31b1d3e
--- /dev/null
@@ -0,0 +1,130 @@
+/*     $NetBSD: pass1b.c,v 1.8 2009/10/19 18:41:08 bouyer Exp $        */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pass1b.c   8.1 (Berkeley) 6/5/93";
+#else
+__RCSID("$NetBSD: pass1b.c,v 1.8 2009/10/19 18:41:08 bouyer Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs.h>
+
+#include <string.h>
+#include "fsck.h"
+#include "extern.h"
+
+static int     pass1bcheck(struct inodesc *);
+static struct  dups *duphead;
+
+void
+pass1b(void)
+{
+       int c;
+       uint32_t i;
+       struct ext2fs_dinode *dp;
+       struct inodesc idesc;
+       ino_t inumber;
+
+       memset(&idesc, 0, sizeof(struct inodesc));
+       idesc.id_type = ADDR;
+       idesc.id_func = pass1bcheck;
+       duphead = duplist;
+       inumber = 0;
+       for (c = 0; c < sblock.e2fs_ncg; c++) {
+               for (i = 0; i < sblock.e2fs.e2fs_ipg; i++, inumber++) {
+                       if ((inumber < EXT2_FIRSTINO) && (inumber != EXT2_ROOTINO))
+                               continue;
+                       dp = ginode(inumber);
+                       if (dp == NULL)
+                               continue;
+                       idesc.id_number = inumber;
+                       if (statemap[inumber] != USTATE &&
+                           (ckinode(dp, &idesc) & STOP))
+                               return;
+               }
+       }
+}
+
+static int
+pass1bcheck(struct inodesc *idesc)
+{
+       struct dups *dlp;
+       int nfrags, res = KEEPON;
+       daddr_t blkno = idesc->id_blkno;
+
+       for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
+               if (chkrange(blkno, 1))
+                       res = SKIP;
+               for (dlp = duphead; dlp; dlp = dlp->next) {
+                       if (dlp->dup == blkno) {
+                               blkerror(idesc->id_number, "DUP", blkno);
+                               dlp->dup = duphead->dup;
+                               duphead->dup = blkno;
+                               duphead = duphead->next;
+                       }
+                       if (dlp == muldup)
+                               break;
+               }
+               if (muldup == 0 || duphead == muldup->next)
+                       return (STOP);
+       }
+       return (res);
+}
diff --git a/sbin/fsck_ext2fs/pass2.c b/sbin/fsck_ext2fs/pass2.c
new file mode 100644 (file)
index 0000000..01f0aa5
--- /dev/null
@@ -0,0 +1,470 @@
+/*     $NetBSD: pass2.c,v 1.15 2009/10/19 18:41:08 bouyer Exp $        */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pass2.c    8.6 (Berkeley) 10/27/94";
+#else
+__RCSID("$NetBSD: pass2.c,v 1.15 2009/10/19 18:41:08 bouyer Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs_dir.h>
+#include <ufs/ext2fs/ext2fs.h>
+
+#include <ufs/ufs/dinode.h> /* for IFMT & friends */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fsck.h"
+#include "fsutil.h"
+#include "extern.h"
+#include "exitvalues.h"
+
+#define MINDIRSIZE     (sizeof (struct ext2fs_dirtemplate))
+
+static int pass2check(struct inodesc *);
+static int blksort(const void *, const void *);
+
+void
+pass2(void)
+{
+       struct ext2fs_dinode *dp;
+       struct inoinfo **inpp, *inp;
+       struct inoinfo **inpend;
+       struct inodesc curino;
+       struct ext2fs_dinode dino;
+       char pathbuf[MAXPATHLEN + 1];
+
+       switch (statemap[EXT2_ROOTINO]) {
+
+       case USTATE:
+               pfatal("ROOT INODE UNALLOCATED");
+               if (reply("ALLOCATE") == 0)
+                       exit(FSCK_EXIT_CHECK_FAILED);
+               if (allocdir(EXT2_ROOTINO, EXT2_ROOTINO, 0755) != EXT2_ROOTINO)
+                       errexit("CANNOT ALLOCATE ROOT INODE");
+               break;
+
+       case DCLEAR:
+               pfatal("DUPS/BAD IN ROOT INODE");
+               if (reply("REALLOCATE")) {
+                       freeino(EXT2_ROOTINO);
+                       if (allocdir(EXT2_ROOTINO, EXT2_ROOTINO, 0755) != EXT2_ROOTINO)
+                               errexit("CANNOT ALLOCATE ROOT INODE");
+                       break;
+               }
+               if (reply("CONTINUE") == 0)
+                       exit(FSCK_EXIT_CHECK_FAILED);
+               break;
+
+       case FSTATE:
+       case FCLEAR:
+               pfatal("ROOT INODE NOT DIRECTORY");
+               if (reply("REALLOCATE")) {
+                       freeino(EXT2_ROOTINO);
+                       if (allocdir(EXT2_ROOTINO, EXT2_ROOTINO, 0755) != EXT2_ROOTINO)
+                               errexit("CANNOT ALLOCATE ROOT INODE");
+                       break;
+               }
+               if (reply("FIX") == 0)
+                       exit(FSCK_EXIT_CHECK_FAILED);
+               dp = ginode(EXT2_ROOTINO);
+               dp->e2di_mode = h2fs16((fs2h16(dp->e2di_mode) & ~IFMT) | IFDIR);
+               inodirty();
+               break;
+
+       case DSTATE:
+               break;
+
+       default:
+               errexit("BAD STATE %d FOR ROOT INODE", statemap[EXT2_ROOTINO]);
+       }
+
+       /*
+        * Sort the directory list into disk block order.
+        */
+       qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort);
+       /*
+        * Check the integrity of each directory.
+        */
+       memset(&curino, 0, sizeof(struct inodesc));
+       curino.id_type = DATA;
+       curino.id_func = pass2check;
+       inpend = &inpsort[inplast];
+       for (inpp = inpsort; inpp < inpend; inpp++) {
+               inp = *inpp;
+               if (inp->i_isize == 0)
+                       continue;
+               if (inp->i_isize < MINDIRSIZE) {
+                       direrror(inp->i_number, "DIRECTORY TOO SHORT");
+                       inp->i_isize = roundup(MINDIRSIZE, sblock.e2fs_bsize);
+                       if (reply("FIX") == 1) {
+                               dp = ginode(inp->i_number);
+                               inossize(dp, inp->i_isize);
+                               inodirty();
+                       }
+               } else if ((inp->i_isize & (sblock.e2fs_bsize - 1)) != 0) {
+                       getpathname(pathbuf, sizeof(pathbuf), inp->i_number,
+                           inp->i_number);
+                       pwarn("DIRECTORY %s: LENGTH %lu NOT MULTIPLE OF %d",
+                           pathbuf, (u_long)inp->i_isize, sblock.e2fs_bsize);
+                       if (preen)
+                               printf(" (ADJUSTED)\n");
+                       inp->i_isize = roundup(inp->i_isize, sblock.e2fs_bsize);
+                       if (preen || reply("ADJUST") == 1) {
+                               dp = ginode(inp->i_number);
+                               inossize(dp, inp->i_isize);
+                               inodirty();
+                       }
+               }
+               memset(&dino, 0, sizeof(struct ext2fs_dinode));
+               dino.e2di_mode = h2fs16(IFDIR);
+               inossize(&dino, inp->i_isize);
+               memcpy(&dino.e2di_blocks[0], &inp->i_blks[0], (size_t)inp->i_numblks);
+               curino.id_number = inp->i_number;
+               curino.id_parent = inp->i_parent;
+               (void)ckinode(&dino, &curino);
+       }
+       /*
+        * Now that the parents of all directories have been found,
+        * make another pass to verify the value of `..'
+        */
+       for (inpp = inpsort; inpp < inpend; inpp++) {
+               inp = *inpp;
+               if (inp->i_parent == 0 || inp->i_isize == 0)
+                       continue;
+               if (inp->i_dotdot == inp->i_parent ||
+                   inp->i_dotdot == (ino_t)-1)
+                       continue;
+               if (inp->i_dotdot == 0) {
+                       inp->i_dotdot = inp->i_parent;
+                       fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
+                       if (reply("FIX") == 0)
+                               continue;
+                       (void)makeentry(inp->i_number, inp->i_parent, "..");
+                       lncntp[inp->i_parent]--;
+                       continue;
+               }
+               fileerror(inp->i_parent, inp->i_number,
+                   "BAD INODE NUMBER FOR '..'");
+               if (reply("FIX") == 0)
+                       continue;
+               lncntp[inp->i_dotdot]++;
+               lncntp[inp->i_parent]--;
+               inp->i_dotdot = inp->i_parent;
+               (void)changeino(inp->i_number, "..", inp->i_parent);
+       }
+       /*
+        * Mark all the directories that can be found from the root.
+        */
+       propagate();
+}
+
+static int
+pass2check(struct inodesc *idesc)
+{
+       struct ext2fs_direct *dirp = idesc->id_dirp;
+       struct inoinfo *inp;
+       int n, entrysize, ret = 0;
+       struct ext2fs_dinode *dp;
+       const char *errmsg;
+       struct ext2fs_direct proto;
+       char namebuf[MAXPATHLEN + 1];
+       char pathbuf[MAXPATHLEN + 1];
+
+       /* 
+        * check for "."
+        */
+       if (idesc->id_entryno != 0)
+               goto chk1;
+       if (fs2h32(dirp->e2d_ino) != 0 && dirp->e2d_namlen == 1 &&
+               dirp->e2d_name[0] == '.') {
+               if (fs2h32(dirp->e2d_ino) != idesc->id_number) {
+                       direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
+                       dirp->e2d_ino = h2fs32(idesc->id_number);
+                       if (reply("FIX") == 1)
+                               ret |= ALTERED;
+               }
+               if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+                   (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)
+                   && (dirp->e2d_type != EXT2_FT_DIR)) {
+                       direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
+                       dirp->e2d_type = EXT2_FT_DIR;
+                       if (reply("FIX") == 1)
+                               ret |= ALTERED;
+               }
+               goto chk1;
+       }
+       direrror(idesc->id_number, "MISSING '.'");
+       proto.e2d_ino = h2fs32(idesc->id_number);
+       proto.e2d_namlen = 1;
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+           (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE))
+               proto.e2d_type = EXT2_FT_DIR;
+       else
+               proto.e2d_type = 0;
+       (void)strlcpy(proto.e2d_name, ".", sizeof(proto.e2d_name));
+       entrysize = EXT2FS_DIRSIZ(proto.e2d_namlen);
+       if (fs2h32(dirp->e2d_ino) != 0 && strcmp(dirp->e2d_name, "..") != 0) {
+               pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
+                       dirp->e2d_name);
+       } else if (fs2h16(dirp->e2d_reclen) < entrysize) {
+               pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
+       } else if (fs2h16(dirp->e2d_reclen) < 2 * entrysize) {
+               proto.e2d_reclen = dirp->e2d_reclen;
+               memcpy(dirp, &proto, (size_t)entrysize);
+               if (reply("FIX") == 1)
+                       ret |= ALTERED;
+       } else {
+               n = fs2h16(dirp->e2d_reclen) - entrysize;
+               proto.e2d_reclen = h2fs16(entrysize);
+               memcpy(dirp, &proto, (size_t)entrysize);
+               idesc->id_entryno++;
+               lncntp[fs2h32(dirp->e2d_ino)]--;
+               dirp = (struct ext2fs_direct *)((char *)(dirp) + entrysize);
+               memset(dirp, 0, (size_t)n);
+               dirp->e2d_reclen = h2fs16(n);
+               if (reply("FIX") == 1)
+                       ret |= ALTERED;
+       }
+chk1:
+       if (idesc->id_entryno > 1)
+               goto chk2;
+       inp = getinoinfo(idesc->id_number);
+       proto.e2d_ino = h2fs32(inp->i_parent);
+       proto.e2d_namlen = 2;
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+           (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE))
+               proto.e2d_type = EXT2_FT_DIR;
+       else
+               proto.e2d_type = 0;
+       (void)strlcpy(proto.e2d_name, "..", sizeof(proto.e2d_name));
+       entrysize = EXT2FS_DIRSIZ(2);
+       if (idesc->id_entryno == 0) {
+               n = EXT2FS_DIRSIZ(dirp->e2d_namlen);
+               if (fs2h16(dirp->e2d_reclen) < n + entrysize)
+                       goto chk2;
+               proto.e2d_reclen = h2fs16(fs2h16(dirp->e2d_reclen) - n);
+               dirp->e2d_reclen = h2fs16(n);
+               idesc->id_entryno++;
+               lncntp[fs2h32(dirp->e2d_ino)]--;
+               dirp = (struct ext2fs_direct *)((char *)(dirp) + n);
+               memset(dirp, 0, (size_t)fs2h16(proto.e2d_reclen));
+               dirp->e2d_reclen = proto.e2d_reclen;
+       }
+       if (fs2h32(dirp->e2d_ino) != 0 &&
+           dirp->e2d_namlen == 2 && 
+           strncmp(dirp->e2d_name, "..", 2) == 0) {
+               inp->i_dotdot = fs2h32(dirp->e2d_ino);
+               if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+                   (sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)
+                   && dirp->e2d_type != EXT2_FT_DIR) {
+                       direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'");
+                       dirp->e2d_type = EXT2_FT_DIR;
+                       if (reply("FIX") == 1)
+                               ret |= ALTERED;
+               }
+               goto chk2;
+       }
+       if (fs2h32(dirp->e2d_ino) != 0 &&
+               dirp->e2d_namlen == 1 &&
+               strncmp(dirp->e2d_name, ".", 1) != 0) {
+               fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
+               pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
+                       dirp->e2d_name);
+               inp->i_dotdot = (ino_t)-1;
+       } else if (fs2h16(dirp->e2d_reclen) < entrysize) {
+               fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
+               pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
+               inp->i_dotdot = (ino_t)-1;
+       } else if (inp->i_parent != 0) {
+               /*
+                * We know the parent, so fix now.
+                */
+               inp->i_dotdot = inp->i_parent;
+               fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
+               proto.e2d_reclen = dirp->e2d_reclen;
+               memcpy(dirp, &proto, (size_t)entrysize);
+               if (reply("FIX") == 1)
+                       ret |= ALTERED;
+       }
+       idesc->id_entryno++;
+       if (fs2h32(dirp->e2d_ino) != 0)
+               lncntp[fs2h32(dirp->e2d_ino)]--;
+       return (ret|KEEPON);
+chk2:
+       if (fs2h32(dirp->e2d_ino) == 0)
+               return (ret|KEEPON);
+       if (dirp->e2d_namlen <= 2 &&
+           dirp->e2d_name[0] == '.' &&
+           idesc->id_entryno >= 2) {
+               if (dirp->e2d_namlen == 1) {
+                       direrror(idesc->id_number, "EXTRA '.' ENTRY");
+                       dirp->e2d_ino = 0;
+                       if (reply("FIX") == 1)
+                               ret |= ALTERED;
+                       return (KEEPON | ret);
+               }
+               if (dirp->e2d_name[1] == '.') {
+                       direrror(idesc->id_number, "EXTRA '..' ENTRY");
+                       dirp->e2d_ino = 0;
+                       if (reply("FIX") == 1)
+                               ret |= ALTERED;
+                       return (KEEPON | ret);
+               }
+       }
+       idesc->id_entryno++;
+       n = 0;
+       if (fs2h32(dirp->e2d_ino) > maxino ||
+               (fs2h32(dirp->e2d_ino) < EXT2_FIRSTINO &&
+                fs2h32(dirp->e2d_ino) != EXT2_ROOTINO)) {
+               fileerror(idesc->id_number, fs2h32(dirp->e2d_ino), "I OUT OF RANGE");
+               n = reply("REMOVE");
+       } else {
+again:
+               switch (statemap[fs2h32(dirp->e2d_ino)]) {
+               case USTATE:
+                       if (idesc->id_entryno <= 2)
+                               break;
+                       fileerror(idesc->id_number, fs2h32(dirp->e2d_ino), "UNALLOCATED");
+                       n = reply("REMOVE");
+                       break;
+
+               case DCLEAR:
+               case FCLEAR:
+                       if (idesc->id_entryno <= 2)
+                               break;
+                       if (statemap[fs2h32(dirp->e2d_ino)] == FCLEAR)
+                               errmsg = "DUP/BAD";
+                       else if (!preen)
+                               errmsg = "ZERO LENGTH DIRECTORY";
+                       else {
+                               n = 1;
+                               break;
+                       }
+                       fileerror(idesc->id_number, fs2h32(dirp->e2d_ino), errmsg);
+                       if ((n = reply("REMOVE")) == 1)
+                               break;
+                       dp = ginode(fs2h32(dirp->e2d_ino));
+                       statemap[fs2h32(dirp->e2d_ino)] =
+                           (fs2h16(dp->e2di_mode) & IFMT) == IFDIR ? DSTATE : FSTATE;
+                       lncntp[fs2h32(dirp->e2d_ino)] = fs2h16(dp->e2di_nlink);
+                       goto again;
+
+               case DSTATE:
+               case DFOUND:
+                       inp = getinoinfo(fs2h32(dirp->e2d_ino));
+                       if (inp->i_parent != 0 && idesc->id_entryno > 2) {
+                               getpathname(pathbuf, sizeof(pathbuf),
+                                   idesc->id_number, idesc->id_number);
+                               getpathname(namebuf, sizeof(namebuf),
+                                   fs2h32(dirp->e2d_ino),
+                                   fs2h32(dirp->e2d_ino));
+                               pwarn("%s %s %s\n", pathbuf,
+                                   "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
+                                   namebuf);
+                               if (preen)
+                                       printf(" (IGNORED)\n");
+                               else if ((n = reply("REMOVE")) == 1)
+                                       break;
+                       }
+                       if (idesc->id_entryno > 2)
+                               inp->i_parent = idesc->id_number;
+                       /* fall through */
+
+               case FSTATE:
+                       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+                           (sblock.e2fs.e2fs_features_incompat &
+                               EXT2F_INCOMPAT_FTYPE) &&
+                           dirp->e2d_type !=
+                               inot2ext2dt(typemap[fs2h32(dirp->e2d_ino)])) {
+                               dirp->e2d_type =
+                                   inot2ext2dt(typemap[fs2h32(dirp->e2d_ino)]);
+                               fileerror(idesc->id_number,
+                                   fs2h32(dirp->e2d_ino),
+                                   "BAD TYPE VALUE");
+                               if (reply("FIX") == 1)
+                                       ret |= ALTERED;
+                       }
+                       lncntp[fs2h32(dirp->e2d_ino)]--;
+                       break;
+
+               default:
+                       errexit("BAD STATE %d FOR INODE I=%d",
+                           statemap[fs2h32(dirp->e2d_ino)], fs2h32(dirp->e2d_ino));
+               }
+       }
+       if (n == 0)
+               return (ret|KEEPON);
+       dirp->e2d_ino = 0;
+       return (ret|KEEPON|ALTERED);
+}
+
+/*
+ * Routine to sort disk blocks.
+ */
+static int
+blksort(const void *inpp1, const void *inpp2)
+{
+       return ((* (const struct inoinfo * const*) inpp1)->i_blks[0] -
+               (* (const struct inoinfo * const*) inpp2)->i_blks[0]);
+}
diff --git a/sbin/fsck_ext2fs/pass3.c b/sbin/fsck_ext2fs/pass3.c
new file mode 100644 (file)
index 0000000..bc19338
--- /dev/null
@@ -0,0 +1,100 @@
+/*     $NetBSD: pass3.c,v 1.7 2009/10/19 18:41:08 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pass3.c    8.1 (Berkeley) 6/5/93";
+#else
+__RCSID("$NetBSD: pass3.c,v 1.7 2009/10/19 18:41:08 bouyer Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include "fsck.h"
+#include "extern.h"
+
+void
+pass3(void)
+{
+       struct inoinfo **inpp, *inp;
+       ino_t orphan;
+       int loopcnt;
+
+       for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) {
+               inp = *inpp;
+               if (inp->i_number == EXT2_ROOTINO ||
+                   !(inp->i_parent == 0 || statemap[inp->i_number] == DSTATE))
+                       continue;
+               if (statemap[inp->i_number] == DCLEAR)
+                       continue;
+               for (loopcnt = 0; ; loopcnt++) {
+                       orphan = inp->i_number;
+                       if (inp->i_parent == 0 ||
+                           statemap[inp->i_parent] != DSTATE ||
+                           loopcnt > numdirs)
+                               break;
+                       inp = getinoinfo(inp->i_parent);
+               }
+               (void)linkup(orphan, inp->i_dotdot);
+               inp->i_parent = inp->i_dotdot = lfdir;
+               lncntp[lfdir]--;
+               statemap[orphan] = DFOUND;
+               propagate();
+       }
+}
diff --git a/sbin/fsck_ext2fs/pass4.c b/sbin/fsck_ext2fs/pass4.c
new file mode 100644 (file)
index 0000000..f184e38
--- /dev/null
@@ -0,0 +1,164 @@
+/*     $NetBSD: pass4.c,v 1.10 2009/10/19 18:41:08 bouyer Exp $        */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pass4.c    8.1 (Berkeley) 6/5/93";
+#else
+__RCSID("$NetBSD: pass4.c,v 1.10 2009/10/19 18:41:08 bouyer Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fsutil.h"
+#include "fsck.h"
+#include "extern.h"
+
+void
+pass4(void)
+{
+       ino_t inumber;
+       struct zlncnt *zlnp;
+       struct ext2fs_dinode *dp;
+       struct inodesc idesc;
+       int n;
+
+       memset(&idesc, 0, sizeof(struct inodesc));
+       idesc.id_type = ADDR;
+       idesc.id_func = pass4check;
+       for (inumber = EXT2_ROOTINO; inumber <= lastino; inumber++) {
+               if (inumber < EXT2_FIRSTINO && inumber > EXT2_ROOTINO)
+                       continue;
+               idesc.id_number = inumber;
+               switch (statemap[inumber]) {
+
+               case FSTATE:
+               case DFOUND:
+                       n = lncntp[inumber];
+                       if (n)
+                               adjust(&idesc, (short)n);
+                       else {
+                               for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
+                                       if (zlnp->zlncnt == inumber) {
+                                               zlnp->zlncnt = zlnhead->zlncnt;
+                                               zlnp = zlnhead;
+                                               zlnhead = zlnhead->next;
+                                               free((char *)zlnp);
+                                               clri(&idesc, "UNREF", 1);
+                                               break;
+                                       }
+                       }
+                       break;
+
+               case DSTATE:
+                       clri(&idesc, "UNREF", 1);
+                       break;
+
+               case DCLEAR:
+                       dp = ginode(inumber);
+                       if (inosize(dp) == 0) {
+                               clri(&idesc, "ZERO LENGTH", 1);
+                               break;
+                       }
+                       /* fall through */
+               case FCLEAR:
+                       clri(&idesc, "BAD/DUP", 1);
+                       break;
+
+               case USTATE:
+                       break;
+
+               default:
+                       errexit("BAD STATE %d FOR INODE I=%llu",
+                           statemap[inumber], (unsigned long long)inumber);
+               }
+       }
+}
+
+int
+pass4check(struct inodesc *idesc)
+{
+       struct dups *dlp;
+       int nfrags, res = KEEPON;
+       daddr_t blkno = idesc->id_blkno;
+
+       for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
+               if (chkrange(blkno, 1)) {
+                       res = SKIP;
+               } else if (testbmap(blkno)) {
+                       for (dlp = duplist; dlp; dlp = dlp->next) {
+                               if (dlp->dup != blkno)
+                                       continue;
+                               dlp->dup = duplist->dup;
+                               dlp = duplist;
+                               duplist = duplist->next;
+                               free((char *)dlp);
+                               break;
+                       }
+                       if (dlp == 0) {
+                               clrbmap(blkno);
+                               n_blks--;
+                       }
+               }
+       }
+       return (res);
+}
diff --git a/sbin/fsck_ext2fs/pass5.c b/sbin/fsck_ext2fs/pass5.c
new file mode 100644 (file)
index 0000000..92467bd
--- /dev/null
@@ -0,0 +1,277 @@
+/*     $NetBSD: pass5.c,v 1.19 2011/08/06 16:42:41 dholland Exp $      */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pass5.c    8.6 (Berkeley) 11/30/94";
+#else
+__RCSID("$NetBSD: pass5.c,v 1.19 2011/08/06 16:42:41 dholland Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <inttypes.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdio.h>
+
+#include "fsutil.h"
+#include "fsck.h"
+#include "extern.h"
+
+
+static void print_bmap(char *, uint32_t);
+
+void
+pass5(void)
+{
+       int c;
+       struct m_ext2fs *fs = &sblock;
+       daddr_t dbase, dmax;
+       daddr_t d;
+       uint32_t i, j;
+       struct inodesc idesc[3];
+       struct bufarea *ino_bitmap = NULL, *blk_bitmap = NULL;
+       char *ibmap, *bbmap;
+       u_int32_t cs_ndir, cs_nbfree, cs_nifree;
+       char msg[255];
+
+       cs_ndir = 0;
+       cs_nbfree = 0;
+       cs_nifree = 0;
+
+       ibmap = malloc(fs->e2fs_bsize);
+       bbmap = malloc(fs->e2fs_bsize);
+       if (ibmap == NULL || bbmap == NULL) {
+               errexit("out of memory");
+       }
+
+       for (c = 0; c < fs->e2fs_ncg; c++) {
+               u_int32_t nbfree = 0;
+               u_int32_t nifree = 0;
+               u_int32_t ndirs = 0;
+
+               nbfree = 0;
+               nifree = fs->e2fs.e2fs_ipg;
+               ndirs = 0;
+
+               if (blk_bitmap == NULL) {
+                       blk_bitmap = getdatablk(fs2h32(fs->e2fs_gd[c].ext2bgd_b_bitmap),
+                               fs->e2fs_bsize);
+               } else {
+                       getblk(blk_bitmap, fs2h32(fs->e2fs_gd[c].ext2bgd_b_bitmap),
+                               fs->e2fs_bsize);
+               }
+               if (ino_bitmap == NULL) {
+                       ino_bitmap = getdatablk(fs2h32(fs->e2fs_gd[c].ext2bgd_i_bitmap),
+                               fs->e2fs_bsize);
+               } else {
+                       getblk(ino_bitmap, fs2h32(fs->e2fs_gd[c].ext2bgd_i_bitmap),
+                               fs->e2fs_bsize);
+               }
+               memset(bbmap, 0, fs->e2fs_bsize);
+               memset(ibmap, 0, fs->e2fs_bsize);
+               memset(&idesc[0], 0, sizeof idesc);
+               for (i = 0; i < 3; i++) {
+                       idesc[i].id_type = ADDR;
+               }       
+
+               j = fs->e2fs.e2fs_ipg * c + 1;
+
+               for (i = 0; i < fs->e2fs.e2fs_ipg; j++, i++) {
+                       if ((j < EXT2_FIRSTINO) && (j != EXT2_ROOTINO)) {
+                               setbit(ibmap, i);
+                               nifree--;
+                               continue;
+                       }
+                       if (j > fs->e2fs.e2fs_icount) {
+                               setbit(ibmap, i);
+                               continue;
+                       }
+                       switch (statemap[j]) {
+
+                       case USTATE:
+                               break;
+
+                       case DSTATE:
+                       case DCLEAR:
+                       case DFOUND:
+                               ndirs++;
+                               /* fall through */
+
+                       case FSTATE:
+                       case FCLEAR:
+                               nifree--;
+                               setbit(ibmap, i);
+                               break;
+
+                       default:
+                               errexit("BAD STATE %d FOR INODE I=%"PRIu32,
+                                   statemap[j], j);
+                       }
+               }
+
+               /* fill in unused par of the inode map */
+               for (i = fs->e2fs.e2fs_ipg / NBBY; i < (uint32_t)fs->e2fs_bsize; i++)
+                       ibmap[i] = 0xff; 
+
+               dbase = c * sblock.e2fs.e2fs_bpg +
+                   sblock.e2fs.e2fs_first_dblock;
+               dmax = (c+1) * sblock.e2fs.e2fs_bpg +
+                   sblock.e2fs.e2fs_first_dblock;
+
+               for (i = 0, d = dbase;
+                    d < dmax;
+                    d ++, i ++) {
+                       if (testbmap(d) || d >= sblock.e2fs.e2fs_bcount) {
+                               setbit(bbmap, i);
+                               continue;
+                       } else {
+                               nbfree++;
+                       }
+
+               }
+               cs_nbfree += nbfree;
+               cs_nifree += nifree;
+               cs_ndir += ndirs;
+
+               if (debug && (fs2h16(fs->e2fs_gd[c].ext2bgd_nbfree) != nbfree ||
+                                         fs2h16(fs->e2fs_gd[c].ext2bgd_nifree) != nifree ||
+                                         fs2h16(fs->e2fs_gd[c].ext2bgd_ndirs) != ndirs)) {
+                       printf("summary info for cg %d is %d, %d, %d,"
+                                       "should be %d, %d, %d\n", c,
+                                       fs2h16(fs->e2fs_gd[c].ext2bgd_nbfree),
+                                       fs2h16(fs->e2fs_gd[c].ext2bgd_nifree),
+                                       fs2h16(fs->e2fs_gd[c].ext2bgd_ndirs),
+                                       nbfree,
+                                       nifree,
+                                       ndirs);
+               }
+               (void)snprintf(msg, sizeof(msg),
+                   "SUMMARY INFORMATIONS WRONG FOR CG #%d", c);
+               if ((fs2h16(fs->e2fs_gd[c].ext2bgd_nbfree) != nbfree ||
+                       fs2h16(fs->e2fs_gd[c].ext2bgd_nifree) != nifree ||
+                       fs2h16(fs->e2fs_gd[c].ext2bgd_ndirs) != ndirs) &&
+                       dofix(&idesc[0], msg)) {
+                       fs->e2fs_gd[c].ext2bgd_nbfree = h2fs16(nbfree);
+                       fs->e2fs_gd[c].ext2bgd_nifree = h2fs16(nifree);
+                       fs->e2fs_gd[c].ext2bgd_ndirs = h2fs16(ndirs);
+                       sbdirty();
+               }
+
+               if (debug && memcmp(blk_bitmap->b_un.b_buf, bbmap, fs->e2fs_bsize)) {
+                       printf("blk_bitmap:\n");
+                       print_bmap(blk_bitmap->b_un.b_buf, fs->e2fs_bsize);
+                       printf("bbmap:\n");
+                       print_bmap(bbmap, fs->e2fs_bsize);
+               }
+
+               (void)snprintf(msg, sizeof(msg),
+                   "BLK(S) MISSING IN BIT MAPS #%d", c);
+               if (memcmp(blk_bitmap->b_un.b_buf, bbmap, fs->e2fs_bsize) &&
+                       dofix(&idesc[1], msg)) {
+                       memcpy(blk_bitmap->b_un.b_buf, bbmap, fs->e2fs_bsize);
+                       dirty(blk_bitmap);
+               }
+               if (debug && memcmp(ino_bitmap->b_un.b_buf, ibmap, fs->e2fs_bsize)) {
+                       printf("ino_bitmap:\n");
+                       print_bmap(ino_bitmap->b_un.b_buf, fs->e2fs_bsize);
+                       printf("ibmap:\n");
+                       print_bmap(ibmap, fs->e2fs_bsize);
+               }
+               (void)snprintf(msg, sizeof(msg),
+                   "INODE(S) MISSING IN BIT MAPS #%d", c);
+               if (memcmp(ino_bitmap->b_un.b_buf, ibmap, fs->e2fs_bsize) &&
+                       dofix(&idesc[1], msg)) {
+                       memcpy(ino_bitmap->b_un.b_buf, ibmap, fs->e2fs_bsize);
+                       dirty(ino_bitmap);
+               }
+
+       }
+       if (debug && (fs->e2fs.e2fs_fbcount != cs_nbfree ||
+               fs->e2fs.e2fs_ficount != cs_nifree)) {
+               printf("summary info bad in superblock: %d, %d should be %d, %d\n",
+               fs->e2fs.e2fs_fbcount, fs->e2fs.e2fs_ficount,
+               cs_nbfree, cs_nifree);
+       }
+       if ((fs->e2fs.e2fs_fbcount != cs_nbfree ||
+               fs->e2fs.e2fs_ficount != cs_nifree)
+           && dofix(&idesc[0], "SUPERBLK SUMMARY INFORMATION BAD")) {
+               fs->e2fs.e2fs_fbcount = cs_nbfree;
+               fs->e2fs.e2fs_ficount = cs_nifree;
+               sbdirty();
+       }
+       free(ibmap);
+       free(bbmap);
+}
+
+static void 
+print_bmap(char *map, uint32_t size)
+{
+       uint32_t i, j;
+
+       i = 0;
+       while (i < size) {
+               printf("%04x: ",i);
+               for (j = 0; j < 16; j++, i++)
+                       printf("%02x ", (unsigned char)map[i] & 0xff);
+               printf("\n");
+       }
+}
diff --git a/sbin/fsck_ext2fs/setup.c b/sbin/fsck_ext2fs/setup.c
new file mode 100644 (file)
index 0000000..d63185b
--- /dev/null
@@ -0,0 +1,559 @@
+/*     $NetBSD: setup.c,v 1.28 2011/09/16 16:13:18 plunky Exp $        */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)setup.c    8.5 (Berkeley) 11/23/94";
+#else
+__RCSID("$NetBSD: setup.c,v 1.28 2011/09/16 16:13:18 plunky Exp $");
+#endif
+#endif /* not lint */
+
+#define FSTYPENAMES
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/file.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "fsck.h"
+#include "extern.h"
+#include "fsutil.h"
+#include "exitvalues.h"
+
+void badsb(int, const char *);
+int calcsb(const char *, int, struct m_ext2fs *);
+static struct disklabel *getdisklabel(const char *, int);
+static int readsb(int);
+
+int
+setup(const char *dev)
+{
+       long cg, asked, i;
+       long bmapsize;
+       struct disklabel *lp;
+#ifndef __minix
+       off_t sizepb;
+#else
+       u64_t sizepb;
+#endif
+       struct stat statb;
+       struct m_ext2fs proto;
+       int doskipclean;
+       u_int64_t maxfilesize;
+
+       havesb = 0;
+       fswritefd = -1;
+       doskipclean = skipclean;
+       if (stat(dev, &statb) < 0) {
+               printf("Can't stat %s: %s\n", dev, strerror(errno));
+               return 0;
+       }
+
+#ifndef __minix
+       if (!S_ISCHR(statb.st_mode)) {
+               pfatal("%s is not a character device", dev);
+               if (reply("CONTINUE") == 0)
+                       return 0;
+       }
+#endif
+
+       if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
+               printf("Can't open %s: %s\n", dev, strerror(errno));
+               return 0;
+       }
+       if (preen == 0)
+               printf("** %s", dev);
+       if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) {
+               fswritefd = -1;
+               if (preen)
+                       pfatal("NO WRITE ACCESS");
+               printf(" (NO WRITE)");
+       }
+       if (preen == 0)
+               printf("\n");
+       fsmodified = 0;
+       lfdir = 0;
+       initbarea(&sblk);
+       initbarea(&asblk);
+       sblk.b_un.b_buf = malloc(SBSIZE);
+       asblk.b_un.b_buf = malloc(SBSIZE);
+       if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
+               errexit("cannot allocate space for superblock");
+       if ((lp = getdisklabel(NULL, fsreadfd)) != NULL)
+               dev_bsize = secsize = lp->d_secsize;
+       else
+               dev_bsize = secsize = DEV_BSIZE;
+       /*
+        * Read in the superblock, looking for alternates if necessary
+        */
+       if (readsb(1) == 0) {
+               if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
+                       return 0;
+               if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
+                       return 0;
+               for (cg = 1; cg < proto.e2fs_ncg; cg++) {
+                       bflag = fsbtodb(&proto,
+                           cg * proto.e2fs.e2fs_bpg +
+                           proto.e2fs.e2fs_first_dblock);
+                       if (readsb(0) != 0)
+                               break;
+               }
+               if (cg >= proto.e2fs_ncg) {
+                       printf("%s %s\n%s %s\n%s %s\n",
+                           "SEARCH FOR ALTERNATE SUPER-BLOCK",
+                           "FAILED. YOU MUST USE THE",
+                           "-b OPTION TO FSCK_FFS TO SPECIFY THE",
+                           "LOCATION OF AN ALTERNATE",
+                           "SUPER-BLOCK TO SUPPLY NEEDED",
+                           "INFORMATION; SEE fsck_ext2fs(8).");
+                       return 0;
+               }
+               doskipclean = 0;
+               pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
+       }
+       if (debug)
+               printf("state = %d\n", sblock.e2fs.e2fs_state);
+       if (sblock.e2fs.e2fs_state == E2FS_ISCLEAN) {
+               if (doskipclean) {
+                       pwarn("%sile system is clean; not checking\n",
+                           preen ? "f" : "** F");
+                       return -1;
+               }
+               if (!preen)
+                       pwarn("** File system is already clean\n");
+       }
+       maxfsblock = sblock.e2fs.e2fs_bcount;
+       maxino = sblock.e2fs_ncg * sblock.e2fs.e2fs_ipg;
+       sizepb = sblock.e2fs_bsize;
+       maxfilesize = sblock.e2fs_bsize * NDADDR - 1;
+       for (i = 0; i < NIADDR; i++) {
+               sizepb *= NINDIR(&sblock);
+               maxfilesize += sizepb;
+       }
+       /*
+        * Check and potentially fix certain fields in the super block.
+        */
+       if (/* (sblock.e2fs.e2fs_rbcount < 0) || */
+           (sblock.e2fs.e2fs_rbcount > sblock.e2fs.e2fs_bcount)) {
+               pfatal("IMPOSSIBLE RESERVED BLOCK COUNT=%d IN SUPERBLOCK",
+                   sblock.e2fs.e2fs_rbcount);
+               if (reply("SET TO DEFAULT") == 1) {
+                       sblock.e2fs.e2fs_rbcount =
+                           sblock.e2fs.e2fs_bcount * MINFREE / 100;
+                       sbdirty();
+                       dirty(&asblk);
+               }
+       }
+       if (sblock.e2fs.e2fs_bpg != sblock.e2fs.e2fs_fpg) {
+               pfatal("WRONG FPG=%d (BPG=%d) IN SUPERBLOCK",
+                   sblock.e2fs.e2fs_fpg, sblock.e2fs.e2fs_bpg);
+               return 0;
+       }
+       if (asblk.b_dirty && !bflag) {
+               copyback_sb(&asblk);
+               flush(fswritefd, &asblk);
+       }
+       /*
+        * read in the summary info.
+        */
+
+       sblock.e2fs_gd = malloc(sblock.e2fs_ngdb * sblock.e2fs_bsize);
+       if (sblock.e2fs_gd == NULL)
+               errexit("out of memory");
+       asked = 0;
+       for (i = 0; i < sblock.e2fs_ngdb; i++) {
+               if (bread(fsreadfd,
+                   (char *)&sblock.e2fs_gd[i * sblock.e2fs_bsize /
+                   sizeof(struct ext2_gd)],
+                   fsbtodb(&sblock, ((sblock.e2fs_bsize > 1024) ? 0 : 1) +
+                   i + 1),
+                   sblock.e2fs_bsize) != 0 && !asked) {
+                       pfatal("BAD SUMMARY INFORMATION");
+                       if (reply("CONTINUE") == 0)
+                               exit(FSCK_EXIT_CHECK_FAILED);
+                       asked++;
+               }
+       }
+       /*
+        * allocate and initialize the necessary maps
+        */
+       bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t));
+       blockmap = calloc((unsigned int)bmapsize, sizeof(char));
+       if (blockmap == NULL) {
+               printf("cannot alloc %u bytes for blockmap\n",
+                   (unsigned int)bmapsize);
+               goto badsblabel;
+       }
+       statemap = calloc((unsigned int)(maxino + 2), sizeof(char));
+       if (statemap == NULL) {
+               printf("cannot alloc %u bytes for statemap\n",
+                   (unsigned int)(maxino + 1));
+               goto badsblabel;
+       }
+       typemap = calloc((unsigned int)(maxino + 1), sizeof(char));
+       if (typemap == NULL) {
+               printf("cannot alloc %u bytes for typemap\n",
+                   (unsigned int)(maxino + 1));
+               goto badsblabel;
+       }
+       lncntp = calloc((unsigned)(maxino + 1), sizeof(int16_t));
+       if (lncntp == NULL) {
+               printf("cannot alloc %u bytes for lncntp\n",
+                   (unsigned int)((maxino + 1) * sizeof(int16_t)));
+               goto badsblabel;
+       }
+       for (numdirs = 0, cg = 0; cg < sblock.e2fs_ncg; cg++) {
+               numdirs += fs2h16(sblock.e2fs_gd[cg].ext2bgd_ndirs);
+       }
+       inplast = 0;
+       listmax = numdirs + 10;
+       inpsort = calloc((unsigned int)listmax, sizeof(struct inoinfo *));
+       inphead = calloc((unsigned int)numdirs, sizeof(struct inoinfo *));
+       if (inpsort == NULL || inphead == NULL) {
+               printf("cannot alloc %u bytes for inphead\n",
+                   (unsigned int)(numdirs * sizeof(struct inoinfo *)));
+               goto badsblabel;
+       }
+       bufinit();
+       return 1;
+
+badsblabel:
+       ckfini(0);
+       return 0;
+}
+
+/*
+ * Read in the super block and its summary info, convert to host byte order.
+ */
+static int
+readsb(int listerr)
+{
+       daddr_t super = bflag ? bflag : SBOFF / dev_bsize;
+
+       if (bread(fsreadfd, (char *)sblk.b_un.b_fs, super, (long)SBSIZE) != 0)
+               return 0;
+       sblk.b_bno = super;
+       sblk.b_size = SBSIZE;
+
+       /* Copy the superblock in memory */
+       e2fs_sbload(sblk.b_un.b_fs, &sblock.e2fs);
+       
+       /*
+        * run a few consistency checks of the super block
+        */
+       if (sblock.e2fs.e2fs_magic != E2FS_MAGIC) {
+               badsb(listerr, "MAGIC NUMBER WRONG");
+               return 0;
+       }
+       if (sblock.e2fs.e2fs_log_bsize > 2) {
+               badsb(listerr, "BAD LOG_BSIZE");
+               return 0;
+       }
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+           (!powerof2(sblock.e2fs.e2fs_inode_size) ||
+            sblock.e2fs.e2fs_inode_size < sizeof(struct ext2fs_dinode) ||
+            sblock.e2fs.e2fs_inode_size >
+             (1024 << sblock.e2fs.e2fs_log_bsize))) {
+               badsb(listerr, "BAD INODE_SIZE");
+               return 0;
+       }
+
+       /* compute the dynamic fields of the in-memory sb */
+       /* compute dynamic sb infos */
+       sblock.e2fs_ncg =
+           howmany(sblock.e2fs.e2fs_bcount - sblock.e2fs.e2fs_first_dblock,
+           sblock.e2fs.e2fs_bpg);
+       /* XXX assume hw bsize = 512 */
+       sblock.e2fs_fsbtodb = sblock.e2fs.e2fs_log_bsize + 1;
+       sblock.e2fs_bsize = 1024 << sblock.e2fs.e2fs_log_bsize;
+       sblock.e2fs_bshift = LOG_MINBSIZE + sblock.e2fs.e2fs_log_bsize;
+       sblock.e2fs_qbmask = sblock.e2fs_bsize - 1;
+       sblock.e2fs_bmask = ~sblock.e2fs_qbmask;
+       sblock.e2fs_ngdb = howmany(sblock.e2fs_ncg,
+           sblock.e2fs_bsize / sizeof(struct ext2_gd));
+       sblock.e2fs_ipb = sblock.e2fs_bsize / EXT2_DINODE_SIZE(&sblock);
+       sblock.e2fs_itpg = howmany(sblock.e2fs.e2fs_ipg, sblock.e2fs_ipb);
+
+       /*
+        * Compute block size that the filesystem is based on,
+        * according to fsbtodb, and adjust superblock block number
+        * so we can tell if this is an alternate later.
+        */
+       super *= dev_bsize;
+       dev_bsize = sblock.e2fs_bsize / fsbtodb(&sblock, 1);
+       sblk.b_bno = super / dev_bsize;
+
+       if (sblock.e2fs_ncg == 1) {
+               /* no alternate superblock; assume it's okay */
+               havesb = 1;
+               return 1;
+       }
+       getblk(&asblk, 1 * sblock.e2fs.e2fs_bpg + sblock.e2fs.e2fs_first_dblock,
+               (long)SBSIZE);
+       if (asblk.b_errs)
+               return 0;
+       if (bflag) {
+               havesb = 1;
+               return 1;
+       }
+
+       /*
+        * Set all possible fields that could differ, then do check
+        * of whole super block against an alternate super block.
+        * When an alternate super-block is specified this check is skipped.
+        */
+       asblk.b_un.b_fs->e2fs_rbcount = sblk.b_un.b_fs->e2fs_rbcount;
+       asblk.b_un.b_fs->e2fs_fbcount = sblk.b_un.b_fs->e2fs_fbcount;
+       asblk.b_un.b_fs->e2fs_ficount = sblk.b_un.b_fs->e2fs_ficount;
+       asblk.b_un.b_fs->e2fs_mtime = sblk.b_un.b_fs->e2fs_mtime;
+       asblk.b_un.b_fs->e2fs_wtime = sblk.b_un.b_fs->e2fs_wtime;
+       asblk.b_un.b_fs->e2fs_mnt_count = sblk.b_un.b_fs->e2fs_mnt_count;
+       asblk.b_un.b_fs->e2fs_max_mnt_count =
+           sblk.b_un.b_fs->e2fs_max_mnt_count;
+       asblk.b_un.b_fs->e2fs_state = sblk.b_un.b_fs->e2fs_state;
+       asblk.b_un.b_fs->e2fs_beh = sblk.b_un.b_fs->e2fs_beh;
+       asblk.b_un.b_fs->e2fs_lastfsck = sblk.b_un.b_fs->e2fs_lastfsck;
+       asblk.b_un.b_fs->e2fs_fsckintv = sblk.b_un.b_fs->e2fs_fsckintv;
+       asblk.b_un.b_fs->e2fs_ruid = sblk.b_un.b_fs->e2fs_ruid;
+       asblk.b_un.b_fs->e2fs_rgid = sblk.b_un.b_fs->e2fs_rgid;
+       asblk.b_un.b_fs->e2fs_block_group_nr =
+           sblk.b_un.b_fs->e2fs_block_group_nr;
+       asblk.b_un.b_fs->e2fs_features_rocompat &= ~EXT2F_ROCOMPAT_LARGEFILE;
+       asblk.b_un.b_fs->e2fs_features_rocompat |=
+           sblk.b_un.b_fs->e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE;
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+           ((sblock.e2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP) ||
+           (sblock.e2fs.e2fs_features_rocompat & ~EXT2F_ROCOMPAT_SUPP))) {
+               if (debug) {
+                       printf("compat 0x%08x, incompat 0x%08x, compat_ro "
+                           "0x%08x\n",
+                           sblock.e2fs.e2fs_features_compat,
+                           sblock.e2fs.e2fs_features_incompat,
+                           sblock.e2fs.e2fs_features_rocompat);
+               }
+               badsb(listerr, "INCOMPATIBLE FEATURE BITS IN SUPER BLOCK");
+               return 0;
+       }
+       if (memcmp(sblk.b_un.b_fs, asblk.b_un.b_fs, SBSIZE)) {
+               if (debug) {
+                       u_int32_t *nlp, *olp, *endlp;
+
+                       printf("superblock mismatches\n");
+                       nlp = (u_int32_t *)asblk.b_un.b_fs;
+                       olp = (u_int32_t *)sblk.b_un.b_fs;
+                       endlp = olp + (SBSIZE / sizeof(*olp));
+                       for ( ; olp < endlp; olp++, nlp++) {
+                               if (*olp == *nlp)
+                                       continue;
+                               printf("offset %ld, original %ld, "
+                                   "alternate %ld\n",
+                                   (long)(olp - (u_int32_t *)sblk.b_un.b_fs),
+                                   (long)fs2h32(*olp),
+                                   (long)fs2h32(*nlp));
+                       }
+               }
+               badsb(listerr,
+                   "VALUES IN SUPER BLOCK DISAGREE WITH "
+                   "THOSE IN FIRST ALTERNATE");
+               return 0;
+       }
+       havesb = 1;
+       return 1;
+}
+
+void
+copyback_sb(struct bufarea *bp)
+{
+       /* Copy the in-memory superblock back to buffer */
+       bp->b_un.b_fs->e2fs_icount = h2fs32(sblock.e2fs.e2fs_icount);
+       bp->b_un.b_fs->e2fs_bcount = h2fs32(sblock.e2fs.e2fs_bcount);
+       bp->b_un.b_fs->e2fs_rbcount = h2fs32(sblock.e2fs.e2fs_rbcount);
+       bp->b_un.b_fs->e2fs_fbcount = h2fs32(sblock.e2fs.e2fs_fbcount);
+       bp->b_un.b_fs->e2fs_ficount = h2fs32(sblock.e2fs.e2fs_ficount);
+       bp->b_un.b_fs->e2fs_first_dblock =
+           h2fs32(sblock.e2fs.e2fs_first_dblock);
+       bp->b_un.b_fs->e2fs_log_bsize = h2fs32(sblock.e2fs.e2fs_log_bsize);
+       bp->b_un.b_fs->e2fs_fsize = h2fs32(sblock.e2fs.e2fs_fsize);
+       bp->b_un.b_fs->e2fs_bpg = h2fs32(sblock.e2fs.e2fs_bpg);
+       bp->b_un.b_fs->e2fs_fpg = h2fs32(sblock.e2fs.e2fs_fpg);
+       bp->b_un.b_fs->e2fs_ipg = h2fs32(sblock.e2fs.e2fs_ipg);
+       bp->b_un.b_fs->e2fs_mtime = h2fs32(sblock.e2fs.e2fs_mtime);
+       bp->b_un.b_fs->e2fs_wtime = h2fs32(sblock.e2fs.e2fs_wtime);
+       bp->b_un.b_fs->e2fs_lastfsck = h2fs32(sblock.e2fs.e2fs_lastfsck);
+       bp->b_un.b_fs->e2fs_fsckintv = h2fs32(sblock.e2fs.e2fs_fsckintv);
+       bp->b_un.b_fs->e2fs_creator = h2fs32(sblock.e2fs.e2fs_creator);
+       bp->b_un.b_fs->e2fs_rev = h2fs32(sblock.e2fs.e2fs_rev);
+       bp->b_un.b_fs->e2fs_mnt_count = h2fs16(sblock.e2fs.e2fs_mnt_count);
+       bp->b_un.b_fs->e2fs_max_mnt_count =
+           h2fs16(sblock.e2fs.e2fs_max_mnt_count);
+       bp->b_un.b_fs->e2fs_magic = h2fs16(sblock.e2fs.e2fs_magic);
+       bp->b_un.b_fs->e2fs_state = h2fs16(sblock.e2fs.e2fs_state);
+       bp->b_un.b_fs->e2fs_beh = h2fs16(sblock.e2fs.e2fs_beh);
+       bp->b_un.b_fs->e2fs_ruid = h2fs16(sblock.e2fs.e2fs_ruid);
+       bp->b_un.b_fs->e2fs_rgid = h2fs16(sblock.e2fs.e2fs_rgid);
+}
+
+void
+badsb(int listerr, const char *s)
+{
+
+       if (!listerr)
+               return;
+       if (preen)
+               printf("%s: ", cdevname());
+       pfatal("BAD SUPER BLOCK: %s\n", s);
+}
+
+/*
+ * Calculate a prototype superblock based on information in the disk label.
+ * When done the cgsblock macro can be calculated and the fs_ncg field
+ * can be used. Do NOT attempt to use other macros without verifying that
+ * their needed information is available!
+ */
+
+int
+calcsb(const char *dev, int devfd, struct m_ext2fs *fs)
+{
+#ifdef __minix
+       errexit("%s: calcsb: can't read disk label under minix", dev);
+#else
+       struct disklabel *lp;
+       struct partition *pp;
+       char *cp;
+
+       cp = strchr(dev, '\0');
+       if (cp-- == dev ||
+           ((*cp < 'a' || *cp > 'h') && !isdigit((unsigned char)*cp))) {
+               pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
+               return 0;
+       }
+       lp = getdisklabel(dev, devfd);
+       if (isdigit((unsigned char)*cp))
+               pp = &lp->d_partitions[0];
+       else
+               pp = &lp->d_partitions[*cp - 'a'];
+       if (pp->p_fstype != FS_EX2FS) {
+               pfatal("%s: NOT LABELED AS A EXT2 FILE SYSTEM (%s)\n",
+                   dev, pp->p_fstype < FSMAXTYPES ?
+                   fstypenames[pp->p_fstype] : "unknown");
+               return 0;
+       }
+       memset(fs, 0, sizeof(struct m_ext2fs));
+       fs->e2fs_bsize = pp->p_fsize;
+       fs->e2fs.e2fs_log_bsize = pp->p_fsize / 1024;
+       fs->e2fs.e2fs_bcount = (pp->p_size * DEV_BSIZE) / fs->e2fs_bsize;
+       fs->e2fs.e2fs_first_dblock = (fs->e2fs.e2fs_log_bsize == 0) ? 1 : 0;
+       fs->e2fs.e2fs_bpg = fs->e2fs_bsize * NBBY;
+       fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
+       fs->e2fs_qbmask = fs->e2fs_bsize - 1;
+       fs->e2fs_bmask = ~fs->e2fs_qbmask;
+       fs->e2fs_ncg =
+           howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
+           fs->e2fs.e2fs_bpg);
+       fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
+       fs->e2fs_ngdb = howmany(fs->e2fs_ncg,
+           fs->e2fs_bsize / sizeof(struct ext2_gd));
+
+       return 1;
+#endif
+}
+
+static struct disklabel *
+getdisklabel(const char *s, int fd)
+{
+       static struct disklabel lab;
+
+#ifdef __minix
+       if (s == NULL)
+               return NULL;
+       errexit("%s: can't read disk label under minix", s);
+#else
+       if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
+               if (s == NULL)
+                       return NULL;
+               pwarn("ioctl (GCINFO): %s\n", strerror(errno));
+               errexit("%s: can't read disk label", s);
+       }
+#endif
+       return &lab;
+}
+
+daddr_t
+cgoverhead(int c)
+{
+       int overh;
+       overh =
+           1 /* block bitmap */ +
+           1 /* inode bitmap */ +
+           sblock.e2fs_itpg;
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+           sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_SPARSESUPER) {
+               if (cg_has_sb(c) == 0)
+                       return overh;
+       }
+       overh += 1 /* superblock */ + sblock.e2fs_ngdb;
+       return overh;
+}
diff --git a/sbin/fsck_ext2fs/utilities.c b/sbin/fsck_ext2fs/utilities.c
new file mode 100644 (file)
index 0000000..1169378
--- /dev/null
@@ -0,0 +1,527 @@
+/*     $NetBSD: utilities.c,v 1.22 2011/06/09 19:57:51 christos Exp $  */
+
+/*
+ * Copyright (c) 1980, 1986, 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.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)utilities.c        8.1 (Berkeley) 6/5/93";
+#else
+__RCSID("$NetBSD: utilities.c,v 1.22 2011/06/09 19:57:51 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs_dir.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <ufs/ufs/dinode.h> /* for IFMT & friends */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "fsutil.h"
+#include "fsck.h"
+#include "extern.h"
+#include "exitvalues.h"
+
+long   diskreads, totalreads;  /* Disk cache statistics */
+
+static void rwerror(const char *, daddr_t);
+
+int
+ftypeok(struct ext2fs_dinode *dp)
+{
+       switch (fs2h16(dp->e2di_mode) & IFMT) {
+
+       case IFDIR:
+       case IFREG:
+       case IFBLK:
+       case IFCHR:
+       case IFLNK:
+       case IFSOCK:
+       case IFIFO:
+               return (1);
+
+       default:
+               if (debug)
+                       printf("bad file type 0%o\n", fs2h16(dp->e2di_mode));
+               return (0);
+       }
+}
+
+int
+reply(const char *question)
+{
+       int persevere;
+       char c;
+
+       if (preen)
+               pfatal("INTERNAL ERROR: GOT TO reply()");
+       persevere = !strcmp(question, "CONTINUE");
+       printf("\n");
+       if (!persevere && (nflag || fswritefd < 0)) {
+               printf("%s? no\n\n", question);
+               return (0);
+       }
+       if (yflag || (persevere && nflag)) {
+               printf("%s? yes\n\n", question);
+               return (1);
+       }
+       do      {
+               printf("%s? [yn] ", question);
+               (void) fflush(stdout);
+               c = getc(stdin);
+               while (c != '\n' && getc(stdin) != '\n')
+                       if (feof(stdin))
+                               return (0);
+       } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
+       printf("\n");
+       if (c == 'y' || c == 'Y')
+               return (1);
+       return (0);
+}
+
+/*
+ * Malloc buffers and set up cache.
+ */
+void
+bufinit(void)
+{
+       struct bufarea *bp;
+       long bufcnt, i;
+       char *bufp;
+
+       diskreads = totalreads = 0;
+       pbp = pdirbp = (struct bufarea *)0;
+       bufhead.b_next = bufhead.b_prev = &bufhead;
+       bufcnt = MAXBUFSPACE / sblock.e2fs_bsize;
+       if (bufcnt < MINBUFS)
+               bufcnt = MINBUFS;
+       for (i = 0; i < bufcnt; i++) {
+               bp = malloc(sizeof(struct bufarea));
+               bufp = malloc((size_t)sblock.e2fs_bsize);
+               if (bp == NULL || bufp == NULL) {
+                       free(bp);
+                       free(bufp);
+                       if (i >= MINBUFS)
+                               break;
+                       errexit("cannot allocate buffer pool");
+               }
+               bp->b_un.b_buf = bufp;
+               bp->b_prev = &bufhead;
+               bp->b_next = bufhead.b_next;
+               bufhead.b_next->b_prev = bp;
+               bufhead.b_next = bp;
+               initbarea(bp);
+       }
+       bufhead.b_size = i;     /* save number of buffers */
+}
+
+/*
+ * Manage a cache of directory blocks.
+ */
+struct bufarea *
+getdatablk(daddr_t blkno, long size)
+{
+       struct bufarea *bp;
+
+       for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
+               if (bp->b_bno == fsbtodb(&sblock, blkno))
+                       goto foundit;
+       for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
+               if ((bp->b_flags & B_INUSE) == 0)
+                       break;
+       if (bp == &bufhead)
+               errexit("deadlocked buffer pool");
+       getblk(bp, blkno, size);
+       diskreads++;
+       /* fall through */
+foundit:
+       totalreads++;
+       bp->b_prev->b_next = bp->b_next;
+       bp->b_next->b_prev = bp->b_prev;
+       bp->b_prev = &bufhead;
+       bp->b_next = bufhead.b_next;
+       bufhead.b_next->b_prev = bp;
+       bufhead.b_next = bp;
+       bp->b_flags |= B_INUSE;
+       return (bp);
+}
+
+void
+getblk(struct bufarea *bp, daddr_t blk, long size)
+{
+       daddr_t dblk;
+
+       dblk = fsbtodb(&sblock, blk);
+       if (bp->b_bno != dblk) {
+               flush(fswritefd, bp);
+               bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size);
+               bp->b_bno = dblk;
+               bp->b_size = size;
+       }
+}
+
+void
+flush(int fd, struct bufarea *bp)
+{
+       int i;
+
+       if (!bp->b_dirty)
+               return;
+       if (bp->b_errs != 0)
+               pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n",
+                   (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
+                   (long long)bp->b_bno);
+       bp->b_dirty = 0;
+       bp->b_errs = 0;
+       bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
+       if (bp != &sblk)
+               return;
+       for (i = 0; i < sblock.e2fs_ngdb; i++) {
+               bwrite(fswritefd, (char *)
+                       &sblock.e2fs_gd[i* sblock.e2fs_bsize / sizeof(struct ext2_gd)],
+                   fsbtodb(&sblock, ((sblock.e2fs_bsize>1024)?0:1)+i+1),
+                   sblock.e2fs_bsize);
+       }
+}
+
+static void
+rwerror(const char *mesg, daddr_t blk)
+{
+
+       if (preen == 0)
+               printf("\n");
+       pfatal("CANNOT %s: BLK %lld", mesg, (long long)blk);
+       if (reply("CONTINUE") == 0)
+               errexit("Program terminated");
+}
+
+void
+ckfini(int markclean)
+{
+       struct bufarea *bp, *nbp;
+       int cnt = 0;
+
+       if (fswritefd < 0) {
+               (void)close(fsreadfd);
+               return;
+       }
+       flush(fswritefd, &sblk);
+       if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
+           !preen && reply("UPDATE STANDARD SUPERBLOCKS")) {
+               sblk.b_bno = SBOFF / dev_bsize;
+               sbdirty();
+               flush(fswritefd, &sblk);
+               copyback_sb(&asblk);
+               asblk.b_dirty = 1;
+               flush(fswritefd, &asblk);
+       }
+       for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
+               cnt++;
+               flush(fswritefd, bp);
+               nbp = bp->b_prev;
+               free(bp->b_un.b_buf);
+               free(bp);
+       }
+       if (bufhead.b_size != cnt)
+               errexit("Panic: lost %d buffers", bufhead.b_size - cnt);
+       pbp = pdirbp = (struct bufarea *)0;
+       if (markclean && (sblock.e2fs.e2fs_state & E2FS_ISCLEAN) == 0) {
+               /*
+                * Mark the file system as clean, and sync the superblock.
+                */
+               if (preen)
+                       pwarn("MARKING FILE SYSTEM CLEAN\n");
+               else if (!reply("MARK FILE SYSTEM CLEAN"))
+                       markclean = 0;
+               if (markclean) {
+                       sblock.e2fs.e2fs_state = E2FS_ISCLEAN;
+                       sbdirty();
+                       flush(fswritefd, &sblk);
+               }
+       }
+       if (debug)
+               printf("cache missed %ld of %ld (%d%%)\n", diskreads,
+                   totalreads, (int)(diskreads * 100 / totalreads));
+       (void)close(fsreadfd);
+       (void)close(fswritefd);
+}
+
+int
+bread(int fd, char *buf, daddr_t blk, long size)
+{
+       char *cp;
+       int i, errs;
+#ifndef __minix
+       off_t offset;
+#else
+       u64_t offset;
+#endif
+
+       offset = blk;
+       offset *= dev_bsize;
+#ifndef __minix
+       if (lseek(fd, offset, 0) < 0)
+               rwerror("SEEK", blk);
+#else
+       if (lseek64(fd, offset, 0, NULL) < 0)
+               rwerror("SEEK", blk);
+#endif
+       else if (read(fd, buf, (int)size) == size)
+               return (0);
+       rwerror("READ", blk);
+#ifndef __minix
+       if (lseek(fd, offset, 0) < 0)
+               rwerror("SEEK", blk);
+#else
+       if (lseek64(fd, offset, 0, NULL) < 0)
+               rwerror("SEEK", blk);
+#endif
+       errs = 0;
+       memset(buf, 0, (size_t)size);
+       printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
+       for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
+               if (read(fd, cp, (int)secsize) != secsize) {
+                       (void)lseek(fd, offset + i + secsize, 0);
+                       if (secsize != dev_bsize && dev_bsize != 1)
+                               printf(" %lld (%lld),",
+                                   (long long)((blk*dev_bsize + i) / secsize),
+                                   (long long)(blk + i / dev_bsize));
+                       else
+                               printf(" %lld,", (long long)(blk +
+                                                       i / dev_bsize));
+                       errs++;
+               }
+       }
+       printf("\n");
+       return (errs);
+}
+
+void
+bwrite(int fd, char *buf, daddr_t blk, long size)
+{
+       int i;
+       char *cp;
+#ifndef __minix
+       off_t offset;
+#else
+       u64_t offset;
+#endif
+
+       if (fd < 0)
+               return;
+       offset = blk;
+       offset *= dev_bsize;
+#ifndef __minix
+       if (lseek(fd, offset, 0) < 0)
+               rwerror("SEEK", blk);
+#else
+       if (lseek64(fd, offset, 0, NULL) < 0)
+               rwerror("SEEK", blk);
+#endif
+       else if (write(fd, buf, (int)size) == size) {
+               fsmodified = 1;
+               return;
+       }
+       rwerror("WRITE", blk);
+#ifndef __minix
+       if (lseek(fd, offset, 0) < 0)
+               rwerror("SEEK", blk);
+#else
+       if (lseek64(fd, offset, 0, NULL) < 0)
+               rwerror("SEEK", blk);
+#endif
+       printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
+       for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
+               if (write(fd, cp, (int)dev_bsize) != dev_bsize) {
+                       (void)lseek(fd, offset + i + dev_bsize, 0);
+                       printf(" %lld,", (long long)(blk + i / dev_bsize));
+               }
+       printf("\n");
+       return;
+}
+
+/*
+ * allocate a data block
+ */
+int
+allocblk(void)
+{
+       int i;
+
+       for (i = 0; i < maxfsblock - 1; i++) {
+               if (testbmap(i))
+                               continue;
+               setbmap(i);
+               n_blks++;
+               return (i);
+       }
+       return (0);
+}
+
+/*
+ * Free a previously allocated block
+ */
+void
+freeblk(daddr_t blkno)
+{
+       struct inodesc idesc;
+
+       idesc.id_blkno = blkno;
+       idesc.id_numfrags = 1;
+       (void)pass4check(&idesc);
+}
+
+/*
+ * Find a pathname
+ */
+void
+getpathname(char *namebuf, size_t namebuflen, ino_t curdir, ino_t ino)
+{
+       int len;
+       char *cp;
+       struct inodesc idesc;
+       static int busy = 0;
+
+       if (curdir == ino && ino == EXT2_ROOTINO) {
+               (void)strlcpy(namebuf, "/", namebuflen);
+               return;
+       }
+       if (busy ||
+           (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) {
+               (void)strlcpy(namebuf, "?", namebuflen);
+               return;
+       }
+       busy = 1;
+       memset(&idesc, 0, sizeof(struct inodesc));
+       idesc.id_type = DATA;
+       idesc.id_fix = IGNORE;
+       cp = &namebuf[MAXPATHLEN - 1];
+       *cp = '\0';
+       if (curdir != ino) {
+               idesc.id_parent = curdir;
+               goto namelookup;
+       }
+       while (ino != EXT2_ROOTINO) {
+               idesc.id_number = ino;
+               idesc.id_func = findino;
+               idesc.id_name = "..";
+               if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
+                       break;
+       namelookup:
+               idesc.id_number = idesc.id_parent;
+               idesc.id_parent = ino;
+               idesc.id_func = findname;
+               idesc.id_name = namebuf;
+               if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
+                       break;
+               len = strlen(namebuf);
+               cp -= len;
+               memcpy(cp, namebuf, (size_t)len);
+               *--cp = '/';
+               if (cp < &namebuf[EXT2FS_MAXNAMLEN])
+                       break;
+               ino = idesc.id_number;
+       }
+       busy = 0;
+       if (ino != EXT2_ROOTINO)
+               *--cp = '?';
+       memcpy(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp));
+}
+
+/*
+ * determine whether an inode should be fixed.
+ */
+int
+dofix(struct inodesc *idesc, const char *msg)
+{
+
+       switch (idesc->id_fix) {
+
+       case DONTKNOW:
+               if (idesc->id_type == DATA)
+                       direrror(idesc->id_number, msg);
+               else
+                       pwarn("%s", msg);
+               if (preen) {
+                       printf(" (SALVAGED)\n");
+                       idesc->id_fix = FIX;
+                       return (ALTERED);
+               }
+               if (reply("SALVAGE") == 0) {
+                       idesc->id_fix = NOFIX;
+                       return (0);
+               }
+               idesc->id_fix = FIX;
+               return (ALTERED);
+
+       case FIX:
+               return (ALTERED);
+
+       case NOFIX:
+       case IGNORE:
+               return (0);
+
+       default:
+               errexit("UNKNOWN INODESC FIX MODE %d", idesc->id_fix);
+       }
+       /* NOTREACHED */
+}
diff --git a/sbin/newfs_ext2fs/Makefile b/sbin/newfs_ext2fs/Makefile
new file mode 100644 (file)
index 0000000..7c426ab
--- /dev/null
@@ -0,0 +1,27 @@
+#      $NetBSD: Makefile,v 1.3 2009/06/05 21:52:31 haad Exp $
+#      @(#)Makefile    8.2 (Berkeley) 3/27/94
+
+WARNS?=        3       # XXX: sign-compare issues
+
+.include <bsd.own.mk>
+
+PROG=  newfs_ext2fs
+SRCS=  newfs_ext2fs.c mke2fs.c ext2fs_bswap.c partutil.c
+MAN=   newfs_ext2fs.8
+
+FSCK=${NETBSDSRCDIR}/sbin/fsck
+MYFSCK=${NETBSDSRCDIR}/sbin/fsck_ext2fs
+CPPFLAGS+=-I${.CURDIR} -I${FSCK}
+
+DPADD+= ${LIBUTIL}
+LDADD+= -lutil
+
+LDADD+=-lprop
+DPADD+=${LIBPROP}
+
+SYMLINKS+= $(BINDIR)/$(PROG)  $(BINDIR)/newfs_ext2 \
+       $(BINDIR)/$(PROG)  $(BINDIR)/mkfs.ext2
+
+.PATH: ${FSCK} ${MYFSCK} #${NETBSDSRCDIR}/sys/ufs/ext2fs 
+
+.include <bsd.prog.mk>
diff --git a/sbin/newfs_ext2fs/extern.h b/sbin/newfs_ext2fs/extern.h
new file mode 100644 (file)
index 0000000..809bd6f
--- /dev/null
@@ -0,0 +1,45 @@
+/*     $NetBSD: extern.h,v 1.4 2009/10/21 01:07:46 snj Exp $   */
+
+/*
+ * Copyright (c) 1997 Christos Zoulas.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/* XXX should be in <sys/ufs/ext2fs.h> */
+#define EXT2_LOG_MAXBSIZE      12
+#define EXT2_MAXBSIZE          (1 << EXT2_LOG_MAXBSIZE)
+
+/* prototypes */
+void mke2fs(const char *, int, int);
+
+/* variables set up by front end. */
+extern int     Nflag;          /* run mkfs without writing file system */
+extern int     Oflag;          /* format as an 4.3BSD file system */
+extern int     verbosity;      /* amount of printf() output */
+extern int64_t fssize;         /* file system size */
+extern uint16_t        inodesize;      /* bytes per inode */
+extern uint    sectorsize;     /* sector size */
+extern uint    fsize;          /* fragment size */
+extern uint    bsize;          /* block size */
+extern uint    minfree;        /* free space threshold */
+extern uint    num_inodes;     /* number of inodes (overrides density) */
+extern char    *volname;       /* volume name */
diff --git a/sbin/newfs_ext2fs/mke2fs.c b/sbin/newfs_ext2fs/mke2fs.c
new file mode 100644 (file)
index 0000000..5ecb882
--- /dev/null
@@ -0,0 +1,1459 @@
+/*     $NetBSD: mke2fs.c,v 1.14 2010/09/10 15:51:20 tsutsui Exp $      */
+
+/*-
+ * Copyright (c) 2007 Izumi Tsutsui.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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) 1980, 1989, 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.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/* mmap/munmap are used in this file just to allocate/free memory
+ * so these functions are ok.
+ */
+#define mmap minix_mmap
+#define munmap minix_munmap
+
+/*
+ * mke2fs.c: "re-invent (dumb but non-GPLed) wheel as a fun project"
+ *
+ *     In spite of this name, there is no piece of code
+ *     derived from GPLed e2fsprogs written for Linux.
+ *     I referred them only to see how each structure
+ *     member should be initialized.
+ *
+ * Reference:
+ *     - All NetBSD sources under src/sys/ufs/ext2fs and src/sbin/fsck_ext2fs
+ *     - Ext2fs Home Page
+ *             http://e2fsprogs.sourceforge.net/ext2.html
+ *     - Design and Implementation of the Second Extended Filesystem
+ *             http://e2fsprogs.sourceforge.net/ext2intro.html
+ *     - Linux Documentation "The Second Extended Filesystem"
+ *             http://www.kernel.org/doc/Documentation/filesystems/ext2.txt
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mkfs.c     8.11 (Berkeley) 5/3/95";
+#else
+__RCSID("$NetBSD: mke2fs.c,v 1.14 2010/09/10 15:51:20 tsutsui Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+#include <ufs/ext2fs/ext2fs_dir.h>
+#include <ufs/ext2fs/ext2fs.h>
+#include <sys/ioctl.h>
+
+#define _MINIX
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <uuid.h>
+#include <assert.h>
+#include <minix/termios.h>
+
+#include "extern.h"
+
+static void initcg(uint);
+static void zap_old_sblock(daddr_t);
+static uint cgoverhead(uint);
+static int fsinit(const struct timeval *);
+static int makedir(struct ext2fs_direct *, int);
+static void copy_dir(struct ext2fs_direct *, struct ext2fs_direct *);
+static void init_resizeino(const struct timeval *);
+static uint32_t alloc(uint32_t, uint16_t);
+static void iput(struct ext2fs_dinode *, ino_t);
+static void rdfs(daddr_t, int, void *);
+static void wtfs(daddr_t, int, void *);
+static int ilog2(uint);
+static int skpc(int, size_t, uint8_t *);
+
+/* XXX: some of these macro should be into <ufs/ext2fs/ext2fs.h>? */
+#define EXT2_DEF_MAX_MNT_COUNT 20
+#define EXT2_DEF_FSCKINTV      (180 * 24 * 60 * 60)    /* 180 days */
+#define EXT2_RESERVED_INODES   (EXT2_FIRSTINO - 1)
+#define EXT2_UMASK             0755
+
+#define EXT2_INO_INDEX(ino)    ((ino) - 1)             /* no inode zero */
+
+#define EXT2_LOSTFOUNDSIZE     16384
+#define EXT2_LOSTFOUNDINO      EXT2_FIRSTINO           /* XXX: not quite */
+#define EXT2_LOSTFOUNDUMASK    0700
+
+#define EXT2_RESIZEINOUMASK    0600
+
+#define NBLOCK_SUPERBLOCK      1
+#define NBLOCK_BLOCK_BITMAP    1
+#define NBLOCK_INODE_BITMAP    1
+
+#define cgbase(fs, c)  \
+       ((fs)->e2fs.e2fs_first_dblock + (fs)->e2fs.e2fs_bpg * (c))
+
+
+/*
+ * ext2fs super block and group descriptor structures
+ *
+ *   We don't have to use or setup whole in-memory m_ext2fs structure,
+ *   but prepare it to use several macro defined in kernel headers.
+ */
+union {
+       struct m_ext2fs m_ext2fs;
+       char pad[SBSIZE];
+} ext2fsun;
+#define sblock ext2fsun.m_ext2fs
+#define gd     ext2fsun.m_ext2fs.e2fs_gd
+
+static uint8_t *iobuf;         /* for superblock and group descriptors */
+static int iobufsize;
+
+static uint8_t buf[MAXBSIZE];  /* for initcg() and makedir() ops */
+
+static int fsi = -1, fso = -1;
+
+void
+mke2fs(const char *fsys, int fi, int fo)
+{
+       struct timeval tv;
+       int64_t minfssize;
+       uint bcount, fbcount, ficount;
+       uint blocks_gd, blocks_per_cg, inodes_per_cg, iblocks_per_cg;
+       uint minblocks_per_cg, blocks_lastcg;
+       uint ncg, cylno, sboff;
+       uuid_t uuid;
+       uint32_t uustat;
+       int i, len, col, delta, fld_width, max_cols;
+       struct winsize winsize;
+
+       gettimeofday(&tv, NULL);
+       fsi = fi;
+       fso = fo;
+
+       /*
+        * collect and verify the block and fragment sizes
+        */
+       if (!powerof2(bsize)) {
+               errx(EXIT_FAILURE,
+                   "block size must be a power of 2, not %u\n",
+                   bsize);
+       }
+       if (!powerof2(fsize)) {
+               errx(EXIT_FAILURE,
+                   "fragment size must be a power of 2, not %u\n",
+                   fsize);
+       }
+       if (fsize < sectorsize) {
+               errx(EXIT_FAILURE,
+                   "fragment size %u is too small, minimum is %u\n",
+                   fsize, sectorsize);
+       }
+       if (bsize < MINBSIZE) {
+               errx(EXIT_FAILURE,
+                   "block size %u is too small, minimum is %u\n",
+                   bsize, MINBSIZE);
+       }
+       if (bsize > EXT2_MAXBSIZE) {
+               errx(EXIT_FAILURE,
+                   "block size %u is too large, maximum is %u\n",
+                   bsize, MAXBSIZE);
+       }
+       if (bsize != fsize) {
+               /*
+                * There is no fragment support on current ext2fs (yet?),
+                * but some kernel code refers fsize or fpg as bsize or bpg
+                * and Linux seems to set the same values to them.
+                */
+               errx(EXIT_FAILURE,
+                   "block size (%u) can't be different from "
+                   "fragment size (%u)\n",
+                   bsize, fsize);
+       }
+
+       /* variable inodesize is REV1 feature */
+       if (Oflag == 0 && inodesize != EXT2_REV0_DINODE_SIZE) {
+               errx(EXIT_FAILURE, "GOOD_OLD_REV file system format"
+                   " doesn't support %d byte inode\n", inodesize);
+       }
+
+       sblock.e2fs.e2fs_log_bsize = ilog2(bsize) - LOG_MINBSIZE;
+       /* Umm, why not e2fs_log_fsize? */
+       sblock.e2fs.e2fs_fsize = ilog2(fsize) - LOG_MINBSIZE;
+
+       sblock.e2fs_bsize = bsize;
+       sblock.e2fs_bshift = sblock.e2fs.e2fs_log_bsize + LOG_MINBSIZE;
+       sblock.e2fs_qbmask = sblock.e2fs_bsize - 1;
+       sblock.e2fs_bmask = ~sblock.e2fs_qbmask;
+       sblock.e2fs_fsbtodb = ilog2(sblock.e2fs_bsize) - ilog2(sectorsize);
+       sblock.e2fs_ipb = sblock.e2fs_bsize / inodesize;
+
+       /*
+        * Ext2fs preserves BBSIZE (1024 bytes) space at the top for
+        * bootloader (though it is not enough at all for our bootloader).
+        * If bsize == BBSIZE we have to preserve one block.
+        * If bsize > BBSIZE, the first block already contains BBSIZE space
+        * before superblock because superblock is allocated at SBOFF and
+        * bsize is a power of two (i.e. 2048 bytes or more).
+        */
+       sblock.e2fs.e2fs_first_dblock = (sblock.e2fs_bsize > BBSIZE) ? 0 : 1;
+       minfssize = fsbtodb(&sblock,
+           sblock.e2fs.e2fs_first_dblock +
+           NBLOCK_SUPERBLOCK +
+           1 /* at least one group descriptor */ +
+           NBLOCK_BLOCK_BITMAP +
+           NBLOCK_INODE_BITMAP +
+           1 /* at least one inode table block */ +
+           1 /* at least one data block for rootdir */ +
+           1 /* at least one data block for data */
+           );                  /* XXX and more? */
+
+       if (fssize < minfssize)
+               errx(EXIT_FAILURE, "Filesystem size %" PRId64
+                   " < minimum size of %" PRId64 "\n", fssize, minfssize);
+
+       bcount = dbtofsb(&sblock, fssize);
+
+       /*
+        * While many people claim that ext2fs is a (bad) clone of ufs/ffs,
+        * it isn't actual ffs so maybe we should call it "block group"
+        * as their native name rather than ffs derived "cylinder group."
+        * But we'll use the latter here since other kernel sources use it.
+        * (I also agree "cylinder" based allocation is obsolete though)
+        */
+
+       /* maybe "simple is the best" */
+       blocks_per_cg = sblock.e2fs_bsize * NBBY;
+
+       ncg = howmany(bcount - sblock.e2fs.e2fs_first_dblock, blocks_per_cg);
+       blocks_gd = howmany(sizeof(struct ext2_gd) * ncg, bsize);
+
+       /* check range of inode number */
+       if (num_inodes < EXT2_FIRSTINO)
+               num_inodes = EXT2_FIRSTINO;     /* needs reserved inodes + 1 */
+       if (num_inodes > UINT16_MAX * ncg)
+               num_inodes = UINT16_MAX * ncg;  /* ext2bgd_nifree is uint16_t */
+
+       inodes_per_cg = num_inodes / ncg;
+       iblocks_per_cg = howmany(inodesize * inodes_per_cg, bsize);
+
+       /* Check that the last cylinder group has enough space for inodes */
+       minblocks_per_cg =
+           NBLOCK_BLOCK_BITMAP +
+           NBLOCK_INODE_BITMAP +
+           iblocks_per_cg +
+           1;  /* at least one data block */
+       if (Oflag == 0 || cg_has_sb(ncg - 1) != 0)
+               minblocks_per_cg += NBLOCK_SUPERBLOCK + blocks_gd;
+
+       blocks_lastcg = bcount - sblock.e2fs.e2fs_first_dblock -
+           blocks_per_cg * (ncg - 1);
+       if (blocks_lastcg < minblocks_per_cg) {
+               /*
+                * Since we make all the cylinder groups the same size, the
+                * last will only be small if there are more than one
+                * cylinder groups. If the last one is too small to store
+                * filesystem data, just kill it.
+                *
+                * XXX: Does fsck_ext2fs(8) properly handle this case?
+                */
+               bcount -= blocks_lastcg;
+               ncg--;
+               blocks_lastcg = blocks_per_cg;
+               blocks_gd = howmany(sizeof(struct ext2_gd) * ncg, bsize);
+               inodes_per_cg = num_inodes / ncg;
+       }
+       /* roundup inodes_per_cg to make it use whole inode table blocks */
+       inodes_per_cg = roundup(inodes_per_cg, sblock.e2fs_ipb);
+       num_inodes = inodes_per_cg * ncg;
+       iblocks_per_cg = inodes_per_cg / sblock.e2fs_ipb;
+
+       /* XXX: probably we should check these adjusted values again */
+
+       sblock.e2fs.e2fs_bcount = bcount;
+       sblock.e2fs.e2fs_icount = num_inodes;
+
+       sblock.e2fs_ncg = ncg;
+       sblock.e2fs_ngdb = blocks_gd;
+       sblock.e2fs_itpg = iblocks_per_cg;
+
+       sblock.e2fs.e2fs_rbcount = sblock.e2fs.e2fs_bcount * minfree / 100;
+       /* e2fs_fbcount will be accounted later */
+       /* e2fs_ficount will be accounted later */
+
+       sblock.e2fs.e2fs_bpg = blocks_per_cg;
+       sblock.e2fs.e2fs_fpg = blocks_per_cg;
+
+       sblock.e2fs.e2fs_ipg = inodes_per_cg;
+
+       sblock.e2fs.e2fs_mtime = 0;
+       sblock.e2fs.e2fs_wtime = tv.tv_sec;
+       sblock.e2fs.e2fs_mnt_count = 0;
+       /* XXX: should add some entropy to avoid checking all fs at once? */
+       sblock.e2fs.e2fs_max_mnt_count = EXT2_DEF_MAX_MNT_COUNT;
+
+       sblock.e2fs.e2fs_magic = E2FS_MAGIC;
+       sblock.e2fs.e2fs_state = E2FS_ISCLEAN;
+       sblock.e2fs.e2fs_beh = E2FS_BEH_DEFAULT;
+       sblock.e2fs.e2fs_minrev = 0;
+       sblock.e2fs.e2fs_lastfsck = tv.tv_sec;
+       sblock.e2fs.e2fs_fsckintv = EXT2_DEF_FSCKINTV;
+
+       /*
+        * Maybe we can use E2FS_OS_FREEBSD here and it would be more proper,
+        * but the purpose of this newfs_ext2fs(8) command is to provide
+        * a filesystem which can be recognized by firmware on some
+        * Linux based appliances that can load bootstrap files only from
+        * (their native) ext2fs, and anyway we will (and should) try to
+        * act like them as much as possible.
+        *
+        * Anyway, I hope that all newer such boxes will keep their support
+        * for the "GOOD_OLD_REV" ext2fs.
+        */
+       sblock.e2fs.e2fs_creator = E2FS_OS_LINUX;
+
+       if (Oflag == 0) {
+               sblock.e2fs.e2fs_rev = E2FS_REV0;
+               sblock.e2fs.e2fs_features_compat   = 0;
+               sblock.e2fs.e2fs_features_incompat = 0;
+               sblock.e2fs.e2fs_features_rocompat = 0;
+       } else {
+               sblock.e2fs.e2fs_rev = E2FS_REV1;
+               /*
+                * e2fsprogs say "REV1" is "dynamic" so
+                * it isn't quite a version and maybe it means
+                * "extended from REV0 so check compat features."
+                *
+                * XXX: We don't have any native tool to activate
+                *      the EXT2F_COMPAT_RESIZE feature and
+                *      fsck_ext2fs(8) might not fix structures for it.
+                */
+               sblock.e2fs.e2fs_features_compat   = EXT2F_COMPAT_RESIZE;
+               sblock.e2fs.e2fs_features_incompat = EXT2F_INCOMPAT_FTYPE;
+               sblock.e2fs.e2fs_features_rocompat =
+                   EXT2F_ROCOMPAT_SPARSESUPER | EXT2F_ROCOMPAT_LARGEFILE;
+       }
+
+       sblock.e2fs.e2fs_ruid = geteuid();
+       sblock.e2fs.e2fs_rgid = getegid();
+
+       sblock.e2fs.e2fs_first_ino = EXT2_FIRSTINO;
+       sblock.e2fs.e2fs_inode_size = inodesize;
+
+       /* e2fs_block_group_nr is set on writing superblock to each group */
+
+       uuid_create(&uuid, &uustat);
+       if (uustat != uuid_s_ok)
+               errx(EXIT_FAILURE, "Failed to generate uuid\n");
+       uuid_enc_le(sblock.e2fs.e2fs_uuid, &uuid);
+       if (volname != NULL) {
+               if (strlen(volname) > sizeof(sblock.e2fs.e2fs_vname))
+                       errx(EXIT_FAILURE, "Volume name is too long");
+               strlcpy(sblock.e2fs.e2fs_vname, volname,
+                   sizeof(sblock.e2fs.e2fs_vname));
+       }
+
+       sblock.e2fs.e2fs_fsmnt[0] = '\0';
+       sblock.e2fs_fsmnt[0] = '\0';
+
+       sblock.e2fs.e2fs_algo = 0;              /* XXX unsupported? */
+       sblock.e2fs.e2fs_prealloc = 0;          /* XXX unsupported? */
+       sblock.e2fs.e2fs_dir_prealloc = 0;      /* XXX unsupported? */
+
+       /* calculate blocks for reserved group descriptors for resize */
+       sblock.e2fs.e2fs_reserved_ngdb = 0;
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+           (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0) {
+               uint64_t target_blocks;
+               uint target_ncg, target_ngdb, reserved_ngdb;
+
+               /* reserve descriptors for size as 1024 times as current */
+               target_blocks =
+                   (sblock.e2fs.e2fs_bcount - sblock.e2fs.e2fs_first_dblock)
+                   * 1024ULL;
+               /* number of blocks must be in uint32_t */
+               if (target_blocks > UINT32_MAX)
+                       target_blocks = UINT32_MAX;
+               target_ncg = howmany(target_blocks, sblock.e2fs.e2fs_bpg);
+               target_ngdb = howmany(sizeof(struct ext2_gd) * target_ncg,
+                   sblock.e2fs_bsize);
+               /*
+                * Reserved group descriptor blocks are preserved as
+                * the second level double indirect reference blocks in
+                * the EXT2_RESIZEINO inode, so the maximum number of
+                * the blocks is NINDIR(fs).
+                * (see also descriptions in init_resizeino() function)
+                *
+                * We check a number including current e2fs_ngdb here
+                * because they will be moved into reserved gdb on
+                * possible future size shrink, though e2fsprogs don't
+                * seem to care about it.
+                */
+               if (target_ngdb > NINDIR(&sblock))
+                       target_ngdb = NINDIR(&sblock);
+
+               reserved_ngdb = target_ngdb - sblock.e2fs_ngdb;
+
+               /* make sure reserved_ngdb fits in the last cg */
+               if (reserved_ngdb >= blocks_lastcg - cgoverhead(ncg - 1))
+                       reserved_ngdb = blocks_lastcg - cgoverhead(ncg - 1);
+               if (reserved_ngdb == 0) {
+                       /* if no space for reserved gdb, disable the feature */
+                       sblock.e2fs.e2fs_features_compat &=
+                           ~EXT2F_COMPAT_RESIZE;
+               }
+               sblock.e2fs.e2fs_reserved_ngdb = reserved_ngdb;
+       }
+
+       /*
+        * Initialize group descriptors
+        */
+       gd = malloc(sblock.e2fs_ngdb * bsize);
+       if (gd == NULL)
+               errx(EXIT_FAILURE, "Can't allocate descriptors buffer");
+       memset(gd, 0, sblock.e2fs_ngdb * bsize);
+
+       fbcount = 0;
+       ficount = 0;
+       for (cylno = 0; cylno < ncg; cylno++) {
+               uint boffset;
+
+               boffset = cgbase(&sblock, cylno);
+               if (sblock.e2fs.e2fs_rev == E2FS_REV0 ||
+                   (sblock.e2fs.e2fs_features_rocompat &
+                    EXT2F_ROCOMPAT_SPARSESUPER) == 0 ||
+                   cg_has_sb(cylno)) {
+                       boffset += NBLOCK_SUPERBLOCK + sblock.e2fs_ngdb;
+                       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+                           (sblock.e2fs.e2fs_features_compat &
+                            EXT2F_COMPAT_RESIZE) != 0)
+                               boffset += sblock.e2fs.e2fs_reserved_ngdb;
+               }
+               gd[cylno].ext2bgd_b_bitmap = boffset;
+               boffset += NBLOCK_BLOCK_BITMAP;
+               gd[cylno].ext2bgd_i_bitmap = boffset;
+               boffset += NBLOCK_INODE_BITMAP;
+               gd[cylno].ext2bgd_i_tables = boffset;
+               if (cylno == (ncg - 1))
+                       gd[cylno].ext2bgd_nbfree =
+                           blocks_lastcg - cgoverhead(cylno);
+               else
+                       gd[cylno].ext2bgd_nbfree =
+                           sblock.e2fs.e2fs_bpg - cgoverhead(cylno);
+               fbcount += gd[cylno].ext2bgd_nbfree;
+               gd[cylno].ext2bgd_nifree = sblock.e2fs.e2fs_ipg;
+               if (cylno == 0) {
+                       /* take reserved inodes off nifree */
+                       gd[cylno].ext2bgd_nifree -= EXT2_RESERVED_INODES;
+               }
+               ficount += gd[cylno].ext2bgd_nifree;
+               gd[cylno].ext2bgd_ndirs = 0;
+       }
+       sblock.e2fs.e2fs_fbcount = fbcount;
+       sblock.e2fs.e2fs_ficount = ficount;
+
+       /*
+        * Dump out summary information about file system.
+        */
+       if (verbosity > 0) {
+               printf("%s: %u.%1uMB (%" PRId64 " sectors) "
+                   "block size %u, fragment size %u\n",
+                   fsys,
+                   (uint)(((uint64_t)bcount * bsize) / (1024 * 1024)),
+                   (uint)((uint64_t)bcount * bsize -
+                   rounddown((uint64_t)bcount * bsize, 1024 * 1024))
+                   / 1024 / 100,
+                   fssize, bsize, fsize);
+               printf("\tusing %u block groups of %u.0MB, %u blks, "
+                   "%u inodes.\n",
+                   ncg, bsize * sblock.e2fs.e2fs_bpg / (1024 * 1024),
+                   sblock.e2fs.e2fs_bpg, sblock.e2fs.e2fs_ipg);
+       }
+
+       /*
+        * allocate space for superblock and group descriptors
+        */
+       iobufsize = (NBLOCK_SUPERBLOCK + sblock.e2fs_ngdb) * sblock.e2fs_bsize;
+       iobuf = mmap(0, iobufsize, PROT_READ|PROT_WRITE,
+           MAP_ANON|MAP_PRIVATE, -1, 0);
+       if (iobuf == NULL)
+               errx(EXIT_FAILURE, "Cannot allocate I/O buffer\n");
+       memset(iobuf, 0, iobufsize);
+
+       /*
+        * We now start writing to the filesystem
+        */
+
+       if (!Nflag) {
+               static const uint pbsize[] = { 1024, 2048, 4096, 0 };
+               uint pblock, epblock;
+               /*
+                * Validate the given file system size.
+                * Verify that its last block can actually be accessed.
+                * Convert to file system fragment sized units.
+                */
+               if (fssize <= 0)
+                       errx(EXIT_FAILURE, "Preposterous size %" PRId64 "\n",
+                           fssize);
+               wtfs(fssize - 1, sectorsize, iobuf);
+
+               /*
+                * Ensure there is nothing that looks like a filesystem
+                * superblock anywhere other than where ours will be.
+                * If fsck_ext2fs finds the wrong one all hell breaks loose!
+                *
+                * XXX: needs to check how fsck_ext2fs programs even
+                *      on other OSes determine alternate superblocks
+                */
+               for (i = 0; pbsize[i] != 0; i++) {
+                       epblock = (uint64_t)bcount * bsize / pbsize[i];
+                       for (pblock = ((pbsize[i] == SBSIZE) ? 1 : 0);
+                           pblock < epblock;
+                           pblock += pbsize[i] * NBBY /* bpg */)
+                               zap_old_sblock((daddr_t)pblock *
+                                   pbsize[i] / sectorsize);
+               }
+       }
+
+       if (verbosity >= 3)
+               printf("super-block backups (for fsck_ext2fs -b #) at:\n");
+       /* If we are printing more than one line of numbers, line up columns */
+       fld_width = verbosity < 4 ? 1 : snprintf(NULL, 0, "%" PRIu64,
+           (uint64_t)cgbase(&sblock, ncg - 1));
+       /* Get terminal width */
+       if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) == 0)
+               max_cols = winsize.ws_col;
+       else
+               max_cols = 80;
+       if (Nflag && verbosity == 3)
+               /* Leave space to add " ..." after one row of numbers */
+               max_cols -= 4;
+#define BASE 0x10000   /* For some fixed-point maths */
+       col = 0;
+       delta = verbosity > 2 ? 0 : max_cols * BASE / ncg;
+       for (cylno = 0; cylno < ncg; cylno++) {
+               fflush(stdout);
+               initcg(cylno);
+               if (verbosity < 2)
+                       continue;
+               /* the first one is a master, not backup */
+               if (cylno == 0)
+                       continue;
+               /* skip if this cylinder doesn't have a backup */
+               if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+                   (sblock.e2fs.e2fs_features_rocompat &
+                    EXT2F_ROCOMPAT_SPARSESUPER) != 0 &&
+                   cg_has_sb(cylno) == 0)
+                       continue;
+
+               if (delta > 0) {
+                       if (Nflag)
+                               /* No point doing dots for -N */
+                               break;
+                       /* Print dots scaled to end near RH margin */
+                       for (col += delta; col > BASE; col -= BASE)
+                               printf(".");
+                       continue;
+               }
+               /* Print superblock numbers */
+               len = printf(" %*" PRIu64 "," + !col, fld_width,
+                   (uint64_t)cgbase(&sblock, cylno));
+               col += len;
+               if (col + len < max_cols)
+                       /* Next number fits */
+                       continue;
+               /* Next number won't fit, need a newline */
+               if (verbosity <= 3) {
+                       /* Print dots for subsequent cylinder groups */
+                       delta = sblock.e2fs_ncg - cylno - 1;
+                       if (delta != 0) {
+                               if (Nflag) {
+                                       printf(" ...");
+                                       break;
+                               }
+                               delta = max_cols * BASE / delta;
+                       }
+               }
+               col = 0;
+               printf("\n");
+       }
+#undef BASE
+       if (col > 0)
+               printf("\n");
+       if (Nflag)
+               return;
+
+       /*
+        * Now construct the initial file system,
+        */
+       if (fsinit(&tv) == 0)
+               errx(EXIT_FAILURE, "Error making filesystem");
+       /*
+        * Write out the superblock and group descriptors
+        */
+       sblock.e2fs.e2fs_block_group_nr = 0;
+       sboff = 0;
+       if (cgbase(&sblock, 0) == 0) {
+               /*
+                * If the first block contains the boot block sectors,
+                * (i.e. in case of sblock.e2fs.e2fs_bsize > BBSIZE)
+                * we have to preserve data in it.
+                */
+               sboff = SBOFF;
+       }
+       e2fs_sbsave(&sblock.e2fs, (struct ext2fs *)(iobuf + sboff));
+       e2fs_cgsave(gd, (struct ext2_gd *)(iobuf + sblock.e2fs_bsize),
+          sizeof(struct ext2_gd) * sblock.e2fs_ncg);
+       wtfs(fsbtodb(&sblock, cgbase(&sblock, 0)) + sboff / sectorsize,
+           iobufsize - sboff, iobuf + sboff);
+
+       munmap(iobuf, iobufsize);
+}
+
+/*
+ * Initialize a cylinder (block) group.
+ */
+void
+initcg(uint cylno)
+{
+       uint nblcg, i, j, sboff;
+       struct ext2fs_dinode *dp;
+
+       /*
+        * Make a copy of the superblock and group descriptors.
+        */
+       if (sblock.e2fs.e2fs_rev == E2FS_REV0 ||
+           (sblock.e2fs.e2fs_features_rocompat &
+            EXT2F_ROCOMPAT_SPARSESUPER) == 0 ||
+           cg_has_sb(cylno)) {
+               sblock.e2fs.e2fs_block_group_nr = cylno;
+               sboff = 0;
+               if (cgbase(&sblock, cylno) == 0) {
+                       /* preserve data in bootblock in cg0 */
+                       sboff = SBOFF;
+               }
+               e2fs_sbsave(&sblock.e2fs, (struct ext2fs *)(iobuf + sboff));
+               e2fs_cgsave(gd, (struct ext2_gd *)(iobuf +
+                   sblock.e2fs_bsize * NBLOCK_SUPERBLOCK),
+                   sizeof(struct ext2_gd) * sblock.e2fs_ncg);
+               /* write superblock and group descriptor backups */
+               wtfs(fsbtodb(&sblock, cgbase(&sblock, cylno)) +
+                   sboff / sectorsize, iobufsize - sboff, iobuf + sboff);
+       }
+
+       /*
+        * Initialize block bitmap.
+        */
+       memset(buf, 0, sblock.e2fs_bsize);
+       if (cylno == (sblock.e2fs_ncg - 1)) {
+               /* The last group could have less blocks than e2fs_bpg. */
+               nblcg = sblock.e2fs.e2fs_bcount -
+                   cgbase(&sblock, sblock.e2fs_ncg - 1);
+               for (i = nblcg; i < roundup(nblcg, NBBY); i++)
+                       setbit(buf, i);
+               memset(&buf[i / NBBY], ~0U, sblock.e2fs.e2fs_bpg - i);
+       }
+       /* set overhead (superblock, group descriptor etc.) blocks used */
+       for (i = 0; i < cgoverhead(cylno) / NBBY; i++)
+               buf[i] = ~0;
+       i = i * NBBY;
+       for (; i < cgoverhead(cylno); i++)
+               setbit(buf, i);
+       wtfs(fsbtodb(&sblock, gd[cylno].ext2bgd_b_bitmap), sblock.e2fs_bsize,
+           buf);
+
+       /*
+        * Initialize inode bitmap.
+        *
+        *  Assume e2fs_ipg is a multiple of NBBY since
+        *  it's a multiple of e2fs_ipb (as we did above).
+        *  Note even (possibly smaller) the last group has the same e2fs_ipg.
+        */
+       assert(!(sblock.e2fs.e2fs_ipg % NBBY));
+       i = sblock.e2fs.e2fs_ipg / NBBY;
+       memset(buf, 0, i);
+       assert(sblock.e2fs_bsize >= i);
+       memset(buf + i, ~0U, sblock.e2fs_bsize - i);
+       if (cylno == 0) {
+               /* mark reserved inodes */
+               for (i = 1; i < EXT2_FIRSTINO; i++)
+                       setbit(buf, EXT2_INO_INDEX(i));
+       }
+       wtfs(fsbtodb(&sblock, gd[cylno].ext2bgd_i_bitmap), sblock.e2fs_bsize,
+           buf);
+
+       /*
+        * Initialize inode tables.
+        *
+        *  Just initialize generation numbers for NFS security.
+        *  XXX: sys/ufs/ext2fs/ext2fs_alloc.c:ext2fs_valloc() seems
+        *       to override these generated numbers.
+        */
+       memset(buf, 0, sblock.e2fs_bsize);
+       for (i = 0; i < sblock.e2fs_itpg; i++) {
+               for (j = 0; j < sblock.e2fs_ipb; j++) {
+                       dp = (struct ext2fs_dinode *)(buf + inodesize * j);
+                       /* h2fs32() just for consistency */
+                       dp->e2di_gen = h2fs32(arc4random());
+               }
+               wtfs(fsbtodb(&sblock, gd[cylno].ext2bgd_i_tables + i),
+                   sblock.e2fs_bsize, buf);
+       }
+}
+
+/*
+ * Zap possible lingering old superblock data
+ */
+static void
+zap_old_sblock(daddr_t sec)
+{
+       static daddr_t cg0_data;
+       uint32_t oldfs[SBSIZE / sizeof(uint32_t)];
+       static const struct fsm {
+               uint32_t offset;
+               uint32_t magic;
+               uint32_t mask;
+       } fs_magics[] = {
+               {offsetof(struct ext2fs, e2fs_magic) / 4, E2FS_MAGIC, 0xffff},
+               {offsetof(struct ext2fs, e2fs_magic) / 4,
+                   E2FS_MAGIC << 16, 0xffff0000},
+               {14, 0xef530000, 0xffff0000},   /* EXT2FS (big) */
+               {0x55c / 4, 0x00011954, ~0U},   /* FS_UFS1_MAGIC */
+               {0x55c / 4, 0x19540119, ~0U},   /* FS_UFS2_MAGIC */
+               {0, 0x70162, ~0U},              /* LFS_MAGIC */
+               {.offset = ~0U},
+       };
+       const struct fsm *fsm;
+
+       if (Nflag)
+               return;
+
+       /* don't override data before superblock */
+       if (sec < SBOFF / sectorsize)
+               return;
+
+       if (cg0_data == 0) {
+               cg0_data =
+                   ((daddr_t)sblock.e2fs.e2fs_first_dblock + cgoverhead(0)) *
+                   sblock.e2fs_bsize / sectorsize;
+       }
+
+       /* Ignore anything that is beyond our filesystem */
+       if (sec >= fssize)
+               return;
+       /* Zero anything inside our filesystem... */
+       if (sec >= sblock.e2fs.e2fs_first_dblock * bsize / sectorsize) {
+               /* ...unless we will write that area anyway */
+               if (sec >= cg0_data)
+                       /* assume iobuf is zero'ed here */
+                       wtfs(sec, roundup(SBSIZE, sectorsize), iobuf);
+               return;
+       }
+
+       /*
+        * The sector might contain boot code, so we must validate it
+        *
+        * XXX: ext2fs won't preserve data after SBOFF,
+        *      but first_dblock could have a different value.
+        */
+       rdfs(sec, sizeof(oldfs), &oldfs);
+       for (fsm = fs_magics;; fsm++) {
+               uint32_t v;
+               if (fsm->mask == 0)
+                       return;
+               v = oldfs[fsm->offset];
+               if ((v & fsm->mask) == fsm->magic ||
+                   (bswap32(v) & fsm->mask) == fsm->magic)
+                       break;
+       }
+
+       /* Just zap the magic number */
+       oldfs[fsm->offset] = 0;
+       wtfs(sec, sizeof(oldfs), &oldfs);
+}
+
+/*
+ * uint cgoverhead(uint c)
+ *
+ *     Return a number of reserved blocks on the specified group.
+ *     XXX: should be shared with src/sbin/fsck_ext2fs/setup.c
+ */
+uint
+cgoverhead(uint c)
+{
+       uint overh;
+
+       overh = NBLOCK_BLOCK_BITMAP + NBLOCK_INODE_BITMAP + sblock.e2fs_itpg;
+
+       if (sblock.e2fs.e2fs_rev == E2FS_REV0 ||
+           (sblock.e2fs.e2fs_features_rocompat &
+            EXT2F_ROCOMPAT_SPARSESUPER) == 0 ||
+           cg_has_sb(c) != 0) {
+               overh += NBLOCK_SUPERBLOCK + sblock.e2fs_ngdb;
+
+               if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+                   (sblock.e2fs.e2fs_features_compat &
+                    EXT2F_COMPAT_RESIZE) != 0)
+                       overh += sblock.e2fs.e2fs_reserved_ngdb;
+       }
+
+       return overh;
+}
+
+/*
+ * Initialize the file system
+ */
+
+#define LOSTDIR                /* e2fsck complains if there is no lost+found */
+
+#define        PREDEFDIR       2
+
+#ifdef LOSTDIR
+#define        PREDEFROOTDIR   (PREDEFDIR + 1)
+#else
+#define        PREDEFROOTDIR   PREDEFDIR
+#endif
+
+struct ext2fs_direct root_dir[] = {
+       { EXT2_ROOTINO, 0, 1, 0, "." },
+       { EXT2_ROOTINO, 0, 2, 0, ".." },
+#ifdef LOSTDIR
+       { EXT2_LOSTFOUNDINO, 0, 10, 0, "lost+found" },
+#endif
+};
+
+#ifdef LOSTDIR
+struct ext2fs_direct lost_found_dir[] = {
+       { EXT2_LOSTFOUNDINO, 0, 1, 0, "." },
+       { EXT2_ROOTINO, 0, 2, 0, ".." },
+};
+struct ext2fs_direct pad_dir = { 0, sizeof(struct ext2fs_direct), 0, 0, "" };
+#endif
+
+int
+fsinit(const struct timeval *tv)
+{
+       struct ext2fs_dinode node;
+#ifdef LOSTDIR
+       uint i, nblks_lostfound, blk;
+#endif
+
+       /*
+        * Initialize the inode for the resizefs feature
+        */
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+           (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0)
+               init_resizeino(tv);
+
+       /*
+        * Initialize the node
+        */
+
+#ifdef LOSTDIR
+       /*
+        * Create the lost+found directory
+        */
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+           sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE) {
+               lost_found_dir[0].e2d_type = EXT2_FT_DIR;
+               lost_found_dir[1].e2d_type = EXT2_FT_DIR;
+       }
+       (void)makedir(lost_found_dir, __arraycount(lost_found_dir));
+
+       /* prepare a bit large directory for preserved files */
+       nblks_lostfound = EXT2_LOSTFOUNDSIZE / sblock.e2fs_bsize;
+       /* ...but only with direct blocks */
+       if (nblks_lostfound > NDADDR)
+               nblks_lostfound = NDADDR;
+
+       memset(&node, 0, sizeof(node));
+       node.e2di_mode = EXT2_IFDIR | EXT2_LOSTFOUNDUMASK;
+       node.e2di_uid = geteuid();
+       node.e2di_size = sblock.e2fs_bsize * nblks_lostfound;
+       node.e2di_atime = tv->tv_sec;
+       node.e2di_ctime = tv->tv_sec;
+       node.e2di_mtime = tv->tv_sec;
+       node.e2di_gid = getegid();
+       node.e2di_nlink = PREDEFDIR;
+       /* e2di_nblock is a number of disk blocks, not ext2fs blocks */
+       node.e2di_nblock = fsbtodb(&sblock, nblks_lostfound);
+       node.e2di_blocks[0] = alloc(sblock.e2fs_bsize, node.e2di_mode);
+       if (node.e2di_blocks[0] == 0) {
+               printf("%s: can't allocate block for lost+found\n", __func__);
+               return 0;
+       }
+       for (i = 1; i < nblks_lostfound; i++) {
+               blk = alloc(sblock.e2fs_bsize, 0);
+               if (blk == 0) {
+                       printf("%s: can't allocate blocks for lost+found\n",
+                           __func__);
+                       return 0;
+               }
+               node.e2di_blocks[i] = blk;
+       }
+       wtfs(fsbtodb(&sblock, node.e2di_blocks[0]), sblock.e2fs_bsize, buf);
+       pad_dir.e2d_reclen = sblock.e2fs_bsize;
+       for (i = 1; i < nblks_lostfound; i++) {
+               memset(buf, 0, sblock.e2fs_bsize);
+               copy_dir(&pad_dir, (struct ext2fs_direct *)buf);
+               wtfs(fsbtodb(&sblock, node.e2di_blocks[i]), sblock.e2fs_bsize,
+                   buf);
+       }
+       iput(&node, EXT2_LOSTFOUNDINO);
+#endif
+       /*
+        * create the root directory
+        */
+       memset(&node, 0, sizeof(node));
+       if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
+           sblock.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE) {
+               root_dir[0].e2d_type = EXT2_FT_DIR;
+               root_dir[1].e2d_type = EXT2_FT_DIR;
+#ifdef LOSTDIR
+               root_dir[2].e2d_type = EXT2_FT_DIR;
+#endif
+       }
+       node.e2di_mode = EXT2_IFDIR | EXT2_UMASK;
+       node.e2di_uid = geteuid();
+       node.e2di_size = makedir(root_dir, __arraycount(root_dir));
+       node.e2di_atime = tv->tv_sec;
+       node.e2di_ctime = tv->tv_sec;
+       node.e2di_mtime = tv->tv_sec;
+       node.e2di_gid = getegid();
+       node.e2di_nlink = PREDEFROOTDIR;
+       /* e2di_nblock is a number of disk block, not ext2fs block */
+       node.e2di_nblock = fsbtodb(&sblock, 1);
+       node.e2di_blocks[0] = alloc(node.e2di_size, node.e2di_mode);
+       if (node.e2di_blocks[0] == 0) {
+               printf("%s: can't allocate block for root dir\n", __func__);
+               return 0;
+       }
+       wtfs(fsbtodb(&sblock, node.e2di_blocks[0]), sblock.e2fs_bsize, buf);
+       iput(&node, EXT2_ROOTINO);
+       return 1;
+}
+
+/*
+ * Construct a set of directory entries in "buf".
+ * return size of directory.
+ */
+int
+makedir(struct ext2fs_direct *protodir, int entries)
+{
+       uint8_t *cp;
+       uint i, spcleft;
+       uint dirblksiz;
+
+       dirblksiz = sblock.e2fs_bsize;
+       memset(buf, 0, dirblksiz);
+       spcleft = dirblksiz;
+       for (cp = buf, i = 0; i < entries - 1; i++) {
+               protodir[i].e2d_reclen = EXT2FS_DIRSIZ(protodir[i].e2d_namlen);
+               copy_dir(&protodir[i], (struct ext2fs_direct *)cp);
+               cp += protodir[i].e2d_reclen;
+               spcleft -= protodir[i].e2d_reclen;
+       }
+       protodir[i].e2d_reclen = spcleft;
+       copy_dir(&protodir[i], (struct ext2fs_direct *)cp);
+       return dirblksiz;
+}
+
+/*
+ * Copy a direntry to a buffer, in fs byte order
+ */
+static void
+copy_dir(struct ext2fs_direct *dir, struct ext2fs_direct *dbuf)
+{
+
+       memcpy(dbuf, dir, EXT2FS_DIRSIZ(dir->e2d_namlen));
+       dbuf->e2d_ino = h2fs32(dir->e2d_ino);
+       dbuf->e2d_reclen = h2fs16(dir->e2d_reclen);
+}
+
+/*
+ * void init_resizeino(const struct timeval *tv);
+ *
+ *     Initialize the EXT2_RESEIZE_INO inode to preserve
+ *     reserved group descriptor blocks for future growth of this ext2fs.
+ */
+void
+init_resizeino(const struct timeval *tv)
+{
+       struct ext2fs_dinode node;
+       uint64_t isize;
+       uint32_t *dindir_block, *reserved_gdb;
+       uint nblock, i, cylno, n;
+
+       memset(&node, 0, sizeof(node));
+
+       /*
+        * Note this function only prepares required structures for
+        * future resize. It's a quite different work to implement
+        * a utility like resize_ext2fs(8) which handles actual
+        * resize ops even on offline.
+        *
+        * Anyway, I'm not sure if there is any documentation about
+        * this resize ext2fs feature and related data structures,
+        * and I've written this function based on things what I see
+        * on some existing implementation and real file system data
+        * created by existing tools. To be honest, they are not
+        * so easy to read, so I will try to implement it here without
+        * any dumb optimization for people who would eventually
+        * work on "yet another wheel" like resize_ext2fs(8).
+        */
+
+       /*
+        * I'm not sure what type is appropriate for this inode.
+        * The release notes of e2fsprogs says they changed e2fsck to allow
+        * IFREG for RESIZEINO since a certain resize tool used it. Hmm.
+        */
+       node.e2di_mode = EXT2_IFREG | EXT2_RESIZEINOUMASK;
+       node.e2di_uid = geteuid();
+       node.e2di_atime = tv->tv_sec;
+       node.e2di_ctime = tv->tv_sec;
+       node.e2di_mtime = tv->tv_sec;
+       node.e2di_gid = getegid();
+       node.e2di_nlink = 1;
+
+       /*
+        * To preserve the reserved group descriptor blocks,
+        * EXT2_RESIZEINO uses only double indirect reference
+        * blocks in its inode entries.
+        *
+        * All entries for direct, single indirect and triple
+        * indirect references are left zero'ed. Maybe it's safe
+        * because no write operation will happen with this inode.
+        *
+        * We have to allocate a block for the first level double
+        * indirect reference block. Indexes of inode entries in
+        * this first level dindirect block are corresponding to
+        * indexes of group descriptors including both used (e2fs_ngdb)
+        * and reserved (e2fs_reserved_ngdb) group descriptor blocks.
+        *
+        * Inode entries of indexes for used (e2fs_ngdb) descriptors are
+        * left zero'ed. Entries for reserved (e2fs_reserved_ngdb) ones
+        * have block numbers of actual reserved group descriptors
+        * allocated at block group zero. This means e2fs_reserved_ngdb
+        * blocks are reserved as the second level dindirect reference
+        * blocks, and they actually contain block numbers of indirect
+        * references. It may be safe since they don't have to keep any
+        * data yet.
+        *
+        * Each these second dindirect blocks (i.e. reserved group
+        * descriptor blocks in the first block group) should have
+        * block numbers of its backups in all other block groups.
+        * I.e. reserved_ngdb[0] block in block group 0 contains block
+        * numbers of resreved_ngdb[0] from group 1 through (e2fs_ncg - 1).
+        * The number of backups can be determined by the
+        * EXT2_ROCOMPAT_SPARSESUPER feature and cg_has_sb() macro
+        * as done in the above initcg() function.
+        */
+
+       /* set e2di_size which occupies whole blocks through DINDIR blocks */
+       isize = (uint64_t)sblock.e2fs_bsize * NDADDR +
+           (uint64_t)sblock.e2fs_bsize * NINDIR(&sblock) +
+           (uint64_t)sblock.e2fs_bsize * NINDIR(&sblock) * NINDIR(&sblock);
+       if (isize > UINT32_MAX &&
+           (sblock.e2fs.e2fs_features_rocompat &
+            EXT2F_ROCOMPAT_LARGEFILE) == 0) {
+               /* XXX should enable it here and update all backups? */
+               errx(EXIT_FAILURE, "%s: large_file rocompat feature is "
+                   "required to enable resize feature for this filesystem\n",
+                   __func__);
+       }
+       /* upper 32bit is stored into e2di_dacl on REV1 feature */
+       node.e2di_size = isize & UINT32_MAX;
+       node.e2di_dacl = isize >> 32;
+
+#define SINGLE 0       /* index of single indirect block */
+#define DOUBLE 1       /* index of double indirect block */
+#define TRIPLE 2       /* index of triple indirect block */
+
+       /* zero out entries for direct references */
+       for (i = 0; i < NDADDR; i++)
+               node.e2di_blocks[i] = 0;
+       /* also zero out entries for single and triple indirect references */
+       node.e2di_blocks[NDADDR + SINGLE] = 0;
+       node.e2di_blocks[NDADDR + TRIPLE] = 0;
+
+       /* allocate a block for the first level double indirect reference */
+       node.e2di_blocks[NDADDR + DOUBLE] =
+           alloc(sblock.e2fs_bsize, node.e2di_mode);
+       if (node.e2di_blocks[NDADDR + DOUBLE] == 0)
+               errx(EXIT_FAILURE, "%s: Can't allocate a dindirect block",
+                   __func__);
+
+       /* account this first block */
+       nblock = fsbtodb(&sblock, 1);
+
+       /* allocate buffer to set data in the dindirect block */
+       dindir_block = malloc(sblock.e2fs_bsize);
+       if (dindir_block == NULL)
+               errx(EXIT_FAILURE,
+                   "%s: Can't allocate buffer for a dindirect block",
+                   __func__);
+
+       /* allocate buffer to set data in the group descriptor blocks */
+       reserved_gdb = malloc(sblock.e2fs_bsize);
+       if (reserved_gdb == NULL)
+               errx(EXIT_FAILURE,
+                   "%s: Can't allocate buffer for group descriptor blocks",
+                   __func__);
+
+       /*
+        * Setup block entries in the first level dindirect blocks
+        */
+       for (i = 0; i < sblock.e2fs_ngdb; i++) {
+               /* no need to handle used group descriptor blocks */
+               dindir_block[i] = 0;
+       }
+       for (; i < sblock.e2fs_ngdb + sblock.e2fs.e2fs_reserved_ngdb; i++) {
+               /*
+                * point reserved group descriptor block in the first
+                * (i.e. master) block group
+                * 
+                * XXX: e2fsprogs seem to use "(i % NINDIR(&sblock))" here
+                *      to store maximum NINDIR(&sblock) reserved gdbs.
+                *      I'm not sure what will be done on future filesystem
+                *      shrink in that case on their way.
+                */
+               if (i >= NINDIR(&sblock))
+                       errx(EXIT_FAILURE, "%s: too many reserved "
+                           "group descriptors (%u) for resize inode",
+                           __func__, sblock.e2fs.e2fs_reserved_ngdb);
+               dindir_block[i] =
+                   h2fs32(cgbase(&sblock, 0) + NBLOCK_SUPERBLOCK + i);
+
+               /*
+                * Setup block entries in the second dindirect blocks
+                * (which are primary reserved group descriptor blocks)
+                * to point their backups.
+                */
+               for (n = 0, cylno = 1; cylno < sblock.e2fs_ncg; cylno++) {
+                       /* skip block groups without backup */
+                       if ((sblock.e2fs.e2fs_features_rocompat &
+                            EXT2F_ROCOMPAT_SPARSESUPER) != 0 &&
+                           cg_has_sb(cylno) == 0)
+                               continue;
+
+                       if (n >= NINDIR(&sblock))
+                               errx(EXIT_FAILURE, "%s: too many block groups "
+                                   "for the resize feature", __func__);
+                       /*
+                        * These blocks are already reserved in
+                        * initcg() so no need to use alloc() here.
+                        */
+                       reserved_gdb[n++] = h2fs32(cgbase(&sblock, cylno) +
+                           NBLOCK_SUPERBLOCK + i);
+                       nblock += fsbtodb(&sblock, 1);
+               }
+               for (; n < NINDIR(&sblock); n++)
+                       reserved_gdb[n] = 0;
+
+               /* write group descriptor block as the second dindirect refs */
+               wtfs(fsbtodb(&sblock, fs2h32(dindir_block[i])),
+                   sblock.e2fs_bsize, reserved_gdb);
+               nblock += fsbtodb(&sblock, 1);
+       }
+       for (; i < NINDIR(&sblock); i++) {
+               /* leave trailing entries unallocated */
+               dindir_block[i] = 0;
+       }
+       free(reserved_gdb);
+
+       /* finally write the first level dindirect block */
+       wtfs(fsbtodb(&sblock, node.e2di_blocks[NDADDR + DOUBLE]),
+           sblock.e2fs_bsize, dindir_block);
+       free(dindir_block);
+
+       node.e2di_nblock = nblock;
+       iput(&node, EXT2_RESIZEINO);
+}
+
+/*
+ * uint32_t alloc(uint32_t size, uint16_t mode)
+ *
+ *     Allocate a block (from cylinder group 0)
+ *     Reference: src/sys/ufs/ext2fs/ext2fs_alloc.c:ext2fs_alloccg()
+ */
+uint32_t
+alloc(uint32_t size, uint16_t mode)
+{
+       uint32_t loc, bno;
+       uint8_t *bbp;
+       uint len, map, i;
+
+       if (gd[0].ext2bgd_nbfree == 0)
+               return 0;
+
+       if (size > sblock.e2fs_bsize)
+               return 0;
+
+       bbp = malloc(sblock.e2fs_bsize);
+       if (bbp == NULL)
+               return 0;
+       rdfs(fsbtodb(&sblock, gd[0].ext2bgd_b_bitmap), sblock.e2fs_bsize, bbp);
+
+       /* XXX: kernel uses e2fs_fpg here */
+       len = sblock.e2fs.e2fs_bpg / NBBY;
+
+#if 0  /* no need block allocation for root or lost+found dir */
+       for (loc = 0; loc < len; loc++) {
+               if (bbp[loc] == 0) {
+                       bno = loc * NBBY;
+                       goto gotit;
+               }
+       }
+#endif
+
+       loc = skpc(~0U, len, bbp);
+       if (loc == 0)
+               return 0;
+       loc = len - loc;
+       map = bbp[loc];
+       bno = loc * NBBY;
+       for (i = 0; i < NBBY; i++, bno++) {
+               if ((map & (1 << i)) == 0)
+                       goto gotit;
+       }
+       return 0;
+       
+ gotit:
+       if (isset(bbp, bno))
+               errx(EXIT_FAILURE, "%s: inconsistent bitmap\n", __func__);
+
+       setbit(bbp, bno);
+       wtfs(fsbtodb(&sblock, gd[0].ext2bgd_b_bitmap), sblock.e2fs_bsize, bbp);
+       free(bbp);
+       /* XXX: modified group descriptors won't be written into backups */
+       gd[0].ext2bgd_nbfree--;
+       if ((mode & EXT2_IFDIR) != 0)
+               gd[0].ext2bgd_ndirs++;
+       sblock.e2fs.e2fs_fbcount--;
+
+       return sblock.e2fs.e2fs_first_dblock + bno;
+}
+
+/*
+ * void iput(struct ext2fs_dinode *ip, ino_t ino)
+ *
+ *     Put an inode entry into the corresponding table.
+ */
+static void
+iput(struct ext2fs_dinode *ip, ino_t ino)
+{
+       daddr_t d;
+       uint c, i;
+       struct ext2fs_dinode *dp;
+       uint8_t *bp;
+
+       bp = malloc(sblock.e2fs_bsize);
+       if (bp == NULL)
+               errx(EXIT_FAILURE, "%s: can't allocate buffer for inode\n",
+                   __func__);
+
+       /*
+        * Reserved inodes are allocated and accounted in initcg()
+        * so skip checks of the bitmap and allocation for them.
+        */
+       if (ino >= EXT2_FIRSTINO) {
+               c = ino_to_cg(&sblock, ino);
+
+               /* sanity check */
+               if (gd[c].ext2bgd_nifree == 0)
+                       errx(EXIT_FAILURE,
+                           "%s: no free inode %" PRIu64 " in block group %u\n",
+                           __func__, (uint64_t)ino, c);
+
+               /* update inode bitmap */
+               rdfs(fsbtodb(&sblock, gd[0].ext2bgd_i_bitmap),
+                   sblock.e2fs_bsize, bp);
+
+               /* more sanity */
+               if (isset(bp, EXT2_INO_INDEX(ino)))
+                       errx(EXIT_FAILURE, "%s: inode %" PRIu64
+                           " already in use\n", __func__, (uint64_t)ino);
+               setbit(bp, EXT2_INO_INDEX(ino));
+               wtfs(fsbtodb(&sblock, gd[0].ext2bgd_i_bitmap),
+                   sblock.e2fs_bsize, bp);
+               gd[c].ext2bgd_nifree--;
+               sblock.e2fs.e2fs_ficount--;
+       }
+
+       if (ino >= sblock.e2fs.e2fs_ipg * sblock.e2fs_ncg)
+               errx(EXIT_FAILURE, "%s: inode value out of range (%" PRIu64
+                   ").\n", __func__, (uint64_t)ino);
+
+       /* update an inode entry in the table */
+       d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino));
+       rdfs(d, sblock.e2fs_bsize, bp);
+
+       dp = (struct ext2fs_dinode *)(bp +
+           inodesize * ino_to_fsbo(&sblock, ino));
+       e2fs_isave(ip, dp);
+       /* e2fs_i_bswap() doesn't swap e2di_blocks addrs */
+       if ((ip->e2di_mode & EXT2_IFMT) != EXT2_IFLNK) {
+               for (i = 0; i < NDADDR + NIADDR; i++)
+                       dp->e2di_blocks[i] = h2fs32(ip->e2di_blocks[i]);
+       }
+       /* h2fs32() just for consistency */
+       dp->e2di_gen = h2fs32(arc4random());
+
+       wtfs(d, sblock.e2fs_bsize, bp);
+       free(bp);
+}
+
+/*
+ * Read a block from the file system
+ */
+void
+rdfs(daddr_t bno, int size, void *bf)
+{
+       int n;
+#ifndef __minix
+       off_t offset;
+#else
+       u64_t offset;
+#endif
+
+       offset = bno;
+#ifndef __minix
+       n = pread(fsi, bf, size, offset * sectorsize);
+#else
+       n = pread64(fsi, bf, size, offset * sectorsize);
+#endif
+       if (n != size)
+               err(EXIT_FAILURE, "%s: read error for sector %" PRId64,
+                   __func__, (int64_t)bno);
+}
+
+/*
+ * Write a block to the file system
+ */
+void
+wtfs(daddr_t bno, int size, void *bf)
+{
+       int n;
+#ifndef __minix
+       off_t offset;
+#else
+       u64_t offset;
+#endif
+
+       if (Nflag)
+               return;
+       offset = bno;
+       errno = 0;
+#ifndef __minix
+       n = pwrite(fso, bf, size, offset * sectorsize);
+#else
+       n = pwrite64(fso, bf, size, offset * sectorsize);
+#endif
+       if (n != size)
+               err(EXIT_FAILURE, "%s: write error for sector %" PRId64,
+                   __func__, (int64_t)bno);
+}
+
+int
+ilog2(uint val)
+{
+
+       if (val == 0 || !powerof2(val))
+               errx(EXIT_FAILURE, "%s: %u is not a power of 2\n",
+                   __func__, val);
+
+       return ffs(val) - 1;
+}
+
+/*
+ * int skpc(int mask, size_t size, uint8_t *cp)
+ *
+ *     Locate an unsigned character of value mask inside cp[].
+ *     (from src/sys/lib/libkern/skpc.c)
+ */
+int
+skpc(int mask, size_t size, uint8_t *cp)
+{
+       uint8_t *end;
+
+       end = &cp[size];
+       while (cp < end && *cp == (uint8_t)mask)
+               cp++;
+
+       return end - cp;
+}
diff --git a/sbin/newfs_ext2fs/newfs_ext2fs.8 b/sbin/newfs_ext2fs/newfs_ext2fs.8
new file mode 100644 (file)
index 0000000..9d87ebc
--- /dev/null
@@ -0,0 +1,326 @@
+.\"    $NetBSD: newfs_ext2fs.8,v 1.11 2010/02/25 13:09:17 tsutsui Exp $
+.\"
+.\" Copyright (c) 1983, 1987, 1991, 1993, 1994
+.\"    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.
+.\"
+.\"     @(#)newfs.8    8.6 (Berkeley) 5/3/95
+.\"
+.Dd March 1, 2009
+.Dt NEWFS_EXT2FS 8
+.Os
+.Sh NAME
+.Nm newfs_ext2fs
+.Nd construct a new ext2 file system
+.Sh SYNOPSIS
+.Nm
+.Op Fl FINZ
+.Op Fl b Ar block-size
+.Op Fl D Ar inodesize
+.Op Fl f Ar frag-size
+.Op Fl i Ar bytes-per-inode
+.Op Fl m Ar free-space
+.Op Fl n Ar inodes
+.Op Fl O Ar filesystem-format
+.Op Fl S Ar sector-size
+.Op Fl s Ar size
+.Op Fl V Ar verbose
+.Op Fl v Ar volname
+.Ar special
+.Sh DESCRIPTION
+.Nm
+is used to initialize and clear ext2 file systems before first use.
+Before running
+.Nm
+the disk must be labeled using
+.Xr disklabel 8 .
+.Nm
+builds a file system on the specified special device
+basing its defaults on the information in the disk label.
+Typically the defaults are reasonable, however
+.Nm
+has numerous options to allow the defaults to be selectively overridden.
+.Pp
+Options with numeric arguments may contain an optional (case-insensitive)
+suffix:
+.Bl -tag -width 3n -offset indent -compact
+.It b
+Bytes; causes no modification.
+(Default)
+.It k
+Kilo; multiply the argument by 1024.
+.It m
+Mega; multiply the argument by 1048576.
+.It g
+Giga; multiply the argument by 1073741824.
+.El
+.Pp
+The following options define the general layout policies.
+.Bl -tag -width Fl
+.It Fl b Ar block-size
+The block size of the file system, in bytes.
+It must be a power of two.
+The smallest allowable size is 1024 bytes.
+The default size depends upon the size of the file system:
+.Pp
+.Bl -tag -width "file system size" -compact -offset indent
+.It Sy "file system size"
+.Ar block-size
+.It \*[Lt]= 512 MB
+1 KB
+.It \*[Gt] 512 MB
+4 KB
+.El
+.It Fl D Ar inodesize
+Set the inode size.
+Defaults to 128, and can also be set to 256 for
+compatibility with ext4.
+.It Fl F
+Create a file system image in
+.Ar special .
+The file system size needs to be specified with
+.Dq Fl s Ar size .
+No attempts to use or update the disk label will be made.
+.It Fl f Ar frag-size
+The fragment size of the file system in bytes.
+It must be the same with blocksize because the current ext2fs
+implementation doesn't support fragmentation.
+.It Fl I
+Do not require that the file system type listed in the disk label is
+.Ql Linux\ Ext2 .
+.It Fl i Ar bytes-per-inode
+This specifies the density of inodes in the file system.
+If fewer inodes are desired, a larger number should be used;
+to create more inodes a smaller number should be given.
+.It Fl m Ar free-space
+The percentage of space reserved from normal users; the minimum free
+space threshold.
+The default value used is 5%.
+.It Fl N
+Causes the file system parameters to be printed out
+without really creating the file system.
+.It Fl n Ar inodes
+This specifies the number of inodes for the file system.
+If both
+.Fl i
+and
+.Fl n
+are specified then
+.Fl n
+takes precedence.
+The default number of inodes is calculated from a number of blocks in
+the file system.
+.It Fl O Ar filesystem-format
+Select the filesystem-format.
+.Bl -tag -width 3n -offset indent -compact
+.It 0
+.Ql GOOD_OLD_REV ;
+this option is primarily used to build root file systems that can be
+understood by old or dumb firmwares for bootstrap.
+(default)
+.It 1
+.Ql DYNAMIC_REV ;
+various extended (and sometimes incompatible) features are enabled
+(though not all features are supported on
+.Nx ) .
+Currently only the following features are supported:
+.Bl -tag -width "SPARSESUPER" -offset indent -compact
+.It RESIZE
+Prepare some reserved structures which enable future file system resizing.
+.It FTYPE
+Store file types in directory entries to improve performance.
+.It SPARSESUPER
+Prepare superblock backups for the
+.Xr fsck_ext2fs 8
+utility on not all but sparse block groups.
+.It LARGEFILE
+Enable files larger than 2G bytes.
+.El
+.El
+.It Fl s Ar size
+The size of the file system in sectors.
+An
+.Sq s
+suffix will be interpreted as the number of sectors (the default).
+All other suffixes are interpreted as per other numeric arguments,
+except that the number is converted into sectors by dividing by the
+sector size (as specified by
+.Fl S Ar secsize )
+after suffix interpretation.
+.Pp
+If no
+.Fl s Ar size
+is specified then the filesystem size defaults to that of the partition, or,
+if
+.Fl F
+is specified, the existing file.
+.Pp
+If
+.Ar size
+is negative the specified size is subtracted from the default size
+(reserving space at the end of the partition).
+.It Fl V Ar verbose
+This controls the amount of information written to stdout:
+.Bl -tag -width 3n -offset indent -compact
+.It 0
+No output.
+.It 1
+Overall size and cylinder group details.
+.It 2
+A progress bar (dots ending at right hand margin).
+.It 3
+The first few super-block backup sector numbers are displayed before the
+progress bar.
+.It 4
+All the super-block backup sector numbers are displayed (no progress bar).
+.El
+The default is 3.
+If
+.Fl N
+is specified
+.Nm
+stops before outputting the progress bar.
+.It Fl v Ar volname
+This specifies a volume name for the file system.
+.It Fl Z
+Pre-zeros the file system image created with
+.Fl F .
+This is necessary if the image is to be used by
+.Xr vnd 4
+(which doesn't support file systems with
+.Sq holes ) .
+.El
+.Pp
+The following option overrides the standard sizes for the disk geometry.
+The default value is taken from the disk label.
+Changing this default is useful only when using
+.Nm
+to build a file system whose raw image will eventually be used on a
+different type of disk than the one on which it is initially created
+(for example on a write-once disk).
+Note that changing this value from its default will make it impossible for
+.Xr fsck_ext2fs 8
+to find the alternative superblocks if the standard superblock is lost.
+.Bl -tag -width Fl
+.It Fl S Ar sector-size
+The size of a sector in bytes (almost never anything but 512).
+Defaults to 512.
+.El
+.Sh NOTES
+There is no option to specify the metadata byte order on the file system
+to be created because the native ext2 file system is always little endian
+even on big endian hosts.
+.Pp
+The file system is created with
+.Sq random
+inode generation numbers to improve NFS security.
+.Pp
+The owner and group IDs of the root node and reserved blocks of the new
+file system are set to the effective UID and GID of the user initializing
+the file system.
+.Pp
+For the
+.Nm
+command to succeed,
+the disk label should first be updated such that the fstype field for the
+partition is set to
+.Ql Linux\ Ext2 ,
+unless
+.Fl F
+or
+.Fl I
+is used.
+.Pp
+.\" To create and populate a filesystem image within a file use the
+.\" .Xr makefs 8
+.\" utility.
+.\" .Pp
+The partition size is found using
+.Xr fstat 2 ,
+not by inspecting the disk label.
+The block size and fragment size will be written back to the disk label
+only if the last character of
+.Ar special
+references the same partition as the minor device number.
+.Sh SEE ALSO
+.Xr fstat 2 ,
+.Xr disklabel 5 ,
+.Xr disktab 5 ,
+.Xr fs 5 ,
+.Xr disklabel 8 ,
+.Xr diskpart 8 ,
+.\" .Xr dumpfs 8 ,
+.\" .Xr format 8 ,
+.Xr fsck_ext2fs 8 ,
+.\" .Xr makefs 8 ,
+.Xr mount 8 ,
+.Xr mount_ext2fs 8 ,
+.Xr newfs 8
+.Rs
+.%A Remy Card
+.%A Theodore Ts'o
+.%A Stephen Tweedie
+.%T "Design and Implementation of the Second Extended Filesystem"
+.%J "The Proceedings of the First Dutch International Symposium on Linux"
+.%U http://e2fsprogs.sourceforge.net/ext2intro.html
+.Re
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Nx 5.0 .
+.Sh AUTHORS
+The
+.Nm
+command was written by
+.An Izumi Tsutsui
+.Aq tsutsui@NetBSD.org .
+.Sh BUGS
+The
+.Nm
+command is still experimental and there are few sanity checks.
+.Pp
+The
+.Nm
+command doesn't have options to specify each REV1 file system feature
+independently.
+.Pp
+The
+.Nm
+command doesn't support the bad block list accounted by the bad blocks inode.
+.Pp
+Many newer ext2 file system features (especially journaling) are
+not supported yet.
+.Pp
+Some features in file systems created by the
+.Nm
+command might not be recognized properly by the
+.Xr fsck_ext2fs 8
+utility.
+.Pp
+There is no native tool in the
+.Nx
+distribution for resizing ext2 file systems yet.
diff --git a/sbin/newfs_ext2fs/newfs_ext2fs.c b/sbin/newfs_ext2fs/newfs_ext2fs.c
new file mode 100644 (file)
index 0000000..be9a998
--- /dev/null
@@ -0,0 +1,530 @@
+/*     $NetBSD: newfs_ext2fs.c,v 1.8 2009/03/02 10:38:13 tsutsui Exp $ */
+
+/*
+ * Copyright (c) 1983, 1989, 1993, 1994
+ *     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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)newfs.c    8.13 (Berkeley) 5/1/95";
+#else
+__RCSID("$NetBSD: newfs_ext2fs.c,v 1.8 2009/03/02 10:38:13 tsutsui Exp $");
+#endif
+#endif /* not lint */
+
+/*
+ * newfs: friendly front end to mke2fs
+ */
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/disk.h>
+#include <sys/file.h>
+#include <sys/mount.h>
+
+#include <ufs/ext2fs/ext2fs.h>
+#include <ufs/ext2fs/ext2fs_dinode.h>
+
+#include <disktab.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+#include <mntopts.h>
+
+#include <minix/partition.h>
+
+#include "extern.h"
+#include "partutil.h"
+
+static int64_t strsuftoi64(const char *, const char *, int64_t, int64_t, int *);
+static void usage(void) __dead;
+
+/*
+ * For file systems smaller than SMALL_FSSIZE we use the S_DFL_* defaults,
+ * otherwise if less than MEDIUM_FSSIZE use M_DFL_*, otherwise use
+ * L_DFL_*.
+ */
+#define SMALL_FSSIZE   ((4 * 1024 * 1024) / sectorsize)        /* 4MB */
+#define S_DFL_BSIZE    1024
+#define MEDIUM_FSSIZE  ((512 * 1024 * 1024) / sectorsize)      /* 512MB */
+#define M_DFL_BSIZE    1024
+#define L_DFL_BSIZE    4096
+
+/*
+ * Each file system has a number of inodes statically allocated.
+ * We allocate one inode slot per 2, 4, or 8 blocks, expecting this
+ * to be far more than we will ever need.
+ */
+#define S_DFL_NINODE(blocks)   ((blocks) / 8)
+#define M_DFL_NINODE(blocks)   ((blocks) / 4)
+#define L_DFL_NINODE(blocks)   ((blocks) / 2)
+
+/*
+ * Default sector size.
+ */
+#define        DFL_SECSIZE     512
+
+int    Nflag;                  /* run without writing file system */
+int    Oflag = 0;              /* format as conservative REV0 by default */
+int    verbosity;              /* amount of printf() output */
+#define DEFAULT_VERBOSITY 3    /* 4 is traditional behavior of newfs(8) */
+int64_t fssize;                        /* file system size */
+uint   sectorsize;             /* bytes/sector */
+uint16_t inodesize = EXT2_REV0_DINODE_SIZE;    /* inode size */
+uint   fsize = 0;              /* fragment size */
+uint   bsize = 0;              /* block size */
+uint   minfree = MINFREE;      /* free space threshold */
+uint   density;                /* number of bytes per inode */
+uint   num_inodes;             /* number of inodes (overrides density) */
+char   *volname = NULL;        /* volume name */
+
+#ifndef __minix
+static char *disktype = NULL;
+#endif
+static char device[MAXPATHLEN];
+
+static const char lmsg[] = "%s: can't read disk label";
+
+int
+main(int argc, char *argv[])
+{
+#ifndef __minix
+       struct disk_geom geo;
+       struct dkwedge_info dkw;
+       struct statvfs *mp;
+       char *s2;
+       int len, n;
+#else
+       u64_t minix_fssize;
+#endif
+       struct stat sb;
+       int ch, fsi, fso, Fflag, Iflag, Zflag;
+       char *cp, *s1, *special;
+       const char *opstring;
+       int byte_sized;
+       uint blocks;                    /* number of blocks */
+
+       cp = NULL;
+       fso = -1;
+       Fflag = Iflag = Zflag = 0;
+       verbosity = -1;
+       opstring = "D:FINO:S:V:Zb:f:i:l:m:n:s:v:B:";
+       byte_sized = 0;
+       while ((ch = getopt(argc, argv, opstring)) != -1)
+               switch (ch) {
+               case 'D':
+                       inodesize = (uint16_t)strtol(optarg, &s1, 0);
+                       if (*s1 || (inodesize != 128 && inodesize != 256))
+                               errx(1, "Bad inode size %d "
+                                   "(only 128 and 256 supported)", inodesize);
+                       break;
+               case 'F':
+                       Fflag = 1;
+                       break;
+#ifndef __minix
+               case 'I':
+                       Iflag = 1;
+                       break;
+#endif
+               case 'N':
+                       Nflag = 1;
+                       if (verbosity == -1)
+                               verbosity = DEFAULT_VERBOSITY;
+                       break;
+               case 'O':
+                       Oflag = strsuftoi64("format", optarg, 0, 1, NULL);
+                       break;
+               case 'S':
+                       /*
+                        * XXX:
+                        * non-512 byte sectors almost certainly don't work.
+                        */
+                       sectorsize = strsuftoi64("sector size",
+                           optarg, 512, 65536, NULL);
+                       if (!powerof2(sectorsize))
+                               errx(EXIT_FAILURE,
+                                   "sector size `%s' is not a power of 2.",
+                                   optarg);
+                       break;
+               case 'V':
+                       verbosity = strsuftoi64("verbose", optarg, 0, 4, NULL);
+                       break;
+#ifndef __minix
+               case 'Z':
+                       Zflag = 1;
+                       break;
+#endif
+               case 'B':
+               case 'b':
+                       bsize = strsuftoi64("block size",
+                           optarg, MINBSIZE, EXT2_MAXBSIZE, NULL);
+                       break;
+               case 'f':
+                       fsize = strsuftoi64("fragment size",
+                           optarg, MINBSIZE, EXT2_MAXBSIZE, NULL);
+                       break;
+               case 'i':
+                       density = strsuftoi64("bytes per inode",
+                           optarg, 1, INT_MAX, NULL);
+                       break;
+               case 'm':
+                       minfree = strsuftoi64("free space %",
+                           optarg, 0, 99, NULL);
+                       break;
+               case 'n':
+                       num_inodes = strsuftoi64("number of inodes",
+                           optarg, 1, INT_MAX, NULL);
+                       break;
+               case 's':
+                       fssize = strsuftoi64("file system size",
+                           optarg, INT64_MIN, INT64_MAX, &byte_sized);
+                       break;
+               case 'v':
+                       volname = optarg;
+                       if (volname[0] == '\0')
+                               errx(EXIT_FAILURE,
+                                   "Volume name cannot be zero length");
+                       break;
+               case '?':
+               default:
+                       usage();
+               }
+       argc -= optind;
+       argv += optind;
+
+       if (verbosity == -1)
+               /* Default to showing cg info */
+               verbosity = DEFAULT_VERBOSITY;
+
+       if (argc != 1)
+               usage();
+
+       memset(&sb, 0, sizeof(sb));
+#ifndef __minix
+       memset(&dkw, 0, sizeof(dkw));
+#endif
+       special = argv[0];
+       if (Fflag) {
+               int fl;
+               /*
+                * It's a file system image
+                * no label, use fixed default for sectorsize.
+                */
+               if (sectorsize == 0)
+                       sectorsize = DFL_SECSIZE;
+
+               /* creating image in a regular file */
+               if (Nflag)
+                       fl = O_RDONLY;
+               else {
+                       if (fssize > 0)
+                               fl = O_RDWR | O_CREAT;
+                       else
+                               fl = O_RDWR;
+               }
+               fsi = open(special, fl, 0777);
+               if (fsi == -1)
+                       err(EXIT_FAILURE, "can't open file %s", special);
+               if (fstat(fsi, &sb) == -1)
+                       err(EXIT_FAILURE, "can't fstat opened %s", special);
+               if (!Nflag)
+                       fso = fsi;
+       } else {        /* !Fflag */
+               fsi = opendisk(special, O_RDONLY, device, sizeof(device), 0);
+               special = device;
+               if (fsi < 0 || fstat(fsi, &sb) == -1)
+                       err(EXIT_FAILURE, "%s: open for read", special);
+
+#ifndef __minix
+               if (!Nflag) {
+                       fso = open(special, O_WRONLY, 0);
+                       if (fso < 0)
+                               err(EXIT_FAILURE,
+                                   "%s: open for write", special);
+
+                       /* Bail if target special is mounted */
+                       n = getmntinfo(&mp, MNT_NOWAIT);
+                       if (n == 0)
+                               err(EXIT_FAILURE, "%s: getmntinfo", special);
+
+                       len = sizeof(_PATH_DEV) - 1;
+                       s1 = special;
+                       if (strncmp(_PATH_DEV, s1, len) == 0)
+                               s1 += len;
+
+                       while (--n >= 0) {
+                               s2 = mp->f_mntfromname;
+                               if (strncmp(_PATH_DEV, s2, len) == 0) {
+                                       s2 += len - 1;
+                                       *s2 = 'r';
+                               }
+                               if (strcmp(s1, s2) == 0 ||
+                                   strcmp(s1, &s2[1]) == 0)
+                                       errx(EXIT_FAILURE,
+                                           "%s is mounted on %s",
+                                           special, mp->f_mntonname);
+                               ++mp;
+                       }
+               }
+
+               if (getdiskinfo(special, fsi, disktype, &geo, &dkw) == -1)
+                       errx(EXIT_FAILURE, lmsg, special);
+
+               if (sectorsize == 0) {
+                       sectorsize = geo.dg_secsize;
+                       if (sectorsize <= 0)
+                               errx(EXIT_FAILURE, "no default sector size");
+               }
+
+               if (dkw.dkw_parent[0]) {
+                       if (dkw.dkw_size == 0)
+                               errx(EXIT_FAILURE,
+                                   "%s partition is unavailable", special);
+
+                       if (!Iflag) {
+                               static const char m[] =
+                                   "%s partition type is not `%s' (or use -I)";
+                               if (strcmp(dkw.dkw_ptype, DKW_PTYPE_EXT2FS))
+                                       errx(EXIT_FAILURE, m,
+                                           special, "Linux Ext2");
+                       }
+               }
+#else
+        {
+               fso = open(special, O_WRONLY, 0);
+               if (fso < 0)
+                       err(EXIT_FAILURE,
+                           "%s: open for write", special);
+
+               if(minix_sizeup(special, &minix_fssize) < 0)
+                       errx(EXIT_FAILURE, "minix_sizeup failed");
+
+               fssize = minix_fssize;
+               byte_sized = 1;
+
+               if (sectorsize == 0)
+                       sectorsize = 512;
+        }
+#endif
+       }
+
+       if (byte_sized)
+               fssize /= sectorsize;
+#ifndef __minix
+       if (fssize <= 0) {
+               if (sb.st_size != 0)
+                       fssize += sb.st_size / sectorsize;
+               else
+                       fssize += dkw.dkw_size;
+               if (fssize <= 0)
+                       errx(EXIT_FAILURE,
+                           "Unable to determine file system size");
+       }
+
+       if (dkw.dkw_parent[0] && fssize > dkw.dkw_size)
+               errx(EXIT_FAILURE,
+                   "size %" PRIu64 " exceeds maximum file system size on "
+                   "`%s' of %" PRIu64 " sectors",
+                   fssize, special, dkw.dkw_size);
+#endif
+
+       printf("fssize = %lld %d-byte sectors\n", fssize, sectorsize);
+
+       /* XXXLUKEM: only ftruncate() regular files ? (dsl: or at all?) */
+       if (Fflag && fso != -1
+           && ftruncate(fso, (off_t)fssize * sectorsize) == -1)
+               err(1, "can't ftruncate %s to %" PRId64, special, fssize);
+
+#ifndef __minix
+       if (Zflag && fso != -1) {       /* pre-zero (and de-sparce) the file */
+               char *buf;
+               int bufsize, i;
+               off_t bufrem;
+
+               struct statvfs sfs;
+               if (fstatvfs(fso, &sfs) == -1) {
+                       warn("can't fstatvfs `%s'", special);
+                       bufsize = 8192;
+               } else
+                       bufsize = sfs.f_iosize;
+
+               if ((buf = calloc(1, bufsize)) == NULL)
+                       err(1, "can't malloc buffer of %d",
+                       bufsize);
+               bufrem = fssize * sectorsize;
+               if (verbosity > 0)
+                       printf("Creating file system image in `%s', "
+                           "size %" PRId64 " bytes, in %d byte chunks.\n",
+                           special, (signed long long) bufrem, bufsize);
+               while (bufrem > 0) {
+                       i = write(fso, buf, MIN(bufsize, bufrem));
+                       if (i == -1)
+                               err(1, "writing image");
+                       bufrem -= i;
+               }
+               free(buf);
+       }
+#endif
+
+       /* Sort out fragment and block sizes */
+       if (bsize == 0) {
+               bsize = fsize;
+               if (bsize == 0) {
+                       if (fssize < SMALL_FSSIZE)
+                               bsize = S_DFL_BSIZE;
+                       else if (fssize < MEDIUM_FSSIZE)
+                               bsize = M_DFL_BSIZE;
+                       else
+                               bsize = L_DFL_BSIZE;
+               }
+       }
+
+       if (fsize == 0)
+               fsize = bsize;
+
+       blocks = fssize * sectorsize / bsize;
+
+       fssize = (u64_t) blocks * bsize / sectorsize;
+
+       if (num_inodes == 0) {
+               if (density != 0)
+                       num_inodes = fssize / density;
+               else {
+                       if (fssize < SMALL_FSSIZE)
+                               num_inodes = S_DFL_NINODE(blocks);
+                       else if (fssize < MEDIUM_FSSIZE)
+                               num_inodes = M_DFL_NINODE(blocks);
+                       else
+                               num_inodes = L_DFL_NINODE(blocks);
+               }
+       }
+       mke2fs(special, fsi, fso);
+
+       if (fsi != -1)
+               close(fsi);
+       if (fso != -1 && fso != fsi)
+               close(fso);
+       exit(EXIT_SUCCESS);
+}
+
+static int64_t
+strsuftoi64(const char *desc, const char *arg, int64_t min, int64_t max,
+    int *num_suffix)
+{
+       int64_t result, r1;
+       int shift = 0;
+       char *ep;
+
+       errno = 0;
+       r1 = strtoll(arg, &ep, 10);
+       if (ep[0] != '\0' && ep[1] != '\0')
+               errx(EXIT_FAILURE,
+                   "%s `%s' is not a valid number.", desc, arg);
+       switch (ep[0]) {
+       case '\0':
+       case 's':
+       case 'S':
+               if (num_suffix != NULL)
+                       *num_suffix = 0;
+               break;
+       case 'g':
+       case 'G':
+               shift += 10;
+               /* FALLTHROUGH */
+       case 'm':
+       case 'M':
+               shift += 10;
+               /* FALLTHROUGH */
+       case 'k':
+       case 'K':
+               shift += 10;
+               /* FALLTHROUGH */
+       case 'b':
+       case 'B':
+               if (num_suffix != NULL)
+                       *num_suffix = 1;
+               break;
+       default:
+               errx(EXIT_FAILURE,
+                   "`%s' is not a valid suffix for %s.", ep, desc);
+       }
+       result = r1 << shift;
+       if (errno == ERANGE || result >> shift != r1)
+               errx(EXIT_FAILURE,
+                   "%s `%s' is too large to convert.", desc, arg);
+       if (result < min)
+               errx(EXIT_FAILURE,
+                   "%s `%s' (%" PRId64 ") is less than the minimum (%"
+                   PRId64 ").", desc, arg, result, min);
+       if (result > max)
+               errx(EXIT_FAILURE,
+                   "%s `%s' (%" PRId64 ") is greater than the maximum (%"
+                   PRId64 ").", desc, arg, result, max);
+       return result;
+}
+
+static const char help_strings[] =
+       "\t-b bsize\tblock size\n"
+       "\t-D inodesize\tsize of an inode in bytes (128 or 256)\n"
+       "\t-F \t\tcreate file system image in regular file\n"
+       "\t-f fsize\tfragment size\n"
+       "\t-I \t\tdo not check that the file system type is `Linux Ext2'\n"
+       "\t-i density\tnumber of bytes per inode\n"
+       "\t-m minfree\tminimum free space %\n"
+       "\t-N \t\tdo not create file system, just print out parameters\n"
+       "\t-n inodes\tnumber of inodes (overrides -i density)\n"
+       "\t-O N\t\tfilesystem revision: 0 ==> REV0, 1 ==> REV1 (default 0)\n"
+       "\t-S secsize\tsector size\n"
+       "\t-s fssize\tfile system size (sectors)\n"
+       "\t-V verbose\toutput verbosity: 0 ==> none, 4 ==> max\n"
+       "\t-v volname\text2fs volume name\n"
+       "\t-Z \t\tpre-zero the image file\n";
+
+static void
+usage(void)
+{
+
+       fprintf(stderr,
+           "usage: %s [ fsoptions ] special-device\n", getprogname());
+       fprintf(stderr, "where fsoptions are:\n");
+       fprintf(stderr, "%s", help_strings);
+
+       exit(EXIT_FAILURE);
+}