diff --git a/distrib/sets/lists/base/mi b/distrib/sets/lists/base/mi index fccfd48143fe..daec5a50dfc4 100644 --- a/distrib/sets/lists/base/mi +++ b/distrib/sets/lists/base/mi @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.939 2011/05/20 01:59:14 msaitoh Exp $ +# $NetBSD: mi,v 1.940 2011/06/27 11:52:22 uch Exp $ # # Note: Don't delete entries from here - mark them as "obsolete" instead, # unless otherwise stated below. @@ -239,6 +239,7 @@ ./sbin/fsck_ffs base-sysutil-root ./sbin/fsck_lfs base-sysutil-root ./sbin/fsck_msdos base-sysutil-root +./sbin/fsck_v7fs base-sysutil-root ./sbin/fsdb base-sysutil-root ./sbin/fsirand base-sysutil-root ./sbin/gpt base-sysutil-root @@ -289,6 +290,7 @@ ./sbin/mount_ufs base-sysutil-root ./sbin/mount_umap base-miscfs-root ./sbin/mount_union base-miscfs-root +./sbin/mount_v7fs base-sysutil-root ./sbin/mountd base-obsolete obsolete ./sbin/newbtconf base-sysutil-root ./sbin/newfs base-sysutil-root @@ -297,6 +299,7 @@ ./sbin/newfs_msdos base-sysutil-root ./sbin/newfs_sysvbfs base-sysutil-root ./sbin/newfs_udf base-sysutil-root +./sbin/newfs_v7fs base-sysutil-root ./sbin/newlfs base-obsolete obsolete ./sbin/nfsd base-obsolete obsolete ./sbin/nfsiod base-obsolete obsolete @@ -796,6 +799,7 @@ ./usr/include/fs/sysvbfs base-c-usr ./usr/include/fs/tmpfs base-c-usr ./usr/include/fs/udf base-c-usr +./usr/include/fs/v7fs base-c-usr ./usr/include/g++ base-cxx-usr ./usr/include/g++/backward base-cxx-usr ./usr/include/g++/bits base-cxx-usr diff --git a/distrib/sets/lists/comp/mi b/distrib/sets/lists/comp/mi index d12dc6001d84..aeb4ff6b1fee 100644 --- a/distrib/sets/lists/comp/mi +++ b/distrib/sets/lists/comp/mi @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.1632 2011/06/26 16:42:40 christos Exp $ +# $NetBSD: mi,v 1.1633 2011/06/27 11:52:22 uch Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. # @@ -663,6 +663,8 @@ ./usr/include/fs/tmpfs/tmpfs_args.h comp-c-include ./usr/include/fs/udf/ecma167-udf.h comp-c-include ./usr/include/fs/udf/udf_mount.h comp-c-include +./usr/include/fs/v7fs/v7fs.h comp-c-include +./usr/include/fs/v7fs/v7fs_args.h comp-c-include ./usr/include/fstab.h comp-c-include ./usr/include/fts.h comp-c-include ./usr/include/ftw.h comp-c-include diff --git a/distrib/sets/lists/man/mi b/distrib/sets/lists/man/mi index ac5496008b5d..27280700a30b 100644 --- a/distrib/sets/lists/man/mi +++ b/distrib/sets/lists/man/mi @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.1321 2011/06/22 20:29:38 jruoho Exp $ +# $NetBSD: mi,v 1.1322 2011/06/27 11:52:23 uch Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. # @@ -2245,6 +2245,7 @@ ./usr/share/man/cat8/fsck_ffs.0 man-sysutil-catman .cat ./usr/share/man/cat8/fsck_lfs.0 man-sysutil-catman .cat ./usr/share/man/cat8/fsck_msdos.0 man-sysutil-catman .cat +./usr/share/man/cat8/fsck_v7fs.0 man-sysutil-catman .cat ./usr/share/man/cat8/fsdb.0 man-sysutil-catman .cat ./usr/share/man/cat8/fsinfo.0 man-sysutil-catman .cat ./usr/share/man/cat8/fsirand.0 man-sysutil-catman .cat @@ -2471,6 +2472,7 @@ ./usr/share/man/cat8/mount_ufs.0 man-sysutil-catman .cat ./usr/share/man/cat8/mount_umap.0 man-miscfs-catman .cat ./usr/share/man/cat8/mount_union.0 man-miscfs-catman .cat +./usr/share/man/cat8/mount_v7fs.0 man-sysutil-catman .cat ./usr/share/man/cat8/mountd.0 man-nfsserver-catman .cat ./usr/share/man/cat8/moused.0 man-sysutil-catman .cat ./usr/share/man/cat8/mrinfo.0 man-netutil-catman .cat @@ -2509,6 +2511,7 @@ ./usr/share/man/cat8/newfs_msdos.0 man-sysutil-catman .cat ./usr/share/man/cat8/newfs_sysvbfs.0 man-sysutil-catman .cat ./usr/share/man/cat8/newfs_udf.0 man-sysutil-catman .cat +./usr/share/man/cat8/newfs_v7fs.0 man-sysutil-catman .cat ./usr/share/man/cat8/newlfs.0 man-obsolete obsolete ./usr/share/man/cat8/news68k/MAKEDEV.0 man-obsolete obsolete ./usr/share/man/cat8/news68k/makedev.0 man-obsolete obsolete @@ -4877,6 +4880,7 @@ ./usr/share/man/html8/fsck_ffs.html man-sysutil-htmlman html ./usr/share/man/html8/fsck_lfs.html man-sysutil-htmlman html ./usr/share/man/html8/fsck_msdos.html man-sysutil-htmlman html +./usr/share/man/html8/fsck_v7fs.html man-sysutil-htmlman html ./usr/share/man/html8/fsdb.html man-sysutil-htmlman html ./usr/share/man/html8/fsinfo.html man-sysutil-htmlman html ./usr/share/man/html8/fsirand.html man-sysutil-htmlman html @@ -5057,6 +5061,7 @@ ./usr/share/man/html8/mount_ufs.html man-sysutil-htmlman html ./usr/share/man/html8/mount_umap.html man-miscfs-htmlman html ./usr/share/man/html8/mount_union.html man-miscfs-htmlman html +./usr/share/man/html8/mount_v7fs.html man-sysutil-htmlman html ./usr/share/man/html8/mountd.html man-nfsserver-htmlman html ./usr/share/man/html8/moused.html man-sysutil-htmlman html ./usr/share/man/html8/mrinfo.html man-netutil-htmlman html @@ -5083,6 +5088,7 @@ ./usr/share/man/html8/newfs_msdos.html man-sysutil-htmlman html ./usr/share/man/html8/newfs_sysvbfs.html man-sysutil-htmlman html ./usr/share/man/html8/newfs_udf.html man-sysutil-htmlman html +./usr/share/man/html8/newfs_v7fs.html man-sysutil-htmlman html ./usr/share/man/html8/newsyslog.html man-sysutil-htmlman html ./usr/share/man/html8/next68k/boot.html man-sys-htmlman html ./usr/share/man/html8/nfsd.html man-nfsserver-htmlman html @@ -7601,6 +7607,7 @@ ./usr/share/man/man8/fsck_ffs.8 man-sysutil-man .man ./usr/share/man/man8/fsck_lfs.8 man-sysutil-man .man ./usr/share/man/man8/fsck_msdos.8 man-sysutil-man .man +./usr/share/man/man8/fsck_v7fs.8 man-sysutil-man .man ./usr/share/man/man8/fsdb.8 man-sysutil-man .man ./usr/share/man/man8/fsinfo.8 man-sysutil-man .man ./usr/share/man/man8/fsirand.8 man-sysutil-man .man @@ -7828,6 +7835,7 @@ ./usr/share/man/man8/mount_ufs.8 man-sysutil-man .man ./usr/share/man/man8/mount_umap.8 man-miscfs-man .man ./usr/share/man/man8/mount_union.8 man-miscfs-man .man +./usr/share/man/man8/mount_v7fs.8 man-sysutil-man .man ./usr/share/man/man8/mountd.8 man-nfsserver-man .man ./usr/share/man/man8/moused.8 man-sysutil-man .man ./usr/share/man/man8/mrinfo.8 man-netutil-man .man @@ -7866,6 +7874,7 @@ ./usr/share/man/man8/newfs_msdos.8 man-sysutil-man .man ./usr/share/man/man8/newfs_sysvbfs.8 man-sysutil-man .man ./usr/share/man/man8/newfs_udf.8 man-sysutil-man .man +./usr/share/man/man8/newfs_v7fs.8 man-sysutil-man .man ./usr/share/man/man8/newlfs.8 man-obsolete obsolete ./usr/share/man/man8/news68k/MAKEDEV.8 man-obsolete obsolete ./usr/share/man/man8/news68k/makedev.8 man-obsolete obsolete diff --git a/sbin/Makefile b/sbin/Makefile index 204952e54948..9078c119bc9b 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.119 2011/02/08 03:20:15 haad Exp $ +# $NetBSD: Makefile,v 1.120 2011/06/27 11:52:23 uch Exp $ # @(#)Makefile 8.5 (Berkeley) 3/31/94 # Not ported: XNSrouted enpload scsiformat startslip @@ -21,6 +21,7 @@ SUBDIR+= newfs_lfs fsck_lfs dump_lfs resize_lfs SUBDIR+= newfs_msdos fsck_msdos SUBDIR+= newfs_sysvbfs SUBDIR+= newfs_udf +SUBDIR+= newfs_v7fs fsck_v7fs SUBDIR+= mount_ados SUBDIR+= mount_cd9660 SUBDIR+= mount_efs @@ -47,6 +48,7 @@ SUBDIR+= mount_sysvbfs SUBDIR+= mount_tmpfs SUBDIR+= mount_umap SUBDIR+= mount_union +SUBDIR+= mount_v7fs .if (${MKCRYPTO} != "no") SUBDIR+= cgdconfig diff --git a/sbin/fsck_v7fs/Makefile b/sbin/fsck_v7fs/Makefile new file mode 100644 index 000000000000..214c65047657 --- /dev/null +++ b/sbin/fsck_v7fs/Makefile @@ -0,0 +1,20 @@ +# $NetBSD: Makefile,v 1.1 2011/06/27 11:52:58 uch Exp $ + +.include + +PROG= fsck_v7fs +MAN= fsck_v7fs.8 +SRCS= fsck_v7fs.c main.c pathname.c inode.c datablock.c freeblock.c \ +v7fs_datablock.c v7fs_io.c v7fs_superblock.c v7fs_inode.c v7fs_file.c \ +v7fs_dirent.c v7fs_endian.c v7fs_io_user.c v7fs_inode_util.c \ +v7fs_file_util.c v7fs_superblock_util.c fsutil.c progress.c + +FSCK= ${NETBSDSRCDIR}/sbin/fsck +V7FS= ${NETBSDSRCDIR}/sys/fs/v7fs +CPPFLAGS+= -I${FSCK} -I${V7FS} -DV7FS_EI -g +.PATH: ${FSCK} ${V7FS} + +LDADD+=-lutil +DPADD+=${LIBUTIL} + +.include diff --git a/sbin/fsck_v7fs/datablock.c b/sbin/fsck_v7fs/datablock.c new file mode 100644 index 000000000000..ed3bc064f4a5 --- /dev/null +++ b/sbin/fsck_v7fs/datablock.c @@ -0,0 +1,403 @@ +/* $NetBSD: datablock.c,v 1.1 2011/06/27 11:52:58 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: datablock.c,v 1.1 2011/06/27 11:52:58 uch Exp $"); +#endif /* not lint */ + +#include +#include + +#include "v7fs.h" +#include "v7fs_endian.h" +#include "v7fs_superblock.h" +#include "v7fs_inode.h" +#include "v7fs_impl.h" +#include "v7fs_datablock.h" +#include "v7fs_file.h" +#include "fsck_v7fs.h" + +static void datablock_dup_remove(struct v7fs_self *, v7fs_ino_t, v7fs_ino_t, + v7fs_daddr_t); + +struct loop_context { + v7fs_ino_t i; + v7fs_ino_t j; + v7fs_daddr_t blk; +}; + +/* + * datablock vs freeblock + */ +static int +freeblock_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t freeblk) +{ + struct loop_context *arg = (struct loop_context *)ctx; + + progress(0); + if (arg->blk == freeblk) { + pwarn("*** ino%d(%s) data block %d found at freeblock", + arg->i, filename(fs, arg->i), freeblk); + if (reply("CORRECT?")) { + freeblock_dup_remove(fs, freeblk); + return V7FS_ITERATOR_ERROR; /* Rescan needed. */ + } + } + + return 0; +} + +static int +datablock_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, + size_t sz __unused) +{ + struct loop_context *arg = (struct loop_context *)ctx; + int ret; + + arg->blk = blk; + if ((ret = v7fs_freeblock_foreach(fs, freeblock_subr, ctx)) == + V7FS_ITERATOR_ERROR) + return ret; + + return 0; +} + +static int +inode_subr(struct v7fs_self *fs, void *ctx, struct v7fs_inode *p, + v7fs_ino_t ino) +{ + struct loop_context *arg = (struct loop_context *)ctx; + int ret; + + arg->i = ino; + + if ((ret = v7fs_datablock_foreach(fs, p, datablock_subr, ctx)) == + V7FS_ITERATOR_ERROR) + return ret; + + return 0; +} + +int +datablock_vs_freeblock_check(struct v7fs_self *fs) +{ + struct v7fs_superblock *sb = &fs->superblock; + int nfree = sb->total_freeblock; + int ndata = sb->volume_size - sb->datablock_start_sector - nfree; + int ret; + + progress(&(struct progress_arg){ .label = "data-free", .tick = (ndata / + PROGRESS_BAR_GRANULE) * nfree }); + + if ((ret = v7fs_ilist_foreach(fs, inode_subr, &(struct loop_context) + { .i = 0, .blk = 0 })) == V7FS_ITERATOR_ERROR) + return FSCK_EXIT_UNRESOLVED; + + return 0; +} + + +/* + * datablock vs datablock + */ +static int +datablock_i_j(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz + __unused) +{ + struct loop_context *arg = (struct loop_context *)ctx; + + progress(0); + if (blk == arg->blk) { + pwarn("*** duplicated block found." + "#%d(%s) and #%d(%s) refer block %d", + arg->i, filename(fs, arg->i), + arg->j, filename(fs, arg->j), blk); + if (reply("CORRECT?")) { + datablock_dup_remove(fs, arg->i, arg->j, blk); + return V7FS_ITERATOR_ERROR; /* Rescan needed. */ + } + } + + return 0; +} + +static int +loopover_j(struct v7fs_self *fs, void *ctx, struct v7fs_inode *p, + v7fs_ino_t ino) +{ + struct loop_context *arg = (struct loop_context *)ctx; + int ret; + + arg->j = ino; + + if (arg->j >= arg->i) + return V7FS_ITERATOR_BREAK; + + if ((ret = v7fs_datablock_foreach(fs, p, datablock_i_j, ctx)) == + V7FS_ITERATOR_ERROR) + return V7FS_ITERATOR_ERROR; + + return 0; +} + +static int +datablock_i(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, + size_t sz __unused) +{ + struct loop_context *arg = (struct loop_context *)ctx; + int ret; + + arg->blk = blk; + + if ((ret = v7fs_ilist_foreach(fs, loopover_j, ctx)) == + V7FS_ITERATOR_ERROR) + return V7FS_ITERATOR_ERROR; + + return 0; +} + +static int +loopover_i(struct v7fs_self *fs, void *ctx, struct v7fs_inode *inode, + v7fs_ino_t ino) +{ + struct loop_context *arg = (struct loop_context *)ctx; + int ret; + + arg->i = ino; + + if ((ret = v7fs_datablock_foreach(fs, inode, datablock_i, ctx)) == + V7FS_ITERATOR_ERROR) + return V7FS_ITERATOR_ERROR; + + return 0; +} + + +int +datablock_vs_datablock_check(struct v7fs_self *fs) +{ + const struct v7fs_superblock *sb = &fs->superblock; + int n = sb->volume_size - sb->total_freeblock; + int ret; + + progress(&(struct progress_arg){ .label = "data-data", .tick = (n / 2) + * ((n - 1) / PROGRESS_BAR_GRANULE) }); + + if ((ret = v7fs_ilist_foreach(fs, loopover_i, &(struct loop_context){ + .i = 0, .j = 0 })) == V7FS_ITERATOR_ERROR) + return FSCK_EXIT_UNRESOLVED; + + return 0; +} + +/* + * Remove duplicated block. + */ +static void +copy_block(struct v7fs_self *fs, v7fs_daddr_t dst, v7fs_daddr_t src) +{ + void *buf; + + if (!(buf = scratch_read(fs, src))) + return; + fs->io.write(fs->io.cookie, buf, dst); + scratch_free(fs, buf); + + pwarn("copy block %d->%d\n", src, dst); +} + +static void +replace_block_direct(struct v7fs_self *fs, struct v7fs_inode *p, int dupidx, + v7fs_daddr_t newblk) +{ + v7fs_daddr_t oldblk; + + oldblk = p->addr[dupidx]; + p->addr[dupidx] = newblk; + v7fs_inode_writeback(fs, p); /* endian conversion done by here. */ + + copy_block(fs, newblk, oldblk); +} + +static void +prepare_list(struct v7fs_self *fs, v7fs_daddr_t listblk, v7fs_daddr_t *p) +{ + size_t i; + + fs->io.read(fs->io.cookie, (void *)p, listblk); + for (i = 0; i < V7FS_DADDR_PER_BLOCK; i++) + p[i] = V7FS_VAL32(fs, p[i]); +} + +static void +replace_block_indexed(struct v7fs_self *fs, v7fs_daddr_t listblk, int dupidx, + v7fs_daddr_t newblk) +{ + void *buf; + v7fs_daddr_t *list; + v7fs_daddr_t oldblk; + + if (!(buf = scratch_read(fs, listblk))) + return; + list = (v7fs_daddr_t *)buf; + oldblk = V7FS_VAL32(fs, list[dupidx]); + list[dupidx] = V7FS_VAL32(fs, newblk); + fs->io.write(fs->io.cookie, buf, listblk); + scratch_free(fs, buf); + + copy_block(fs, newblk, oldblk); + pwarn("dup block replaced by %d\n", newblk); +} + +static bool +dupfind_loop1(struct v7fs_self *fs, v7fs_daddr_t listblk, v7fs_daddr_t dupblk, + v7fs_daddr_t newblk) +{ + v7fs_daddr_t list[V7FS_DADDR_PER_BLOCK]; + size_t i; + + prepare_list(fs, listblk, list); + for (i = 0; i < V7FS_DADDR_PER_BLOCK; i++) { + if (list[i] == dupblk) { + replace_block_indexed(fs, listblk, i, newblk); + return true; + } + } + + return false; +} + +static bool +dupfind_loop2(struct v7fs_self *fs, v7fs_daddr_t listblk, v7fs_daddr_t dupblk, + v7fs_daddr_t newblk) +{ + v7fs_daddr_t list[V7FS_DADDR_PER_BLOCK]; + v7fs_daddr_t blk; + size_t i; + + prepare_list(fs, listblk, list); + for (i = 0; i < V7FS_DADDR_PER_BLOCK; i++) { + if ((blk = list[i]) == dupblk) { + replace_block_indexed(fs, listblk, i, newblk); + return true; + } + if (dupfind_loop1(fs, blk, dupblk, newblk)) + return true; + } + + return false; +} + +static void +do_replace(struct v7fs_self *fs, struct v7fs_inode *p, v7fs_daddr_t dupblk, + v7fs_daddr_t newblk) +{ + size_t i; + v7fs_daddr_t blk, blk2; + v7fs_daddr_t list[V7FS_DADDR_PER_BLOCK]; + + /* Direct */ + for (i = 0; i < V7FS_NADDR_DIRECT; i++) { + if (p->addr[i] == dupblk) { + replace_block_direct(fs, p, i, newblk); + return; + } + } + + /* Index 1 */ + if ((blk = p->addr[V7FS_NADDR_INDEX1]) == dupblk) { + replace_block_direct(fs, p, V7FS_NADDR_INDEX1, newblk); + return; + } + if (dupfind_loop1(fs, blk, dupblk, newblk)) + return; + + /* Index 2 */ + if ((blk = p->addr[V7FS_NADDR_INDEX2]) == dupblk) { + replace_block_direct(fs, p, V7FS_NADDR_INDEX2, newblk); + return; + } + if (dupfind_loop2(fs, blk, dupblk, newblk)) + return; + + /* Index 3 */ + if ((blk = p->addr[V7FS_NADDR_INDEX3]) == dupblk) { + replace_block_direct(fs, p, V7FS_NADDR_INDEX3, newblk); + return; + } + prepare_list(fs, blk, list); + for (i = 0; i < V7FS_DADDR_PER_BLOCK; i++) { + if ((blk2 = list[i]) == dupblk) { + replace_block_indexed(fs, blk, i, newblk); + return; + } + if (dupfind_loop2(fs, blk2, dupblk, newblk)) + return; + } +} + +static void +datablock_dup_remove(struct v7fs_self *fs, v7fs_ino_t i, v7fs_ino_t j, + v7fs_daddr_t dupblk) +{ + struct v7fs_inode inode; + v7fs_ino_t victim; + v7fs_daddr_t newblk; + int error; + + pwarn("Is victim %s (%s is preserved)", filename(fs, i), + filename(fs, j)); + if (reply("?")) { + victim = i; + } else { + pwarn("Is victim %s (%s is preserved)", + filename(fs, j), filename(fs, i)); + if (reply("?")) { + victim = j; + } else { + pwarn("Don't correct.\n"); + return; + } + } + + if ((error = v7fs_inode_load(fs, &inode, victim))) + return; + + /* replace block. */ + if ((error = v7fs_datablock_allocate(fs, &newblk))) { + pwarn("Can't allocate substitute block."); + return; + } + + do_replace(fs, &inode, dupblk, newblk); +} + diff --git a/sbin/fsck_v7fs/freeblock.c b/sbin/fsck_v7fs/freeblock.c new file mode 100644 index 000000000000..cdd2bd40afa2 --- /dev/null +++ b/sbin/fsck_v7fs/freeblock.c @@ -0,0 +1,294 @@ +/* $NetBSD: freeblock.c,v 1.1 2011/06/27 11:52:58 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: freeblock.c,v 1.1 2011/06/27 11:52:58 uch Exp $"); +#endif /* not lint */ + +#include +#include +#include + +#include "v7fs.h" +#include "v7fs_superblock.h" +#include "v7fs_inode.h" +#include "v7fs_impl.h" +#include "v7fs_datablock.h" +#include "fsck_v7fs.h" + +struct freeblock_arg { + v7fs_daddr_t i; + v7fs_daddr_t j; + v7fs_daddr_t blk; +}; + +static int +freeblock_subr_cnt(struct v7fs_self *fs __unused, void *ctx, + v7fs_daddr_t blk __unused) +{ + ((struct freeblock_arg *)ctx)->blk++; + progress(0); + + return 0; +} + +static int +freeblock_subr_j(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk) +{ + struct freeblock_arg *arg = (struct freeblock_arg *)ctx; + + if (!datablock_number_sanity(fs, blk)) { + pwarn("invalid block#%d in freeblock", blk); + /* This problem should be fixed at freeblock_check(). */ + return FSCK_EXIT_CHECK_FAILED; + } + + if (arg->j >= arg->i) + return V7FS_ITERATOR_BREAK; + + progress(0); + + if (arg->blk == blk) { + pwarn("freeblock duplicate %d %d blk=%d", arg->i, arg->j, blk); + if (reply("CORRECT?")) { + freeblock_dup_remove(fs, blk); + } + return FSCK_EXIT_UNRESOLVED; /* Rescan needed. */ + } + + arg->j++; + + return 0; /*continue */ +} + +static int +freeblock_subr_i(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk) +{ + struct freeblock_arg *arg = (struct freeblock_arg *)ctx; + int ret; + + if (!datablock_number_sanity(fs, blk)) { + pwarn("invalid block#%d in freeblock", blk); + /* This problem should be fixed at freeblock_check(). */ + return FSCK_EXIT_CHECK_FAILED; + } + + arg->j = 0; + arg->blk = blk; + ret = v7fs_freeblock_foreach(fs, freeblock_subr_j, ctx); + if (!((ret == 0) || (ret == V7FS_ITERATOR_BREAK))) + return ret; + + arg->i++; + + return 0; +} + +int +freeblock_vs_freeblock_check(struct v7fs_self *fs) +{ + struct v7fs_superblock *sb = &fs->superblock; + int n = sb->total_freeblock; + + progress(&(struct progress_arg){ .label = "free-free", .tick = (n / 2) + * ((n - 1) / PROGRESS_BAR_GRANULE) }); + + return v7fs_freeblock_foreach(fs, freeblock_subr_i, + &(struct freeblock_arg){ .i = 0 }); +} + +/* + * Remove duplicated block. + */ +void +freeblock_dup_remove(struct v7fs_self *fs, v7fs_daddr_t dupblk) +{ + struct v7fs_superblock *sb = &fs->superblock; + struct v7fs_freeblock *fb; + int i, total, n; + void *buf; + v7fs_daddr_t blk; + + n = sb->total_freeblock; + + /* Superblock cache. */ + total = 0; + for (i = sb->nfreeblock - 1; (i > 0) && (n >= 0); i--, n--, total++) { + if (sb->freeblock[i] == dupblk) { /* Duplicate found. */ + memmove(sb->freeblock + i, sb->freeblock + i + 1, + sb->nfreeblock - 1 - i); + sb->nfreeblock--; + sb->modified = 1; + v7fs_superblock_writeback(fs); + pwarn("remove duplicated freeblock %d" + "from superblock", dupblk); + return; + } + } + if (!n) + return; + blk = sb->freeblock[0]; + + do { + if (!blk) + break; + buf = scratch_read(fs, blk); + fb = (struct v7fs_freeblock *)buf; + v7fs_freeblock_endian_convert(fs, fb); + + if (blk == dupblk) { + /* This is difficult probrem. give up! */ + /* or newly allocate block, and copy it and link. */ + pwarn("duplicated block is freeblock list." + "Shortage freeblock %d->%d.", + sb->nfreeblock, total); + sb->nfreeblock = total; /*shotage freeblock list. */ + sb->modified = 1; + v7fs_superblock_writeback(fs); + return; + } + total++; + + blk = fb->freeblock[0]; /* next freeblock list */ + + for (i = fb->nfreeblock - 1; (i > 0) && (n >= 0); + i--, n--, total++) { + if (fb->freeblock[i] == dupblk) { + pwarn("remove duplicated freeblock" + "%d from list %d", dupblk, blk); + memmove(fb->freeblock + i, fb->freeblock + i + + 1, fb->nfreeblock - 1 - i); + /* Writeback superblock. */ + sb->nfreeblock--; + sb->modified = 1; + v7fs_superblock_writeback(fs); + /* Writeback freeblock list block. */ + v7fs_freeblock_endian_convert(fs, fb); + fs->io.write(fs->io.cookie, buf, blk); + return; + } + } + scratch_free(fs, buf); + } while (n); + + return; +} + +int +v7fs_freeblock_foreach(struct v7fs_self *fs, + int (*func)(struct v7fs_self *, void *, v7fs_daddr_t), void *ctx) +{ + struct v7fs_superblock *sb = &fs->superblock; + struct v7fs_freeblock *fb; + int i, n; + void *buf; + v7fs_daddr_t blk; + int ret; + + n = sb->total_freeblock; + + /* Superblock cache. */ + for (i = sb->nfreeblock - 1; (i > 0) && (n >= 0); i--, n--) { + if ((ret = func(fs, ctx, sb->freeblock[i]))) + return ret; + } + if (!n) + return 0; + blk = sb->freeblock[0]; + if (!datablock_number_sanity(fs, blk)) { + pwarn("invalid freeblock list block#%d.", blk); + return 0; + } + do { + if (!blk) + break; + if (!(buf = scratch_read(fs, blk))) + return 0; + fb = (struct v7fs_freeblock *)buf; + + if (v7fs_freeblock_endian_convert(fs, fb)) { + pwarn("***corrupt freeblock list blk#%d", blk); + return 0; + } + + /* freeblock list is used as freeblock. */ + if ((ret = func(fs, ctx, blk))) + return ret; + + blk = fb->freeblock[0]; /* next freeblock list */ + + for (i = fb->nfreeblock - 1; (i > 0) && (n >= 0); i--, n--) + if ((ret = func(fs, ctx, fb->freeblock[i]))) { + scratch_free(fs, buf); + return ret; + } + scratch_free(fs, buf); + } while (n); + + return 0; +} + +int +freeblock_check(struct v7fs_self *fs) +{ + struct v7fs_superblock *sb = &fs->superblock; + struct freeblock_arg freeblock_arg = { .blk = 0 }; + v7fs_daddr_t blk; + v7fs_daddr_t datablock_size = sb->volume_size - + sb->datablock_start_sector; + int error = 0; + struct progress_arg progress_arg = { .label = "freeblock", .tick = + sb->total_freeblock / PROGRESS_BAR_GRANULE }; + + progress(&progress_arg); + v7fs_freeblock_foreach(fs, freeblock_subr_cnt, &freeblock_arg); + progress(&progress_arg); + + blk = freeblock_arg.blk; + pwarn("\ndatablock usage: %d/%d (%d)\n", datablock_size - blk, + datablock_size, blk); + + if (sb->total_freeblock != blk) { + pwarn("corrupt # of freeblocks. %d(sb) != %d(cnt)", + sb->total_freeblock, blk); + if (reply_trivial("CORRECT?")) { + sb->total_freeblock = blk; + sb->modified = 1; + v7fs_superblock_writeback(fs); + } else { + error = FSCK_EXIT_CHECK_FAILED; + } + } + + + return error; +} diff --git a/sbin/fsck_v7fs/fsck_v7fs.8 b/sbin/fsck_v7fs/fsck_v7fs.8 new file mode 100644 index 000000000000..4e992f8b7904 --- /dev/null +++ b/sbin/fsck_v7fs/fsck_v7fs.8 @@ -0,0 +1,94 @@ +.\" $NetBSD: fsck_v7fs.8,v 1.1 2011/06/27 11:52:58 uch Exp $ +.\" +.\" Copyright (c) 2011 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by UCHIYAMA Yasushi. +.\" +.\" 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. +.\" +.Dd April 29, 2011 +.Dt FSCK_V7FS 8 +.Os +.Sh NAME +.Nm fsck_v7fs +.Nd 7th Edition(V7) filesystem consistency checker +.Sh SYNOPSIS +.Nm +.Op Fl o Ar options +.Op Fl B Ar byteorder +.Op Fl nypP +.Op Fl F +.Ar filesystem ... +.Sh DESCRIPTION +The +.Nm +utility verifies and repairs +.Tn Version 7 +filesystems +.Pp +The following flags are interpreted by +.Nm . +.Bl -tag -width XBXbyteorderXX -offset indent +.It Fl B Ar byteorder +Convert the file system metadata to +.Ar byteorder +byte order if needed. +Valid byte orders are +.Dq be +and +.Dq le +and +.Dq pdp . +.It Fl F +Check file system to a regular file. +.It Fl n +Don't correct file system. +.It Fl y +Causes +.Nm +to assume yes as the answer to all operator questions. +.It Fl p +preen mode. See fsck(8) +.It Fl P +Display a progress meter for the file system check. +.It Fl o +Options are specified with a +.Fl o +flag followed by a comma separated string of options. +The following options are available: +.Bl -tag -width data +.It Cm data +.Tn Check data block duplication. +.It Cm free +.Tn Check free block duplication. +.El + +.El +.Sh SEE ALSO +.Xr fsck 8 , +.Xr mount_v7fs 8 , +.Xr newfs_v7fs 8 +.Sh BUGS +.Nm +is still under construction. diff --git a/sbin/fsck_v7fs/fsck_v7fs.c b/sbin/fsck_v7fs/fsck_v7fs.c new file mode 100644 index 000000000000..e3faaa97bc87 --- /dev/null +++ b/sbin/fsck_v7fs/fsck_v7fs.c @@ -0,0 +1,223 @@ +/* $NetBSD: fsck_v7fs.c,v 1.1 2011/06/27 11:52:58 uch Exp $ */ + +/*- + * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: fsck_v7fs.c,v 1.1 2011/06/27 11:52:58 uch Exp $"); +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "v7fs_impl.h" +#include "fsck_v7fs.h" +#include "progress.h" + +static void usage(void) __dead; +static void catopt(char **, const char *); + +enum fsck_operate fsck_operate; +bool verbose = true; +#define VPRINTF(fmt, args...) { if (verbose) printf(fmt, ##args); } + +int +main(int argc, char **argv) +{ + const char *device; + struct disklabel d; + struct partition *p; + struct stat st; + int Fflag = 0; + int part; + int fd, ch; + int endian = _BYTE_ORDER; + int openflags = O_RDWR; + size_t part_sectors; + int fsck_flags = 0; + char *options = 0; + bool progress_bar_enable = false; + + fsck_operate = ASK; + + if (argc < 2) + usage(); + + while ((ch = getopt(argc, argv, "pPqynfx:dFB:o:")) != -1) { + switch (ch) { + /* + * generic fsck options + */ + case 'd': /* Not supported */ + break; + case 'f': /* Always forced */ + break; + case 'p': + fsck_operate = PREEN; + break; + case 'y': + fsck_operate = ALWAYS_YES; + break; + case 'n': + fsck_operate = ALWAYS_NO; + openflags = O_RDONLY; + break; + case 'P': + progress_bar_enable = true; + break; + case 'q': /* Not supported */ + break; + case 'x': /* Not supported */ + break; + /* + * v7fs fsck options + */ + case 'F': + Fflag = 1; + break; + case 'B': + switch (optarg[0]) { + case 'l': + endian = _LITTLE_ENDIAN; + break; + case 'b': + endian = _BIG_ENDIAN; + break; + case 'p': + endian = _PDP_ENDIAN; + break; + } + break; + case 'o': /* datablock, freeblock duplication check */ + if (*optarg) + catopt(&options, optarg); + break; + default: + usage(); + /*NOTREACHED*/ + } + } + + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + device = argv[0]; + + if (options) { + if (strstr(options, "data")) + fsck_flags |= V7FS_FSCK_DATABLOCK_DUP; + if (strstr(options, "free")) + fsck_flags |= V7FS_FSCK_FREEBLOCK_DUP; + } + + if (Fflag) { + if ((fd = open(device, openflags)) == -1) { + pfatal("%s", device); + } + if (fstat(fd, &st)) { + pfatal("stat"); + } + part_sectors = st.st_size >> V7FS_BSHIFT; + setcdevname(device, fsck_operate == PREEN); + } else { + /* blockcheck sets 'hot' */ + device = blockcheck(device); + setcdevname(device, fsck_operate == PREEN); + + if ((fd = open(device, openflags)) == -1) { + pfatal("%s", device); + } + part = DISKPART(st.st_rdev); + + if (ioctl(fd, DIOCGDINFO, &d) == -1) { + pfatal("DIOCGDINFO"); + } + p = &d.d_partitions[part]; + part_sectors = p->p_size; + VPRINTF("partition=%d size=%d offset=%d fstype=%d secsize=%d\n", + part, p->p_size, p->p_offset, p->p_fstype, d.d_secsize); + if (p->p_fstype != FS_V7) { + pfatal("not a Version 7 partition."); + } + } + + progress_switch(progress_bar_enable); + progress_init(); + progress(&(struct progress_arg){ .cdev = device }); + + struct v7fs_mount_device mount; + mount.device.fd = fd; + mount.endian = endian; + mount.sectors = part_sectors; + int error = v7fs_fsck(&mount, fsck_flags); + + close(fd); + + return error; +} + +static void +catopt(char **sp, const char *o) +{ + char *s, *n; + + s = *sp; + if (s) { + if (asprintf(&n, "%s,%s", s, o) < 0) + err(1, "asprintf"); + free(s); + s = n; + } else + s = strdup(o); + *sp = s; +} + +static void +usage(void) +{ + + (void)fprintf(stderr, "usage: %s [-ynpP] [-o options] [-B endian] " + "special-device\n", + getprogname()); + (void)fprintf(stderr, "usage: %s -F [-ynpP] [-o options] [-B endian] " + "file\n", + getprogname()); + + exit(FSCK_EXIT_USAGE); +} diff --git a/sbin/fsck_v7fs/fsck_v7fs.h b/sbin/fsck_v7fs/fsck_v7fs.h new file mode 100644 index 000000000000..17ad21da7804 --- /dev/null +++ b/sbin/fsck_v7fs/fsck_v7fs.h @@ -0,0 +1,82 @@ +/* $NetBSD: fsck_v7fs.h,v 1.1 2011/06/27 11:52:58 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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 _SBIN_FSCK_V7FS_FSCK_V7FS_H_ +#define _SBIN_FSCK_V7FS_FSCK_V7FS_H_ + +enum fsck_operate { + PREEN, + ASK, + ALWAYS_YES, + ALWAYS_NO, +}; + +#define V7FS_FSCK_DATABLOCK_DUP 0x01 +#define V7FS_FSCK_FREEBLOCK_DUP 0x02 + +#define PROGRESS_BAR_GRANULE 100 +struct progress_arg { + const char *cdev; + const char *label; + off_t tick; + off_t cnt; + off_t total; +}; + +__BEGIN_DECLS +char *filename(struct v7fs_self *, v7fs_ino_t); +void progress(const struct progress_arg *); + +int v7fs_fsck(const struct v7fs_mount_device *, int); +int reply(const char *); +int reply_trivial(const char *); + +int pathname_check(struct v7fs_self *); +int ilist_check(struct v7fs_self *); +int freeinode_check(struct v7fs_self *); +int freeblock_check(struct v7fs_self *); +int datablock_vs_datablock_check(struct v7fs_self *); +int datablock_vs_freeblock_check(struct v7fs_self *); +int freeblock_vs_freeblock_check(struct v7fs_self *); + +void freeblock_dup_remove(struct v7fs_self *, v7fs_daddr_t); + +int v7fs_freeblock_foreach(struct v7fs_self *, + int (*)(struct v7fs_self *, void *, v7fs_daddr_t), void *); +__END_DECLS + +extern enum fsck_operate fsck_operate; +extern struct v7fs_inode lost_and_found; + +#include "fsutil.h" +#include "exitvalues.h" + +#endif /*!_SBIN_FSCK_V7FS_FSCK_V7FS_H_ */ diff --git a/sbin/fsck_v7fs/inode.c b/sbin/fsck_v7fs/inode.c new file mode 100644 index 000000000000..1ffcf22821f6 --- /dev/null +++ b/sbin/fsck_v7fs/inode.c @@ -0,0 +1,160 @@ +/* $NetBSD: inode.c,v 1.1 2011/06/27 11:52:58 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: inode.c,v 1.1 2011/06/27 11:52:58 uch Exp $"); +#endif /* not lint */ + +#include +#include +#include + +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_inode.h" +#include "v7fs_superblock.h" +#include "fsck_v7fs.h" + +struct ilistcheck_arg { + int total; + int alloc; +}; + +int +freeinode_check(struct v7fs_self *fs) +{ + struct v7fs_superblock *sb = &fs->superblock; + v7fs_ino_t *f = sb->freeinode; + int16_t n = sb->nfreeinode; + int16_t i, j; + int bogus = false; + + /* Check # of cached free inode. */ + if (n > V7FS_MAX_FREEINODE || n < 0) { + pwarn("*** corrupt nfreeinode %d (0-%d)***", n, + V7FS_MAX_FREEINODE); + + if (reply("PURGE?")) { + sb->nfreeinode = 0; + sb->modified = 1; + v7fs_superblock_writeback(fs); + return FSCK_EXIT_UNRESOLVED; + } + return FSCK_EXIT_CHECK_FAILED; + } + + /* Check dup. */ + for (i = 0; i < n; i++) + for (j = 0; j < i; j++) + if (f[i] == f[j]) { + pwarn("*** freeinode DUP %d %d", i, j); + bogus = true; + } + if (bogus) { + if (reply("PURGE?")) { + memset(sb->freeinode, 0, sizeof(*sb->freeinode)); + sb->nfreeinode = 0; + sb->modified = 1; + v7fs_superblock_writeback(fs); + return FSCK_EXIT_UNRESOLVED; + } else { + return FSCK_EXIT_CHECK_FAILED; + } + } + + return FSCK_EXIT_OK; +} + +/* Counting freeinode and find partialy allocated inode. */ +static int +v7fs_inode_check(struct v7fs_self *fs, struct v7fs_inode *p, v7fs_ino_t ino) +{ + int error = 0; + + if (v7fs_inode_allocated(p) && !p->nlink) { + pwarn("*** partialy allocated inode #%d", ino); + v7fs_inode_dump(p); + if (reply_trivial("REMOVE?")) { + memset(p, 0, sizeof(*p)); + v7fs_inode_deallocate(fs, ino); + } else { + error = FSCK_EXIT_CHECK_FAILED; + } + } + + return error; +} + +static int +ilistcheck_subr(struct v7fs_self *fs, void *ctx, struct v7fs_inode *p, + v7fs_ino_t ino) +{ + struct ilistcheck_arg *arg = (struct ilistcheck_arg *)ctx; + int error = 0; + + if (ino != 1) + error = v7fs_inode_check(fs, p, ino); + + arg->total++; + if (v7fs_inode_allocated(p)) + arg->alloc++; + + return error; +} + +int +ilist_check(struct v7fs_self *fs) +{ + struct v7fs_superblock *sb = &fs->superblock; + struct ilistcheck_arg arg = { .total = 0, .alloc = 0 }; + int error = 0; + + if ((error = v7fs_ilist_foreach(fs, ilistcheck_subr, &arg))) + return error; + int nfree = arg.total - arg.alloc; + + if (nfree != sb->total_freeinode) { + pwarn("*** corrupt total freeinode. %d(sb) != %d(cnt)\n", + sb->total_freeinode, nfree); + if (reply_trivial("CORRECT?")) { + sb->total_freeinode = nfree; + sb->modified = true; + v7fs_superblock_writeback(fs); + v7fs_superblock_dump(fs); + } else { + error = FSCK_EXIT_CHECK_FAILED; + } + } + + pwarn("\ninode usage: %d/%d (%d)\n", arg.alloc, arg.total, nfree); + return error; +} diff --git a/sbin/fsck_v7fs/main.c b/sbin/fsck_v7fs/main.c new file mode 100644 index 000000000000..a7bbdd44d572 --- /dev/null +++ b/sbin/fsck_v7fs/main.c @@ -0,0 +1,263 @@ +/* $NetBSD: main.c,v 1.1 2011/06/27 11:52:58 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: main.c,v 1.1 2011/06/27 11:52:58 uch Exp $"); +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_superblock.h" +#include "v7fs_inode.h" +#include "v7fs_file.h" + +#include "fsck_v7fs.h" +#include "progress.h" + +static int check_filesystem(struct v7fs_self *, int); +static int make_lost_and_found(struct v7fs_self *, struct v7fs_inode *); + +struct v7fs_inode lost_and_found; + +int +v7fs_fsck(const struct v7fs_mount_device *mount, int flags) +{ + struct v7fs_self *fs; + int error; + + if ((error = v7fs_io_init(&fs, mount, V7FS_BSIZE))) { + pfatal("I/O setup failed"); + return FSCK_EXIT_CHECK_FAILED; + } + + if ((error = v7fs_superblock_load(fs))) { + if ((error != EINVAL)) { + pfatal("Can't load superblock"); + return FSCK_EXIT_CHECK_FAILED; + } + pwarn("Inavalid superblock"); + if (!reply_trivial("CONTINUE?")) { + return FSCK_EXIT_CHECK_FAILED; + } + } + + error = check_filesystem(fs, flags); + + printf("write backing...(no progress report)"); fflush(stdout); + v7fs_io_fini(fs); + printf("done.\n"); + + return error; +} + +int +check_filesystem(struct v7fs_self *fs, int flags) +{ + int error; + + /* Check superblock cached freeinode list. */ + pwarn("[Superblock information]\n"); + v7fs_superblock_dump(fs); + pwarn("[1] checking free inode in superblock...\n"); + if ((error = freeinode_check(fs))) + return error; + + /* Check free block linked list. */ + pwarn("[2] checking free block link...\n"); + if ((error = freeblock_check(fs))) + return error; + + /* Check inode all. */ + pwarn("[3] checking all ilist...\n"); + if ((error = ilist_check(fs))) + return error; + + /* Setup lost+found. */ + pwarn("prepare lost+found\n"); + if ((error = make_lost_and_found(fs, &lost_and_found))) + return FSCK_EXIT_CHECK_FAILED; + + /* Check path(child and parent). Orphans are linked to lost+found. */ + pwarn("[4] checking path name...\n"); + if ((error = pathname_check(fs))) + return error; + + if (flags & V7FS_FSCK_FREEBLOCK_DUP) { + /* Check duplicated block in freeblock. */ + pwarn("[5] checking freeblock duplication...\n"); + if ((error = freeblock_vs_freeblock_check(fs))) + return error; + } + + if (flags & V7FS_FSCK_DATABLOCK_DUP) { + /* Check duplicated block in datablock. */ + pwarn("[6] checking datablock duplication(vs datablock)...\n"); + if ((error = datablock_vs_datablock_check(fs))) + return error; + } + + if ((flags & V7FS_FSCK_DATABLOCK_DUP) && (flags & + V7FS_FSCK_FREEBLOCK_DUP)) { + /* Check off-diagonal. */ + pwarn("[7] checking datablock duplication (vs freeblock)...\n"); + if ((error = datablock_vs_freeblock_check(fs))) + return error; + } + + return 0; +} + +static int +reply_subr(const char *str, bool trivial) +{ + int c; + char *line = NULL; + size_t linesize = 0; + ssize_t linelen; + + printf("%s ", str); + switch (fsck_operate) { + case PREEN: + return trivial; + case ALWAYS_YES: + printf("[Y]\n"); + return 1; + case ALWAYS_NO: + if (strstr(str, "CONTINUE")) { + printf("[Y]\n"); + return 1; + } + printf("[N]\n"); + return 0; + case ASK: + break; + } + fflush(stdout); + + if ((linelen = getline(&line, &linesize, stdin)) == -1) { + clearerr(stdin); + return 0; + } + c = line[0]; + + return c == 'y' || c == 'Y'; +} + +int +reply(const char *str) +{ + return reply_subr(str, false); +} + +int +reply_trivial(const char *str) +{ + return reply_subr(str, true); +} + +void +progress(const struct progress_arg *p) +{ + static struct progress_arg Progress; + static char cdev[32]; + static char label[32]; + + if (p) { + if (Progress.tick) { + progress_done(); + } + Progress = *p; + if (p->cdev) + strcpy(cdev, p->cdev); + if (p->label) + strcpy(label, p->label); + } + + if (fsck_operate == PREEN) + return; + if (!Progress.tick) + return; + if (++Progress.cnt > Progress.tick) { + Progress.cnt = 0; + Progress.total++; + progress_bar(cdev, label, Progress.total, PROGRESS_BAR_GRANULE); + } +} + +int +make_lost_and_found(struct v7fs_self *fs, struct v7fs_inode *p) +{ + struct v7fs_inode root_inode; + struct v7fs_fileattr attr; + v7fs_ino_t ino; + int error = 0; + + if ((error = v7fs_inode_load(fs, &root_inode, V7FS_ROOT_INODE))) { + errno = error; + warn("(%s) / missing.", __func__); + return error; + } + + memset(&attr, 0, sizeof(attr)); + attr.uid = 0; + attr.gid = 0; + attr.mode = V7FS_IFDIR | 0755; + attr.device = 0; + attr.ctime = attr.mtime = attr.atime = (v7fs_time_t)time(NULL); + + /* If lost+found already exists, returns EEXIST */ + if (!(error = v7fs_file_allocate + (fs, &root_inode, "lost+found", &attr, &ino))) + v7fs_superblock_writeback(fs); + + if (error == EEXIST) + error = 0; + + if (error) { + errno = error; + warn("(%s) Couldn't create lost+found", __func__); + return error; + } + + if ((error = v7fs_inode_load(fs, p, ino))) { + errno = error; + warn("(%s:)lost+found is created, but missing.", __func__); + } + + return error; +} diff --git a/sbin/fsck_v7fs/pathname.c b/sbin/fsck_v7fs/pathname.c new file mode 100644 index 000000000000..25596d501774 --- /dev/null +++ b/sbin/fsck_v7fs/pathname.c @@ -0,0 +1,349 @@ +/* $NetBSD: pathname.c,v 1.1 2011/06/27 11:52:58 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: pathname.c,v 1.1 2011/06/27 11:52:58 uch Exp $"); +#endif /* not lint */ + +#include +#include /*PATH_MAX */ +#include +#include +#include + +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_inode.h" +#include "v7fs_datablock.h" +#include "v7fs_superblock.h" +#include "v7fs_dirent.h" +#include "v7fs_file.h" +#include "fsck_v7fs.h" + +/* + * Check pathname. for each inode, check parent, if it is directory, + * check child. + */ + +static int +connect_lost_and_found(struct v7fs_self *fs, v7fs_ino_t ino) +{ + char name[V7FS_NAME_MAX]; + v7fs_time_t t; + + if (!lost_and_found.mode || !reply("CONNECT?")) + return FSCK_EXIT_CHECK_FAILED; + + snprintf(name, sizeof(name), "%d", ino); + v7fs_directory_add_entry(fs, &lost_and_found, ino, name); + t = (v7fs_time_t)time(NULL); + lost_and_found.mtime = lost_and_found.atime = t; + v7fs_inode_writeback(fs, &lost_and_found); + v7fs_superblock_writeback(fs); /* # of freeblocks may change. */ + + return 0; +} + +/* Check child (dir) */ +struct lookup_child_arg { + int dir_cnt; + bool print; + struct v7fs_inode *parent; +}; + +static int +lookup_child_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz) +{ + struct lookup_child_arg *arg = (struct lookup_child_arg *)ctx; + void *buf; + int error = 0; + + if (!(buf = scratch_read(fs, blk))) + return 0; + struct v7fs_dirent *dir = (struct v7fs_dirent *)buf; + size_t i, n = sz / sizeof(*dir); + if (!v7fs_dirent_endian_convert(fs, dir, n)) { + pwarn("*** bogus entry found *** dir#%d entry=%zu\n", + arg->parent->inode_number, n); + arg->print = true; + } + + for (i = 0; i < n; i++, dir++) { + struct v7fs_inode inode; + if (arg->print) + pwarn("%s %d\n", dir->name, dir->inode_number); + /* Bogus enties are removed here. */ + if ((error = v7fs_inode_load(fs, &inode, dir->inode_number))) + { + pwarn("entry #%d not found.", dir->inode_number); + if (reply("REMOVE?")) + v7fs_directory_remove_entry(fs, arg->parent, + dir->name); + } else { + /* Count child dir. */ + if (v7fs_inode_isdir(&inode)) + arg->dir_cnt++; + } + } + scratch_free(fs, buf); + + return error; +} + +static int +lookup_child_from_dir(struct v7fs_self *fs, struct v7fs_inode *p, bool print) +{ + struct lookup_child_arg arg = { .dir_cnt = 0, .print = print, + .parent = p }; + + v7fs_datablock_foreach(fs, p, lookup_child_subr, &arg); + + return arg.dir_cnt; +} + +/* Find parent directory (file) */ +struct lookup_parent_arg { + v7fs_ino_t target_ino; + v7fs_ino_t parent_ino; +}; + +static int +lookup_parent_from_file_subr(struct v7fs_self *fs, void *ctx, + struct v7fs_inode *p, v7fs_ino_t ino) +{ + struct lookup_parent_arg *arg = (struct lookup_parent_arg *)ctx; + + if (!v7fs_inode_isdir(p)) + return 0; + + if (v7fs_file_lookup_by_number(fs, p, arg->target_ino, NULL)) { + arg->parent_ino = ino; /* My inode found. */ + return V7FS_ITERATOR_BREAK; + } + + return 0; /* not found. */ +} + + +static v7fs_ino_t +lookup_parent_from_file(struct v7fs_self *fs, v7fs_ino_t ino) +{ + struct lookup_parent_arg arg = { .target_ino = ino, .parent_ino = 0 }; + + v7fs_ilist_foreach(fs, lookup_parent_from_file_subr, &arg); + + return arg.parent_ino; +} + +/* Find parent directory (dir) */ +static int +lookup_parent_from_dir_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, + size_t sz) +{ + struct lookup_parent_arg *arg = (struct lookup_parent_arg *)ctx; + void *buf; + int ret = 0; + + if (!(buf = scratch_read(fs, blk))) + return 0; + struct v7fs_dirent *dir = (struct v7fs_dirent *)buf; + size_t i, n = sz / sizeof(*dir); + if (!v7fs_dirent_endian_convert(fs, dir, n)) { + scratch_free(fs, buf); + return V7FS_ITERATOR_ERROR; + } + + for (i = 0; i < n; i++, dir++) { + if (strncmp(dir->name, "..", 2) != 0) + continue; + + arg->parent_ino = dir->inode_number; + ret = V7FS_ITERATOR_BREAK; + break; + } + + scratch_free(fs, buf); + return ret; +} + +static v7fs_ino_t +lookup_parent_from_dir(struct v7fs_self *fs, struct v7fs_inode *p) +{ + struct lookup_parent_arg arg = { .target_ino = 0, .parent_ino = 0 }; + + /* Search parent("..") from my dirent. */ + v7fs_datablock_foreach(fs, p, lookup_parent_from_dir_subr, &arg); + + return arg.parent_ino; +} + +static int +pathname_check_file(struct v7fs_self *fs, struct v7fs_inode *p, v7fs_ino_t ino) +{ + v7fs_ino_t parent_ino; + struct v7fs_inode parent_inode; + int error = 0; + + if (ino == 1) /* reserved. */ + return 0; + + /* Check parent. */ + if (!(parent_ino = lookup_parent_from_file(fs, ino)) || + (error = v7fs_inode_load(fs, &parent_inode, parent_ino)) || + !v7fs_inode_isdir(&parent_inode)) { + pwarn("*** inode#%d don't have parent.", ino); + v7fs_inode_dump(p); + error = connect_lost_and_found(fs, ino); + } + + return error; +} + +static int +pathname_check_dir(struct v7fs_self *fs, struct v7fs_inode *p, v7fs_ino_t ino) +{ + v7fs_ino_t parent_ino; + struct v7fs_inode parent_inode; + int error = 0; + + /* Check parent */ + if (!(parent_ino = lookup_parent_from_dir(fs, p)) || + (error = v7fs_inode_load(fs, &parent_inode, parent_ino)) || + !v7fs_inode_isdir(&parent_inode)) { + pwarn("*** ino#%d parent dir missing parent=%d", ino, + parent_ino); + /* link to lost+found */ + v7fs_inode_dump(p); + if ((error = connect_lost_and_found(fs, ino))) + return error; + } + + /* Check child */ + int cnt = lookup_child_from_dir(fs, p, false); + if ((error = (cnt != p->nlink))) { + pwarn("*** ino#%d corrupt link # of child" + " dir:%d(inode) != %d(cnt)", ino, p->nlink, cnt); + v7fs_inode_dump(p); + lookup_child_from_dir(fs, p, true); + + if (reply("CORRECT?")) { + p->nlink = cnt; + v7fs_inode_writeback(fs, p); + error = 0; + } else { + error = FSCK_EXIT_CHECK_FAILED; + } + } + + return error; +} + +static int +pathname_subr(struct v7fs_self *fs, void *ctx __unused, struct v7fs_inode *p, + v7fs_ino_t ino) +{ + int error = 0; + + if (!v7fs_inode_allocated(p)) + return 0; + + progress(0); + + if (v7fs_inode_isdir(p)) { + error = pathname_check_dir(fs, p, ino); + } else if (v7fs_inode_isfile(p)) { + error = pathname_check_file(fs, p, ino); + } + + return error; +} + +int +pathname_check(struct v7fs_self *fs) +{ + struct v7fs_superblock *sb = &fs->superblock; + int inodes = V7FS_MAX_INODE(sb) - sb->total_freeinode; + + progress(&(struct progress_arg){ .label = "pathname", .tick = inodes / + PROGRESS_BAR_GRANULE }); + + return v7fs_ilist_foreach(fs, pathname_subr, 0); +} + + +char * +filename(struct v7fs_self *fs, v7fs_ino_t ino) +{ + static char path[V7FS_PATH_MAX]; + struct v7fs_inode inode; + v7fs_ino_t parent; + int error; + char name[V7FS_NAME_MAX + 1]; + char *p = path + V7FS_PATH_MAX; + size_t n; + + if ((error = v7fs_inode_load(fs, &inode, ino))) + return 0; + + /* Lookup the 1st parent. */ + if (v7fs_inode_isdir(&inode)) + parent = lookup_parent_from_dir(fs, &inode); + else + parent = lookup_parent_from_file(fs, ino); + + if ((error = v7fs_inode_load(fs, &inode, parent))) + return 0; + + if (!v7fs_file_lookup_by_number(fs, &inode, ino, name)) + return 0; + + n = strlen(name) + 1; + strcpy(p -= n, name); + + /* Lookup until / */ + ino = parent; + while (parent != V7FS_ROOT_INODE) { + parent = lookup_parent_from_dir(fs, &inode); + if ((error = v7fs_inode_load(fs, &inode, parent))) + return 0; + if (!v7fs_file_lookup_by_number(fs, &inode, ino, name)) + return 0; + ino = parent; + n = strlen(name) + 1; + strcpy(p - n, name); + p[-1] = '/'; + p -= n; + } + *--p = '/'; + + return p; +} diff --git a/sbin/mount_v7fs/Makefile b/sbin/mount_v7fs/Makefile new file mode 100644 index 000000000000..50d452ddbe33 --- /dev/null +++ b/sbin/mount_v7fs/Makefile @@ -0,0 +1,16 @@ +# $NetBSD: Makefile,v 1.1 2011/06/27 11:52:58 uch Exp $ + +.include + +PROG= mount_v7fs +SRCS= mount_v7fs.c fattr.c pathadj.c +MAN= mount_v7fs.8 + +MOUNT= ${NETBSDSRCDIR}/sbin/mount +CPPFLAGS+= -I${MOUNT} +.PATH: ${MOUNT} + +DPADD+=${LIBUTIL} +LDADD+=-lutil + +.include diff --git a/sbin/mount_v7fs/mount_v7fs.8 b/sbin/mount_v7fs/mount_v7fs.8 new file mode 100644 index 000000000000..f9a9100a6890 --- /dev/null +++ b/sbin/mount_v7fs/mount_v7fs.8 @@ -0,0 +1,112 @@ +.\" $NetBSD: mount_v7fs.8,v 1.1 2011/06/27 11:52:58 uch Exp $ +.\" +.\" Copyright (c) 2011 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by UCHIYAMA Yasushi. +.\" +.\" 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) 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. +.\" +.\" @(#)mount.8 8.7 (Berkeley) 3/27/94 +.\" +.Dd April 29, 2011 +.Dt MOUNT_V7FS 8 +.Os +.Sh NAME +.Nm mount_v7fs +.Nd mount a 7th Edition(V7) File System +.Sh SYNOPSIS +.Nm +.Op Fl B Ar byte-order +.Op Fl o Ar options +.Ar special node +.Sh DESCRIPTION +The +.Nm +command attaches the 7th Edition(V7) File System on the +.Ar special +device on to the file system tree at point +.Ar node . +Both +.Ar special +and +.Ar node +are converted to absolute paths before use. +.Pp +This command is normally executed by +.Xr mount 8 +at boot time. +The options are as follows: +.Bl -tag -width Fl +.It Fl B Ar byte-order +Specify the metadata byte order of the file system. +Valid byte orders are +.Sq be +and +.Sq le +and +.Sq pdp . +If no byte order is specified, the file system is mounted in host +byte order. +.It Fl o +Options are specified with a +.Fl o +flag followed by a comma separated string of options. +See the +.Xr mount 8 +man page for possible options and their meanings. +.El +.Sh SEE ALSO +.Xr mount 2 , +.Xr unmount 2 , +.Xr fstab 5 , +.Xr mount 8 +.Sh BUGS +The v7fs support is still experimental. diff --git a/sbin/mount_v7fs/mount_v7fs.c b/sbin/mount_v7fs/mount_v7fs.c new file mode 100644 index 000000000000..036148ab4d7f --- /dev/null +++ b/sbin/mount_v7fs/mount_v7fs.c @@ -0,0 +1,191 @@ +/* $NetBSD: mount_v7fs.c,v 1.1 2011/06/27 11:52:58 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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) 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 +__RCSID("$NetBSD: mount_v7fs.c,v 1.1 2011/06/27 11:52:58 uch Exp $"); +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "mountprog.h" +#include "mount_v7fs.h" + +static const struct mntopt mopts[] = { + MOPT_STDOPTS, + MOPT_UPDATE, + MOPT_GETARGS, + MOPT_NULL, +}; + +static void v7fs_usage(void) __dead; + +#ifndef MOUNT_NOMAIN +int +main(int argc, char **argv) +{ + + return mount_v7fs(argc, argv); +} +#endif + +int +mount_v7fs(int argc, char *argv[]) +{ + struct v7fs_args args; + char canon_dev[MAXPATHLEN], canon_dir[MAXPATHLEN]; + const char *errcause; + int mntflags; + + mount_v7fs_parseargs(argc, argv, &args, &mntflags, + canon_dev, canon_dir); + + if (mount(MOUNT_V7FS, canon_dir, mntflags, &args, sizeof args) == -1) { + switch (errno) { + case EMFILE: + errcause = "mount table full"; + break; + case EINVAL: + if (mntflags & MNT_UPDATE) + errcause = + "specified device does not match mounted device"; + else + errcause = "incorrect super block"; + break; + default: + errcause = strerror(errno); + break; + } + errx(EXIT_FAILURE, "%s on %s: %s", canon_dev, canon_dir, + errcause); + } + + if (mntflags & MNT_GETARGS) { + printf("endian=%d\n", args.endian); + } + + return EXIT_SUCCESS; +} + +void +mount_v7fs_parseargs(int argc, char **argv, struct v7fs_args *args, + int *mntflags, char *canon_dev, char *canon_dir) +{ + int ch; + mntoptparse_t mp; + int endian = _BYTE_ORDER; + *mntflags = 0; + optind = optreset = 1; /* Reset for parse of new argv. */ + while ((ch = getopt(argc, argv, "o:B:")) != -1) + switch (ch) { + case 'o': + mp = getmntopts(optarg, mopts, mntflags, 0); + if (mp == NULL) + err(1, "getmntopts"); + freemntopts(mp); + break; + case 'B': + switch (optarg[0]) { + case 'l': + endian = _LITTLE_ENDIAN; + break; + case 'b': + endian = _BIG_ENDIAN; + break; + case 'p': + endian = _PDP_ENDIAN; + break; + } + break; + case '?': + + default: + v7fs_usage(); + } + argc -= optind; + argv += optind; + + if (argc != 2) + v7fs_usage(); + + pathadj(argv[0], canon_dev); + args->endian = endian; + args->fspec = canon_dev; + pathadj(argv[1], canon_dir); +} + +static void +v7fs_usage(void) +{ + + fprintf(stderr, "usage: \n %s [-o options] [-B endian] special node\n", + getprogname()); + exit(EXIT_FAILURE); +} diff --git a/sbin/mount_v7fs/mount_v7fs.h b/sbin/mount_v7fs/mount_v7fs.h new file mode 100644 index 000000000000..798aa45e54b1 --- /dev/null +++ b/sbin/mount_v7fs/mount_v7fs.h @@ -0,0 +1,38 @@ +/* $NetBSD: mount_v7fs.h,v 1.1 2011/06/27 11:52:58 uch Exp $ */ + +/* + * Copyright (c) 2008, 2011 The NetBSD Foundation. 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 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 _SBIN_MOUNT_V7FS_MOUNT_V7FS_H_ +#define _SBIN_MOUNT_V7FS_MOUNT_V7FS_H_ + +#include + +__BEGIN_DECLS +int mount_v7fs(int, char **); +void mount_v7fs_parseargs(int, char **, struct v7fs_args *, int *, + char *, char *); +__END_DECLS +#endif /* _SBIN_MOUNT_V7FS_MOUNT_V7FS_H_ */ diff --git a/sbin/newfs_v7fs/Makefile b/sbin/newfs_v7fs/Makefile new file mode 100644 index 000000000000..6f4e2887d29b --- /dev/null +++ b/sbin/newfs_v7fs/Makefile @@ -0,0 +1,23 @@ +# $NetBSD: Makefile,v 1.1 2011/06/27 11:52:58 uch Exp $ + +.include + +V7FS = ${NETBSDSRCDIR}/sys/fs/v7fs +PROG= newfs_v7fs +MAN= newfs_v7fs.8 +SRCS= newfs_v7fs.c main.c v7fs_endian.c v7fs_superblock.c v7fs_inode.c \ +v7fs_datablock.c v7fs_dirent.c v7fs_io.c v7fs_io_user.c progress.c + +# use progress meter. +FSCK= ${NETBSDSRCDIR}/sbin/fsck + +DPADD+= ${LIBUTIL} +LDADD+= -lutil +CPPFLAGS+=-DV7FS_EI -I${V7FS} -I${FSCK} -g +.PATH: ${V7FS} ${FSCK} + +.if defined(HAVE_GCC) && ${HAVE_GCC} == 4 +COPTS.newfs_v7fs.c+= -Wno-pointer-sign +.endif + +.include diff --git a/sbin/newfs_v7fs/main.c b/sbin/newfs_v7fs/main.c new file mode 100644 index 000000000000..0ddfd59dd954 --- /dev/null +++ b/sbin/newfs_v7fs/main.c @@ -0,0 +1,277 @@ +/* $NetBSD: main.c,v 1.1 2011/06/27 11:52:58 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: main.c,v 1.1 2011/06/27 11:52:58 uch Exp $"); +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include + +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_endian.h" +#include "v7fs_superblock.h" +#include "v7fs_inode.h" +#include "v7fs_datablock.h" /*v7fs_datablock_expand/last */ +#include "newfs_v7fs.h" +#include "progress.h" /*../sbin/fsck */ + +#define VPRINTF(fmt, args...) { if (verbose) printf(fmt, ##args); } + +static v7fs_daddr_t +determine_ilist_size(v7fs_daddr_t volume_size, int32_t files) +{ + v7fs_daddr_t ilist_size; + + if (files) + ilist_size = roundup2(files, V7FS_INODE_PER_BLOCK) / + V7FS_INODE_PER_BLOCK; + else + ilist_size = volume_size / 25; /* 4% */ + if (ilist_size > (v7fs_daddr_t)V7FS_ILISTBLK_MAX) + ilist_size = V7FS_ILISTBLK_MAX; + + return ilist_size; +} + +static int +make_root(struct v7fs_self *fs) +{ + struct v7fs_inode inode; + struct v7fs_dirent *dir; + int error; + + /* INO 1 badblk (don't used) */ + memset(&inode, 0, sizeof(inode)); + inode.inode_number = 1; + inode.mode = V7FS_IFREG; /* V7 manner */ + v7fs_inode_writeback(fs, &inode); + + /* INO 2 root */ + v7fs_ino_t ino; + if ((error = v7fs_inode_allocate(fs, &ino))) { + errno = error; + warn("Can't allocate / inode"); + return error; + } + + memset(&inode, 0, sizeof(inode)); + inode.inode_number = ino; + inode.mode = 0777 | V7FS_IFDIR; + inode.uid = 0; + inode.gid = 0; + inode.nlink = 2; /* . + .. */ + inode.atime = inode.mtime = inode.ctime = time(0); + + /* root dirent. */ + v7fs_datablock_expand(fs, &inode, sizeof(*dir) * 2); + v7fs_daddr_t blk = inode.addr[0]; + void *buf; + if (!(buf = scratch_read(fs, blk))) { + v7fs_inode_deallocate(fs, ino); + errno = error = EIO; + warn("Can't read / dirent."); + return error; + } + dir = (struct v7fs_dirent *)buf; /*disk endian */ + + strcpy(dir[0].name, "."); + dir[0].inode_number = V7FS_VAL16(fs, ino); + strcpy(dir[1].name, ".."); + dir[1].inode_number = V7FS_VAL16(fs, ino); + if (!fs->io.write(fs->io.cookie, buf, blk)) {/*writeback */ + scratch_free(fs, buf); + errno = error = EIO; + warn("Can't write / dirent."); + return error; + } + scratch_free(fs, buf); + v7fs_inode_writeback(fs, &inode); + if ((error = v7fs_superblock_writeback(fs))) { + errno = error; + warn("Can't write superblock."); + } + + return error; +} + +static v7fs_daddr_t +make_freeblocklist(struct v7fs_self *fs, v7fs_daddr_t listblk, uint8_t *buf) +{ + uint32_t (*val32)(uint32_t) = fs->val.conv32; + uint16_t (*val16)(uint16_t) = fs->val.conv16; + struct v7fs_freeblock *fb = (struct v7fs_freeblock *)buf; + int i, j, k; + + memset(buf, 0, V7FS_BSIZE); + + for (i = V7FS_MAX_FREEBLOCK - 1, j = listblk + 1, k = 0; i >= 0; + i--, j++, k++) { + progress(0); + if (j == (int32_t)fs->superblock.volume_size) + { + VPRINTF("\nlast freeblock #%d\n", + (*val32)(fb->freeblock[i + 1])); + fb->nfreeblock = (*val16)(k); + + memmove(fb->freeblock + 1, fb->freeblock + i + 1, k * + sizeof(v7fs_daddr_t)); + fb->freeblock[0] = 0; /* Terminate link; */ + VPRINTF("last freeblock contains #%d\n", + (*val16)(fb->nfreeblock)); + fs->io.write(fs->io.cookie, buf, listblk); + return 0; + } + fb->freeblock[i] = (*val32)(j); + } + fb->nfreeblock = (*val16)(k); + + if (!fs->io.write(fs->io.cookie, buf, listblk)) { + errno = EIO; + warn("blk=%ld", (long)listblk); + return 0; + } + + /* Return next link block */ + return (*val32)(fb->freeblock[0]); +} + +static int +make_filesystem(struct v7fs_self *fs, v7fs_daddr_t volume_size, + v7fs_daddr_t ilist_size) +{ + struct v7fs_superblock *sb; + v7fs_daddr_t blk; + uint8_t buf[V7FS_BSIZE]; + int error = 0; + int32_t i, j; + + /* Setup ilist. (ilist must be zero filled. becuase of they are free) */ + VPRINTF("Zero clear ilist.\n"); + progress(&(struct progress_arg){ .label = "zero ilist", .tick = + ilist_size / PROGRESS_BAR_GRANULE }); + memset(buf, 0, sizeof buf); + for (i = V7FS_ILIST_SECTOR; i < (int32_t)ilist_size; i++) { + fs->io.write(fs->io.cookie, buf, i); + progress(0); + } + progress_done(); + VPRINTF("\n"); + + /* Construct superblock */ + sb = &fs->superblock; + sb->volume_size = volume_size; + sb->datablock_start_sector = ilist_size + V7FS_ILIST_SECTOR; + sb->update_time = time(NULL); + + /* fill free inode cache. */ + VPRINTF("Setup inode cache.\n"); + sb->nfreeinode = V7FS_MAX_FREEINODE; + for (i = V7FS_MAX_FREEINODE - 1, j = V7FS_ROOT_INODE; i >= 0; i--, j++) + sb->freeinode[i] = j; + sb->total_freeinode = ilist_size * V7FS_INODE_PER_BLOCK - 1; + + /* fill free block cache. */ + VPRINTF("Setup free block cache.\n"); + sb->nfreeblock = V7FS_MAX_FREEBLOCK; + for (i = V7FS_MAX_FREEBLOCK - 1, j = sb->datablock_start_sector; i >= 0; + i--, j++) + sb->freeblock[i] = j; + sb->total_freeblock = volume_size - sb->datablock_start_sector - 1; + + /* Write superblock. */ + sb->modified = 1; + if ((error = v7fs_superblock_writeback(fs))) { + errno = error; + warn("Can't write back superblock."); + return error; + } + + /* Construct freeblock list */ + VPRINTF("Setup whole freeblock list.\n"); + progress(&(struct progress_arg){ .label = "freeblock list", .tick = + (volume_size - sb->datablock_start_sector) / PROGRESS_BAR_GRANULE}); + blk = sb->freeblock[0]; + while ((blk = make_freeblocklist(fs, blk, buf))) + continue; + progress_done(); + + VPRINTF("done.\n"); + + return 0; +} + +int +v7fs_newfs(const struct v7fs_mount_device *mount, int32_t maxfile) +{ + struct v7fs_self *fs; + v7fs_daddr_t ilist_size; + int error; + v7fs_daddr_t volume_size = mount->sectors; + + /* Check and determine ilistblock, datablock size. */ + if (volume_size > V7FS_DADDR_MAX + 1) + return ENOSPC; + + ilist_size = determine_ilist_size(volume_size, maxfile); + + VPRINTF("volume size=%d, ilist size=%d, endian=%d, NAME_MAX=%d\n", + volume_size, ilist_size, mount->endian, V7FS_NAME_MAX); + + /* Setup I/O ops. */ + if ((error = v7fs_io_init(&fs, mount, V7FS_BSIZE))) { + errno = error; + warn("I/O setup failed."); + return error; + } + fs->endian = mount->endian; + v7fs_endian_init(fs); + + /* Construct filesystem. */ + if ((error = make_filesystem(fs, volume_size, ilist_size))) { + return error; + } + + /* Setup root. */ + if ((error = make_root(fs))) { + return error; + } + + v7fs_io_fini(fs); + + return 0; +} diff --git a/sbin/newfs_v7fs/newfs_v7fs.8 b/sbin/newfs_v7fs/newfs_v7fs.8 new file mode 100644 index 000000000000..5dd579db9d38 --- /dev/null +++ b/sbin/newfs_v7fs/newfs_v7fs.8 @@ -0,0 +1,117 @@ +.\" $NetBSD: newfs_v7fs.8,v 1.1 2011/06/27 11:52:58 uch Exp $ +.\" +.\" Copyright (c) 2011 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by UCHIYAMA Yasushi. +.\" +.\" 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) 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. +.\" +.\" @(#)newlfs.8 8.1 (Berkeley) 6/19/93 +.\" +.Dd April 29, 2011 +.Dt NEWFS_V7FS 8 +.Os +.Sh NAME +.Nm newfs_v7fs +.Nd construct a new 7th Edition(V7) File System +.Sh SYNOPSIS +.Nm +.Op Fl B Ar byte-order +.Op Fl FZvP +.Op Fl s Ar sectors +.Op Fl n Ar inodes +.Ar special +.Sh DESCRIPTION +.Nm +builds a 7th Edition(V7) file system on the specified special. +If it is a device, the size information will be taken from the disk label and +before running +.Nm +the disk must be labeled using +.Xr disklabel 8 ; +the proper fstype is +.Dq Version 7 . +Otherwise, the size must be specified on the command line. +V7 filesystem's block size and sector size are 512byte. +disk address limits are 24bit. +.Pp +The following arguments are supported: +.Bl -tag -width Fl +.It Fl P +Display a progress meter for the file system construct. +.It Fl v +verbose. +.It Fl F +Create file system to a regular file.(needs -s option) +.It Fl s Ar sectors +Create file system with specified number of disk sectors. +.It Fl Z +Fill file with zeroes instead of creating a sparse file. +.It Fl B Ar byte-order +Specify the metadata byte order of the file system to be created. +Valid byte orders are +.Sq be +and +.Sq le +and +.Sq pdp . +If no byte order is specified, the file system is created in host +byte order. +.It Fl n Ar inodes +This specifies the number of inodes for the filesystem. +If number of inodes exceeds 65536, contracted to 65536. +.El +.Sh SEE ALSO +.Xr disklabel 5 , +.Xr disktab 5 , +.\" .Xr fs 5 , +.Xr disklabel 8 , +.Xr diskpart 8 diff --git a/sbin/newfs_v7fs/newfs_v7fs.c b/sbin/newfs_v7fs/newfs_v7fs.c new file mode 100644 index 000000000000..03123811467c --- /dev/null +++ b/sbin/newfs_v7fs/newfs_v7fs.c @@ -0,0 +1,242 @@ +/* $NetBSD: newfs_v7fs.c,v 1.1 2011/06/27 11:52:58 uch Exp $ */ + +/*- + * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: newfs_v7fs.c,v 1.1 2011/06/27 11:52:58 uch Exp $"); +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "v7fs_impl.h" +#include "progress.h" +#include "newfs_v7fs.h" + +static void usage(void) __dead; +static bool progress_bar_enable = false; +bool verbose = false; + +int +main(int argc, char **argv) +{ + const char *device; + struct disklabel d; + struct partition *p; + struct stat st; + uint32_t partsize; + int Fflag, Zflag; + int part; + int fd, ch; + int endian = _BYTE_ORDER; + int32_t maxfile = 0; + + if (argc < 2) + usage(); + + Fflag = Zflag = partsize = 0; + while ((ch = getopt(argc, argv, "Fs:Zs:n:B:vP")) != -1) { + switch (ch) { + case 'P': + progress_bar_enable = true; + break; + case 'v': + verbose = true; + break; + case 'F': + Fflag = 1; + break; + case 's': + partsize = atoi(optarg); + break; + case 'n': + maxfile = atoi(optarg); + break; + case 'Z': + Zflag = 1; + break; + case 'B': + switch (optarg[0]) { + case 'l': + endian = _LITTLE_ENDIAN; + break; + case 'b': + endian = _BIG_ENDIAN; + break; + case 'p': + endian = _PDP_ENDIAN; + break; + } + break; + default: + usage(); + /*NOTREACHED*/ + } + } + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + device = argv[0]; + + if (progress_bar_enable) { + progress_switch(progress_bar_enable); + progress_init(); + progress(&(struct progress_arg){ .cdev = device }); + } + + if (!Fflag) { + if ((fd = open(device, O_RDWR)) == -1) { + err(EXIT_FAILURE, "%s", device); + } + if (fstat(fd, &st) != 0) { + goto err_exit; + } + if (!S_ISCHR(st.st_mode)) { + warnx("not a raw device.\n"); + } + + part = DISKPART(st.st_rdev); + + if (ioctl(fd, DIOCGDINFO, &d) == -1) { + goto err_exit; + } + p = &d.d_partitions[part]; + if (verbose) { + printf("partition=%d size=%d offset=%d fstype=%d" + " secsize=%d\n", part, p->p_size, p->p_offset, + p->p_fstype, d.d_secsize); + } + if (p->p_fstype != FS_V7) { + warnx("not a Version 7 partition."); + goto err_exit; + } + partsize = p->p_size; + } else { + off_t filesize; + uint8_t zbuf[8192] = {0, }; + + if (partsize == 0) { + errx(EXIT_FAILURE, "-F requires -s"); + } + + filesize = partsize << V7FS_BSHIFT; + + fd = open(device, O_RDWR|O_CREAT|O_TRUNC, 0666); + if (fd == -1) { + err(EXIT_FAILURE, "%s", device); + } + + if (Zflag) { + while (filesize > 0) { + size_t writenow = MIN(filesize, + (off_t)sizeof(zbuf)); + + if ((size_t)write(fd, zbuf, writenow) != + writenow) { + err(EXIT_FAILURE, NULL); + } + filesize -= writenow; + } + } else { + if (lseek(fd, filesize - 1, SEEK_SET) == -1) { + goto err_exit; + } + if (write(fd, zbuf, 1) != 1) { + goto err_exit; + } + if (lseek(fd, 0, SEEK_SET) == -1) { + goto err_exit; + } + } + } + + if (v7fs_newfs(&(struct v7fs_mount_device) + { .device.fd = fd, .endian = endian, .sectors = partsize }, + maxfile) != 0) + goto err_exit; + + close(fd); + + return EXIT_SUCCESS; + err_exit: + close(fd); + err(EXIT_FAILURE, NULL); +} + +void +progress(const struct progress_arg *p) +{ + static struct progress_arg Progress; + static char cdev[32]; + static char label[32]; + + if (!progress_bar_enable) + return; + + if (p) { + Progress = *p; + if (p->cdev) + strcpy(cdev, p->cdev); + if (p->label) + strcpy(label, p->label); + } + + if (!Progress.tick) + return; + if (++Progress.cnt > Progress.tick) { + Progress.cnt = 0; + Progress.total++; + progress_bar(cdev, label, Progress.total, PROGRESS_BAR_GRANULE); + } +} + +static void +usage(void) +{ + + (void)fprintf(stderr, "usage: \n%s [-vP] [-n maxfile]" + " [-B endian] special\n", getprogname()); + (void)fprintf(stderr, "%s -F -s partsize [-vPZ] [-n maxfile]" + " [-B endian] file\n", getprogname()); + + exit(EXIT_FAILURE); +} diff --git a/sbin/newfs_v7fs/newfs_v7fs.h b/sbin/newfs_v7fs/newfs_v7fs.h new file mode 100644 index 000000000000..fc8d0d09089e --- /dev/null +++ b/sbin/newfs_v7fs/newfs_v7fs.h @@ -0,0 +1,48 @@ +/* $NetBSD: newfs_v7fs.h,v 1.1 2011/06/27 11:52:58 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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 _SBIN_NEWFS_V7FS_NEWFS_V7FS_H_ +#define _SBIN_NEWFS_V7FS_NEWFS_V7FS_H_ + +#define PROGRESS_BAR_GRANULE 100 +struct progress_arg { + const char *cdev; + const char *label; + off_t tick; + off_t cnt; + off_t total; +}; +__BEGIN_DECLS +void progress(const struct progress_arg *); +int v7fs_newfs(const struct v7fs_mount_device *, int32_t); +extern bool verbose; +__END_DECLS +#endif /* !_SBIN_NEWFS_V7FS_NEWFS_V7FS_H_ */ diff --git a/sys/conf/files b/sys/conf/files index 62babcc46f84..3ceb087266c6 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $NetBSD: files,v 1.1017 2011/06/23 23:42:43 matt Exp $ +# $NetBSD: files,v 1.1018 2011/06/27 11:52:24 uch Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 version 20100430 @@ -1376,6 +1376,7 @@ include "fs/smbfs/files.smbfs" include "fs/sysvbfs/files.sysvbfs" include "fs/tmpfs/files.tmpfs" include "fs/union/files.union" +include "fs/v7fs/files.v7fs" include "miscfs/fdesc/files.fdesc" include "miscfs/kernfs/files.kernfs" include "miscfs/nullfs/files.nullfs" diff --git a/sys/fs/Makefile b/sys/fs/Makefile index af275487853a..ec4f4580a5c7 100644 --- a/sys/fs/Makefile +++ b/sys/fs/Makefile @@ -1,6 +1,6 @@ -# $NetBSD: Makefile,v 1.19 2010/06/14 14:40:47 pooka Exp $ +# $NetBSD: Makefile,v 1.20 2011/06/27 11:52:24 uch Exp $ SUBDIR= adosfs cd9660 efs filecorefs hfs msdosfs nilfs ntfs ptyfs \ - puffs smbfs sysvbfs tmpfs udf union + puffs smbfs sysvbfs tmpfs udf union v7fs .include diff --git a/sys/fs/v7fs/Makefile b/sys/fs/v7fs/Makefile new file mode 100644 index 000000000000..e677fa395c58 --- /dev/null +++ b/sys/fs/v7fs/Makefile @@ -0,0 +1,7 @@ +# $NetBSD: Makefile,v 1.1 2011/06/27 11:52:24 uch Exp $ + +INCSDIR= /usr/include/fs/v7fs + +INCS= v7fs.h v7fs_args.h + +.include diff --git a/sys/fs/v7fs/files.v7fs b/sys/fs/v7fs/files.v7fs new file mode 100644 index 000000000000..509253f84d48 --- /dev/null +++ b/sys/fs/v7fs/files.v7fs @@ -0,0 +1,22 @@ +# $NetBSD: files.v7fs,v 1.1 2011/06/27 11:52:24 uch Exp $ + +deffs V7FS +defflag opt_v7fs.h V7FS_EI + +# Core. OS independent. These files are used by userland program.(fsck,newfs) +file fs/v7fs/v7fs_endian.c v7fs +file fs/v7fs/v7fs_superblock.c v7fs +file fs/v7fs/v7fs_inode.c v7fs +file fs/v7fs/v7fs_dirent.c v7fs +file fs/v7fs/v7fs_datablock.c v7fs +file fs/v7fs/v7fs_file.c v7fs +file fs/v7fs/v7fs_io.c v7fs +# util. +file fs/v7fs/v7fs_file_util.c v7fs +file fs/v7fs/v7fs_inode_util.c v7fs +file fs/v7fs/v7fs_superblock_util.c v7fs +# OS glue +file fs/v7fs/v7fs_io_kern.c v7fs +file fs/v7fs/v7fs_extern.c v7fs +file fs/v7fs/v7fs_vnops.c v7fs +file fs/v7fs/v7fs_vfsops.c v7fs diff --git a/sys/fs/v7fs/v7fs.h b/sys/fs/v7fs/v7fs.h new file mode 100644 index 000000000000..b4a2a12ba596 --- /dev/null +++ b/sys/fs/v7fs/v7fs.h @@ -0,0 +1,180 @@ +/* $NetBSD: v7fs.h,v 1.1 2011/06/27 11:52:24 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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 _V7FS_H_ +/* 7th Edition of Unix(PDP-11) Filesystem definition. */ +#define _V7FS_H_ +#include +#ifndef _KERNEL +#include +#endif +/* + * V7 File System + * + * +------------------ + * |Boot block (512byte) sector [0] + * | + * +------------------ + * |Super block (512byte) sector [1] + * | + * +------------------ + * |v7fs_inode(64byte sector [2] + * . + * . + * | + * +------------------ + * |data block sector [datablock_start_sector] + * | + * . + * . + * | + * +------------------ + * <- [sector volume_size] + * + * | + * +------------------ volume size. + * + * Max volume size is 8GB (24bit daddr_t) + * Max file size is ~1GB + * + */ + +/* V7 type. */ +typedef uint16_t v7fs_ino_t; +typedef uint32_t v7fs_daddr_t; +typedef int32_t v7fs_time_t; +typedef uint32_t v7fs_off_t; +typedef uint16_t v7fs_dev_t; +typedef uint16_t v7fs_mode_t; +#define V7FS_DADDR_MAX 0x00ffffff +#define V7FS_INODE_MAX 0xffff + +#define V7FS_BSIZE 512 +#define V7FS_BSHIFT 9 +#define V7FS_ROUND_BSIZE(x) \ + ((((x) + (V7FS_BSIZE - 1)) & ~(V7FS_BSIZE - 1))) +#define V7FS_TRUNC_BSIZE(x) ((x) & ~(V7FS_BSIZE - 1)) + +#define V7FS_RESIDUE_BSIZE(x) \ + ((x) - ((((x) - 1) >> V7FS_BSHIFT) << V7FS_BSHIFT)) + +/* Disk location. */ +#define V7FS_BOOTBLOCK_SECTOR 0 +#define V7FS_SUPERBLOCK_SECTOR 1 +#define V7FS_ILIST_SECTOR 2 + +/* Superblock */ +/* cache. */ +#define V7FS_MAX_FREEBLOCK 50 +#define V7FS_MAX_FREEINODE 100 +struct v7fs_superblock { + /* [3 ... (datablock_start_sector-1)]are ilist */ + uint16_t datablock_start_sector; + v7fs_daddr_t volume_size; + int16_t nfreeblock; /* # of freeblock in superblock cache. */ + v7fs_daddr_t freeblock[V7FS_MAX_FREEBLOCK]; /* cache. */ + int16_t nfreeinode; /* # of free inode in superblock cache. */ + v7fs_ino_t freeinode[V7FS_MAX_FREEINODE]; /* cache. */ + int8_t lock_freeblock; + int8_t lock_freeinode; + int8_t modified; + int8_t readonly; + v7fs_time_t update_time; + v7fs_daddr_t total_freeblock; + v7fs_ino_t total_freeinode; +} __packed; + +/* Datablock */ +#define V7FS_NADDR 13 +#define V7FS_NADDR_DIRECT 10 +#define V7FS_NADDR_INDEX1 10 +#define V7FS_NADDR_INDEX2 11 +#define V7FS_NADDR_INDEX3 12 +/* daddr index. */ +#define V7FS_DADDR_PER_BLOCK (V7FS_BSIZE / sizeof(v7fs_daddr_t)) +struct v7fs_freeblock { + int16_t nfreeblock; + v7fs_daddr_t freeblock[V7FS_MAX_FREEBLOCK]; +} __packed; + + +/* Dirent */ +#define V7FS_NAME_MAX 14 +#define V7FS_PATH_MAX PATH_MAX /* No V7 limit. */ +#define V7FS_LINK_MAX LINK_MAX /* No V7 limit. */ +struct v7fs_dirent { + v7fs_ino_t inode_number; + char name[V7FS_NAME_MAX]; +} __packed; /*16byte */ + +/* Inode */ +#define V7FS_BALBLK_INODE 1 /* monument */ +#define V7FS_ROOT_INODE 2 +#define V7FS_MAX_INODE(s) \ + (((s)->datablock_start_sector - V7FS_ILIST_SECTOR) * \ + V7FS_BSIZE / sizeof(struct v7fs_inode_diskimage)) +#define V7FS_INODE_PER_BLOCK \ + (V7FS_BSIZE / sizeof(struct v7fs_inode_diskimage)) +#define V7FS_ILISTBLK_MAX (V7FS_INODE_MAX / V7FS_INODE_PER_BLOCK) + +struct v7fs_inode_diskimage { + int16_t mode; + int16_t nlink; /* [DIR] # of child directories. [REG] link count. */ + int16_t uid; + int16_t gid; + v7fs_off_t filesize; /* byte */ +#define V7FS_DINODE_ADDR_LEN 40 + /* 39 used; 13 addresses of 3 byte each. */ + uint8_t addr[V7FS_DINODE_ADDR_LEN]; + /*for device node: addr[0] is major << 8 | minor. */ + v7fs_time_t atime; + v7fs_time_t mtime; + v7fs_time_t ctime; +} __packed; /*64byte */ + +/* File type */ +#define V7FS_IFMT 0170000 /* File type mask */ +#define V7FS_IFCHR 0020000 /* charcter device */ +#define V7FS_IFDIR 0040000 /* directory */ +#define V7FS_IFBLK 0060000 /* block device */ +#define V7FS_IFREG 0100000 /* file. */ +/* Obsoleted file type. */ +#define V7FS_IFMPC 0030000 /* multiplexed char special */ +#define V7FS_IFMPB 0070000 /* multiplexed block special */ +/* Don't apear original V7 filesystem. Found at 2.10BSD. */ +#define V7FSBSD_IFLNK 0120000 /* symbolic link */ +#define V7FSBSD_IFSOCK 0140000 /* socket */ +/* Don't apear original V7 filesystem. NetBSD. */ +#define V7FSBSD_IFFIFO 0010000 /* Named pipe. */ + +#define V7FSBSD_MAXSYMLINKS 8 + +#endif /*!_V7FS_H_ */ diff --git a/sys/fs/v7fs/v7fs_args.h b/sys/fs/v7fs/v7fs_args.h new file mode 100644 index 000000000000..017518cba661 --- /dev/null +++ b/sys/fs/v7fs/v7fs_args.h @@ -0,0 +1,40 @@ +/* $NetBSD: v7fs_args.h,v 1.1 2011/06/27 11:52:24 uch Exp $ */ + +/*- + * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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 _FS_V7FS_V7FS_ARGS_H_ +#define _FS_V7FS_V7FS_ARGS_H_ + +struct v7fs_args { + char *fspec; /* blocks special holding the fs to mount */ + int endian; /* target filesystem endian */ +}; + +#endif /* _FS_V7FS_V7FS_ARGS_H_ */ diff --git a/sys/fs/v7fs/v7fs_datablock.c b/sys/fs/v7fs/v7fs_datablock.c new file mode 100644 index 000000000000..93d9fa1e4440 --- /dev/null +++ b/sys/fs/v7fs/v7fs_datablock.c @@ -0,0 +1,721 @@ +/* $NetBSD: v7fs_datablock.c,v 1.1 2011/06/27 11:52:24 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_datablock.c,v 1.1 2011/06/27 11:52:24 uch Exp $"); +#if defined _KERNEL_OPT +#include "opt_v7fs.h" +#endif + +#include +#ifdef _KERNEL +#include +#include +#else +#include +#include +#include +#endif + +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_endian.h" +#include "v7fs_inode.h" +#include "v7fs_datablock.h" +#include "v7fs_superblock.h" + +#ifdef V7FS_DATABLOCK_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +struct v7fs_daddr_map { + int level; /* direct, index1, index2, index3 */ + v7fs_daddr_t index[3]; +}; + +static int v7fs_datablock_addr(size_t, struct v7fs_daddr_map *); +static int v7fs_datablock_deallocate(struct v7fs_self *, v7fs_daddr_t); +static int loop1(struct v7fs_self *, v7fs_daddr_t, size_t *, + int (*)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *); +static int loop2(struct v7fs_self *, v7fs_daddr_t, size_t *, + int (*)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *); +static v7fs_daddr_t link(struct v7fs_self *, v7fs_daddr_t, int); +static v7fs_daddr_t add_leaf(struct v7fs_self *, v7fs_daddr_t, int); +static v7fs_daddr_t unlink(struct v7fs_self *, v7fs_daddr_t, int); +static v7fs_daddr_t remove_leaf(struct v7fs_self *, v7fs_daddr_t, int); +static v7fs_daddr_t remove_self(struct v7fs_self *, v7fs_daddr_t); + +#ifdef V7FS_DATABLOCK_DEBUG +void daddr_map_dump(const struct v7fs_daddr_map *); +#else +#define daddr_map_dump(x) ((void)0) +#endif + +bool +datablock_number_sanity(const struct v7fs_self *fs, v7fs_daddr_t blk) +{ + const struct v7fs_superblock *sb = &fs->superblock; + bool ok = (blk >= sb->datablock_start_sector) && + (blk < sb->volume_size); + +#ifdef V7FS_DATABLOCK_DEBUG + if (!ok) { + DPRINTF("Bad data block #%d\n", blk); + } +#endif + + return ok; +} + +int +v7fs_datablock_allocate(struct v7fs_self *fs, v7fs_daddr_t *block_number) +{ + struct v7fs_superblock *sb = &fs->superblock; + v7fs_daddr_t blk; + int error = 0; + + *block_number = 0; + SUPERB_LOCK(fs); + do { + if (!sb->total_freeblock) { + DPRINTF("free block exhausted!!!\n"); + SUPERB_UNLOCK(fs); + return ENOSPC; + } + + /* Get free block from superblock cache. */ + blk = sb->freeblock[--sb->nfreeblock]; + sb->total_freeblock--; + sb->modified = 1; + + /* If nfreeblock is zero, it block is next freeblock link. */ + if (sb->nfreeblock == 0) { + if ((error = v7fs_freeblock_update(fs, blk))) { + DPRINTF("no freeblock!!!\n"); + SUPERB_UNLOCK(fs); + return error; + } + /* This freeblock link is no longer required. */ + /* use as data block. */ + } + } while (!datablock_number_sanity(fs, blk)); /* skip bogus block. */ + SUPERB_UNLOCK(fs); + + DPRINTF("Get freeblock %d\n", blk); + /* Zero clear datablock. */ + void *buf; + if (!(buf = scratch_read(fs, blk))) + return EIO; + memset(buf, 0, V7FS_BSIZE); + if (!fs->io.write(fs->io.cookie, buf, blk)) + error = EIO; + scratch_free(fs, buf); + + if (error == 0) + *block_number = blk; + + return error; +} + +static int +v7fs_datablock_deallocate(struct v7fs_self *fs, v7fs_daddr_t blk) +{ + struct v7fs_superblock *sb = &fs->superblock; + void *buf; + int error = 0; + + if (!datablock_number_sanity(fs, blk)) + return EIO; + + /* Add to in-core freelist. */ + SUPERB_LOCK(fs); + if (sb->nfreeblock < V7FS_MAX_FREEBLOCK) { + sb->freeblock[sb->nfreeblock++] = blk; + sb->total_freeblock++; + sb->modified = 1; + DPRINTF("n_freeblock=%d\n", sb->total_freeblock); + SUPERB_UNLOCK(fs); + return 0; + } + + /* No space to push. */ + /* Make this block to freeblock list.and current cache moved to this. */ + if (!(buf = scratch_read(fs, blk))) { + SUPERB_UNLOCK(fs); + return EIO; /* Fatal */ + } + + struct v7fs_freeblock *fb = (struct v7fs_freeblock *)buf; + fb->nfreeblock = V7FS_MAX_FREEBLOCK; + int i; + for (i = 0; i < V7FS_MAX_FREEBLOCK; i++) + fb->freeblock[i] = V7FS_VAL32(fs, sb->freeblock[i]); + + if (!fs->io.write(fs->io.cookie, (uint8_t *)fb, blk)) { + error = EIO; /* Fatal */ + } else { + /* Link. on next allocate, this block is used as datablock, */ + /* and swap outed freeblock list is restored. */ + sb->freeblock[0] = blk; + sb->nfreeblock = 1; + sb->total_freeblock++; + sb->modified = 1; + DPRINTF("n_freeblock=%d\n", sb->total_freeblock); + } + SUPERB_UNLOCK(fs); + scratch_free(fs, buf); + + return error; +} + +static int +v7fs_datablock_addr(size_t sz, struct v7fs_daddr_map *map) +{ +#define NIDX V7FS_DADDR_PER_BLOCK +#define DIRECT_SZ (V7FS_NADDR_DIRECT * V7FS_BSIZE) +#define IDX1_SZ (NIDX * V7FS_BSIZE) +#define IDX2_SZ (NIDX * NIDX * V7FS_BSIZE) +#define ROUND(x, a) ((((x) + ((a) - 1)) & ~((a) - 1))) + if (!sz) { + map->level = 0; + map->index[0] = 0; + return 0; + } + + sz = V7FS_ROUND_BSIZE(sz); + + /* Direct */ + if (sz <= DIRECT_SZ) { + map->level = 0; + map->index[0] = (sz >> V7FS_BSHIFT) - 1; + return 0; + } + /* Index 1 */ + sz -= DIRECT_SZ; + + if (sz <= IDX1_SZ) { + map->level = 1; + map->index[0] = (sz >> V7FS_BSHIFT) - 1; + return 0; + } + sz -= IDX1_SZ; + + /* Index 2 */ + if (sz <= IDX2_SZ) { + map->level = 2; + map->index[0] = ROUND(sz, IDX1_SZ) / IDX1_SZ - 1; + map->index[1] = ((sz - (map->index[0] * IDX1_SZ)) >> + V7FS_BSHIFT) - 1; + return 0; + } + sz -= IDX2_SZ; + + /* Index 3 */ + map->level = 3; + map->index[0] = ROUND(sz, IDX2_SZ) / IDX2_SZ - 1; + sz -= map->index[0] * IDX2_SZ; + map->index[1] = ROUND(sz, IDX1_SZ) / IDX1_SZ - 1; + sz -= map->index[1] * IDX1_SZ; + map->index[2] = (sz >> V7FS_BSHIFT) - 1; + + return map->index[2] >= NIDX ? ENOSPC : 0; +} + +int +v7fs_datablock_foreach(struct v7fs_self *fs, struct v7fs_inode *p, + int (*func)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *ctx) +{ + size_t i; + v7fs_daddr_t blk, blk2; + size_t filesize; + bool last; + int ret; + + if (!(filesize = v7fs_inode_filesize(p))) + return 0; +#ifdef V7FS_DATABLOCK_DEBUG + size_t sz = filesize; +#endif + + /* Direct */ + for (i = 0; i < V7FS_NADDR_DIRECT; i++, filesize -= V7FS_BSIZE) { + blk = p->addr[i]; + if (!datablock_number_sanity(fs, blk)) { + DPRINTF("inode#%d direct=%zu filesize=%zu\n", + p->inode_number, i, sz); + return EIO; + } + + last = filesize <= V7FS_BSIZE; + if ((ret = func(fs, ctx, blk, last ? filesize : V7FS_BSIZE))) + return ret; + if (last) + return V7FS_ITERATOR_END; + } + + /* Index 1 */ + blk = p->addr[V7FS_NADDR_INDEX1]; + if (!datablock_number_sanity(fs, blk)) + return EIO; + + if ((ret = loop1(fs, blk, &filesize, func, ctx))) + return ret; + + /* Index 2 */ + blk = p->addr[V7FS_NADDR_INDEX2]; + if (!datablock_number_sanity(fs, blk)) + return EIO; + + if ((ret = loop2(fs, blk, &filesize, func, ctx))) + return ret; + + /* Index 3 */ + blk = p->addr[V7FS_NADDR_INDEX3]; + if (!datablock_number_sanity(fs, blk)) + return EIO; + + for (i = 0; i < V7FS_DADDR_PER_BLOCK; i++) { + blk2 = link(fs, blk, i); + if (!datablock_number_sanity(fs, blk)) + return EIO; + + if ((ret = loop2(fs, blk2, &filesize, func, ctx))) + return ret; + } + + return EFBIG; +} + +static int +loop2(struct v7fs_self *fs, v7fs_daddr_t listblk, size_t *filesize, + int (*func)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *ctx) +{ + v7fs_daddr_t blk; + int ret; + size_t j; + + for (j = 0; j < V7FS_DADDR_PER_BLOCK; j++) { + blk = link(fs, listblk, j); + if (!datablock_number_sanity(fs, blk)) + return EIO; + if ((ret = loop1(fs, blk, filesize, func, ctx))) + return ret; + } + + return 0; +} + +static int +loop1(struct v7fs_self *fs, v7fs_daddr_t listblk, size_t *filesize, + int (*func)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *ctx) +{ + v7fs_daddr_t blk; + bool last; + int ret; + size_t k; + + for (k = 0; k < V7FS_DADDR_PER_BLOCK; k++, *filesize -= V7FS_BSIZE) { + blk = link(fs, listblk, k); + if (!datablock_number_sanity(fs, blk)) + return EIO; + last = *filesize <= V7FS_BSIZE; + if ((ret = func(fs, ctx, blk, last ? *filesize : V7FS_BSIZE))) + return ret; + if (last) + return V7FS_ITERATOR_END; + } + + return 0; +} + +v7fs_daddr_t +v7fs_datablock_last(struct v7fs_self *fs, struct v7fs_inode *inode, + v7fs_off_t ofs) +{ + struct v7fs_daddr_map map; + v7fs_daddr_t blk = 0; + v7fs_daddr_t *addr = inode->addr; + + /* Inquire last data block location. */ + if (v7fs_datablock_addr(ofs, &map) != 0) + return 0; + + switch (map.level) + { + case 0: /*Direct */ + blk = inode->addr[map.index[0]]; + break; + case 1: /*Index1 */ + blk = link(fs, addr[V7FS_NADDR_INDEX1], map.index[0]); + break; + case 2: /*Index2 */ + blk = link(fs, link(fs, addr[V7FS_NADDR_INDEX2], map.index[0]), + map.index[1]); + break; + case 3: /*Index3 */ + blk = link(fs, link(fs, link(fs, addr[V7FS_NADDR_INDEX3], + map.index[0]), map.index[1]), map.index[2]); + break; + } + + return blk; +} + +int +v7fs_datablock_expand(struct v7fs_self *fs, struct v7fs_inode *inode, size_t sz) +{ + size_t old_filesize = inode->filesize; + size_t new_filesize = old_filesize + sz; + struct v7fs_daddr_map oldmap, newmap; + v7fs_daddr_t blk, idxblk; + int error; + v7fs_daddr_t old_nblk = V7FS_ROUND_BSIZE(old_filesize) >> V7FS_BSHIFT; + v7fs_daddr_t new_nblk = V7FS_ROUND_BSIZE(new_filesize) >> V7FS_BSHIFT; + + if (old_nblk == new_nblk) { + inode->filesize += sz; + v7fs_inode_writeback(fs, inode); + return 0; /* no need to expand. */ + } + struct v7fs_inode backup = *inode; + v7fs_daddr_t required_blk = new_nblk - old_nblk; + + DPRINTF("%zu->%zu, required block=%d\n", old_filesize, new_filesize, + required_blk); + + v7fs_datablock_addr(old_filesize, &oldmap); + v7fs_daddr_t i; + for (i = 0; i < required_blk; i++) { + v7fs_datablock_addr(old_filesize + (i+1) * V7FS_BSIZE, &newmap); + daddr_map_dump(&oldmap); + daddr_map_dump(&newmap); + + if (oldmap.level != newmap.level) { + /* Allocate index area */ + if ((error = v7fs_datablock_allocate(fs, &idxblk))) + return error; + + switch (newmap.level) { + case 1: + DPRINTF("0->1\n"); + inode->addr[V7FS_NADDR_INDEX1] = idxblk; + blk = add_leaf(fs, idxblk, 0); + break; + case 2: + DPRINTF("1->2\n"); + inode->addr[V7FS_NADDR_INDEX2] = idxblk; + blk = add_leaf(fs, add_leaf(fs, idxblk, 0), 0); + break; + case 3: + DPRINTF("2->3\n"); + inode->addr[V7FS_NADDR_INDEX3] = idxblk; + blk = add_leaf(fs, add_leaf(fs, add_leaf(fs, + idxblk, 0), 0), 0); + break; + } + } else { + switch (newmap.level) { + case 0: + if ((error = v7fs_datablock_allocate(fs, &blk))) + return error; + inode->addr[newmap.index[0]] = blk; + DPRINTF("direct index %d = blk%d\n", + newmap.index[0], blk); + break; + case 1: + idxblk = inode->addr[V7FS_NADDR_INDEX1]; + blk = add_leaf(fs, idxblk, newmap.index[0]); + break; + case 2: + idxblk = inode->addr[V7FS_NADDR_INDEX2]; + if (oldmap.index[0] != newmap.index[0]) + add_leaf(fs, idxblk, newmap.index[0]); + blk = add_leaf(fs, link(fs,idxblk, + newmap.index[0]), newmap.index[1]); + break; + case 3: + idxblk = inode->addr[V7FS_NADDR_INDEX3]; + + if (oldmap.index[0] != newmap.index[0]) + add_leaf(fs, idxblk, newmap.index[0]); + + if (oldmap.index[1] != newmap.index[1]) + add_leaf(fs, link(fs, idxblk, + newmap.index[0]), newmap.index[1]); + blk = add_leaf(fs, link(fs, link(fs, idxblk, + newmap.index[0]), newmap.index[1]), + newmap.index[2]); + break; + } + } + if (!blk) { + *inode = backup; /* structure copy; */ + return ENOSPC; + } + oldmap = newmap; + } + inode->filesize += sz; + v7fs_inode_writeback(fs, inode); + + return 0; +} + +static v7fs_daddr_t +link(struct v7fs_self *fs, v7fs_daddr_t listblk, int n) +{ + v7fs_daddr_t *list; + v7fs_daddr_t blk; + void *buf; + + if (!datablock_number_sanity(fs, listblk)) + return 0; + if (!(buf = scratch_read(fs, listblk))) + return 0; + list = (v7fs_daddr_t *)buf; + blk = V7FS_VAL32(fs, list[n]); + scratch_free(fs, buf); + + if (!datablock_number_sanity(fs, blk)) + return 0; + + return blk; +} + +static v7fs_daddr_t +add_leaf(struct v7fs_self *fs, v7fs_daddr_t up, int idx) +{ + v7fs_daddr_t newblk; + v7fs_daddr_t *daddr_list; + int error = 0; + void *buf; + + if (!up) + return 0; + if (!datablock_number_sanity(fs, up)) + return 0; + + if ((error = v7fs_datablock_allocate(fs, &newblk))) + return 0; + if (!(buf = scratch_read(fs, up))) + return 0; + daddr_list = (v7fs_daddr_t *)buf; + daddr_list[idx] = V7FS_VAL32(fs, newblk); + if (!fs->io.write(fs->io.cookie, buf, up)) + newblk = 0; + scratch_free(fs, buf); + + return newblk; +} + +int +v7fs_datablock_contract(struct v7fs_self *fs, struct v7fs_inode *inode, + size_t sz) +{ + size_t old_filesize = inode->filesize; + size_t new_filesize = old_filesize - sz; + struct v7fs_daddr_map oldmap, newmap; + v7fs_daddr_t blk, idxblk; + int error = 0; + v7fs_daddr_t old_nblk = V7FS_ROUND_BSIZE(old_filesize) >> V7FS_BSHIFT; + v7fs_daddr_t new_nblk = V7FS_ROUND_BSIZE(new_filesize) >> V7FS_BSHIFT; + + if (old_nblk == new_nblk) { + inode->filesize -= sz; + v7fs_inode_writeback(fs, inode); + return 0; /* no need to contract; */ + } + v7fs_daddr_t erase_blk = old_nblk - new_nblk; + + DPRINTF("%zu->%zu # of erased block=%d\n", old_filesize, new_filesize, + erase_blk); + + v7fs_datablock_addr(old_filesize, &oldmap); + v7fs_daddr_t i; + for (i = 0; i < erase_blk; i++) { + v7fs_datablock_addr(old_filesize - (i+1) * V7FS_BSIZE, &newmap); + + if (oldmap.level != newmap.level) { + switch (newmap.level) { + case 0: /*1->0 */ + DPRINTF("1->0\n"); + idxblk = inode->addr[V7FS_NADDR_INDEX1]; + inode->addr[V7FS_NADDR_INDEX1] = 0; + error = v7fs_datablock_deallocate(fs, + remove_self(fs, idxblk)); + break; + case 1: /*2->1 */ + DPRINTF("2->1\n"); + idxblk = inode->addr[V7FS_NADDR_INDEX2]; + inode->addr[V7FS_NADDR_INDEX2] = 0; + error = v7fs_datablock_deallocate(fs, + remove_self(fs, remove_self(fs, idxblk))); + break; + case 2:/*3->2 */ + DPRINTF("3->2\n"); + idxblk = inode->addr[V7FS_NADDR_INDEX3]; + inode->addr[V7FS_NADDR_INDEX3] = 0; + error = v7fs_datablock_deallocate(fs, + remove_self(fs, remove_self(fs, + remove_self(fs, idxblk)))); + break; + } + } else { + switch (newmap.level) { + case 0: + DPRINTF("[0] %d\n", oldmap.index[0]); + blk = inode->addr[oldmap.index[0]]; + error = v7fs_datablock_deallocate(fs, blk); + break; + case 1: + DPRINTF("[1] %d\n", oldmap.index[0]); + idxblk = inode->addr[V7FS_NADDR_INDEX1]; + remove_leaf(fs, idxblk, oldmap.index[0]); + + break; + case 2: + DPRINTF("[2] %d %d\n", oldmap.index[0], + oldmap.index[1]); + idxblk = inode->addr[V7FS_NADDR_INDEX2]; + remove_leaf(fs, link(fs, idxblk, + oldmap.index[0]), oldmap.index[1]); + if (oldmap.index[0] != newmap.index[0]) { + remove_leaf(fs, idxblk, + oldmap.index[0]); + } + break; + case 3: + DPRINTF("[2] %d %d %d\n", oldmap.index[0], + oldmap.index[1], oldmap.index[2]); + idxblk = inode->addr[V7FS_NADDR_INDEX3]; + remove_leaf(fs, link(fs, link(fs, idxblk, + oldmap.index[0]), oldmap.index[1]), + oldmap.index[2]); + + if (oldmap.index[1] != newmap.index[1]) { + remove_leaf(fs, link(fs, idxblk, + oldmap.index[0]), oldmap.index[1]); + } + if (oldmap.index[0] != newmap.index[0]) { + remove_leaf(fs, idxblk, + oldmap.index[0]); + } + break; + } + } + oldmap = newmap; + } + inode->filesize -= sz; + v7fs_inode_writeback(fs, inode); + + return error; +} + +static v7fs_daddr_t +unlink(struct v7fs_self *fs, v7fs_daddr_t idxblk, int n) +{ + v7fs_daddr_t *daddr_list; + v7fs_daddr_t blk; + void *buf; + + if (!(buf = scratch_read(fs, idxblk))) + return 0; + daddr_list = (v7fs_daddr_t *)buf; + blk = V7FS_VAL32(fs, daddr_list[n]); + daddr_list[n] = 0; + fs->io.write(fs->io.cookie, buf, idxblk); + scratch_free(fs, buf); + + return blk; /* unlinked block. */ +} + +static v7fs_daddr_t +remove_self(struct v7fs_self *fs, v7fs_daddr_t up) +{ + v7fs_daddr_t down; + + if (!datablock_number_sanity(fs, up)) + return 0; + + /* At 1st, remove from datablock list. */ + down = unlink(fs, up, 0); + + /* link self to freelist. */ + v7fs_datablock_deallocate(fs, up); + + return down; +} + +static v7fs_daddr_t +remove_leaf(struct v7fs_self *fs, v7fs_daddr_t up, int n) +{ + v7fs_daddr_t down; + + if (!datablock_number_sanity(fs, up)) + return 0; + + /* At 1st, remove from datablock list. */ + down = unlink(fs, up, n); + + /* link leaf to freelist. */ + v7fs_datablock_deallocate(fs, down); + + return down; +} + +int +v7fs_datablock_size_change(struct v7fs_self *fs, size_t newsz, + struct v7fs_inode *inode) +{ + ssize_t diff = newsz - v7fs_inode_filesize(inode); + int error = 0; + + if (diff > 0) + error = v7fs_datablock_expand(fs, inode, diff); + else if (diff < 0) + error = v7fs_datablock_contract(fs, inode, -diff); + + return error; +} + +#ifdef V7FS_DATABLOCK_DEBUG +void +daddr_map_dump(const struct v7fs_daddr_map *map) +{ + + DPRINTF("level %d ", map->level); + int m, n = !map->level ? 1 : map->level; + for (m = 0; m < n; m++) + printf("[%d]", map->index[m]); + printf("\n"); +} +#endif diff --git a/sys/fs/v7fs/v7fs_datablock.h b/sys/fs/v7fs/v7fs_datablock.h new file mode 100644 index 000000000000..17d2885869cf --- /dev/null +++ b/sys/fs/v7fs/v7fs_datablock.h @@ -0,0 +1,46 @@ +/* $NetBSD: v7fs_datablock.h,v 1.1 2011/06/27 11:52:24 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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 _V7FS_DATABLOCK_H_ +#define _V7FS_DATABLOCK_H_ + +__BEGIN_DECLS +bool datablock_number_sanity(const struct v7fs_self *, v7fs_daddr_t); +int v7fs_datablock_allocate(struct v7fs_self *, v7fs_daddr_t *); +int v7fs_datablock_foreach(struct v7fs_self *, struct v7fs_inode *, + int (*)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *); +v7fs_daddr_t v7fs_datablock_last(struct v7fs_self *, struct v7fs_inode *, + v7fs_off_t); +int v7fs_datablock_expand(struct v7fs_self *, struct v7fs_inode *, size_t); +int v7fs_datablock_contract(struct v7fs_self *, struct v7fs_inode *, size_t); +int v7fs_datablock_size_change(struct v7fs_self *, size_t, struct v7fs_inode *); +__END_DECLS +#endif /*!_V7FS_INODE_H_ */ diff --git a/sys/fs/v7fs/v7fs_dirent.c b/sys/fs/v7fs/v7fs_dirent.c new file mode 100644 index 000000000000..a3ed995d2ddf --- /dev/null +++ b/sys/fs/v7fs/v7fs_dirent.c @@ -0,0 +1,85 @@ +/* $NetBSD: v7fs_dirent.c,v 1.1 2011/06/27 11:52:24 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_dirent.c,v 1.1 2011/06/27 11:52:24 uch Exp $"); +#if defined _KERNEL_OPT +#include "opt_v7fs.h" +#endif + +#ifdef _KERNEL +#include +#include +#else +#include +#include +#endif + +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_endian.h" +#include "v7fs_inode.h" +#include "v7fs_dirent.h" + +#ifdef V7FS_DIRENT_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +bool +v7fs_dirent_endian_convert(struct v7fs_self *fs, struct v7fs_dirent *dir, int n) +{ + struct v7fs_superblock *sb = &fs->superblock; + int i; + v7fs_ino_t ino; + bool ok = true; + + for (i = 0; i < n; i++, dir++) { + ino = V7FS_VAL16(fs, dir->inode_number); + if (v7fs_inode_number_sanity(sb, ino)) { + DPRINTF("Invalid inode# %d %s\n", ino, dir->name); + ok = false; + } + dir->inode_number = ino; + } + + return ok; +} + +void +v7fs_dirent_filename(char *dst/* size must be V7FS_NAME_MAX + 1 */, + const char *src) +{ + + strncpy(dst, src, V7FS_NAME_MAX); + dst[V7FS_NAME_MAX] = '\0'; +} diff --git a/sys/fs/v7fs/v7fs_dirent.h b/sys/fs/v7fs/v7fs_dirent.h new file mode 100644 index 000000000000..46ca28d4e92d --- /dev/null +++ b/sys/fs/v7fs/v7fs_dirent.h @@ -0,0 +1,38 @@ +/* $NetBSD: v7fs_dirent.h,v 1.1 2011/06/27 11:52:24 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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 _V7FS_DIRENT_H_ +#define _V7FS_DIRENT_H_ +__BEGIN_DECLS +bool v7fs_dirent_endian_convert(struct v7fs_self *, struct v7fs_dirent *, int); +void v7fs_dirent_filename(char *, const char *); +__END_DECLS +#endif /*!_V7FS_DIRENT_H_ */ diff --git a/sys/fs/v7fs/v7fs_endian.c b/sys/fs/v7fs/v7fs_endian.c new file mode 100644 index 000000000000..b59ab9ccc1a1 --- /dev/null +++ b/sys/fs/v7fs/v7fs_endian.c @@ -0,0 +1,227 @@ +/* $NetBSD: v7fs_endian.c,v 1.1 2011/06/27 11:52:24 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_endian.c,v 1.1 2011/06/27 11:52:24 uch Exp $"); +#if defined _KERNEL_OPT +#include "opt_v7fs.h" +#endif + +#include "v7fs.h" +#include "v7fs_endian.h" +#include "v7fs_impl.h" + +#ifndef BYTE_ORDER +#error +#endif + +/* PDP to Little */ +#define bswap32pdp_le(x) \ + ((uint32_t) \ + ((((x) & 0xffff0000) >> 16) | \ + (((x) & 0x0000ffff) << 16))) +/* PDP to Big */ +#define bswap32pdp_be(x) \ + ((uint32_t) \ + ((((x) & 0xff00ff00) >> 8) | \ + (((x) & 0x00ff00ff) << 8))) +#ifdef V7FS_EI +static uint32_t val32_normal_order(uint32_t); +static uint32_t val32_reverse_order(uint32_t); +#if BYTE_ORDER == LITTLE_ENDIAN +static uint32_t val32_pdp_to_little(uint32_t); +#else +static uint32_t val32_pdp_to_big(uint32_t); +#endif +static uint16_t val16_normal_order(uint16_t); +static uint16_t val16_reverse_order(uint16_t); +static v7fs_daddr_t val24_reverse_order_read(uint8_t *); +static void val24_reverse_order_write(v7fs_daddr_t, uint8_t *); +static v7fs_daddr_t val24_pdp_read(uint8_t *); +static void val24_pdp_write(v7fs_daddr_t, uint8_t *); + +static uint32_t +val32_normal_order(uint32_t v) +{ + + return v; +} + +static uint32_t +val32_reverse_order(uint32_t v) +{ + + return bswap32(v); +} +#if BYTE_ORDER == LITTLE_ENDIAN +static uint32_t +val32_pdp_to_little(uint32_t v) +{ + + return bswap32pdp_le(v); +} +#else +static uint32_t +val32_pdp_to_big(uint32_t v) +{ + + return bswap32pdp_be(v); +} +#endif +static uint16_t +val16_normal_order(uint16_t v) +{ + + return v; +} + +static uint16_t +val16_reverse_order(uint16_t v) +{ + + return bswap16(v); +} + +static v7fs_daddr_t +val24_reverse_order_read(uint8_t *a) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return (a[0] << 16) | (a[1] << 8) | a[2]; +#else + return (a[2] << 16) | (a[1] << 8) | a[0]; +#endif +} + +static void +val24_reverse_order_write(v7fs_daddr_t addr, uint8_t *a) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + a[0] = (addr >> 16) & 0xff; + a[1] = (addr >> 8) & 0xff; + a[2] = addr & 0xff; +#else + a[0] = addr & 0xff; + a[1] = (addr >> 8) & 0xff; + a[2] = (addr >> 16) & 0xff; +#endif +} + +static v7fs_daddr_t +val24_pdp_read(uint8_t *a) +{ + + return (a[0] << 16) | a[1] | (a[2] << 8); +} + +static void +val24_pdp_write(v7fs_daddr_t addr, uint8_t *a) +{ + + a[0] = (addr >> 16) & 0xff; + a[1] = addr & 0xff; + a[2] = (addr >> 8) & 0xff; +} + +void +v7fs_endian_init(struct v7fs_self *fs) +{ + struct endian_conversion_ops *ops = &fs->val; + + switch (fs->endian) + { +#if BYTE_ORDER == LITTLE_ENDIAN + case LITTLE_ENDIAN: + ops->conv32 = val32_normal_order; + ops->conv16 = val16_normal_order; + ops->conv24read = val24_normal_order_read; + ops->conv24write = val24_normal_order_write; + break; + case BIG_ENDIAN: + ops->conv32 = val32_reverse_order; + ops->conv16 = val16_reverse_order; + ops->conv24read = val24_reverse_order_read; + ops->conv24write = val24_reverse_order_write; + break; + case PDP_ENDIAN: + ops->conv32 = val32_pdp_to_little; + ops->conv16 = val16_normal_order; + ops->conv24read = val24_pdp_read; + ops->conv24write = val24_pdp_write; + break; +#else /* BIG_ENDIAN */ + case LITTLE_ENDIAN: + ops->conv32 = val32_reverse_order; + ops->conv16 = val16_reverse_order; + ops->conv24read = val24_reverse_order_read; + ops->conv24write = val24_reverse_order_write; + break; + case BIG_ENDIAN: + ops->conv32 = val32_normal_order; + ops->conv16 = val16_normal_order; + ops->conv24read = val24_normal_order_read; + ops->conv24write = val24_normal_order_write; + break; + case PDP_ENDIAN: + ops->conv32 = val32_pdp_to_big; + ops->conv16 = val16_reverse_order; + ops->conv24read = val24_pdp_read; + ops->conv24write = val24_pdp_write; + break; +#endif + } +} +#endif /* V7FS_EI */ +v7fs_daddr_t +val24_normal_order_read(uint8_t *a) +{ + /*(v7fs_daddr_t)cast is required for int 16bit system. */ +#if BYTE_ORDER == LITTLE_ENDIAN + return ((v7fs_daddr_t)a[2] << 16) | ((v7fs_daddr_t)a[1] << 8) | + (v7fs_daddr_t)a[0]; +#else + return ((v7fs_daddr_t)a[0] << 16) | ((v7fs_daddr_t)a[1] << 8) | + (v7fs_daddr_t)a[2]; +#endif +} + +void +val24_normal_order_write(v7fs_daddr_t addr, uint8_t *a) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + a[0] = addr & 0xff; + a[1] = (addr >> 8) & 0xff; + a[2] = (addr >> 16) & 0xff; +#else + a[0] = (addr >> 16) & 0xff; + a[1] = (addr >> 8) & 0xff; + a[2] = addr & 0xff; +#endif +} diff --git a/sys/fs/v7fs/v7fs_endian.h b/sys/fs/v7fs/v7fs_endian.h new file mode 100644 index 000000000000..1d6411cae8be --- /dev/null +++ b/sys/fs/v7fs/v7fs_endian.h @@ -0,0 +1,52 @@ +/* $NetBSD: v7fs_endian.h,v 1.1 2011/06/27 11:52:24 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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 _V7FS_ENDIAN_H_ +#define _V7FS_ENDIAN_H_ + +struct v7fs_self; +__BEGIN_DECLS; +v7fs_daddr_t val24_normal_order_read(uint8_t *); +void val24_normal_order_write(v7fs_daddr_t, uint8_t *); +__END_DECLS +#ifdef V7FS_EI +#define V7FS_VAL32(x, v) ((*(x)->val.conv32)(v)) +#define V7FS_VAL16(x, v) ((*(x)->val.conv16)(v)) +#define V7FS_VAL24_READ(x, a) ((*(x)->val.conv24read)(a)) +#define V7FS_VAL24_WRITE(x, v, a) ((*(x)->val.conv24write)(v, a)) +void v7fs_endian_init(struct v7fs_self *); +#else +#define V7FS_VAL32(x, v) (v) +#define V7FS_VAL16(x, v) (v) +#define V7FS_VAL24_READ(x, a) (val24_normal_order_read(a)) +#define V7FS_VAL24_WRITE(x, v, a) (val24_normal_order_write(v, a)) +#endif /*V7FS_EI */ +#endif /*!_V7FS_ENDIAN_H_ */ diff --git a/sys/fs/v7fs/v7fs_extern.c b/sys/fs/v7fs/v7fs_extern.c new file mode 100644 index 000000000000..7d4c73706792 --- /dev/null +++ b/sys/fs/v7fs/v7fs_extern.c @@ -0,0 +1,262 @@ +/* $NetBSD: v7fs_extern.c,v 1.1 2011/06/27 11:52:24 uch Exp $ */ + +/*- + * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_extern.c,v 1.1 2011/06/27 11:52:24 uch Exp $"); + +#if defined _KERNEL_OPT +#include "opt_v7fs.h" +#endif +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +MODULE(MODULE_CLASS_VFS, v7fs, NULL); + +/* External interfaces */ + +int (**v7fs_vnodeop_p)(void *); /* filled by getnewvnode (vnode.h) */ + +const struct vnodeopv_entry_desc v7fs_vnodeop_entries[] = { + { &vop_default_desc, vn_default_error }, + { &vop_lookup_desc, v7fs_lookup }, /* lookup */ + { &vop_create_desc, v7fs_create }, /* create */ + { &vop_mknod_desc, v7fs_mknod }, /* mknod */ + { &vop_open_desc, v7fs_open }, /* open */ + { &vop_close_desc, v7fs_close }, /* close */ + { &vop_access_desc, v7fs_access }, /* access */ + { &vop_getattr_desc, v7fs_getattr }, /* getattr */ + { &vop_setattr_desc, v7fs_setattr }, /* setattr */ + { &vop_read_desc, v7fs_read }, /* read */ + { &vop_write_desc, v7fs_write }, /* write */ + { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ + { &vop_ioctl_desc, genfs_enoioctl }, /* ioctl */ + { &vop_poll_desc, genfs_poll }, /* poll */ + { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ + { &vop_revoke_desc, genfs_revoke }, /* revoke */ + { &vop_mmap_desc, genfs_mmap }, /* mmap */ + { &vop_fsync_desc, v7fs_fsync }, /* fsync */ + { &vop_seek_desc, genfs_seek }, /* seek */ + { &vop_remove_desc, v7fs_remove }, /* remove */ + { &vop_link_desc, v7fs_link }, /* link */ + { &vop_rename_desc, v7fs_rename }, /* rename */ + { &vop_mkdir_desc, v7fs_mkdir }, /* mkdir */ + { &vop_rmdir_desc, v7fs_rmdir }, /* rmdir */ + { &vop_symlink_desc, v7fs_symlink }, /* symlink */ + { &vop_readdir_desc, v7fs_readdir }, /* readdir */ + { &vop_readlink_desc, v7fs_readlink }, /* readlink */ + { &vop_abortop_desc, genfs_abortop }, /* abortop */ + { &vop_inactive_desc, v7fs_inactive }, /* inactive */ + { &vop_reclaim_desc, v7fs_reclaim }, /* reclaim */ + { &vop_lock_desc, genfs_lock }, /* lock */ + { &vop_unlock_desc, genfs_unlock }, /* unlock */ + { &vop_bmap_desc, v7fs_bmap }, /* bmap */ + { &vop_strategy_desc, v7fs_strategy }, /* strategy */ + { &vop_print_desc, v7fs_print }, /* print */ + { &vop_islocked_desc, genfs_islocked }, /* islocked */ + { &vop_pathconf_desc, v7fs_pathconf }, /* pathconf */ + { &vop_advlock_desc, v7fs_advlock }, /* advlock */ + { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ + { &vop_getpages_desc, genfs_getpages }, /* getpages */ + { &vop_putpages_desc, genfs_putpages }, /* putpages */ + { NULL, NULL } +}; + + +int (**v7fs_specop_p)(void *); +const struct vnodeopv_entry_desc v7fs_specop_entries[] = { + { &vop_default_desc, vn_default_error }, + { &vop_lookup_desc, spec_lookup }, /* lookup */ + { &vop_create_desc, spec_create }, /* create xxx*/ + { &vop_mknod_desc, spec_mknod }, /* mknod xxx*/ + { &vop_open_desc, spec_open }, /* open */ + { &vop_close_desc, spec_close }, /* close */ + { &vop_access_desc, v7fs_access }, /* access */ + { &vop_getattr_desc, v7fs_getattr }, /* getattr */ + { &vop_setattr_desc, v7fs_setattr }, /* setattr */ + { &vop_read_desc, spec_read }, /* read */ + { &vop_write_desc, spec_write }, /* write */ + { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ + { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ + { &vop_poll_desc, spec_poll }, /* poll */ + { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ + { &vop_revoke_desc, spec_revoke }, /* revoke */ + { &vop_mmap_desc, spec_mmap }, /* mmap */ + { &vop_fsync_desc, spec_fsync }, /* fsync */ + { &vop_seek_desc, spec_seek }, /* seek */ + { &vop_remove_desc, spec_remove }, /* remove */ + { &vop_link_desc, spec_link }, /* link */ + { &vop_rename_desc, spec_rename }, /* rename */ + { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ + { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ + { &vop_symlink_desc, spec_symlink }, /* symlink */ + { &vop_readdir_desc, spec_readdir }, /* readdir */ + { &vop_readlink_desc, spec_readlink }, /* readlink */ + { &vop_abortop_desc, spec_abortop }, /* abortop */ + { &vop_inactive_desc, v7fs_inactive }, /* inactive */ + { &vop_reclaim_desc, v7fs_reclaim }, /* reclaim */ + { &vop_lock_desc, genfs_lock }, /* lock */ + { &vop_unlock_desc, genfs_unlock }, /* unlock */ + { &vop_bmap_desc, spec_bmap }, /* bmap */ + { &vop_strategy_desc, spec_strategy }, /* strategy */ + { &vop_print_desc, spec_print }, /* print */ + { &vop_islocked_desc, genfs_islocked }, /* islocked */ + { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ + { &vop_advlock_desc, spec_advlock }, /* advlock */ + { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ + { &vop_getpages_desc, spec_getpages }, /* getpages */ + { &vop_putpages_desc, spec_putpages }, /* putpages */ + { NULL, NULL } +}; + +int (**v7fs_fifoop_p)(void *); +const struct vnodeopv_entry_desc v7fs_fifoop_entries[] = { + { &vop_default_desc, vn_default_error }, + { &vop_lookup_desc, vn_fifo_bypass }, /* lookup */ + { &vop_create_desc, vn_fifo_bypass }, /* create */ + { &vop_mknod_desc, vn_fifo_bypass }, /* mknod */ + { &vop_open_desc, vn_fifo_bypass }, /* open */ + { &vop_close_desc, vn_fifo_bypass }, /* close */ + { &vop_access_desc, v7fs_access }, /* access */ + { &vop_getattr_desc, v7fs_getattr }, /* getattr */ + { &vop_setattr_desc, v7fs_setattr }, /* setattr */ + { &vop_read_desc, vn_fifo_bypass }, /* read */ + { &vop_write_desc, vn_fifo_bypass }, /* write */ + { &vop_ioctl_desc, vn_fifo_bypass }, /* ioctl */ + { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ + { &vop_poll_desc, vn_fifo_bypass }, /* poll */ + { &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */ + { &vop_revoke_desc, vn_fifo_bypass }, /* revoke */ + { &vop_mmap_desc, vn_fifo_bypass }, /* mmap */ + { &vop_fsync_desc, vn_fifo_bypass }, /* fsync */ + { &vop_seek_desc, vn_fifo_bypass }, /* seek */ + { &vop_remove_desc, vn_fifo_bypass }, /* remove */ + { &vop_link_desc, vn_fifo_bypass }, /* link */ + { &vop_rename_desc, vn_fifo_bypass }, /* rename */ + { &vop_mkdir_desc, vn_fifo_bypass }, /* mkdir */ + { &vop_rmdir_desc, vn_fifo_bypass }, /* rmdir */ + { &vop_symlink_desc, vn_fifo_bypass }, /* symlink */ + { &vop_readdir_desc, vn_fifo_bypass }, /* readdir */ + { &vop_readlink_desc, vn_fifo_bypass }, /* readlink */ + { &vop_abortop_desc, vn_fifo_bypass }, /* abortop */ + { &vop_inactive_desc, v7fs_inactive }, /* inactive */ + { &vop_reclaim_desc, v7fs_reclaim }, /* reclaim */ + { &vop_lock_desc, vn_fifo_bypass }, /* lock */ + { &vop_unlock_desc, vn_fifo_bypass }, /* unlock */ + { &vop_bmap_desc, vn_fifo_bypass }, /* bmap */ + { &vop_strategy_desc, vn_fifo_bypass }, /* strategy */ + { &vop_print_desc, vn_fifo_bypass }, /* print */ + { &vop_islocked_desc, vn_fifo_bypass }, /* islocked */ + { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */ + { &vop_advlock_desc, vn_fifo_bypass }, /* advlock */ + { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ + { &vop_putpages_desc, vn_fifo_bypass }, /* putpages */ + { NULL, NULL } +}; + +const struct vnodeopv_desc v7fs_fifoop_opv_desc = { + &v7fs_fifoop_p, + v7fs_fifoop_entries +}; + +const struct vnodeopv_desc v7fs_vnodeop_opv_desc = { + &v7fs_vnodeop_p, + v7fs_vnodeop_entries +}; + +const struct vnodeopv_desc v7fs_specop_opv_desc = { + &v7fs_specop_p, + v7fs_specop_entries +}; + +const struct vnodeopv_desc *v7fs_vnodeopv_descs[] = { + &v7fs_vnodeop_opv_desc, + &v7fs_specop_opv_desc, + &v7fs_fifoop_opv_desc, + NULL, +}; + +const struct genfs_ops v7fs_genfsops = { + .gop_size = genfs_size, + .gop_alloc = v7fs_gop_alloc, + .gop_write = genfs_gop_write, +}; + +struct vfsops v7fs_vfsops = { + MOUNT_V7FS, + sizeof(struct v7fs_args), + v7fs_mount, + v7fs_start, + v7fs_unmount, + v7fs_root, + (void *)eopnotsupp, /* vfs_quotactl */ + v7fs_statvfs, + v7fs_sync, + v7fs_vget, + v7fs_fhtovp, + v7fs_vptofh, + v7fs_init, + v7fs_reinit, + v7fs_done, + v7fs_mountroot, + (int (*)(struct mount *, struct vnode *, struct timespec *)) + eopnotsupp, /* snapshot */ + vfs_stdextattrctl, + (void *)eopnotsupp, /* vfs_suspendctl */ + genfs_renamelock_enter, + genfs_renamelock_exit, + (void *)eopnotsupp, + v7fs_vnodeopv_descs, + 0, + { NULL, NULL } +}; + +static int +v7fs_modcmd(modcmd_t cmd, void *arg) +{ + + switch (cmd) { + case MODULE_CMD_INIT: + return vfs_attach(&v7fs_vfsops); + case MODULE_CMD_FINI: + return vfs_detach(&v7fs_vfsops); + default: + return ENOTTY; + } +} diff --git a/sys/fs/v7fs/v7fs_extern.h b/sys/fs/v7fs/v7fs_extern.h new file mode 100644 index 000000000000..80c4f9cc2638 --- /dev/null +++ b/sys/fs/v7fs/v7fs_extern.h @@ -0,0 +1,116 @@ +/* $NetBSD: v7fs_extern.h,v 1.1 2011/06/27 11:52:24 uch Exp $ */ + +/*- + * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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 _FS_V7FS_EXTERN_H_ +#define _FS_V7FS_EXTERN_H_ + +#include + +#include +#include +#include + +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_inode.h" + +struct v7fs_mount { + struct mount *mountp; + struct vnode *devvp; /* block device mounted vnode */ + struct v7fs_self *core; /* filesystem dependent implementation*/ + LIST_HEAD(, v7fs_node) v7fs_node_head; +}; + +struct v7fs_node { + struct genfs_node gnode; + struct v7fs_inode inode; /* filesystem dependent implementation */ + struct vnode *vnode; /* back-link */ + struct v7fs_mount *v7fsmount; /* our filesystem */ + struct lockf *lockf; /* advlock */ + + int update_ctime; + int update_atime; + int update_mtime; + + LIST_ENTRY(v7fs_node) link; +}; + +#define VFSTOV7FS(mp) ((struct v7fs_mount *)((mp)->mnt_data)) + +__BEGIN_DECLS +/* v-node ops. */ +int v7fs_lookup(void *); +int v7fs_create(void *); +int v7fs_open(void *); +int v7fs_close(void *); +int v7fs_access(void *); +int v7fs_getattr(void *); +int v7fs_setattr(void *); +int v7fs_read(void *); +int v7fs_write(void *); +int v7fs_fsync(void *); +int v7fs_remove(void *); +int v7fs_rename(void *); +int v7fs_readdir(void *); +int v7fs_inactive(void *); +int v7fs_reclaim(void *); +int v7fs_bmap(void *); +int v7fs_strategy(void *); +int v7fs_print(void *); +int v7fs_advlock(void *); +int v7fs_pathconf(void *); + +int v7fs_link(void *); +int v7fs_symlink(void *); +int v7fs_readlink(void *); + +int v7fs_mkdir(void *); +int v7fs_rmdir(void *); + +int v7fs_mknod(void *); + +/* vfs ops. */ +VFS_PROTOS(v7fs); + +int v7fs_mountroot(void); +extern int (**v7fs_vnodeop_p)(void *); +extern int (**v7fs_specop_p)(void *); +extern int (**v7fs_fifoop_p)(void *); + +/* genfs ops */ +int v7fs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t); +extern const struct genfs_ops v7fs_genfsops; + +/* internal service */ +int v7fs_update(struct vnode *, const struct timespec *, + const struct timespec *, int); +__END_DECLS +#endif /* _FS_V7FS_EXTERN_H_ */ diff --git a/sys/fs/v7fs/v7fs_file.c b/sys/fs/v7fs/v7fs_file.c new file mode 100644 index 000000000000..89dfac21dfc8 --- /dev/null +++ b/sys/fs/v7fs/v7fs_file.c @@ -0,0 +1,411 @@ +/* $NetBSD: v7fs_file.c,v 1.1 2011/06/27 11:52:24 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_file.c,v 1.1 2011/06/27 11:52:24 uch Exp $"); +#if defined _KERNEL_OPT +#include "opt_v7fs.h" +#endif + +#ifdef _KERNEL +#include +#include +#else +#include +#include +#include +#define MIN(a,b) ((/*CONSTCOND*/(a)<(b))?(a):(b)) +#endif + +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_endian.h" +#include "v7fs_inode.h" +#include "v7fs_dirent.h" +#include "v7fs_file.h" +#include "v7fs_datablock.h" + +#ifdef V7FS_FILE_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +static int lookup_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t); +static int remove_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t); + +int +v7fs_file_lookup_by_name(struct v7fs_self *fs, struct v7fs_inode *parent_dir, + const char *name, v7fs_ino_t *ino) +{ + char filename[V7FS_NAME_MAX + 1]; + char *q; + int error; + size_t len; + + if ((q = strchr(name, '/'))) { + /* Zap following path. */ + len = MIN(V7FS_NAME_MAX + 1, q - name); + memcpy(filename, name, len); + filename[len] = '\0'; /* '/' -> '\0' */ + } else { + v7fs_dirent_filename(filename, name); + } + DPRINTF("%s(%s) dir=%d\n", filename, name, parent_dir->inode_number); + + struct v7fs_lookup_arg lookup_arg = { .name = filename, + .inode_number = 0 }; + if ((error = v7fs_datablock_foreach(fs, parent_dir, lookup_subr, + &lookup_arg)) != V7FS_ITERATOR_BREAK) { + DPRINTF("not found.\n"); + return ENOENT; + } + + *ino = lookup_arg.inode_number; + DPRINTF("done. ino=%d\n", *ino); + + return 0; +} + +static int +lookup_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz) +{ + struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx; + struct v7fs_dirent *dir; + const char *name = p->name; + void *buf; + size_t i, n; + int ret = 0; + + if (!(buf = scratch_read(fs, blk))) + return EIO; + + dir = (struct v7fs_dirent *)buf; + n = sz / sizeof(*dir); + v7fs_dirent_endian_convert(fs, dir, n); + + for (i = 0; i < n; i++, dir++) { + if (dir->inode_number < 1) { + DPRINTF("*** bad inode #%d ***\n", dir->inode_number); + continue; + } + + if (strncmp((const char *)dir->name, name, V7FS_NAME_MAX) == 0) + { + p->inode_number = dir->inode_number; + ret = V7FS_ITERATOR_BREAK; /* found */ + break; + } + } + scratch_free(fs, buf); + + return ret; +} + +int +v7fs_file_allocate(struct v7fs_self *fs, struct v7fs_inode *parent_dir, + const char *srcname, struct v7fs_fileattr *attr, v7fs_ino_t *ino) +{ + struct v7fs_inode inode; + char filename[V7FS_NAME_MAX + 1]; + struct v7fs_dirent *dir; + int error; + + /* Truncate filename. */ + v7fs_dirent_filename(filename, srcname); + DPRINTF("%s(%s)\n", filename, srcname); + + /* Check filename. */ + if (v7fs_file_lookup_by_name(fs, parent_dir, filename, ino) == 0) { + DPRINTF("%s exists\n", filename); + return EEXIST; + } + + /* Get new inode. */ + if ((error = v7fs_inode_allocate(fs, ino))) + return error; + + /* Set initial attribute. */ + memset(&inode, 0, sizeof(inode)); + inode.inode_number = *ino; + inode.mode = attr->mode; + inode.uid = attr->uid; + inode.gid = attr->gid; + if (attr->ctime) + inode.ctime = attr->ctime; + if (attr->mtime) + inode.mtime = attr->mtime; + if (attr->atime) + inode.atime = attr->atime; + + switch (inode.mode & V7FS_IFMT) { + default: + DPRINTF("Can't allocate %o type.\n", inode.mode); + v7fs_inode_deallocate(fs, *ino); + return EINVAL; + case V7FS_IFCHR: + /* FALLTHROUGH */ + case V7FS_IFBLK: + inode.nlink = 1; + inode.device = attr->device; + inode.addr[0] = inode.device; + break; + case V7FSBSD_IFFIFO: + /* FALLTHROUGH */ + case V7FSBSD_IFSOCK: + /* FALLTHROUGH */ + case V7FSBSD_IFLNK: + /* FALLTHROUGH */ + case V7FS_IFREG: + inode.nlink = 1; + break; + case V7FS_IFDIR: + inode.nlink = 2; /* . + .. */ + if ((error = v7fs_datablock_expand(fs, &inode, sizeof(*dir) * 2 + ))) { + v7fs_inode_deallocate(fs, *ino); + return error; + } + v7fs_daddr_t blk = inode.addr[0]; + void *buf; + if (!(buf = scratch_read(fs, blk))) { + v7fs_inode_deallocate(fs, *ino); + return EIO; + } + dir = (struct v7fs_dirent *)buf; + strcpy(dir[0].name, "."); + dir[0].inode_number = V7FS_VAL16(fs, *ino); + strcpy(dir[1].name, ".."); + dir[1].inode_number = V7FS_VAL16(fs, parent_dir->inode_number); + if (!fs->io.write(fs->io.cookie, buf, blk)) { + scratch_free(fs, buf); + return EIO; + } + scratch_free(fs, buf); + break; + } + + v7fs_inode_writeback(fs, &inode); + + /* Link this inode to parent directory. */ + if ((error = v7fs_directory_add_entry(fs, parent_dir, *ino, filename))) + { + DPRINTF("can't add dirent.\n"); + return error; + } + + return 0; +} + +int +v7fs_file_deallocate(struct v7fs_self *fs, struct v7fs_inode *parent_dir, + const char *name) +{ + v7fs_ino_t ino; + struct v7fs_inode inode; + int error; + + DPRINTF("%s\n", name); + if ((error = v7fs_file_lookup_by_name(fs, parent_dir, name, &ino))) { + DPRINTF("no such a file: %s\n", name); + return error; + } + DPRINTF("%s->#%d\n", name, ino); + if ((error = v7fs_inode_load(fs, &inode, ino))) + return error; + + if (v7fs_inode_isdir(&inode)) { + /* Check child directory exists. */ + if (v7fs_inode_filesize(&inode) != + sizeof(struct v7fs_dirent) * 2 /*"." + ".."*/) { + DPRINTF("file exists.\n"); + return EEXIST; + } + inode.nlink = 0; /* remove this. */ + } else { + /* Decrement reference count. */ + --inode.nlink; /* regular file. */ + } + + + if ((error = v7fs_directory_remove_entry(fs, parent_dir, name))) + return error; + DPRINTF("remove dirent\n"); + + if (inode.nlink == 0) { + v7fs_datablock_contract(fs, &inode, inode.filesize); + DPRINTF("remove datablock\n"); + v7fs_inode_deallocate(fs, ino); + DPRINTF("remove inode\n"); + } else { + v7fs_inode_writeback(fs, &inode); + } + + return 0; +} + +int +v7fs_directory_add_entry(struct v7fs_self *fs, struct v7fs_inode *parent_dir, + v7fs_ino_t ino, const char *srcname) +{ + struct v7fs_inode inode; + struct v7fs_dirent *dir; + int error = 0; + v7fs_daddr_t blk; + void *buf; + char filename[V7FS_NAME_MAX + 1]; + + /* Truncate filename. */ + v7fs_dirent_filename(filename, srcname); + DPRINTF("%s(%s) %d\n", filename, srcname, ino); + + /* Target inode */ + if ((error = v7fs_inode_load(fs, &inode, ino))) + return error; + + /* Expand datablock. */ + if ((error = v7fs_datablock_expand(fs, parent_dir, sizeof(*dir)))) + return error; + + /* Read last entry. */ + if (!(blk = v7fs_datablock_last(fs, parent_dir, + v7fs_inode_filesize(parent_dir)))) + return EIO; + + /* Load dirent block. This vnode(parent dir) is locked by VFS layer. */ + if (!(buf = scratch_read(fs, blk))) + return EIO; + + size_t sz = v7fs_inode_filesize(parent_dir); + sz = V7FS_RESIDUE_BSIZE(sz); /* last block payload. */ + int n = sz / sizeof(*dir) - 1; + /* Add dirent. */ + dir = (struct v7fs_dirent *)buf; + dir[n].inode_number = V7FS_VAL16(fs, ino); + memcpy((char *)dir[n].name, filename, V7FS_NAME_MAX); + /* Write back datablock */ + if (!fs->io.write(fs->io.cookie, buf, blk)) + error = EIO; + scratch_free(fs, buf); + + if (v7fs_inode_isdir(&inode)) { + parent_dir->nlink++; + v7fs_inode_writeback(fs, parent_dir); + } + + DPRINTF("done. (dirent size=%dbyte)\n", parent_dir->filesize); + + return error; +} + +int +v7fs_directory_remove_entry(struct v7fs_self *fs, struct v7fs_inode *parent_dir, + const char *name) +{ + struct v7fs_inode inode; + int error; + struct v7fs_dirent lastdirent; + v7fs_daddr_t lastblk; + size_t sz, lastsz; + v7fs_off_t pos; + void *buf; + + /* Setup replaced entry. */ + sz = parent_dir->filesize; + lastblk = v7fs_datablock_last(fs, parent_dir, + v7fs_inode_filesize(parent_dir)); + lastsz = V7FS_RESIDUE_BSIZE(sz); + pos = lastsz - sizeof(lastdirent); + + if (!(buf = scratch_read(fs, lastblk))) + return EIO; + lastdirent = *((struct v7fs_dirent *)((uint8_t *)buf + pos)); + scratch_free(fs, buf); + DPRINTF("last dirent=%d %s pos=%d\n", + V7FS_VAL16(fs, lastdirent.inode_number), lastdirent.name, pos); + + struct v7fs_lookup_arg lookup_arg = + { .name = name, .replace = &lastdirent/*disk endian */ }; + /* Search entry that removed. replace it to last dirent. */ + if ((error = v7fs_datablock_foreach(fs, parent_dir, remove_subr, + &lookup_arg)) != V7FS_ITERATOR_BREAK) + return ENOENT; + + /* Contract dirent entries. */ + v7fs_datablock_contract(fs, parent_dir, sizeof(lastdirent)); + DPRINTF("done. (dirent size=%dbyte)\n", parent_dir->filesize); + + /* Target inode */ + if ((error = v7fs_inode_load(fs, &inode, lookup_arg.inode_number))) + return error; + + if (v7fs_inode_isdir(&inode)) { + parent_dir->nlink--; + v7fs_inode_writeback(fs, parent_dir); + } + + return 0; +} + +static int +remove_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz) +{ + struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx; + struct v7fs_dirent *dir; + void *buf; + size_t i; + int ret = 0; + + DPRINTF("match start blk=%x\n", blk); + if (!(buf = scratch_read(fs, blk))) + return EIO; + + dir = (struct v7fs_dirent *)buf; + + for (i = 0; i < sz / sizeof(*dir); i++, dir++) { + DPRINTF("%d\n", V7FS_VAL16(fs, dir->inode_number)); + if (strncmp(p->name, + (const char *)dir->name, V7FS_NAME_MAX) == 0) { + p->inode_number = V7FS_VAL16(fs, dir->inode_number); + /* Replace to last dirent. */ + *dir = *(p->replace); /* disk endian */ + /* Write back. */ + if (!fs->io.write(fs->io.cookie, buf, blk)) + ret = EIO; + else + ret = V7FS_ITERATOR_BREAK; + break; + } + } + scratch_free(fs, buf); + + return ret; +} diff --git a/sys/fs/v7fs/v7fs_file.h b/sys/fs/v7fs/v7fs_file.h new file mode 100644 index 000000000000..5fd1a4eefc49 --- /dev/null +++ b/sys/fs/v7fs/v7fs_file.h @@ -0,0 +1,64 @@ +/* $NetBSD: v7fs_file.h,v 1.1 2011/06/27 11:52:24 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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 _V7FS_FILE_H_ +#define _V7FS_FILE_H_ + +struct v7fs_lookup_arg { + const char *name; + char *buf; + v7fs_ino_t inode_number; + struct v7fs_dirent *replace; +}; + +__BEGIN_DECLS +/* core */ +int v7fs_file_lookup_by_name(struct v7fs_self *, struct v7fs_inode *, + const char*, v7fs_ino_t *); +int v7fs_file_allocate(struct v7fs_self *, struct v7fs_inode *, const char *, + struct v7fs_fileattr *, v7fs_ino_t *); +int v7fs_file_deallocate(struct v7fs_self *, struct v7fs_inode *, const char *); +int v7fs_directory_add_entry(struct v7fs_self *,struct v7fs_inode *, v7fs_ino_t, + const char *); +int v7fs_directory_remove_entry(struct v7fs_self *,struct v7fs_inode *, + const char *); + +/* util */ +int v7fs_file_rename(struct v7fs_self *, struct v7fs_inode *, const char *, + struct v7fs_inode *, const char *); +int v7fs_directory_replace_entry(struct v7fs_self *, struct v7fs_inode *, + const char *, v7fs_ino_t); +int v7fs_file_link(struct v7fs_self *, struct v7fs_inode *, struct v7fs_inode *, + const char *); +bool v7fs_file_lookup_by_number(struct v7fs_self *, struct v7fs_inode *, + v7fs_ino_t, char *); +__END_DECLS +#endif /*!_V7FS_INODE_H_ */ diff --git a/sys/fs/v7fs/v7fs_file_util.c b/sys/fs/v7fs/v7fs_file_util.c new file mode 100644 index 000000000000..78a7dca63816 --- /dev/null +++ b/sys/fs/v7fs/v7fs_file_util.c @@ -0,0 +1,223 @@ +/* $NetBSD: v7fs_file_util.c,v 1.1 2011/06/27 11:52:24 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_file_util.c,v 1.1 2011/06/27 11:52:24 uch Exp $"); +#ifdef _KERNEL +#include +#include +#else +#include +#include +#include +#endif + +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_endian.h" +#include "v7fs_inode.h" +#include "v7fs_dirent.h" +#include "v7fs_file.h" +#include "v7fs_datablock.h" + +#ifdef V7FS_FILE_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +static int replace_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t); +static int lookup_by_number_subr(struct v7fs_self *, void *, v7fs_daddr_t, + size_t); + +int +v7fs_file_link(struct v7fs_self *fs, struct v7fs_inode *parent_dir, + struct v7fs_inode *p, const char *name) +{ + int error = 0; + + DPRINTF("%d %d %s\n", parent_dir->inode_number, p->inode_number, name); + if ((error = v7fs_directory_add_entry(fs, parent_dir, p->inode_number, + name))) { + DPRINTF("can't add entry"); + return error; + } + p->nlink++; + v7fs_inode_writeback(fs, p); + + return 0; +} + +int +v7fs_file_rename(struct v7fs_self *fs, struct v7fs_inode *parent_from, + const char *from, struct v7fs_inode *parent_to, const char *to) +{ + v7fs_ino_t from_ino, to_ino; + int error; + + if ((error = v7fs_file_lookup_by_name(fs, parent_from, from, + &from_ino))) { + DPRINTF("%s don't exists\n", from); + return error; + } + + /* If target file exists, remove. */ + error = v7fs_file_lookup_by_name(fs, parent_to, to, &to_ino); + if (error == 0) { + DPRINTF("%s already exists\n", to); + if ((error = v7fs_file_deallocate(fs, parent_to, to))) { + DPRINTF("%s can't remove\n", to); + return error; + } + } else if (error != ENOENT) { + DPRINTF("error=%d\n", error); + return error; + } + + if ((error = v7fs_directory_add_entry(fs, parent_to, from_ino, to))) { + DPRINTF("can't add entry"); + return error; + } + + if ((error = v7fs_directory_remove_entry(fs, parent_from, from))) { + DPRINTF("can't remove entry"); + return error; + } + + if (parent_from != parent_to) { + /* If directory move, update ".." */ + struct v7fs_inode inode; + v7fs_inode_load(fs, &inode, from_ino); + if (v7fs_inode_isdir(&inode)) { + if ((error = v7fs_directory_replace_entry(fs, &inode, + "..", parent_to->inode_number))) { + DPRINTF("can't replace parent dir"); + return error; + } + v7fs_inode_writeback(fs, &inode); + } + } + + return 0; +} + + +int +v7fs_directory_replace_entry(struct v7fs_self *fs, struct v7fs_inode *self_dir, + const char *name, v7fs_ino_t ino) +{ + int error; + + /* Search entry that replaced. replace it to new inode number. */ + struct v7fs_lookup_arg lookup_arg = { .name = name, + .inode_number = ino }; + if ((error = v7fs_datablock_foreach(fs, self_dir, replace_subr, + &lookup_arg)) != V7FS_ITERATOR_BREAK) + return ENOENT; + + return 0; +} + +static int +replace_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz) +{ + struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx; + struct v7fs_dirent *dir; + void *buf; + size_t i, n; + int ret = 0; + + DPRINTF("match start blk=%x\n", blk); + if (!(buf = scratch_read(fs, blk))) + return EIO; + + dir = (struct v7fs_dirent *)buf; + n = sz / sizeof(*dir); + + for (i = 0; i < n; i++, dir++) { /*disk endian */ + if (strncmp(p->name, (const char *)dir->name, V7FS_NAME_MAX) + == 0) { + /* Replace inode# */ + dir->inode_number = V7FS_VAL16(fs, p->inode_number); + /* Write back. */ + if (!fs->io.write(fs->io.cookie, buf, blk)) + ret = EIO; + else + ret = V7FS_ITERATOR_BREAK; + break; + } + } + scratch_free(fs, buf); + + return ret; +} + +bool +v7fs_file_lookup_by_number(struct v7fs_self *fs, struct v7fs_inode *parent_dir, + v7fs_ino_t ino, char *buf) +{ + int ret; + + ret = v7fs_datablock_foreach(fs, parent_dir, lookup_by_number_subr, + &(struct v7fs_lookup_arg){ .inode_number = ino, .buf = buf }); + + return ret == V7FS_ITERATOR_BREAK; +} + +static int +lookup_by_number_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, + size_t sz) +{ + struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx; + struct v7fs_dirent *dir; + void *buf; + size_t i, n; + int ret = 0; + + if (!(buf = scratch_read(fs, blk))) + return EIO; + + dir = (struct v7fs_dirent *)buf; + n = sz / sizeof(*dir); + v7fs_dirent_endian_convert(fs, dir, n); + + for (i = 0; i < n; i++, dir++) { + if (dir->inode_number == p->inode_number) { + if (p->buf) + v7fs_dirent_filename(p->buf, dir->name); + ret = V7FS_ITERATOR_BREAK; + break; + } + } + scratch_free(fs, buf); + + return ret; +} diff --git a/sys/fs/v7fs/v7fs_impl.h b/sys/fs/v7fs/v7fs_impl.h new file mode 100644 index 000000000000..a6cf6a39dcb4 --- /dev/null +++ b/sys/fs/v7fs/v7fs_impl.h @@ -0,0 +1,154 @@ +/* $NetBSD: v7fs_impl.h,v 1.1 2011/06/27 11:52:25 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +/* V7FS implementation. */ +#ifndef _V7FS_IMPL_H_ +#define _V7FS_IMPL_H_ + +#ifndef _KERNEL +#include +#include +#define KDASSERT(x) assert(x) +#endif + +struct block_io_ops { + void *cookie; + bool (*drive)(void *, uint8_t); + bool (*read)(void *, uint8_t *, daddr_t); + bool (*read_n)(void *, uint8_t *, daddr_t, int); + bool (*write)(void *, uint8_t *, daddr_t); + bool (*write_n)(void *, uint8_t *, daddr_t, int); +}; + +#ifdef V7FS_EI +struct endian_conversion_ops { + uint32_t (*conv32)(uint32_t); + uint16_t (*conv16)(uint16_t); + /* For daddr packing */ + v7fs_daddr_t (*conv24read)(uint8_t *); + void (*conv24write)(v7fs_daddr_t, uint8_t *); +}; +#endif +#ifdef _KERNEL +#define V7FS_LOCK +#endif +#ifdef V7FS_LOCK +struct lock_ops { + void *cookie; + void (*lock)(void*); + void (*unlock)(void *); +}; +#define SUPERB_LOCK(x) ((x)->sb_lock.lock((x)->sb_lock.cookie)) +#define SUPERB_UNLOCK(x) ((x)->sb_lock.unlock((x)->sb_lock.cookie)) +#define ILIST_LOCK(x) ((x)->ilist_lock.lock((x)->ilist_lock.cookie)) +#define ILIST_UNLOCK(x) ((x)->ilist_lock.unlock((x)->ilist_lock.cookie)) +#define MEM_LOCK(x) ((x)->mem_lock.lock((x)->mem_lock.cookie)) +#define MEM_UNLOCK(x) ((x)->mem_lock.unlock((x)->mem_lock.cookie)) +#else /*V7FS_LOCK */ +#define SUPERB_LOCK(x) ((void)0) +#define SUPERB_UNLOCK(x) ((void)0) +#define ILIST_LOCK(x) ((void)0) +#define ILIST_UNLOCK(x) ((void)0) +#define MEM_LOCK(x) ((void)0) +#define MEM_UNLOCK(x) ((void)0) +#endif /*V7FS_LOCK */ + +struct v7fs_stat { + int32_t total_blocks; + int32_t free_blocks; + int32_t total_inode; + int32_t free_inode; + int32_t total_files; +}; + +struct v7fs_fileattr { + int16_t uid; + int16_t gid; + v7fs_mode_t mode; + v7fs_dev_t device; + v7fs_time_t ctime; + v7fs_time_t mtime; + v7fs_time_t atime; +}; + +struct v7fs_self { +#define V7FS_SELF_NSCRATCH 3 + uint8_t scratch[V7FS_SELF_NSCRATCH][V7FS_BSIZE]; + int scratch_free; /* free block bitmap. */ + int scratch_remain; /* for statistic */ + struct block_io_ops io; +#ifdef V7FS_EI + struct endian_conversion_ops val; +#endif +#ifdef V7FS_LOCK + /* in-core superblock access. (freeblock/freeinode) split? -uch */ + struct lock_ops sb_lock; + struct lock_ops ilist_lock; /* disk ilist access. */ + struct lock_ops mem_lock; /* work memory allocation lock. */ +#endif + struct v7fs_superblock superblock; + struct v7fs_stat stat; + int endian; +}; + +struct v7fs_mount_device { + union { + void *vnode; /* NetBSD kernel */ + int fd; /* NetBSD newfs,fsck */ + const char *filename;/* misc test */ + } device; + daddr_t sectors; /*total size in sector. */ + int endian; +}; + +#define V7FS_ITERATOR_BREAK (-1) +#define V7FS_ITERATOR_END (-2) +#define V7FS_ITERATOR_ERROR (-3) +__BEGIN_DECLS +int v7fs_io_init(struct v7fs_self **, const struct v7fs_mount_device *, size_t); +void v7fs_io_fini(struct v7fs_self *); +void *scratch_read(struct v7fs_self *, daddr_t); +void scratch_free(struct v7fs_self *, void *); +int scratch_remain(const struct v7fs_self *); +__END_DECLS + +#if 0 +#define V7FS_IO_DEBUG +#define V7FS_SUPERBLOCK_DEBUG +#define V7FS_DATABLOCK_DEBUG +#define V7FS_INODE_DEBUG +#define V7FS_DIRENT_DEBUG +#define V7FS_FILE_DEBUG +#define V7FS_VFSOPS_DEBUG +#define V7FS_VNOPS_DEBUG +#endif + +#endif /*!_V7FS_IMPL_H_ */ diff --git a/sys/fs/v7fs/v7fs_inode.c b/sys/fs/v7fs/v7fs_inode.c new file mode 100644 index 000000000000..c4e0fdd8a43b --- /dev/null +++ b/sys/fs/v7fs/v7fs_inode.c @@ -0,0 +1,297 @@ +/* $NetBSD: v7fs_inode.c,v 1.1 2011/06/27 11:52:25 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_inode.c,v 1.1 2011/06/27 11:52:25 uch Exp $"); +#if defined _KERNEL_OPT +#include "opt_v7fs.h" +#endif + +#ifdef _KERNEL +#include +#include +#else +#include +#include +#include +#include +#endif + +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_endian.h" +#include "v7fs_inode.h" +#include "v7fs_superblock.h" + +#ifdef V7FS_INODE_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +static void v7fs_inode_setup_disk_image(const struct v7fs_self *, + struct v7fs_inode *, struct v7fs_inode_diskimage *); +static int v7fs_inode_inquire_disk_location(const struct v7fs_self *, + v7fs_ino_t, v7fs_daddr_t *, v7fs_daddr_t *); +#ifdef V7FS_INODE_DEBUG +static int v7fs_inode_block_sanity(const struct v7fs_superblock *, + v7fs_daddr_t); + +static int +v7fs_inode_block_sanity(const struct v7fs_superblock *sb, v7fs_daddr_t blk) +{ + + if ((blk < V7FS_ILIST_SECTOR) || (blk >= sb->datablock_start_sector)) { + DPRINTF("invalid inode block#%d (%d-%d)\n", blk, + V7FS_ILIST_SECTOR, sb->datablock_start_sector); + return ENOSPC; + } + + return 0; +} +#endif /* V7FS_INODE_DEBUG */ + +int +v7fs_inode_number_sanity(const struct v7fs_superblock *sb, v7fs_ino_t ino) +{ + + if (ino < V7FS_ROOT_INODE || ((size_t)ino >= V7FS_MAX_INODE(sb))) { + DPRINTF("invalid inode#%d (%d-%zu)\n", ino, + V7FS_ROOT_INODE, V7FS_MAX_INODE(sb)); + return ENOSPC; + } + + return 0; +} + +int +v7fs_inode_allocate(struct v7fs_self *fs, v7fs_ino_t *ino) +{ + struct v7fs_superblock *sb = &fs->superblock; + v7fs_ino_t inode_number; + int error = ENOSPC; + *ino = 0; + + SUPERB_LOCK(fs); + if (sb->total_freeinode == 0) { + DPRINTF("inode exhausted!(1)\n"); + goto errexit; + } + + /* If there is no free inode cache, update it. */ + if (sb->nfreeinode <= 0 && (error = v7fs_freeinode_update(fs))) { + DPRINTF("inode exhausted!(2)\n"); + goto errexit; + } + /* Get inode from superblock cache. */ + KDASSERT(sb->nfreeinode <= V7FS_MAX_FREEINODE); + inode_number = sb->freeinode[--sb->nfreeinode]; + sb->total_freeinode--; + sb->modified = 1; + + if ((error = v7fs_inode_number_sanity(sb, inode_number))) { + DPRINTF("new inode#%d %d %d\n", inode_number, sb->nfreeinode, + sb->total_freeinode); + DPRINTF("free inode list corupt\n"); + goto errexit; + } + *ino = inode_number; + +errexit: + SUPERB_UNLOCK(fs); + + return error; +} + +void +v7fs_inode_deallocate(struct v7fs_self *fs, v7fs_ino_t ino) +{ + struct v7fs_superblock *sb = &fs->superblock; + struct v7fs_inode inode; + + memset(&inode, 0, sizeof(inode)); + inode.inode_number = ino; + v7fs_inode_writeback(fs, &inode); + + SUPERB_LOCK(fs); + if (sb->nfreeinode < V7FS_MAX_FREEINODE) { + /* link to freeinode list. */ + sb->freeinode[sb->nfreeinode++] = ino; + } + /* If superblock inode cache is full, this inode charged by + v7fs_freeinode_update() later. */ + sb->total_freeinode++; + sb->modified = true; + SUPERB_UNLOCK(fs); +} + +void +v7fs_inode_setup_memory_image(const struct v7fs_self *fs __unused, + struct v7fs_inode *mem, struct v7fs_inode_diskimage *disk) +{ +#define conv16(m) (mem->m = V7FS_VAL16(fs, (disk->m))) +#define conv32(m) (mem->m = V7FS_VAL32(fs, (disk->m))) + uint32_t addr; + int i; + + memset(mem, 0, sizeof(*mem)); + conv16(mode); + conv16(nlink); + conv16(uid); + conv16(gid); + conv32(filesize); + conv32(atime); + conv32(mtime); + conv32(ctime); + + for (i = 0; i < V7FS_NADDR; i++) { + int j = i * 3; /* 3 byte each. (v7fs_daddr is 24bit) */ + /* expand to 4byte with endian conversion. */ + addr = V7FS_VAL24_READ(fs, &disk->addr[j]); + mem->addr[i] = addr; + } + mem->device = 0; + if (v7fs_inode_iscdev(mem) || v7fs_inode_isbdev(mem)) { + mem->device = mem->addr[0]; + } + +#undef conv16 +#undef conv32 +} + +static void +v7fs_inode_setup_disk_image(const struct v7fs_self *fs __unused, + struct v7fs_inode *mem, struct v7fs_inode_diskimage *disk) +{ +#define conv16(m) (disk->m = V7FS_VAL16(fs, (mem->m))) +#define conv32(m) (disk->m = V7FS_VAL32(fs, (mem->m))) + + conv16(mode); + conv16(nlink); + conv16(uid); + conv16(gid); + conv32(filesize); + conv32(atime); + conv32(mtime); + conv32(ctime); + + int i; + for (i = 0; i < V7FS_NADDR; i++) { + int j = i * 3; /* 3 byte each. */ + V7FS_VAL24_WRITE(fs, mem->addr[i], disk->addr + j); + } +#undef conv16 +#undef conv32 +} + +/* Load inode from disk. */ +int +v7fs_inode_load(struct v7fs_self *fs, struct v7fs_inode *p, v7fs_ino_t n) +{ + v7fs_daddr_t blk, ofs; + struct v7fs_inode_diskimage *di; + void *buf; + + if (v7fs_inode_inquire_disk_location(fs, n, &blk, &ofs) != 0) + return ENOENT; + + ILIST_LOCK(fs); + if (!(buf = scratch_read(fs, blk))) { + ILIST_UNLOCK(fs); + return EIO; + } + ILIST_UNLOCK(fs); + di = (struct v7fs_inode_diskimage *)buf; + + /* Decode disk address, convert endian. */ + v7fs_inode_setup_memory_image(fs, p, di + ofs); + p->inode_number = n; + + scratch_free(fs, buf); + + return 0; +} + +/* Write back inode to disk. */ +int +v7fs_inode_writeback(struct v7fs_self *fs, struct v7fs_inode *mem) +{ + struct v7fs_inode_diskimage disk; + v7fs_ino_t ino = mem->inode_number; + v7fs_daddr_t blk; + v7fs_daddr_t ofs; + void *buf; + int error = 0; + + if (v7fs_inode_inquire_disk_location(fs, ino, &blk, &ofs) != 0) + return ENOENT; + + v7fs_inode_setup_disk_image(fs, mem, &disk); + + ILIST_LOCK(fs); + if (!(buf = scratch_read(fs, blk))) { + ILIST_UNLOCK(fs); + return EIO; + } + struct v7fs_inode_diskimage *di = (struct v7fs_inode_diskimage *)buf; + di[ofs] = disk; /* structure copy; */ + if (!fs->io.write(fs->io.cookie, buf, blk)) + error = EIO; + ILIST_UNLOCK(fs); + + scratch_free(fs, buf); + + return error; +} + +static int +v7fs_inode_inquire_disk_location(const struct v7fs_self *fs + __unused, v7fs_ino_t n, v7fs_daddr_t *block, + v7fs_daddr_t *offset) +{ + v7fs_daddr_t ofs, blk; +#ifdef V7FS_INODE_DEBUG + v7fs_inode_number_sanity(&fs->superblock, n); +#endif + ofs = (n - 1/*inode start from 1*/) * + sizeof(struct v7fs_inode_diskimage); + blk = ofs >> V7FS_BSHIFT; + + *block = blk + V7FS_ILIST_SECTOR; + *offset = (ofs - blk * V7FS_BSIZE) / + sizeof(struct v7fs_inode_diskimage); +#ifdef V7FS_INODE_DEBUG + return v7fs_inode_block_sanity(&fs->superblock, *block); +#else + return 0; +#endif +} + diff --git a/sys/fs/v7fs/v7fs_inode.h b/sys/fs/v7fs/v7fs_inode.h new file mode 100644 index 000000000000..7dc42db5a401 --- /dev/null +++ b/sys/fs/v7fs/v7fs_inode.h @@ -0,0 +1,91 @@ +/* $NetBSD: v7fs_inode.h,v 1.1 2011/06/27 11:52:25 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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 _V7FS_INODE_H_ +#define _V7FS_INODE_H_ + +/* Software implementation of inode. (memory image) */ +struct v7fs_inode { + v7fs_ino_t inode_number; /* inode location */ + /* attr */ + uint16_t mode; + int16_t nlink; + int16_t uid; + int16_t gid; + v7fs_time_t atime; + v7fs_time_t mtime; + v7fs_time_t ctime; + /* open mode */ + bool append_mode; + + v7fs_dev_t device; /* for special file.(cdev, bdev) */ + /* payload. */ + v7fs_off_t filesize; /* size of file (byte) */ + v7fs_daddr_t addr[V7FS_NADDR]; /* data block address list */ +}; + +#define v7fs_inode_filesize(i) ((i)->filesize) +#define v7fs_inode_allocated(i) ((i)->mode) +#define v7fs_inode_nlink(i) ((i)->nlink) +/* V7 original */ +#define v7fs_inode_isdir(i) (((i)->mode & V7FS_IFMT) == V7FS_IFDIR) +#define v7fs_inode_isfile(i) (((i)->mode & V7FS_IFMT) == V7FS_IFREG) +#define v7fs_inode_iscdev(i) (((i)->mode & V7FS_IFMT) == V7FS_IFCHR) +#define v7fs_inode_isbdev(i) (((i)->mode & V7FS_IFMT) == V7FS_IFBLK) +/* 2BSD extension (implementation is different) */ +#define v7fs_inode_islnk(i) (((i)->mode & V7FS_IFMT) == V7FSBSD_IFLNK) +#define v7fs_inode_issock(i) (((i)->mode & V7FS_IFMT) == V7FSBSD_IFSOCK) +/* NetBSD Extension */ +#define v7fs_inode_isfifo(i) (((i)->mode & V7FS_IFMT) == V7FSBSD_IFFIFO) + +__BEGIN_DECLS +/* Free inode access ops. */ +int v7fs_inode_allocate(struct v7fs_self *, v7fs_ino_t *); +void v7fs_inode_deallocate(struct v7fs_self *, v7fs_ino_t); + +/* Disk I/O ops. */ +int v7fs_inode_load(struct v7fs_self *, struct v7fs_inode *, v7fs_ino_t); +int v7fs_inode_writeback(struct v7fs_self *, struct v7fs_inode *); +void v7fs_inode_setup_memory_image(const struct v7fs_self *, + struct v7fs_inode *, struct v7fs_inode_diskimage *); + +/* Check. */ +int v7fs_inode_number_sanity(const struct v7fs_superblock *, v7fs_ino_t); + +/* Util. */ +void v7fs_inode_chmod(struct v7fs_inode *, v7fs_mode_t); +void v7fs_inode_dump(const struct v7fs_inode *); + +/* Loop over all inode in ilist. */ +int v7fs_ilist_foreach(struct v7fs_self *, int (*)(struct v7fs_self *, void *, + struct v7fs_inode *, v7fs_ino_t), void *); +__END_DECLS +#endif /*!_V7FS_INODE_H_ */ diff --git a/sys/fs/v7fs/v7fs_inode_util.c b/sys/fs/v7fs/v7fs_inode_util.c new file mode 100644 index 000000000000..34b0aef48412 --- /dev/null +++ b/sys/fs/v7fs/v7fs_inode_util.c @@ -0,0 +1,124 @@ +/* $NetBSD: v7fs_inode_util.c,v 1.1 2011/06/27 11:52:25 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_inode_util.c,v 1.1 2011/06/27 11:52:25 uch Exp $"); +#if defined _KERNEL_OPT +#include "opt_v7fs.h" +#endif + +#ifdef _KERNEL +#include +#include +#else +#include +#include +#endif + +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_inode.h" + +#ifdef V7FS_INODE_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +void +v7fs_inode_chmod(struct v7fs_inode *inode, v7fs_mode_t mode) +{ +#define V7FS_MODE_MASK 0xfff + DPRINTF("setattr %08o -> %08o\n", inode->mode, mode); + + inode->mode &= ~V7FS_MODE_MASK; + inode->mode |= (mode & V7FS_MODE_MASK); + DPRINTF("setattr %08o -> %08o\n", inode->mode, mode); +} + +void +v7fs_inode_dump(const struct v7fs_inode *p) +{ + printf("nlink %d mode %06o %d/%d %d bytes\n", + p->nlink, p->mode, + p->uid, p->gid, p->filesize); + + printf("atime %d mtime %d ctime %d\n", + p->atime, p->mtime, p->ctime); +#ifndef _KERNEL + time_t at = p->atime; + time_t mt = p->mtime; + time_t ct = p->ctime; + printf(" atime %s mtime %s ctime %s", ctime(&at), ctime(&mt), + ctime(&ct)); +#endif + if (v7fs_inode_iscdev(p) || v7fs_inode_isbdev(p)) { + printf("device:%d/%d\n", (p->device >> 8), p->device & 0xff); + } + printf("\n"); +} + + +int +v7fs_ilist_foreach +(struct v7fs_self *fs, + int (*func)(struct v7fs_self *, void *, struct v7fs_inode *, v7fs_ino_t), + void *ctx) +{ + struct v7fs_superblock *sb = &fs->superblock; + size_t i, j, k; + int ret; + + /* Loop over ilist. */ + for (k = 1, i = V7FS_ILIST_SECTOR; i < sb->datablock_start_sector; + i++) { + struct v7fs_inode_diskimage *di; + struct v7fs_inode inode; + void *buf; + + if (!(buf = scratch_read(fs, i))) { + DPRINTF("block %zu I/O error.\n", i); + k += V7FS_INODE_PER_BLOCK; + continue; + } + di = (struct v7fs_inode_diskimage *)buf; + for (j = 0; j < V7FS_INODE_PER_BLOCK; j++, k++) { + v7fs_inode_setup_memory_image(fs, &inode, di + j); + inode.inode_number = k; + if ((ret = func(fs, ctx, &inode, k))) { + scratch_free(fs, buf); + return ret; + } + } + scratch_free(fs, buf); + } + return 0; +} diff --git a/sys/fs/v7fs/v7fs_io.c b/sys/fs/v7fs/v7fs_io.c new file mode 100644 index 000000000000..beb6d179496a --- /dev/null +++ b/sys/fs/v7fs/v7fs_io.c @@ -0,0 +1,136 @@ +/* $NetBSD: v7fs_io.c,v 1.1 2011/06/27 11:52:25 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_io.c,v 1.1 2011/06/27 11:52:25 uch Exp $"); +#if defined _KERNEL_OPT +#include "opt_v7fs.h" +#endif + +#ifdef _KERNEL +#include +#else +#include +#include +#include +#endif + +#include "v7fs.h" +#include "v7fs_impl.h" + +#if defined _KERNEL +#define STATIC_BUFFER +#endif + +#ifdef V7FS_IO_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +void * +scratch_read(struct v7fs_self *fs, daddr_t blk) +{ +#ifdef STATIC_BUFFER + int i; + MEM_LOCK(fs); + for (i = 0; i < V7FS_SELF_NSCRATCH; i++) { + if (fs->scratch_free & (1 << i)) { + fs->scratch_free &= ~(1 << i); + break; + } + } + if (i == V7FS_SELF_NSCRATCH) { + DPRINTF("No scratch area. increase V7FS_SELF_NSCRATCH\n"); + assert(0); + MEM_UNLOCK(fs); + return NULL; + } + + if (!fs->io.read(fs->io.cookie, fs->scratch[i], blk)) { + DPRINTF("*** I/O error block %ld\n", (long)blk); + fs->scratch_free |= (1 << i); + MEM_UNLOCK(fs); + return NULL; + } + MEM_UNLOCK(fs); + /* Statistic */ + int n; + if ((n = scratch_remain(fs)) < fs->scratch_remain) + fs->scratch_remain = n; + + return fs->scratch[i]; +#else + uint8_t *buf = malloc(V7FS_BSIZE); + if (!fs->io.read(fs->io.cookie, buf, blk)) { + DPRINTF("*** I/O error block %ld\n",(long)blk); + return NULL; + } + return buf; +#endif +} + +int +scratch_remain(const struct v7fs_self *fs) +{ +#ifdef STATIC_BUFFER + int nfree; + int i; + MEM_LOCK(fs); + for (i = 0, nfree = 0; i < V7FS_SELF_NSCRATCH; i++) { + if (fs->scratch_free & (1 << i)) { + nfree++; + } + } + MEM_UNLOCK(fs); + return nfree; +#else + return -1; +#endif +} + +void +scratch_free(struct v7fs_self *fs __unused, void *p) +{ +#ifdef STATIC_BUFFER + int i; + MEM_LOCK(fs); + for (i = 0; i < V7FS_SELF_NSCRATCH; i++) + if (fs->scratch[i] == p) { + fs->scratch_free |= (1 << i); + break; + } + MEM_UNLOCK(fs); + assert(i != V7FS_SELF_NSCRATCH); +#else + free(p); +#endif +} diff --git a/sys/fs/v7fs/v7fs_io_kern.c b/sys/fs/v7fs/v7fs_io_kern.c new file mode 100644 index 000000000000..6a2ba9df514f --- /dev/null +++ b/sys/fs/v7fs/v7fs_io_kern.c @@ -0,0 +1,250 @@ +/* $NetBSD: v7fs_io_kern.c,v 1.1 2011/06/27 11:52:25 uch Exp $ */ + +/*- + * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_io_kern.c,v 1.1 2011/06/27 11:52:25 uch Exp $"); +#if defined _KERNEL_OPT +#include "opt_v7fs.h" +#endif +#include + +__KERNEL_RCSID(0, "$NetBSD: v7fs_io_kern.c,v 1.1 2011/06/27 11:52:25 uch Exp $"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "v7fs_endian.h" +#include "v7fs_impl.h" + +#ifdef V7FS_IO_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +struct local_io { + struct vnode *vp; + kauth_cred_t cred; +}; + +static bool v7fs_os_read_n(void *, uint8_t *, daddr_t, int); +static bool v7fs_os_read(void *, uint8_t *, daddr_t); +static bool v7fs_os_write_n(void *, uint8_t *, daddr_t, int); +static bool v7fs_os_write(void *, uint8_t *, daddr_t); +static void v7fs_os_lock(void *); +static void v7fs_os_unlock(void *); +static bool lock_init(struct lock_ops *); + +MALLOC_JUSTDEFINE(M_V7FS, "v7fs core", "v7fs internal structures"); + +int +v7fs_io_init(struct v7fs_self **fs, + const struct v7fs_mount_device *mount_device, size_t block_size) +{ + struct vnode *vp = mount_device->device.vnode; + struct v7fs_self *p; + struct local_io *local; + int error = 0; + + /* Allocate myself */ + if (!(p = (struct v7fs_self *)malloc(sizeof(*p), M_TEMP, M_WAITOK | + M_ZERO))) + return ENOMEM; + memset(p, 0, sizeof(*p)); + + p->scratch_free = -1; + p->scratch_remain = V7FS_SELF_NSCRATCH; + + /* Endian */ + p->endian = mount_device->endian; +#ifdef V7FS_EI + v7fs_endian_init(p); +#endif + /* IO */ + if (!(local = (struct local_io *)malloc(sizeof(*local), M_TEMP, + M_WAITOK | M_ZERO))) { + error = ENOMEM; + goto errexit; + } + p->io.read = v7fs_os_read; + p->io.read_n = v7fs_os_read_n; + p->io.write = v7fs_os_write; + p->io.write_n = v7fs_os_write_n; + p->scratch_free = -1; /* free all scratch buffer */ + + p->io.cookie = local; + local->vp = vp; + local->cred = NOCRED; /* upper layer check cred. */ + + /*LOCK */ + error = ENOMEM; + if (!lock_init(&p->sb_lock)) + goto errexit; + if (!lock_init(&p->ilist_lock)) + goto errexit; + if (!lock_init(&p->mem_lock)) + goto errexit; + error = 0; + + *fs = p; + return 0; + +errexit: + if (p->io.cookie) + free(p->io.cookie, M_TEMP); + if (p->sb_lock.cookie) + free(p->sb_lock.cookie, M_TEMP); + if (p->ilist_lock.cookie) + free(p->ilist_lock.cookie, M_TEMP); + if (p->mem_lock.cookie) + free(p->mem_lock.cookie, M_TEMP); + free(p, M_TEMP); + + return error; +} + +static bool +lock_init(struct lock_ops *ops) +{ + if (!(ops->cookie = (kmutex_t *)malloc(sizeof(kmutex_t), M_TEMP, + M_WAITOK | M_ZERO))) { + return false; + } + mutex_init(ops->cookie, MUTEX_DEFAULT, IPL_NONE); + ops->lock = v7fs_os_lock; + ops->unlock = v7fs_os_unlock; + + return true; +} + +void +v7fs_io_fini(struct v7fs_self *fs) +{ + mutex_destroy(fs->sb_lock.cookie); + mutex_destroy(fs->ilist_lock.cookie); + mutex_destroy(fs->mem_lock.cookie); + + free(fs->io.cookie, M_TEMP); + free(fs->sb_lock.cookie, M_TEMP); + free(fs->ilist_lock.cookie, M_TEMP); + free(fs, M_TEMP); +} + +static bool +v7fs_os_read_n(void *self, uint8_t *buf, daddr_t block, int count) +{ + int i; + + for (i = 0; i < count; i++) { + if (!v7fs_os_read(self, buf, block)) + return false; + buf += DEV_BSIZE; + block++; + } + + return true; +} + +static bool +v7fs_os_read(void *self, uint8_t *buf, daddr_t block) +{ + struct local_io *bio = (struct local_io *)self; + struct buf *bp = NULL; + + if (bread(bio->vp, block, DEV_BSIZE, bio->cred, 0, &bp) != 0) + goto error_exit; + memcpy(buf, bp->b_data, DEV_BSIZE); + brelse(bp, 0); + + return true; +error_exit: + DPRINTF("block %ld read failed.\n", (long)block); + + if (bp != NULL) + brelse(bp, 0); + return false; +} + +static bool +v7fs_os_write_n(void *self, uint8_t *buf, daddr_t block, int count) +{ + int i; + + for (i = 0; i < count; i++) { + if (!v7fs_os_write(self, buf, block)) + return false; + buf += DEV_BSIZE; + block++; + } + + return true; +} + +static bool +v7fs_os_write(void *self, uint8_t *buf, daddr_t block) +{ + struct local_io *bio = (struct local_io *)self; + struct buf *bp; + + if ((bp = getblk(bio->vp, block, DEV_BSIZE, 0, 0)) == 0) { + DPRINTF("getblk failed. block=%ld\n", (long)block); + return false; + } + + memcpy(bp->b_data, buf, DEV_BSIZE); + + if (bwrite(bp) != 0) { + DPRINTF("bwrite failed. block=%ld\n", (long)block); + return false; + } + + return true; +} + +static void +v7fs_os_lock(void *self) +{ + + mutex_enter((kmutex_t *)self); +} + +static void +v7fs_os_unlock(void *self) +{ + + mutex_exit((kmutex_t *)self); +} diff --git a/sys/fs/v7fs/v7fs_io_user.c b/sys/fs/v7fs/v7fs_io_user.c new file mode 100644 index 000000000000..761f4ab8e630 --- /dev/null +++ b/sys/fs/v7fs/v7fs_io_user.c @@ -0,0 +1,169 @@ +/* $NetBSD: v7fs_io_user.c,v 1.1 2011/06/27 11:52:25 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: v7fs_io_user.c,v 1.1 2011/06/27 11:52:25 uch Exp $"); +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include "v7fs.h" +#include "v7fs_endian.h" +#include "v7fs_impl.h" + +#ifdef V7FS_IO_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +struct local_io { + int fd; + size_t size; + size_t blksz; + uint8_t *addr; +} local; + +static bool read_sector(void *, uint8_t *, daddr_t); +static bool write_sector(void *, uint8_t *, daddr_t); +static bool read_mmap(void *, uint8_t *, daddr_t); +static bool write_mmap(void *, uint8_t *, daddr_t); + +int +v7fs_io_init(struct v7fs_self **fs, const struct v7fs_mount_device *mount, + size_t block_size) +{ + struct v7fs_self *p; + + if (!(p = (struct v7fs_self *)malloc(sizeof(*p)))) + return ENOMEM; + memset(p, 0, sizeof(*p)); + + /* Endian */ + p->endian = mount->endian; +#ifdef V7FS_EI + v7fs_endian_init(p); +#endif + local.blksz = block_size; + local.fd = mount->device.fd; + local.size = mount->sectors * block_size; + local.addr = mmap(NULL, local.size, PROT_READ | PROT_WRITE | PROT_NONE, + MAP_FILE | MAP_SHARED/*writeback*/, local.fd, 0); + if (local.addr == MAP_FAILED) { + warn("mmap failed. use direct I/O."); + local.addr = 0; + p->io.read = read_sector; + p->io.write = write_sector; + } else { + DPRINTF("mmaped addr=%p\n", local.addr); + p->io.read = read_mmap; + p->io.write = write_mmap; + } + + p->io.cookie = &local; + *fs = p; + + return 0; +} + +void +v7fs_io_fini(struct v7fs_self *fs) +{ + struct local_io *lio = (struct local_io *)fs->io.cookie; + + if (lio->addr) { + if (munmap(lio->addr, lio->size) != 0) + warn(0); + } + fsync(lio->fd); + + free(fs); +} + +static bool +read_sector(void *ctx, uint8_t *buf, daddr_t sector) +{ + struct local_io *lio = (struct local_io *)ctx; + size_t blksz = lio->blksz; + int fd = lio->fd; + + if ((lseek(fd, sector * blksz, SEEK_SET) < 0) || + (read(fd, buf, blksz) < (ssize_t)blksz)) { + warn("sector=%ld\n", (long)sector); + return false; + } + + return true; +} + +static bool +write_sector(void *ctx, uint8_t *buf, daddr_t sector) +{ + struct local_io *lio = (struct local_io *)ctx; + size_t blksz = lio->blksz; + int fd = lio->fd; + + if ((lseek(fd, sector * blksz, SEEK_SET) < 0) || + (write(fd, buf, blksz) < (ssize_t)blksz)) { + warn("sector=%ld\n", (long)sector); + return false; + } + + return true; +} + +static bool +read_mmap(void *ctx, uint8_t *buf, daddr_t sector) +{ + struct local_io *lio = (struct local_io *)ctx; + size_t blksz = lio->blksz; + + memcpy(buf, lio->addr + sector * blksz, blksz); + + return true; +} + +static bool +write_mmap(void *ctx, uint8_t *buf, daddr_t sector) +{ + struct local_io *lio = (struct local_io *)ctx; + size_t blksz = lio->blksz; + + memcpy(lio->addr + sector * blksz, buf, blksz); + + return true; +} diff --git a/sys/fs/v7fs/v7fs_superblock.c b/sys/fs/v7fs/v7fs_superblock.c new file mode 100644 index 000000000000..150fac1c90b4 --- /dev/null +++ b/sys/fs/v7fs/v7fs_superblock.c @@ -0,0 +1,259 @@ +/* $NetBSD: v7fs_superblock.c,v 1.1 2011/06/27 11:52:25 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_superblock.c,v 1.1 2011/06/27 11:52:25 uch Exp $"); +#if defined _KERNEL_OPT +#include "opt_v7fs.h" +#endif + +#ifdef _KERNEL +#include +#include /* errno */ +#else +#include +#include +#include +#endif + +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_endian.h" +#include "v7fs_superblock.h" +#include "v7fs_inode.h" +#include "v7fs_datablock.h" + +#ifdef V7FS_SUPERBLOCK_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) +#define DPRINTF_(fmt, args...) printf(fmt, ##args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#define DPRINTF_(fmt, args...) ((void)0) +#endif + +static void v7fs_superblock_endian_convert(struct v7fs_self *, + struct v7fs_superblock *, struct v7fs_superblock *); +static int v7fs_superblock_sanity(struct v7fs_self *); + +/* Load superblock from disk. */ +int +v7fs_superblock_load(struct v7fs_self *fs) +{ + struct v7fs_superblock *disksb; + void *buf; + int error; + + if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR))) + return EIO; + disksb = (struct v7fs_superblock *)buf; + v7fs_superblock_endian_convert(fs, &fs->superblock, disksb); + scratch_free(fs, buf); + + if ((error = v7fs_superblock_sanity(fs))) + return error; + + return 0; +} + +/* Writeback superblock to disk. */ +int +v7fs_superblock_writeback(struct v7fs_self *fs) +{ + struct v7fs_superblock *memsb = &fs->superblock; + struct v7fs_superblock *disksb; + void *buf; + int error = 0; + + if (!memsb->modified) + return 0; + + if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR))) + return EIO; + disksb = (struct v7fs_superblock *)buf; + v7fs_superblock_endian_convert(fs, disksb, memsb); + if (!fs->io.write(fs->io.cookie, buf, V7FS_SUPERBLOCK_SECTOR)) + error = EIO; + scratch_free(fs, buf); + + memsb->modified = 0; + DPRINTF("done. %d\n", error); + + return error; +} + +/* Check endian mismatch. */ +static int +v7fs_superblock_sanity(struct v7fs_self *fs) +{ + const struct v7fs_superblock *sb = &fs->superblock; + void *buf = 0; + + if ((sb->volume_size < 128) || /* smaller than 64KB. */ + (sb->datablock_start_sector > sb->volume_size) || + (sb->nfreeinode > V7FS_MAX_FREEINODE) || + (sb->nfreeblock > V7FS_MAX_FREEBLOCK) || + (sb->update_time < 0) || + (sb->total_freeblock > sb->volume_size) || + ((sb->nfreeinode == 0) && (sb->nfreeblock == 0) && + (sb->total_freeblock == 0) && (sb->total_freeinode == 0)) || + (!(buf = scratch_read(fs, sb->volume_size - 1)))) { + DPRINTF("invalid super block.\n"); + return EINVAL; + } + if (buf) + scratch_free(fs, buf); + + return 0; +} + +/* Fill free block to superblock cache. */ +int +v7fs_freeblock_update(struct v7fs_self *fs, v7fs_daddr_t blk) +{ + /* Assume superblock is locked by caller. */ + struct v7fs_superblock *sb = &fs->superblock; + struct v7fs_freeblock *fb; + void *buf; + int error; + + /* Read next freeblock table from disk. */ + if (!datablock_number_sanity(fs, blk) || !(buf = scratch_read(fs, blk))) + return EIO; + + /* Update in-core superblock freelist. */ + fb = (struct v7fs_freeblock *)buf; + if ((error = v7fs_freeblock_endian_convert(fs, fb))) { + scratch_free(fs, buf); + return error; + } + DPRINTF("freeblock table#%d, nfree=%d\n", blk, fb->nfreeblock); + + memcpy(sb->freeblock, fb->freeblock, sizeof(blk) * fb->nfreeblock); + sb->nfreeblock = fb->nfreeblock; + sb->modified = true; + scratch_free(fs, buf); + + return 0; +} + +int +v7fs_freeblock_endian_convert(struct v7fs_self *fs __unused, + struct v7fs_freeblock *fb __unused) +{ +#ifdef V7FS_EI + int i; + int16_t nfree; + + nfree = V7FS_VAL16(fs, fb->nfreeblock); + if (nfree <= 0 || nfree > V7FS_MAX_FREEBLOCK) { + DPRINTF("invalid freeblock list. %d (max=%d)\n", nfree, + V7FS_MAX_FREEBLOCK); + return ENOSPC; + } + fb->nfreeblock = nfree; + + for (i = 0; i < nfree; i++) { + fb->freeblock[i] = V7FS_VAL32(fs, fb->freeblock[i]); + } +#endif /* V7FS_EI */ + + return 0; +} + +/* Fill free inode to superblock cache. */ +int +v7fs_freeinode_update(struct v7fs_self *fs) +{ + /* Assume superblock is locked by caller. */ + struct v7fs_superblock *sb = &fs->superblock; + v7fs_ino_t *freeinode = sb->freeinode; + size_t i, j, k; + v7fs_ino_t ino; + + /* Loop over all inode list. */ + for (i = V7FS_ILIST_SECTOR, ino = 1/* inode start from 1*/, k = 0; + i < sb->datablock_start_sector; i++) { + struct v7fs_inode_diskimage *di; + void *buf; + if (!(buf = scratch_read(fs, i))) { + DPRINTF("block %zu I/O error.\n", i); + ino += V7FS_INODE_PER_BLOCK; + continue; + } + di = (struct v7fs_inode_diskimage *)buf; + + for (j = 0; + (j < V7FS_INODE_PER_BLOCK) && (k < V7FS_MAX_FREEINODE); + j++, di++, ino++) { + if (v7fs_inode_allocated(di)) + continue; + DPRINTF("free inode%d\n", ino); + freeinode[k++] = ino; + } + scratch_free(fs, buf); + } + sb->nfreeinode = k; + + return 0; +} + +static void +v7fs_superblock_endian_convert(struct v7fs_self *fs __unused, + struct v7fs_superblock *to, struct v7fs_superblock *from) +{ +#ifdef V7FS_EI +#define conv16(m) (to->m = V7FS_VAL16(fs, from->m)) +#define conv32(m) (to->m = V7FS_VAL32(fs, from->m)) + int i; + + conv16(datablock_start_sector); + conv32(volume_size); + conv16(nfreeblock); + v7fs_daddr_t *dfrom = from->freeblock; + v7fs_daddr_t *dto = to->freeblock; + for (i = 0; i < V7FS_MAX_FREEBLOCK; i++, dfrom++, dto++) + *dto = V7FS_VAL32(fs, *dfrom); + + conv16(nfreeinode); + v7fs_ino_t *ifrom = from->freeinode; + v7fs_ino_t *ito = to->freeinode; + for (i = 0; i < V7FS_MAX_FREEINODE; i++, ifrom++, ito++) + *ito = V7FS_VAL16(fs, *ifrom); + + conv32(update_time); + conv32(total_freeblock); + conv16(total_freeinode); +#undef conv16 +#undef conv32 +#else /* V7FS_EI */ + memcpy(to, from , sizeof(*to)); +#endif /* V7FS_EI */ +} diff --git a/sys/fs/v7fs/v7fs_superblock.h b/sys/fs/v7fs/v7fs_superblock.h new file mode 100644 index 000000000000..b58716ceee13 --- /dev/null +++ b/sys/fs/v7fs/v7fs_superblock.h @@ -0,0 +1,48 @@ +/* $NetBSD: v7fs_superblock.h,v 1.1 2011/06/27 11:52:25 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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 _V7FS_SUPERBLOCK_H_ +#define _V7FS_SUPERBLOCK_H_ +struct v7fs_self; + +__BEGIN_DECLS +/* core */ +int v7fs_superblock_load(struct v7fs_self *); +int v7fs_superblock_writeback(struct v7fs_self *); +int v7fs_freeblock_update(struct v7fs_self *, v7fs_daddr_t); +int v7fs_freeblock_endian_convert(struct v7fs_self *, struct v7fs_freeblock *); +int v7fs_freeinode_update(struct v7fs_self *); + +/* util. */ +void v7fs_superblock_status(struct v7fs_self *); +void v7fs_superblock_dump(const struct v7fs_self *); +__END_DECLS +#endif /*!_V7FS_SUPERBLOCK_H_ */ diff --git a/sys/fs/v7fs/v7fs_superblock_util.c b/sys/fs/v7fs/v7fs_superblock_util.c new file mode 100644 index 000000000000..6c40e1a9ef5a --- /dev/null +++ b/sys/fs/v7fs/v7fs_superblock_util.c @@ -0,0 +1,97 @@ +/* $NetBSD: v7fs_superblock_util.c,v 1.1 2011/06/27 11:52:25 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_superblock_util.c,v 1.1 2011/06/27 11:52:25 uch Exp $"); +#if defined _KERNEL_OPT +#include "opt_v7fs.h" +#endif + +#ifdef _KERNEL +#include +#include /* errno */ +#else +#include +#include +#endif + +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_superblock.h" +#include "v7fs_inode.h" + +#ifdef V7FS_SUPERBLOCK_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) +#define DPRINTF_(fmt, args...) printf(fmt, ##args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#define DPRINTF_(fmt, args...) ((void)0) +#endif + +void +v7fs_superblock_status(struct v7fs_self *fs) +{ + struct v7fs_superblock *sb = &fs->superblock; + struct v7fs_stat *stat = &fs->stat; + + stat->total_blocks = sb->volume_size - sb->datablock_start_sector; + stat->total_inode = V7FS_MAX_INODE(sb); + stat->free_inode = sb->total_freeinode; + stat->free_blocks = sb->total_freeblock; + stat->total_files = stat->total_inode - sb->total_freeinode - 1; + + DPRINTF("block %d/%d, inode %d/%d\n", stat->free_blocks, + stat->total_blocks, stat->free_inode, stat->total_inode); +} + +void +v7fs_superblock_dump(const struct v7fs_self *fs) +{ + const struct v7fs_superblock *sb = &fs->superblock; + +#define print(x) printf("%s: %d\n", #x, sb->x) + print(datablock_start_sector); + print(volume_size); + print(nfreeblock); + print(nfreeinode); + print(update_time); + print(lock_freeblock); + print(lock_freeinode); + print(modified); + print(readonly); +#if !defined _KERNEL + time_t t = sb->update_time; + printf("%s", ctime(&t)); +#endif + print(total_freeblock); + print(total_freeinode); +#undef print +} diff --git a/sys/fs/v7fs/v7fs_vfsops.c b/sys/fs/v7fs/v7fs_vfsops.c new file mode 100644 index 000000000000..9d846f73bd85 --- /dev/null +++ b/sys/fs/v7fs/v7fs_vfsops.c @@ -0,0 +1,602 @@ +/* $NetBSD: v7fs_vfsops.c,v 1.1 2011/06/27 11:52:25 uch Exp $ */ + +/*- + * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_vfsops.c,v 1.1 2011/06/27 11:52:25 uch Exp $"); +#if defined _KERNEL_OPT +#include "opt_v7fs.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* v-node */ +#include +#include +/* devsw */ +#include + +#include "v7fs_extern.h" +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_inode.h" +#include "v7fs_superblock.h" + +#ifdef V7FS_VFSOPS_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) +#else +#define DPRINTF(arg...) ((void)0) +#endif + +MALLOC_JUSTDEFINE(M_V7FS_VFS, "v7fs vfs", "v7fs vfs structures"); + +struct pool v7fs_node_pool; + +static int v7fs_mountfs(struct vnode *, struct mount *, int); +static int v7fs_openfs(struct vnode *, struct mount *, struct lwp *); +static void v7fs_closefs(struct vnode *, struct mount *); +static bool is_v7fs_partition(struct vnode *); +static enum vtype v7fs_mode_to_vtype(v7fs_mode_t mode); + +int +v7fs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) +{ + struct lwp *l = curlwp; + struct v7fs_args *args = data; + struct v7fs_mount *v7fsmount = (void *)mp->mnt_data; + struct vnode *devvp = NULL; + int error; + bool update = mp->mnt_flag & MNT_UPDATE; + + DPRINTF("mnt_flag=%x %s\n", mp->mnt_flag, update ? "update" : ""); + + if (*data_len < sizeof(*args)) + return EINVAL; + + if (mp->mnt_flag & MNT_GETARGS) { + if (!v7fsmount) + return EIO; + args->fspec = NULL; + args->endian = v7fsmount->core->endian; + *data_len = sizeof(*args); + return 0; + } + + DPRINTF("args->fspec=%s endian=%d\n", args->fspec, args->endian); + if (args->fspec == NULL) { + /* nothing to do. */ + return EINVAL; + } + + if (args->fspec != NULL) { + /* Look up the name and verify that it's sane. */ + error = namei_simple_user(args->fspec, + NSM_FOLLOW_NOEMULROOT, &devvp); + if (error != 0) + return (error); + DPRINTF("mount device=%lx\n", (long)devvp->v_rdev); + + if (!update) { + /* + * Be sure this is a valid block device + */ + if (devvp->v_type != VBLK) + error = ENOTBLK; + else if (bdevsw_lookup(devvp->v_rdev) == NULL) + error = ENXIO; + } else { + KDASSERT(v7fsmount); + /* + * Be sure we're still naming the same device + * used for our initial mount + */ + if (devvp != v7fsmount->devvp) { + DPRINTF("devvp %p != %p rootvp=%p\n", devvp, + v7fsmount->devvp, rootvp); + if (rootvp == v7fsmount->devvp) { + vrele(devvp); + devvp = rootvp; + vref(devvp); + } else { + error = EINVAL; + } + } + } + } + + /* + * If mount by non-root, then verify that user has necessary + * permissions on the device. + * + * Permission to update a mount is checked higher, so here we presume + * updating the mount is okay (for example, as far as securelevel goes) + * which leaves us with the normal check. + */ + if (error == 0) { + int accessmode = VREAD; + if (update ? + (mp->mnt_iflag & IMNT_WANTRDWR) != 0 : + (mp->mnt_flag & MNT_RDONLY) == 0) + accessmode |= VWRITE; + error = genfs_can_mount(devvp, accessmode, l->l_cred); + } + + if (error) { + vrele(devvp); + return error; + } + + if (!update) { + if ((error = v7fs_openfs(devvp, mp, l))) { + vrele(devvp); + return error; + } + + if ((error = v7fs_mountfs(devvp, mp, args->endian))) { + v7fs_closefs(devvp, mp); + VOP_UNLOCK(devvp); + vrele(devvp); + return error; + } + VOP_UNLOCK(devvp); + } else if (mp->mnt_flag & MNT_RDONLY) { + /* XXX: r/w -> read only */ + } + + return set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE, + mp->mnt_op->vfs_name, mp, l); +} + +static bool +is_v7fs_partition(struct vnode *devvp) +{ + struct partinfo dpart; + int error; + + if ((error = VOP_IOCTL(devvp, DIOCGPART, &dpart, FREAD, NOCRED)) != 0) { + DPRINTF("VOP_IOCTL=%d\n", error); + return false; + } + DPRINTF("fstype=%d dtype=%d bsize=%d\n", dpart.part->p_fstype, + dpart.disklab->d_type, dpart.disklab->d_secsize); + + return dpart.part->p_fstype == FS_V7; +} + +static int +v7fs_openfs(struct vnode *devvp, struct mount *mp, struct lwp *l) +{ + kauth_cred_t cred = l->l_cred; + int oflags; + int error; + + /* Flush buffer */ + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); + if ((error = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0))) + goto unlock_exit; + + /* Open block device */ + oflags = FREAD; + if ((mp->mnt_flag & MNT_RDONLY) == 0) + oflags |= FWRITE; + + if ((error = VOP_OPEN(devvp, oflags, NOCRED)) != 0) { + DPRINTF("VOP_OPEN=%d\n", error); + goto unlock_exit; + } + + /* Get partition information */ + if (!is_v7fs_partition(devvp)) + goto close_exit; + + return 0; /* lock held */ + +close_exit: + VOP_CLOSE(devvp, oflags, NOCRED); +unlock_exit: + VOP_UNLOCK(devvp); + + return error; +} + +static void +v7fs_closefs(struct vnode *devvp, struct mount *mp) +{ + int oflags = FREAD; + + if ((mp->mnt_flag & MNT_RDONLY) == 0) + oflags |= FWRITE; + + VOP_CLOSE(devvp, oflags, NOCRED); +} + +static int +v7fs_mountfs(struct vnode *devvp, struct mount *mp, int endian) +{ + struct v7fs_mount *v7fsmount; + int error; + struct v7fs_mount_device mount; + + DPRINTF("%d\n",endian); + + v7fsmount = malloc(sizeof(*v7fsmount), M_V7FS_VFS, M_WAITOK); + if (v7fsmount == NULL) { + return ENOMEM; + } + v7fsmount->devvp = devvp; + v7fsmount->mountp = mp; + + mount.device.vnode = devvp; + mount.endian = endian; + + if ((error = v7fs_io_init(&v7fsmount->core, &mount, V7FS_BSIZE))) { + goto err_exit; + } + struct v7fs_self *fs = v7fsmount->core; + + if ((error = v7fs_superblock_load(fs))) { + v7fs_io_fini(fs); + goto err_exit; + } + + LIST_INIT(&v7fsmount->v7fs_node_head); + + mp->mnt_data = v7fsmount; + mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)devvp->v_rdev; + mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_V7FS); + mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; + mp->mnt_stat.f_namemax = V7FS_NAME_MAX; + mp->mnt_flag |= MNT_LOCAL; + mp->mnt_dev_bshift = V7FS_BSHIFT; + mp->mnt_fs_bshift = V7FS_BSHIFT; + + return 0; + +err_exit: + free(v7fsmount, M_V7FS_VFS); + return error; +} + +int +v7fs_start(struct mount *mp, int flags) +{ + + DPRINTF("\n"); + /* Nothing to do. */ + return 0; +} + +int +v7fs_unmount(struct mount *mp, int mntflags) +{ + struct v7fs_mount *v7fsmount = (void *)mp->mnt_data; + int error; + + DPRINTF("%p\n", v7fsmount); + + if ((error = vflush(mp, NULLVP, + mntflags & MNT_FORCE ? FORCECLOSE : 0)) != 0) + return error; + + vn_lock(v7fsmount->devvp, LK_EXCLUSIVE | LK_RETRY); + error = VOP_CLOSE(v7fsmount->devvp, FREAD, NOCRED); + vput(v7fsmount->devvp); + + v7fs_io_fini(v7fsmount->core); + + free(v7fsmount, M_V7FS_VFS); + mp->mnt_data = NULL; + mp->mnt_flag &= ~MNT_LOCAL; + + return 0; +} + +int +v7fs_root(struct mount *mp, struct vnode **vpp) +{ + struct vnode *vp; + int error; + + DPRINTF("\n"); + if ((error = VFS_VGET(mp, V7FS_ROOT_INODE, &vp)) != 0) { + DPRINTF("error=%d\n", error); + return error; + } + *vpp = vp; + DPRINTF("done.\n"); + + return 0; +} + +int +v7fs_statvfs(struct mount *mp, struct statvfs *f) +{ + struct v7fs_mount *v7fsmount = mp->mnt_data; + struct v7fs_self *fs = v7fsmount->core; + + DPRINTF("scratch remain=%d\n", fs->scratch_remain); + + v7fs_superblock_status(fs); + + f->f_bsize = V7FS_BSIZE; + f->f_frsize = V7FS_BSIZE; + f->f_iosize = V7FS_BSIZE; + f->f_blocks = fs->stat.total_blocks; + f->f_bfree = fs->stat.free_blocks; + f->f_bavail = fs->stat.free_blocks; + f->f_bresvd = 0; + f->f_files = fs->stat.total_files; + f->f_ffree = fs->stat.free_inode; + f->f_favail = f->f_ffree; + f->f_fresvd = 0; + copy_statvfs_info(f, mp); + + return 0; +} + +int +v7fs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) +{ + struct v7fs_mount *v7fsmount = mp->mnt_data; + struct v7fs_self *fs = v7fsmount->core; + struct v7fs_node *v7fs_node; + struct v7fs_inode *inode; + struct vnode *v; + int err, error; + int retry_cnt; + + DPRINTF("\n"); + + v7fs_superblock_writeback(fs); + for (retry_cnt = 0; retry_cnt < 2; retry_cnt++) { + error = 0; + + mutex_enter(&mntvnode_lock); + for (v7fs_node = LIST_FIRST(&v7fsmount->v7fs_node_head); + v7fs_node != NULL; v7fs_node = LIST_NEXT(v7fs_node, link)) { + inode = &v7fs_node->inode; + if (!v7fs_inode_allocated(inode)) { + continue; + } + v = v7fs_node->vnode; + mutex_enter(v->v_interlock); + mutex_exit(&mntvnode_lock); + err = vget(v, LK_EXCLUSIVE | LK_NOWAIT); + if (err == 0) { + err = VOP_FSYNC(v, cred, FSYNC_WAIT, 0, 0); + vput(v); + } + if (err != 0) + error = err; + mutex_enter(&mntvnode_lock); + } + mutex_exit(&mntvnode_lock); + + if (error == 0) + break; + } + + return error; +} + +static enum vtype +v7fs_mode_to_vtype (v7fs_mode_t mode) +{ + enum vtype table[] = { VCHR, VDIR, VBLK, VREG, VLNK, VSOCK }; + + if ((mode & V7FS_IFMT) == V7FSBSD_IFFIFO) + return VFIFO; + + return table[((mode >> 13) & 7) - 1]; +} + +int +v7fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) +{ + struct v7fs_mount *v7fsmount = mp->mnt_data; + struct v7fs_self *fs = v7fsmount->core; + struct vnode *vp; + struct v7fs_node *v7fs_node; + struct v7fs_inode inode; + int error; + + /* Lookup requested i-node */ + if ((error = v7fs_inode_load(fs, &inode, ino))) { + DPRINTF("v7fs_inode_load failed.\n"); + return error; + } + +retry: + mutex_enter(&mntvnode_lock); + for (v7fs_node = LIST_FIRST(&v7fsmount->v7fs_node_head); + v7fs_node != NULL; v7fs_node = LIST_NEXT(v7fs_node, link)) { + if (v7fs_node->inode.inode_number == ino) { + vp = v7fs_node->vnode; + mutex_enter(vp->v_interlock); + mutex_exit(&mntvnode_lock); + if (vget(vp, LK_EXCLUSIVE) == 0) { + *vpp = vp; + return 0; + } else { + DPRINTF("retry!\n"); + goto retry; + } + } + } + mutex_exit(&mntvnode_lock); + + /* Allocate v-node. */ + if ((error = getnewvnode(VT_V7FS, mp, v7fs_vnodeop_p, NULL, &vp))) { + DPRINTF("getnewvnode error.\n"); + return error; + } + /* Lock vnode here */ + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + + /* Allocate i-node */ + vp->v_data = pool_get(&v7fs_node_pool, PR_WAITOK); + memset(vp->v_data, 0, sizeof(*v7fs_node)); + v7fs_node = vp->v_data; + mutex_enter(&mntvnode_lock); + LIST_INSERT_HEAD(&v7fsmount->v7fs_node_head, v7fs_node, link); + mutex_exit(&mntvnode_lock); + v7fs_node->vnode = vp; + v7fs_node->v7fsmount = v7fsmount; + v7fs_node->inode = inode;/*structure copy */ + v7fs_node->lockf = NULL; /* advlock */ + + genfs_node_init(vp, &v7fs_genfsops); + uvm_vnp_setsize(vp, v7fs_inode_filesize(&inode)); + + if (ino == V7FS_ROOT_INODE) { + vp->v_type = VDIR; + vp->v_vflag |= VV_ROOT; + } else { + vp->v_type = v7fs_mode_to_vtype(inode.mode); + + if (vp->v_type == VBLK || vp->v_type == VCHR) { + dev_t rdev = inode.device; + vp->v_op = v7fs_specop_p; + spec_node_init(vp, rdev); + } else if (vp->v_type == VFIFO) { + vp->v_op = v7fs_fifoop_p; + } + } + + *vpp = vp; + + return 0; +} + + +int +v7fs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp) +{ + + DPRINTF("\n"); + /* notyet */ + return EOPNOTSUPP; +} + +int +v7fs_vptofh(struct vnode *vpp, struct fid *fid, size_t *fh_size) +{ + + DPRINTF("\n"); + /* notyet */ + return EOPNOTSUPP; +} + +MALLOC_DECLARE(M_V7FS); +MALLOC_DECLARE(M_V7FS_VNODE); + +void +v7fs_init(void) +{ + + DPRINTF("\n"); + malloc_type_attach(M_V7FS_VFS); + malloc_type_attach(M_V7FS); + malloc_type_attach(M_V7FS_VNODE); + pool_init(&v7fs_node_pool, sizeof(struct v7fs_node), 0, 0, 0, + "v7fs_node_pool", &pool_allocator_nointr, IPL_NONE); +} + +void +v7fs_reinit(void) +{ + + /* Nothing to do. */ + DPRINTF("\n"); +} + +void +v7fs_done(void) +{ + + DPRINTF("\n"); + pool_destroy(&v7fs_node_pool); + malloc_type_detach(M_V7FS); + malloc_type_detach(M_V7FS_VFS); + malloc_type_detach(M_V7FS_VNODE); +} + +int +v7fs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags, + kauth_cred_t cred) +{ + + DPRINTF("\n"); + return 0; +} + +int +v7fs_mountroot(void) +{ + struct mount *mp; + int error; + + DPRINTF(""); + /* On mountroot, devvp (rootdev) is opened by vfs_mountroot */ + if (!is_v7fs_partition (rootvp)) + return EINVAL; + + if ((error = vfs_rootmountalloc(MOUNT_V7FS, "root_device", &mp))) { + DPRINTF("mountalloc error=%d\n", error); + vrele(rootvp); + return error; + } + + if ((error = v7fs_mountfs(rootvp, mp, _BYTE_ORDER))) { + DPRINTF("mountfs error=%d\n", error); + vfs_unbusy(mp, false, NULL); + vfs_destroy(mp); + return error; + } + + mutex_enter(&mountlist_lock); + CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); + mutex_exit(&mountlist_lock); + + vfs_unbusy(mp, false, NULL); + + return 0; +} diff --git a/sys/fs/v7fs/v7fs_vnops.c b/sys/fs/v7fs/v7fs_vnops.c new file mode 100644 index 000000000000..e844bc22b934 --- /dev/null +++ b/sys/fs/v7fs/v7fs_vnops.c @@ -0,0 +1,1281 @@ +/* $NetBSD: v7fs_vnops.c,v 1.1 2011/06/27 11:52:25 uch Exp $ */ + +/*- + * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: v7fs_vnops.c,v 1.1 2011/06/27 11:52:25 uch Exp $"); +#if defined _KERNEL_OPT +#include "opt_v7fs.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /*APPEND */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef V7FS_VNOPS_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) +#else +#define DPRINTF(arg...) ((void)0) +#endif + +MALLOC_JUSTDEFINE(M_V7FS_VNODE, "v7fs vnode", "v7fs vnode structures"); +MALLOC_DECLARE(M_V7FS); + +static v7fs_mode_t vtype_to_v7fs_mode(enum vtype); +static uint8_t v7fs_mode_to_d_type(v7fs_mode_t); + +static v7fs_mode_t +vtype_to_v7fs_mode(enum vtype type) +{ + /* Convert Vnode types to V7FS types (sys/vnode.h)*/ + v7fs_mode_t table[] = { 0, V7FS_IFREG, V7FS_IFDIR, V7FS_IFBLK, + V7FS_IFCHR, V7FSBSD_IFLNK, V7FSBSD_IFSOCK, + V7FSBSD_IFFIFO }; + return table[type]; +} + +static uint8_t +v7fs_mode_to_d_type(v7fs_mode_t mode) +{ + /* Convert V7FS types to dirent d_type (sys/dirent.h)*/ + + return (mode & V7FS_IFMT) >> 12; +} + +int +v7fs_lookup(void *v) +{ + struct vop_lookup_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + } */ *a = v; + struct vnode *dvp = a->a_dvp; + struct v7fs_node *parent_node = dvp->v_data; + struct v7fs_inode *parent = &parent_node->inode; + struct v7fs_self *fs = parent_node->v7fsmount->core;/* my filesystem */ + struct vnode *vpp; + struct componentname *cnp = a->a_cnp; + int nameiop = cnp->cn_nameiop; + const char *name = cnp->cn_nameptr; + int namelen = cnp->cn_namelen; + int flags = cnp->cn_flags; + bool isdotdot = flags & ISDOTDOT; + bool islastcn = flags & ISLASTCN; + v7fs_ino_t ino; + int error; + + DPRINTF("%s op=%d flags=%d parent=%d %o %dbyte\n", name, + nameiop, cnp->cn_flags, parent->inode_number, parent->mode, + parent->filesize); + + *a->a_vpp = 0; + + /* Check directory permission for search */ + if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred))) { + DPRINTF("***perm.\n"); + return error; + } + + /* Deny last component write operation on a read-only mount */ + if (islastcn && (dvp->v_mount->mnt_flag & MNT_RDONLY) && + (nameiop == DELETE || nameiop == RENAME)) { + DPRINTF("***ROFS.\n"); + return EROFS; + } + + /* "." */ + if (namelen == 1 && name[0] == '.') { + vref(dvp); /* v_usecount++ */ + *a->a_vpp = dvp; + DPRINTF("done.(.)\n"); + return 0; + } + + /* ".." and reguler file. */ + if ((error = v7fs_file_lookup_by_name(fs, parent, name, &ino))) { + /* Not found. Tell this entry be able to allocate. */ + if (((nameiop == CREATE) || (nameiop == RENAME)) && islastcn) { + /* Check directory permission to allocate. */ + if ((error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred))) { + DPRINTF("access denied. (%s)\n", name); + return error; + } + DPRINTF("EJUSTRETURN op=%d (%s)\n", nameiop, name); + return EJUSTRETURN; + } + DPRINTF("lastcn=%d\n", flags & ISLASTCN); + return error; + } + + /* Entry found. Allocate v-node */ + // Check permissions? + vpp = 0; + if (isdotdot) { + VOP_UNLOCK(dvp); /* preserve reference count. (not vput) */ + } + DPRINTF("enter vget\n"); + if ((error = v7fs_vget(dvp->v_mount, ino, &vpp))) { + DPRINTF("***can't get vnode.\n"); + return error; + } + DPRINTF("exit vget\n"); + if (isdotdot) { + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + } + *a->a_vpp = vpp; + DPRINTF("done.\n"); + + return 0; +} + +int +v7fs_create(void *v) +{ + struct vop_create_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + } */ *a = v; + struct v7fs_node *parent_node = a->a_dvp->v_data; + struct v7fs_mount *v7fsmount = parent_node->v7fsmount; + struct v7fs_self *fs = v7fsmount->core; + struct mount *mp = v7fsmount->mountp; + struct v7fs_fileattr attr; + struct vattr *va = a->a_vap; + kauth_cred_t cr = a->a_cnp->cn_cred; + v7fs_ino_t ino; + int error = 0; + + DPRINTF("%s parent#%d\n", a->a_cnp->cn_nameptr, + parent_node->inode.inode_number); + KDASSERT((va->va_type == VREG) || (va->va_type == VSOCK)); + + memset(&attr, 0, sizeof(attr)); + attr.uid = kauth_cred_geteuid(cr); + attr.gid = kauth_cred_getegid(cr); + attr.mode = va->va_mode | vtype_to_v7fs_mode (va->va_type); + attr.device = 0; + + /* Allocate disk entry. and register its entry to parent directory. */ + if ((error = v7fs_file_allocate(fs, &parent_node->inode, + a->a_cnp->cn_nameptr, &attr, &ino))) { + DPRINTF("v7fs_file_allocate failed.\n"); + goto unlock_exit; + } + /* Sync dirent size change. */ + uvm_vnp_setsize(a->a_dvp, v7fs_inode_filesize(&parent_node->inode)); + + /* Get myself vnode. */ + *a->a_vpp = 0; + if ((error = v7fs_vget(mp, ino, a->a_vpp))) { + DPRINTF("v7fs_vget failed.\n"); + goto unlock_exit; + } + + /* Scheduling update time. real update by v7fs_update */ + struct v7fs_node *newnode = (*a->a_vpp)->v_data; + newnode->update_ctime = true; + newnode->update_mtime = true; + newnode->update_atime = true; + DPRINTF("allocated %s->#%d\n", a->a_cnp->cn_nameptr, ino); + +unlock_exit: + /* unlock parent directory */ + vput(a->a_dvp); /* locked at v7fs_lookup(); */ + + return error; +} + +int +v7fs_mknod(void *v) +{ + struct vop_mknod_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + } */ *a = v; + struct componentname *cnp = a->a_cnp; + kauth_cred_t cr = cnp->cn_cred; + struct vnode *dvp = a->a_dvp; + struct vattr *va = a->a_vap; + struct v7fs_node *parent_node = dvp->v_data; + struct v7fs_mount *v7fsmount = parent_node->v7fsmount; + struct v7fs_self *fs = v7fsmount->core; + struct mount *mp = v7fsmount->mountp; + struct v7fs_fileattr attr; + + v7fs_ino_t ino; + int error = 0; + + DPRINTF("%s %06o %lx %d\n", cnp->cn_nameptr, va->va_mode, + (long)va->va_rdev, va->va_type); + memset(&attr, 0, sizeof(attr)); + attr.uid = kauth_cred_geteuid(cr); + attr.gid = kauth_cred_getegid(cr); + attr.mode = va->va_mode | vtype_to_v7fs_mode(va->va_type); + attr.device = va->va_rdev; + + if ((error = v7fs_file_allocate(fs, &parent_node->inode, + cnp->cn_nameptr, &attr, &ino))) + goto unlock_exit; + /* Sync dirent size change. */ + uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); + + if ((error = v7fs_vget(mp, ino, a->a_vpp))) { + DPRINTF("can't get vnode.\n"); + goto unlock_exit; + } + struct v7fs_node *newnode = (*a->a_vpp)->v_data; + newnode->update_ctime = true; + newnode->update_mtime = true; + newnode->update_atime = true; + +unlock_exit: + vput(dvp); + + return error; +} + +int +v7fs_open(void *v) +{ + struct vop_open_args /* { + struct vnode *a_vp; + int a_mode; + kauth_cred_t a_cred; + } */ *a = v; + + struct vnode *vp = a->a_vp; + struct v7fs_node *v7node = vp->v_data; + struct v7fs_inode *inode = &v7node->inode; + + DPRINTF("inode %d\n", inode->inode_number); + /* Append mode file pointer is managed by kernel. */ + if (inode->append_mode && + ((a->a_mode & (FWRITE | O_APPEND)) == FWRITE)) { + DPRINTF("file is already opened by append mode.\n"); + return EPERM; + } + + return 0; +} + +int +v7fs_close(void *v) +{ + struct vop_close_args /* { + struct vnodeop_desc *a_desc; + struct vnode *a_vp; + int a_fflag; + kauth_cred_t a_cred; + } */ *a = v; + struct vnode *vp = a->a_vp; +#ifdef V7FS_VNOPS_DEBUG + struct v7fs_node *v7node = vp->v_data; + struct v7fs_inode *inode = &v7node->inode; +#endif + DPRINTF("#%d (i)%dbyte (v)%zubyte\n", inode->inode_number, + v7fs_inode_filesize(inode), vp->v_size); + + /* Update timestamp */ + v7fs_update(vp, 0, 0, UPDATE_WAIT); + + return 0; +} + +static int +v7fs_check_possible(struct vnode *vp, struct v7fs_node *v7node, + mode_t mode) +{ + + if (!(mode & VWRITE)) + return 0; + + switch (vp->v_type) { + default: + /* special file is always writable. */ + return 0; + case VDIR: + case VLNK: + case VREG: + break; + } + + return vp->v_mount->mnt_flag & MNT_RDONLY ? EROFS : 0; +} + +static int +v7fs_check_permitted(struct vnode *vp, struct v7fs_node *v7node, + mode_t mode, kauth_cred_t cred) +{ + + struct v7fs_inode *inode = &v7node->inode; + + return genfs_can_access(vp->v_type, inode->mode, inode->uid, inode->gid, + mode, cred); +} + +int +v7fs_access(void *v) +{ + struct vop_access_args /* { + struct vnode *a_vp; + int a_mode; + kauth_cred_t a_cred; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct v7fs_node *v7node = vp->v_data; + int error; + + error = v7fs_check_possible(vp, v7node, ap->a_mode); + if (error) + return error; + + error = v7fs_check_permitted(vp, v7node, ap->a_mode, ap->a_cred); + + return error; +} + +int +v7fs_getattr(void *v) +{ + struct vop_getattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + kauth_cred_t a_cred; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct v7fs_node *v7node = vp->v_data; + struct v7fs_inode *inode = &v7node->inode; + struct v7fs_mount *v7fsmount = v7node->v7fsmount; + struct vattr *vap = ap->a_vap; + + DPRINTF("\n"); + vap->va_type = vp->v_type; + vap->va_mode = inode->mode; + vap->va_nlink = inode->nlink; + vap->va_uid = inode->uid; + vap->va_gid = inode->gid; + vap->va_fsid = v7fsmount->devvp->v_rdev; + vap->va_fileid = inode->inode_number; + vap->va_size = vp->v_size; + vap->va_atime.tv_sec = inode->atime; + vap->va_mtime.tv_sec = inode->mtime; + vap->va_ctime.tv_sec = inode->ctime; + vap->va_birthtime.tv_sec = 0; + vap->va_gen = 1; + vap->va_flags = 0; + vap->va_rdev = inode->device; + vap->va_bytes = vap->va_size; /* No sparse support. */ + vap->va_filerev = 0; + vap->va_vaflags = 0; + /* PAGE_SIZE is larger than sizeof(struct dirent). OK. + getcwd_scandir()@vfs_getcwd.c */ + vap->va_blocksize = PAGE_SIZE; + + return 0; +} + +int +v7fs_setattr(void *v) +{ + struct vop_setattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + kauth_cred_t a_cred; + struct proc *p; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct vattr *vap = ap->a_vap; + struct v7fs_node *v7node = vp->v_data; + struct v7fs_self *fs = v7node->v7fsmount->core; + struct v7fs_inode *inode = &v7node->inode; + int error = 0; + + DPRINTF("\n"); + + if (vp->v_mount->mnt_flag & MNT_RDONLY) { + switch (vp->v_type) { + default: + /* special file is always writable. */ + break; + case VDIR: + case VLNK: + case VREG: + DPRINTF("read-only mount\n"); + return EROFS; + } + } + + if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || + (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || + (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || + ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { + DPRINTF("invalid request\n"); + return EINVAL; + } + /* File pointer mode. */ + if ((vap->va_flags != VNOVAL) && (vap->va_flags & SF_APPEND)) { + DPRINTF("Set append-mode.\n"); + inode->append_mode = true; + } + + /* File size change. */ + if ((vap->va_size != VNOVAL) && (vp->v_type == VREG)) { + error = v7fs_datablock_size_change(fs, vap->va_size, inode); + if (error == 0) + uvm_vnp_setsize(vp, vap->va_size); + } + + if (vap->va_uid != (uid_t)VNOVAL) + inode->uid = vap->va_uid; + if (vap->va_gid != (uid_t)VNOVAL) + inode->gid = vap->va_gid; + if (vap->va_mode != (mode_t)VNOVAL) + v7fs_inode_chmod(inode, vap->va_mode); + if (vap->va_atime.tv_sec != VNOVAL) + inode->atime = vap->va_atime.tv_sec; + if (vap->va_mtime.tv_sec != VNOVAL) + inode->mtime = vap->va_mtime.tv_sec; + if (vap->va_ctime.tv_sec != VNOVAL) + inode->ctime = vap->va_ctime.tv_sec; + + v7fs_update(vp, 0, 0, 0); + + return error; +} + +int +v7fs_read(void *v) +{ + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + kauth_cred_t a_cred; + } */ *a = v; + struct vnode *vp = a->a_vp; + struct uio *uio = a->a_uio; + struct v7fs_node *v7node = vp->v_data; + struct v7fs_inode *inode = &v7node->inode; + vsize_t sz, filesz = v7fs_inode_filesize(inode); + const int advice = IO_ADV_DECODE(a->a_ioflag); + int error = 0; + + DPRINTF("type=%d inode=%d\n", vp->v_type, v7node->inode.inode_number); + + while (uio->uio_resid > 0) { + if ((sz = MIN(filesz - uio->uio_offset, uio->uio_resid)) == 0) + break; + + error = ubc_uiomove(&vp->v_uobj, uio, sz, advice, UBC_READ | + UBC_PARTIALOK | UBC_UNMAP_FLAG(v)); + if (error) { + break; + } + DPRINTF("read %zubyte\n", sz); + } + v7node->update_atime = true; + + return error; +} + +int +v7fs_write(void *v) +{ + struct vop_write_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + kauth_cred_t a_cred; + } */ *a = v; + struct vnode *vp = a->a_vp; + struct uio *uio = a->a_uio; + int advice = IO_ADV_DECODE(a->a_ioflag); + struct v7fs_node *v7node = vp->v_data; + struct v7fs_inode *inode = &v7node->inode; + struct v7fs_self *fs = v7node->v7fsmount->core; + vsize_t sz; + int error = 0; + + if (uio->uio_resid == 0) + return 0; + + sz = v7fs_inode_filesize(inode); + DPRINTF("(i)%ld (v)%zu ofs=%zu + res=%zu = %zu\n", sz, vp->v_size, + uio->uio_offset, uio->uio_resid, uio->uio_offset + uio->uio_resid); + + /* Append mode file offset is managed by kernel. */ + if (a->a_ioflag & IO_APPEND) + uio->uio_offset = sz; + + /* If write region is over filesize, expand. */ + size_t newsize= uio->uio_offset + uio->uio_resid; + ssize_t expand = newsize - sz; + if (expand > 0) { + if ((error = v7fs_datablock_expand(fs, inode, expand))) + return error; + uvm_vnp_setsize(vp, newsize); + } + + while (uio->uio_resid > 0) { + sz = uio->uio_resid; + if ((error = ubc_uiomove(&vp->v_uobj, uio, sz, advice, + UBC_WRITE | UBC_UNMAP_FLAG(v)))) + break; + DPRINTF("write %zubyte\n", sz); + } + v7node->update_mtime = true; + + return error; +} + +int +v7fs_fsync(void *v) +{ + struct vop_fsync_args /* { + struct vnode *a_vp; + kauth_cred_t a_cred; + int a_flags; + off_t offlo; + off_t offhi; + } */ *a = v; + struct vnode *vp = a->a_vp; + int error, wait; + + DPRINTF("%p\n", a->a_vp); + if (a->a_flags & FSYNC_CACHE) { + return EOPNOTSUPP; + } + + wait = (a->a_flags & FSYNC_WAIT); + error = vflushbuf(vp, wait); + + if (error == 0 && (a->a_flags & FSYNC_DATAONLY) == 0) + error = v7fs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0); + + return error; +} + +int +v7fs_remove(void *v) +{ + struct vop_remove_args /* { + struct vnodeop_desc *a_desc; + struct vnode * a_dvp; + struct vnode * a_vp; + struct componentname * a_cnp; + } */ *a = v; + struct v7fs_node *parent_node = a->a_dvp->v_data; + struct v7fs_mount *v7fsmount = parent_node->v7fsmount; + struct vnode *vp = a->a_vp; + struct v7fs_inode *inode = &((struct v7fs_node *)vp->v_data)->inode; + struct vnode *dvp = a->a_dvp; + struct v7fs_self *fs = v7fsmount->core; + bool remove; + int error = 0; + + DPRINTF("delete %s\n", a->a_cnp->cn_nameptr); + + if (vp->v_type == VDIR) { + error = EPERM; + goto out; + } + + remove = v7fs_inode_nlink(inode) == 1; + if (remove) + uvm_vnp_setsize(vp, 0); + + if ((error = v7fs_file_deallocate(fs, &parent_node->inode, + a->a_cnp->cn_nameptr))) { + DPRINTF("v7fs_file_delete failed.\n"); + goto out; + } + /* Sync dirent size change. */ + uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); + /* This inode is no longer used. -> v7fs_inactive */ + if (remove) + memset(inode, 0, sizeof(*inode)); + +out: + if (dvp == vp) + vrele(vp); /* v_usecount-- of unlocked vp */ + else + vput(vp); /* unlock vp and then v_usecount-- */ + vput(dvp); + + return error; +} + +int +v7fs_link(void *v) +{ + struct vop_link_args /* { + struct vnode *a_dvp; + struct vnode *a_vp; + struct componentname *a_cnp; + } */ *a = v; + struct vnode *dvp = a->a_dvp; + struct vnode *vp = a->a_vp; + struct v7fs_node *parent_node = dvp->v_data; + struct v7fs_node *node = vp->v_data; + struct v7fs_inode *parent = &parent_node->inode; + struct v7fs_inode *p = &node->inode; + struct v7fs_self *fs = node->v7fsmount->core; + struct componentname *cnp = a->a_cnp; + int error = 0; + + DPRINTF("%p\n", vp); + /* Lock soruce file */ + if ((error = vn_lock(vp, LK_EXCLUSIVE))) { + DPRINTF("lock failed. %p\n", vp); + VOP_ABORTOP(dvp, cnp); + goto unlock; + } + error = v7fs_file_link(fs, parent, p, cnp->cn_nameptr); + /* Sync dirent size change. */ + uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); + + VOP_UNLOCK(vp); +unlock: + vput(dvp); + + return error; +} + +int +v7fs_rename(void *v) +{ + struct vop_rename_args /* { + struct vnode *a_fdvp; from parent-directory + struct vnode *a_fvp; from file + struct componentname *a_fcnp; + struct vnode *a_tdvp; to parent-directory + struct vnode *a_tvp; to file + struct componentname *a_tcnp; + } */ *a = v; + struct vnode *fvp = a->a_fvp; + struct vnode *tvp = a->a_tvp; + struct vnode *fdvp = a->a_fdvp; + struct vnode *tdvp = a->a_tdvp; + struct v7fs_node *parent_from = fdvp->v_data; + struct v7fs_node *parent_to = tdvp->v_data; + struct v7fs_node *v7node = fvp->v_data; + struct v7fs_self *fs = v7node->v7fsmount->core; + const char *from_name = a->a_fcnp->cn_nameptr; + const char *to_name = a->a_tcnp->cn_nameptr; + int error; + + DPRINTF("%s->%s\n", from_name, to_name); + /* tvp may be NULL. allocated here. */ + if ((fvp->v_mount != tdvp->v_mount) || + (tvp && (fvp->v_mount != tvp->v_mount))) { + error = EXDEV; + DPRINTF("cross-device link\n"); + goto out; + } + // XXXsource file lock? + error = v7fs_file_rename(fs, &parent_from->inode, from_name, + &parent_to->inode, to_name); + /* Sync dirent size change. */ + uvm_vnp_setsize(tdvp, v7fs_inode_filesize(&parent_to->inode)); + uvm_vnp_setsize(fdvp, v7fs_inode_filesize(&parent_from->inode)); +out: + if (tvp) + vput(tvp); /* locked on entry */ + if (tdvp == tvp) + vrele(tdvp); + else + vput(tdvp); + vrele(fdvp); + vrele(fvp); + + return error; +} + +int +v7fs_mkdir(void *v) +{ + struct vop_mkdir_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + } */ *a = v; + struct componentname *cnp = a->a_cnp; + kauth_cred_t cr = cnp->cn_cred; + struct vnode *dvp = a->a_dvp; + struct vattr *va = a->a_vap; + struct v7fs_node *parent_node = dvp->v_data; + struct v7fs_mount *v7fsmount = parent_node->v7fsmount; + struct v7fs_self *fs = v7fsmount->core; + struct v7fs_fileattr attr; + struct mount *mp = v7fsmount->mountp; + v7fs_ino_t ino; + int error = 0; + + DPRINTF("\n"); + memset(&attr, 0, sizeof(attr)); + attr.uid = kauth_cred_geteuid(cr); + attr.gid = kauth_cred_getegid(cr); + attr.mode = va->va_mode | vtype_to_v7fs_mode(va->va_type); + + if ((error = v7fs_file_allocate(fs, &parent_node->inode, + cnp->cn_nameptr, &attr, &ino))) + goto unlock_exit; + /* Sync dirent size change. */ + uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); + + if ((error = v7fs_vget(mp, ino, a->a_vpp))) { + DPRINTF("can't get vnode.\n"); + } + struct v7fs_node *newnode = (*a->a_vpp)->v_data; + newnode->update_ctime = true; + newnode->update_mtime = true; + newnode->update_atime = true; + +unlock_exit: + vput(dvp); + + return error; +} + +int +v7fs_rmdir(void *v) +{ + struct vop_rmdir_args /* { + struct vnode *a_dvp; + struct vnode *a_vp; + struct componentname *a_cnp; + } */ *a = v; + struct vnode *vp = a->a_vp; + struct vnode *dvp = a->a_dvp; + struct v7fs_node *parent_node = dvp->v_data; + struct v7fs_mount *v7fsmount = parent_node->v7fsmount; + struct v7fs_inode *inode = &((struct v7fs_node *)vp->v_data)->inode; + struct v7fs_self *fs = v7fsmount->core; + int error = 0; + + DPRINTF("delete %s\n", a->a_cnp->cn_nameptr); + + KDASSERT(vp->v_type == VDIR); + + if ((error = v7fs_file_deallocate(fs, &parent_node->inode, + a->a_cnp->cn_nameptr))) { + DPRINTF("v7fs_directory_deallocate failed.\n"); + goto out; + } + uvm_vnp_setsize(vp, 0); + /* Sync dirent size change. */ + uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); + /* This inode is no longer used. -> v7fs_inactive */ + memset(inode, 0, sizeof(*inode)); +out: + vput(vp); + vput(dvp); + + return error; +} + +struct v7fs_readdir_arg { + struct dirent *dp; + struct uio *uio; + int start; + int end; + int cnt; +}; +static int readdir_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t); + +int +readdir_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz) +{ + struct v7fs_readdir_arg *p = (struct v7fs_readdir_arg *)ctx; + struct v7fs_dirent *dir; + struct dirent *dp = p->dp; + struct v7fs_inode inode; + char filename[V7FS_NAME_MAX + 1]; + int i, n; + int error = 0; + void *buf; + + if (!(buf = scratch_read(fs, blk))) + return EIO; + dir = (struct v7fs_dirent *)buf; + + n = sz / sizeof(*dir); + + for (i = 0; (i < n) && (p->cnt < p->end); i++, dir++, p->cnt++) { + if (p->cnt < p->start) + continue; + + if ((error = v7fs_inode_load(fs, &inode, dir->inode_number))) + break; + + v7fs_dirent_filename(filename, dir->name); + + DPRINTF("inode=%d name=%s %s\n", dir->inode_number, filename, + v7fs_inode_isdir(&inode) ? "DIR" : "FILE"); + memset(dp, 0, sizeof(*dp)); + dp->d_fileno = dir->inode_number; + dp->d_type = v7fs_mode_to_d_type(inode.mode); + dp->d_namlen = strlen(filename); + strcpy(dp->d_name, filename); + dp->d_reclen = sizeof(*dp); + if ((error = uiomove(dp, dp->d_reclen, p->uio))) { + DPRINTF("uiomove failed.\n"); + break; + } + } + scratch_free(fs, buf); + + return error; +} + +int +v7fs_readdir(void *v) +{ + struct vop_readdir_args /* { + struct vnode *a_vp; + struct uio *a_uio; + kauth_cred_t a_cred; + int *a_eofflag; + off_t **a_cookies; + int *a_ncookies; + } */ *a = v; + struct uio *uio = a->a_uio; + struct vnode *vp = a->a_vp; + struct v7fs_node *v7node = vp->v_data; + struct v7fs_inode *inode = &v7node->inode; + struct v7fs_self *fs = v7node->v7fsmount->core; + struct dirent *dp; + int error; + + DPRINTF("offset=%zu residue=%zu\n", uio->uio_offset, uio->uio_resid); + + KDASSERT(vp->v_type == VDIR); + KDASSERT(uio->uio_offset >= 0); + KDASSERT(v7fs_inode_isdir(inode)); + + struct v7fs_readdir_arg arg; + arg.start = uio->uio_offset / sizeof(*dp); + arg.end = arg.start + uio->uio_resid / sizeof(*dp); + if (arg.start == arg.end) {/* user buffer has not enuf space. */ + DPRINTF("uio buffer too small\n"); + return ENOMEM; + } + dp = malloc(sizeof(*dp), M_V7FS, M_WAITOK | M_ZERO); + arg.cnt = 0; + arg.dp = dp; + arg.uio = uio; + + *a->a_eofflag = false; + error = v7fs_datablock_foreach(fs, inode, readdir_subr, &arg); + if (error == V7FS_ITERATOR_END) { + *a->a_eofflag = true; + } + if (error < 0) + error = 0; + + free(dp, M_V7FS); + + return error; +} + +int +v7fs_inactive(void *v) +{ + struct vop_inactive_args /* { + struct vnode *a_vp; + bool *a_recycle; + } */ *a = v; + struct vnode *vp = a->a_vp; + struct v7fs_node *v7node = vp->v_data; + struct v7fs_inode *inode = &v7node->inode; + + DPRINTF("%p\n", vp); + + if (v7fs_inode_allocated(inode)) { + v7fs_update(vp, 0, 0, UPDATE_WAIT); + } + + *a->a_recycle = true; + + VOP_UNLOCK(vp); + + return 0; +} + +int +v7fs_reclaim(void *v) +{ + /*This vnode is no longer referenced by kernel. */ + extern struct pool v7fs_node_pool; + struct vop_reclaim_args /* { + struct vnode *a_vp; + } */ *a = v; + struct vnode *vp = a->a_vp; + struct v7fs_node *v7node = vp->v_data; + + DPRINTF("%p\n", vp); + mutex_enter(&mntvnode_lock); + LIST_REMOVE(v7node, link); + mutex_exit(&mntvnode_lock); + genfs_node_destroy(vp); + pool_put(&v7fs_node_pool, v7node); + vp->v_data = NULL; + + return 0; +} + +int +v7fs_bmap(void *v) +{ + struct vop_bmap_args /* { + struct vnode *a_vp; + daddr_t a_bn; + struct vnode **a_vpp; + daddr_t *a_bnp; + int *a_runp; + } */ *a = v; + struct vnode *vp = a->a_vp; + struct v7fs_node *v7node = vp->v_data; + struct v7fs_mount *v7fsmount = v7node->v7fsmount; + struct v7fs_self *fs = v7node->v7fsmount->core; + struct v7fs_inode *inode = &v7node->inode; + int error = 0; + + DPRINTF("inode=%d offset=%zu %p\n", inode->inode_number, a->a_bn, vp); + DPRINTF("filesize: %d\n", inode->filesize); + if (!a->a_bnp) + return 0; + + v7fs_daddr_t blk; + if (!(blk = v7fs_datablock_last(fs, inode, + (a->a_bn + 1) << V7FS_BSHIFT))) { + /* +1 converts block # to file offset. */ + return ENOSPC; + } + + *a->a_bnp = blk; + + if (a->a_vpp) + *a->a_vpp = v7fsmount->devvp; + if (a->a_runp) + *a->a_runp = 0; /*XXX TODO */ + + DPRINTF("%d %zu->%zu status=%d\n", inode->inode_number, a->a_bn, + *a->a_bnp, error); + + return error; +} + +int +v7fs_strategy(void *v) +{ + struct vop_strategy_args /* { + struct vnode *a_vp; + struct buf *a_bp; + } */ *a = v; + struct buf *b = a->a_bp; + struct vnode *vp = a->a_vp; + struct v7fs_node *v7node = vp->v_data; + struct v7fs_mount *v7fsmount = v7node->v7fsmount; + int error; + + DPRINTF("%p\n", vp); + KDASSERT(vp->v_type == VREG); + if (b->b_blkno == b->b_lblkno) { + error = VOP_BMAP(vp, b->b_lblkno, NULL, &b->b_blkno, NULL); + if (error) { + b->b_error = error; + biodone(b); + return error; + } + if ((long)b->b_blkno == -1) + clrbuf(b); + } + if ((long)b->b_blkno == -1) { + biodone(b); + return 0; + } + + return VOP_STRATEGY(v7fsmount->devvp, b); +} + +int +v7fs_print(void *v) +{ + struct vop_print_args /* { + struct vnode *a_vp; + } */ *a = v; + struct v7fs_node *v7node = a->a_vp->v_data; + + v7fs_inode_dump(&v7node->inode); + + return 0; +} + +int +v7fs_advlock(void *v) +{ + struct vop_advlock_args /* { + struct vnode *a_vp; + void *a_id; + int a_op; + struct flock *a_fl; + int a_flags; + } */ *a = v; + struct v7fs_node *v7node = a->a_vp->v_data; + + DPRINTF("op=%d\n", a->a_op); + + return lf_advlock(a, &v7node->lockf, + v7fs_inode_filesize(&v7node->inode)); +} + +int +v7fs_pathconf(void *v) +{ + struct vop_pathconf_args /* { + struct vnode *a_vp; + int a_name; + register_t *a_retval; + } */ *a = v; + int err = 0; + + DPRINTF("%p\n", a->a_vp); + + switch (a->a_name) { + case _PC_LINK_MAX: + *a->a_retval = V7FS_LINK_MAX; + break; + case _PC_NAME_MAX: + *a->a_retval = V7FS_NAME_MAX; + break; + case _PC_PATH_MAX: + *a->a_retval = V7FS_PATH_MAX; + break; + case _PC_CHOWN_RESTRICTED: + *a->a_retval = 1; + break; + case _PC_NO_TRUNC: + *a->a_retval = 0; + break; + case _PC_SYNC_IO: + *a->a_retval = 1; + break; + case _PC_FILESIZEBITS: + *a->a_retval = 30; /* ~1G */ + break; + case _PC_SYMLINK_MAX: + *a->a_retval = MAXPATHLEN; + break; + case _PC_2_SYMLINKS: + *a->a_retval = 1; + break; + default: + err = EINVAL; + break; + } + + return err; +} + +int +v7fs_update(struct vnode *vp, const struct timespec *acc, + const struct timespec *mod, int flags) +{ + struct v7fs_node *v7node = vp->v_data; + struct v7fs_inode *inode = &v7node->inode; + struct v7fs_self *fs = v7node->v7fsmount->core; + bool update = false; + + DPRINTF("%p %zu %d\n", vp, vp->v_size, v7fs_inode_filesize(inode)); + KDASSERT(vp->v_size == v7fs_inode_filesize(inode)); + + if (v7node->update_atime) { + inode->atime = acc ? acc->tv_sec : time_second; + v7node->update_atime = false; + update = true; + } + if (v7node->update_ctime) { + inode->ctime = time_second; + v7node->update_ctime = false; + update = true; + } + if (v7node->update_mtime) { + inode->mtime = mod ? mod->tv_sec : time_second; + v7node->update_mtime = false; + update = true; + } + + if (update) + v7fs_inode_writeback(fs, inode); + + return 0; +} + +int +v7fs_symlink(void *v) +{ + struct vop_symlink_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + char *a_target; + } */ *a = v; + struct v7fs_node *parent_node = a->a_dvp->v_data; + struct v7fs_mount *v7fsmount = parent_node->v7fsmount; + struct v7fs_self *fs = v7fsmount->core; + struct vattr *va = a->a_vap; + kauth_cred_t cr = a->a_cnp->cn_cred; + struct componentname *cnp = a->a_cnp; + struct v7fs_fileattr attr; + v7fs_ino_t ino; + const char *from = a->a_target; + const char *to = cnp->cn_nameptr; + size_t len = strlen(from) + 1; + int error = 0; + + if (len > V7FS_BSIZE) { /* limited to 512byte pathname */ + DPRINTF("too long pathname."); + return ENAMETOOLONG; + } + + memset(&attr, 0, sizeof(attr)); + attr.uid = kauth_cred_geteuid(cr); + attr.gid = kauth_cred_getegid(cr); + attr.mode = va->va_mode | vtype_to_v7fs_mode(va->va_type); + + if ((error = v7fs_file_allocate + (fs, &parent_node->inode, to, &attr, &ino))) { + goto unlock_exit; + } + /* Sync dirent size change. */ + uvm_vnp_setsize(a->a_dvp, v7fs_inode_filesize(&parent_node->inode)); + + /* Get myself vnode. */ + if ((error = v7fs_vget(v7fsmount->mountp, ino, a->a_vpp))) { + DPRINTF("can't get vnode.\n"); + } + + struct v7fs_node *newnode = (*a->a_vpp)->v_data; + struct v7fs_inode *p = &newnode->inode; + + if ((error = v7fs_datablock_expand(fs, p, len))) { + v7fs_inode_deallocate(fs, ino); + error = ENOSPC; + goto unlock_exit; + } + v7fs_daddr_t blk = p->addr[0]; /* 1block only. */ + void *buf; + if (!(buf = scratch_read(fs, blk))) { + v7fs_inode_deallocate(fs, ino); + error = EIO; + goto unlock_exit; + } + strncpy(buf, from, V7FS_BSIZE); + if (!fs->io.write(fs->io.cookie, buf, blk)) { + scratch_free(fs, buf); + error = EIO; + goto unlock_exit; + } + scratch_free(fs, buf); + uvm_vnp_setsize(*a->a_vpp, v7fs_inode_filesize(p)); + + newnode->update_ctime = true; + newnode->update_mtime = true; + newnode->update_atime = true; +unlock_exit: + /* unlock parent directory */ + vput(a->a_dvp); + + return error; +} + +int +v7fs_readlink(void *v) +{ + struct vop_readlink_args /* { + struct vnode *a_vp; + struct uio *a_uio; + kauth_cred_t a_cred; + } */ *a = v; + struct uio *uio = a->a_uio; + struct vnode *vp = a->a_vp; + struct v7fs_node *v7node = vp->v_data; + struct v7fs_inode *inode = &v7node->inode; + struct v7fs_self *fs = v7node->v7fsmount->core; + int error = 0; + + KDASSERT(vp->v_type == VLNK); + KDASSERT(uio->uio_offset >= 0); + KDASSERT(v7fs_inode_islnk(inode)); + + v7fs_daddr_t blk = inode->addr[0]; + void *buf; + if (!(buf = scratch_read(fs, blk))) { + error = EIO; + goto error_exit; + } + + if ((error = uiomove(buf, strlen(buf), uio))) { + DPRINTF("uiomove failed.\n"); + } + scratch_free(fs, buf); + +error_exit: + return error; +} + + diff --git a/sys/sys/disklabel.h b/sys/sys/disklabel.h index ace6a21c898b..61989cd9e358 100644 --- a/sys/sys/disklabel.h +++ b/sys/sys/disklabel.h @@ -1,4 +1,4 @@ -/* $NetBSD: disklabel.h,v 1.108 2011/01/18 19:52:24 matt Exp $ */ +/* $NetBSD: disklabel.h,v 1.109 2011/06/27 11:52:24 uch Exp $ */ /* * Copyright (c) 1987, 1988, 1993 @@ -328,7 +328,7 @@ static const char *const dktypenames[] = { DKTYPE_DEFN(DKTYPE_NAMES) NULL }; x(UNUSED, 0, "unused", NULL, NULL) /* unused */ \ x(SWAP, 1, "swap", NULL, NULL) /* swap */ \ x(V6, 2, "Version 6", NULL, NULL) /* Sixth Edition */ \ -x(V7, 3, "Version 7", NULL, NULL) /* Seventh Edition */ \ +x(V7, 3, "Version 7", "v7fs", "v7fs") /* Seventh Edition */ \ x(SYSV, 4, "System V", NULL, NULL) /* System V */ \ x(V71K, 5, "4.1BSD", NULL, NULL) /* V7, 1K blocks (4.1, 2.9) */ \ x(V8, 6, "Eighth Edition",NULL, NULL) /* Eighth Edition, 4K blocks */ \ @@ -355,6 +355,7 @@ x(SYSVBFS, 25, "SysVBFS", NULL, "sysvbfs")/* System V boot file system */ \ x(EFS, 26, "EFS", NULL, "efs") /* SGI's Extent Filesystem */ \ x(NILFS, 27, "NiLFS", NULL, "nilfs") /* NTT's NiLFS(2) */ + #ifndef _LOCORE #define FS_TYPENUMS(tag, number, name, fsck, mount) __CONCAT(FS_,tag=number), enum { FSTYPE_DEFN(FS_TYPENUMS) FSMAXTYPES }; diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 4be0c4b0263f..b07453b151b5 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -1,4 +1,4 @@ -/* $NetBSD: mount.h,v 1.199 2011/04/02 04:57:35 rmind Exp $ */ +/* $NetBSD: mount.h,v 1.200 2011/06/27 11:52:24 uch Exp $ */ /* * Copyright (c) 1989, 1991, 1993 @@ -94,6 +94,7 @@ #define MOUNT_ZFS "zfs" /* Sun ZFS */ #define MOUNT_NILFS "nilfs" /* NTT's NiLFS(2) logging file system */ #define MOUNT_RUMPFS "rumpfs" /* rump virtual file system */ +#define MOUNT_V7FS "v7fs" /* 7th Edition of Unix Filesystem */ #ifndef _STANDALONE diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index a76ea3ec5c21..638528939470 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -1,4 +1,4 @@ -/* $NetBSD: vnode.h,v 1.232 2011/06/21 17:28:11 riz Exp $ */ +/* $NetBSD: vnode.h,v 1.233 2011/06/27 11:52:24 uch Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -105,7 +105,7 @@ enum vtagtype { VT_AFS, VT_ISOFS, VT_UNION, VT_ADOSFS, VT_EXT2FS, VT_CODA, VT_FILECORE, VT_NTFS, VT_VFS, VT_OVERLAY, VT_SMBFS, VT_PTYFS, VT_TMPFS, VT_UDF, VT_SYSVBFS, VT_PUFFS, VT_HFS, VT_EFS, VT_ZFS, - VT_RUMP, VT_NILFS + VT_RUMP, VT_NILFS, VT_V7FS }; #define VNODE_TAGS \ @@ -114,7 +114,7 @@ enum vtagtype { "VT_AFS", "VT_ISOFS", "VT_UNION", "VT_ADOSFS", "VT_EXT2FS", "VT_CODA", \ "VT_FILECORE", "VT_NTFS", "VT_VFS", "VT_OVERLAY", "VT_SMBFS", "VT_PTYFS", \ "VT_TMPFS", "VT_UDF", "VT_SYSVBFS", "VT_PUFFS", "VT_HFS", "VT_EFS", \ - "VT_ZFS", "VT_RUMP", "VT_NILFS" + "VT_ZFS", "VT_RUMP", "VT_NILFS", "VT_V7FS" struct vnode; struct buf;