From 94715d8e544a29153969034072cc27e737b55671 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Thu, 22 Dec 2011 17:54:36 +0100 Subject: [PATCH] import netbsd ext2fs fsck and newfs --- commands/setup/setup.sh | 12 +- common/include/minix/partition.h | 4 + common/include/sys/disklabel.h | 2 + lib/nbsd_libc/uuid/uuid_create.c | 25 + nbsd_include/Makefile | 14 + nbsd_include/ufs/chfs/chfs.h | 768 ++++++++++++ nbsd_include/ufs/chfs/chfs_args.h | 53 + nbsd_include/ufs/chfs/chfs_inode.h | 136 +++ nbsd_include/ufs/chfs/chfs_pool.h | 84 ++ nbsd_include/ufs/chfs/debug.h | 97 ++ nbsd_include/ufs/chfs/ebh.h | 318 +++++ nbsd_include/ufs/chfs/ebh_media.h | 116 ++ nbsd_include/ufs/chfs/ebh_misc.h | 88 ++ nbsd_include/ufs/chfs/media.h | 200 ++++ nbsd_include/ufs/ext2fs/ext2fs.h | 372 ++++++ nbsd_include/ufs/ext2fs/ext2fs_dinode.h | 186 +++ nbsd_include/ufs/ext2fs/ext2fs_dir.h | 180 +++ nbsd_include/ufs/ext2fs/ext2fs_extern.h | 179 +++ nbsd_include/ufs/ffs/ffs_extern.h | 211 ++++ nbsd_include/ufs/ffs/fs.h | 752 ++++++++++++ nbsd_include/ufs/lfs/lfs.h | 1156 ++++++++++++++++++ nbsd_include/ufs/lfs/lfs_extern.h | 287 +++++ nbsd_include/ufs/mfs/mfs_extern.h | 79 ++ nbsd_include/ufs/mfs/mfsnode.h | 91 ++ nbsd_include/ufs/ufs/dinode.h | 180 +++ nbsd_include/ufs/ufs/dir.h | 160 +++ nbsd_include/ufs/ufs/dirhash.h | 129 ++ nbsd_include/ufs/ufs/extattr.h | 128 ++ nbsd_include/ufs/ufs/inode.h | 300 +++++ nbsd_include/ufs/ufs/quota.h | 97 ++ nbsd_include/ufs/ufs/quota1.h | 111 ++ nbsd_include/ufs/ufs/quota2.h | 131 ++ nbsd_include/ufs/ufs/ufs_bswap.h | 80 ++ nbsd_include/ufs/ufs/ufs_extern.h | 188 +++ nbsd_include/ufs/ufs/ufs_quota.h | 130 ++ nbsd_include/ufs/ufs/ufs_wapbl.h | 178 +++ nbsd_include/ufs/ufs/ufsmount.h | 197 +++ sbin/Makefile | 2 +- sbin/fsck/fsck.c | 9 + sbin/fsck/partutil.c | 4 + sbin/fsck_ext2fs/Makefile | 19 + sbin/fsck_ext2fs/dir.c | 723 +++++++++++ sbin/fsck_ext2fs/ext2fs_bswap.c | 121 ++ sbin/fsck_ext2fs/extern.h | 73 ++ sbin/fsck_ext2fs/fsck.h | 238 ++++ sbin/fsck_ext2fs/fsck_ext2fs.8 | 253 ++++ sbin/fsck_ext2fs/inode.c | 736 ++++++++++++ sbin/fsck_ext2fs/main.c | 358 ++++++ sbin/fsck_ext2fs/pass1.c | 394 ++++++ sbin/fsck_ext2fs/pass1b.c | 130 ++ sbin/fsck_ext2fs/pass2.c | 470 ++++++++ sbin/fsck_ext2fs/pass3.c | 100 ++ sbin/fsck_ext2fs/pass4.c | 164 +++ sbin/fsck_ext2fs/pass5.c | 277 +++++ sbin/fsck_ext2fs/setup.c | 559 +++++++++ sbin/fsck_ext2fs/utilities.c | 527 ++++++++ sbin/newfs_ext2fs/Makefile | 27 + sbin/newfs_ext2fs/extern.h | 45 + sbin/newfs_ext2fs/mke2fs.c | 1459 +++++++++++++++++++++++ sbin/newfs_ext2fs/newfs_ext2fs.8 | 326 +++++ sbin/newfs_ext2fs/newfs_ext2fs.c | 530 ++++++++ 61 files changed, 14958 insertions(+), 5 deletions(-) create mode 100644 nbsd_include/ufs/chfs/chfs.h create mode 100644 nbsd_include/ufs/chfs/chfs_args.h create mode 100644 nbsd_include/ufs/chfs/chfs_inode.h create mode 100644 nbsd_include/ufs/chfs/chfs_pool.h create mode 100644 nbsd_include/ufs/chfs/debug.h create mode 100644 nbsd_include/ufs/chfs/ebh.h create mode 100644 nbsd_include/ufs/chfs/ebh_media.h create mode 100644 nbsd_include/ufs/chfs/ebh_misc.h create mode 100644 nbsd_include/ufs/chfs/media.h create mode 100644 nbsd_include/ufs/ext2fs/ext2fs.h create mode 100644 nbsd_include/ufs/ext2fs/ext2fs_dinode.h create mode 100644 nbsd_include/ufs/ext2fs/ext2fs_dir.h create mode 100644 nbsd_include/ufs/ext2fs/ext2fs_extern.h create mode 100644 nbsd_include/ufs/ffs/ffs_extern.h create mode 100644 nbsd_include/ufs/ffs/fs.h create mode 100644 nbsd_include/ufs/lfs/lfs.h create mode 100644 nbsd_include/ufs/lfs/lfs_extern.h create mode 100644 nbsd_include/ufs/mfs/mfs_extern.h create mode 100644 nbsd_include/ufs/mfs/mfsnode.h create mode 100644 nbsd_include/ufs/ufs/dinode.h create mode 100644 nbsd_include/ufs/ufs/dir.h create mode 100644 nbsd_include/ufs/ufs/dirhash.h create mode 100644 nbsd_include/ufs/ufs/extattr.h create mode 100644 nbsd_include/ufs/ufs/inode.h create mode 100644 nbsd_include/ufs/ufs/quota.h create mode 100644 nbsd_include/ufs/ufs/quota1.h create mode 100644 nbsd_include/ufs/ufs/quota2.h create mode 100644 nbsd_include/ufs/ufs/ufs_bswap.h create mode 100644 nbsd_include/ufs/ufs/ufs_extern.h create mode 100644 nbsd_include/ufs/ufs/ufs_quota.h create mode 100644 nbsd_include/ufs/ufs/ufs_wapbl.h create mode 100644 nbsd_include/ufs/ufs/ufsmount.h create mode 100644 sbin/fsck_ext2fs/Makefile create mode 100644 sbin/fsck_ext2fs/dir.c create mode 100644 sbin/fsck_ext2fs/ext2fs_bswap.c create mode 100644 sbin/fsck_ext2fs/extern.h create mode 100644 sbin/fsck_ext2fs/fsck.h create mode 100644 sbin/fsck_ext2fs/fsck_ext2fs.8 create mode 100644 sbin/fsck_ext2fs/inode.c create mode 100644 sbin/fsck_ext2fs/main.c create mode 100644 sbin/fsck_ext2fs/pass1.c create mode 100644 sbin/fsck_ext2fs/pass1b.c create mode 100644 sbin/fsck_ext2fs/pass2.c create mode 100644 sbin/fsck_ext2fs/pass3.c create mode 100644 sbin/fsck_ext2fs/pass4.c create mode 100644 sbin/fsck_ext2fs/pass5.c create mode 100644 sbin/fsck_ext2fs/setup.c create mode 100644 sbin/fsck_ext2fs/utilities.c create mode 100644 sbin/newfs_ext2fs/Makefile create mode 100644 sbin/newfs_ext2fs/extern.h create mode 100644 sbin/newfs_ext2fs/mke2fs.c create mode 100644 sbin/newfs_ext2fs/newfs_ext2fs.8 create mode 100644 sbin/newfs_ext2fs/newfs_ext2fs.c diff --git a/commands/setup/setup.sh b/commands/setup/setup.sh index 8b045d423..311dbd3e7 100644 --- a/commands/setup/setup.sh +++ b/commands/setup/setup.sh @@ -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. diff --git a/common/include/minix/partition.h b/common/include/minix/partition.h index 0cbd9930c..07f64b436 100644 --- a/common/include/minix/partition.h +++ b/common/include/minix/partition.h @@ -10,6 +10,10 @@ #include #endif +#include + +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 */ diff --git a/common/include/sys/disklabel.h b/common/include/sys/disklabel.h index ff424ea6f..5d2c0e700 100644 --- a/common/include/sys/disklabel.h +++ b/common/include/sys/disklabel.h @@ -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 diff --git a/lib/nbsd_libc/uuid/uuid_create.c b/lib/nbsd_libc/uuid/uuid_create.c index bb40f20d5..da1fe28e1 100644 --- a/lib/nbsd_libc/uuid/uuid_create.c +++ b/lib/nbsd_libc/uuid/uuid_create.c @@ -38,6 +38,31 @@ __RCSID("$NetBSD: uuid_create.c,v 1.1 2004/09/13 21:44:54 thorpej Exp $"); #include +#ifdef __minix +#include +#include +/* 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: diff --git a/nbsd_include/Makefile b/nbsd_include/Makefile index f5e5e19bb..04309c7c0 100644 --- a/nbsd_include/Makefile +++ b/nbsd_include/Makefile @@ -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 index 000000000..53fc3d60d --- /dev/null +++ b/nbsd_include/ufs/chfs/chfs.h @@ -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 + * Copyright (C) 2009 Zoltan Sogor + * Copyright (C) 2009 David Tengeri + * Copyright (C) 2009 Tamas Toth + * Copyright (C) 2010 Adam Hoka + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* 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 index 000000000..a222b4bc1 --- /dev/null +++ b/nbsd_include/ufs/chfs/chfs_args.h @@ -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 index 000000000..0661437c1 --- /dev/null +++ b/nbsd_include/ufs/chfs/chfs_inode.h @@ -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 + * Copyright (C) 2010 Adam Hoka + * 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 +#include +#include +#include + +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 index 000000000..78cb991a3 --- /dev/null +++ b/nbsd_include/ufs/chfs/chfs_pool.h @@ -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 index 000000000..6128f7f01 --- /dev/null +++ b/nbsd_include/ufs/chfs/debug.h @@ -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 , + * Zoltan Sogor , + * ... + * 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 index 000000000..51e6999ba --- /dev/null +++ b/nbsd_include/ufs/chfs/ebh.h @@ -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 + * Copyright (c) 2010 Adam Hoka + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* 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 index 000000000..a1a9b11ad --- /dev/null +++ b/nbsd_include/ufs/chfs/ebh_media.h @@ -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 + * Copyright (C) 2009 Zoltan Sogor + * Copyright (C) 2009 David Tengeri + * Copyright (C) 2010 Adam Hoka + * 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 index 000000000..75b09ae14 --- /dev/null +++ b/nbsd_include/ufs/chfs/ebh_misc.h @@ -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 index 000000000..1f94131a9 --- /dev/null +++ b/nbsd_include/ufs/chfs/media.h @@ -0,0 +1,200 @@ +/*- + * Copyright (c) 2010 Department of Software Engineering, + * University of Szeged, Hungary + * Copyright (C) 2009 Ferenc Havasi + * Copyright (C) 2009 Zoltan Sogor + * Copyright (C) 2009 David Tengeri + * Copyright (C) 2010 Adam Hoka + * 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 index 000000000..6b994a237 --- /dev/null +++ b/nbsd_include/ufs/ext2fs/ext2fs.h @@ -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 + +/* + * 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 index 000000000..0020e9a4a --- /dev/null +++ b/nbsd_include/ufs/ext2fs/ext2fs_dinode.h @@ -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 + +/* + * 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 index 000000000..e1dc152b8 --- /dev/null +++ b/nbsd_include/ufs/ext2fs/ext2fs_dir.h @@ -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 index 000000000..aacff80e7 --- /dev/null +++ b/nbsd_include/ufs/ext2fs/ext2fs_extern.h @@ -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 index 000000000..c46631bae --- /dev/null +++ b/nbsd_include/ufs/ffs/ffs_extern.h @@ -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 + +#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 +#include +#include + +/* 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 index 000000000..7e5af7c89 --- /dev/null +++ b/nbsd_include/ufs/ffs/fs.h @@ -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 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 index 000000000..9f6ae8d7e --- /dev/null +++ b/nbsd_include/ufs/lfs/lfs.h @@ -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 . + * + * 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 +#include +#include +#include + +/* + * 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 + +#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 index 000000000..46a9555e7 --- /dev/null +++ b/nbsd_include/ufs/lfs/lfs_extern.h @@ -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 . + * + * 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 + +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 index 000000000..b64449902 --- /dev/null +++ b/nbsd_include/ufs/mfs/mfs_extern.h @@ -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 +#include +#include + +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 + +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 index 000000000..c1ed9c37b --- /dev/null +++ b/nbsd_include/ufs/mfs/mfsnode.h @@ -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 index 000000000..af0dabb0d --- /dev/null +++ b/nbsd_include/ufs/ufs/dinode.h @@ -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 index 000000000..74cf7e739 --- /dev/null +++ b/nbsd_include/ufs/ufs/dir.h @@ -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 index 000000000..914eeca8d --- /dev/null +++ b/nbsd_include/ufs/ufs/dirhash.h @@ -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 index 000000000..e87d0632c --- /dev/null +++ b/nbsd_include/ufs/ufs/extattr.h @@ -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 index 000000000..a904ef97b --- /dev/null +++ b/nbsd_include/ufs/ufs/inode.h @@ -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 +#include +#include +#include +#include +#include + +/* + * 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 index 000000000..58b14528d --- /dev/null +++ b/nbsd_include/ufs/ufs/quota.h @@ -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 +__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 + +__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 index 000000000..3fdf13777 --- /dev/null +++ b/nbsd_include/ufs/ufs/quota1.h @@ -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 +#include + +/* + * 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 index 000000000..f2456a201 --- /dev/null +++ b/nbsd_include/ufs/ufs/quota2.h @@ -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 +#include + + +/* 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 index 000000000..c793e55f8 --- /dev/null +++ b/nbsd_include/ufs/ufs/ufs_bswap.h @@ -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 + +/* 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 index 000000000..61e42eefb --- /dev/null +++ b/nbsd_include/ufs/ufs/ufs_extern.h @@ -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 + +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 index 000000000..efc87f1a8 --- /dev/null +++ b/nbsd_include/ufs/ufs/ufs_quota.h @@ -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 +#include + +/* 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 index 000000000..6dc878c63 --- /dev/null +++ b/nbsd_include/ufs/ufs/ufs_wapbl.h @@ -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 index 000000000..9fcc89739 --- /dev/null +++ b/nbsd_include/ufs/ufs/ufsmount.h @@ -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 /* 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 + +#include +#include + +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_ */ diff --git a/sbin/Makefile b/sbin/Makefile index 0b8c6276a..220ff19f3 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -2,6 +2,6 @@ .include -SUBDIR= fsck +SUBDIR= fsck fsck_ext2fs newfs_ext2fs .include diff --git a/sbin/fsck/fsck.c b/sbin/fsck/fsck.c index 4bf0296e0..e57ec3065 100644 --- a/sbin/fsck/fsck.c +++ b/sbin/fsck/fsck.c @@ -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 } diff --git a/sbin/fsck/partutil.c b/sbin/fsck/partutil.c index 4d626619a..88cf59d9e 100644 --- a/sbin/fsck/partutil.c +++ b/sbin/fsck/partutil.c @@ -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 index 000000000..c93408a3c --- /dev/null +++ b/sbin/fsck_ext2fs/Makefile @@ -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 + +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 + +LDADD+=-lutil +DPADD+=${LIBUTIL} diff --git a/sbin/fsck_ext2fs/dir.c b/sbin/fsck_ext2fs/dir.c new file mode 100644 index 000000000..8036f5298 --- /dev/null +++ b/sbin/fsck_ext2fs/dir.c @@ -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 +#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 +#include +#include +#include +#include +#include + +#include /* for IFMT & friends */ + +#include +#include +#include +#include + +#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 index 000000000..ba0ddc462 --- /dev/null +++ b/sbin/fsck_ext2fs/ext2fs_bswap.c @@ -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 +__KERNEL_RCSID(0, "$NetBSD: ext2fs_bswap.c,v 1.16 2009/10/19 18:41:17 bouyer Exp $"); + +#include +#include +#include + +#if defined(_KERNEL) +#include +#else +#include +#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 index 000000000..fdaca8e89 --- /dev/null +++ b/sbin/fsck_ext2fs/extern.h @@ -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 index 000000000..cd02016c3 --- /dev/null +++ b/sbin/fsck_ext2fs/fsck.h @@ -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 index 000000000..4dcefa89c --- /dev/null +++ b/sbin/fsck_ext2fs/fsck_ext2fs.8 @@ -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 index 000000000..3c0f88fe9 --- /dev/null +++ b/sbin/fsck_ext2fs/inode.c @@ -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 +#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 +#include +#include +#include +#include + +#include /* for IFMT & friends */ +#ifndef SMALL +#include +#endif +#include +#include +#include +#include + +#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 index 000000000..2160e9098 --- /dev/null +++ b/sbin/fsck_ext2fs/main.c @@ -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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..12fe784b1 --- /dev/null +++ b/sbin/fsck_ext2fs/pass1.c @@ -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 +#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 +#include +#include +#include +#include + +#include /* for IFMT & friends */ + +#include +#include +#include +#include + +#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 index 000000000..31b1d3e26 --- /dev/null +++ b/sbin/fsck_ext2fs/pass1b.c @@ -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 +#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 +#include +#include +#include + +#include +#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 index 000000000..01f0aa589 --- /dev/null +++ b/sbin/fsck_ext2fs/pass2.c @@ -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 +#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 +#include +#include +#include +#include + +#include /* for IFMT & friends */ + +#include +#include +#include + +#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 index 000000000..bc19338c9 --- /dev/null +++ b/sbin/fsck_ext2fs/pass3.c @@ -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 +#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 +#include +#include +#include +#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 index 000000000..f184e38ec --- /dev/null +++ b/sbin/fsck_ext2fs/pass4.c @@ -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 +#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 +#include +#include +#include +#include +#include + +#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 index 000000000..92467bd87 --- /dev/null +++ b/sbin/fsck_ext2fs/pass5.c @@ -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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..d63185bd5 --- /dev/null +++ b/sbin/fsck_ext2fs/setup.c @@ -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 +#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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 index 000000000..116937876 --- /dev/null +++ b/sbin/fsck_ext2fs/utilities.c @@ -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 +#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 +#include +#include +#include +#include +#include /* for IFMT & friends */ +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..7c426ab11 --- /dev/null +++ b/sbin/newfs_ext2fs/Makefile @@ -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 + +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 diff --git a/sbin/newfs_ext2fs/extern.h b/sbin/newfs_ext2fs/extern.h new file mode 100644 index 000000000..809bd6f9d --- /dev/null +++ b/sbin/newfs_ext2fs/extern.h @@ -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 */ +#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 index 000000000..5ecb882f4 --- /dev/null +++ b/sbin/newfs_ext2fs/mke2fs.c @@ -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 +#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 +#include +#include +#include +#include +#include +#include + +#define _MINIX +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ? */ +#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 index 000000000..9d87ebc91 --- /dev/null +++ b/sbin/newfs_ext2fs/newfs_ext2fs.8 @@ -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 index 000000000..be9a99831 --- /dev/null +++ b/sbin/newfs_ext2fs/newfs_ext2fs.c @@ -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 +#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 +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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); +}