diff options
Diffstat (limited to 'usr.sbin/makefs/ffs')
-rw-r--r-- | usr.sbin/makefs/ffs/Makefile.inc | 9 | ||||
-rw-r--r-- | usr.sbin/makefs/ffs/buf.c | 222 | ||||
-rw-r--r-- | usr.sbin/makefs/ffs/buf.h | 67 | ||||
-rw-r--r-- | usr.sbin/makefs/ffs/ffs_alloc.c | 681 | ||||
-rw-r--r-- | usr.sbin/makefs/ffs/ffs_balloc.c | 578 | ||||
-rw-r--r-- | usr.sbin/makefs/ffs/ffs_bswap.c | 260 | ||||
-rw-r--r-- | usr.sbin/makefs/ffs/ffs_extern.h | 77 | ||||
-rw-r--r-- | usr.sbin/makefs/ffs/ffs_subr.c | 193 | ||||
-rw-r--r-- | usr.sbin/makefs/ffs/mkfs.c | 839 | ||||
-rw-r--r-- | usr.sbin/makefs/ffs/newfs_extern.h | 36 | ||||
-rw-r--r-- | usr.sbin/makefs/ffs/ufs_bmap.c | 140 | ||||
-rw-r--r-- | usr.sbin/makefs/ffs/ufs_bswap.h | 90 | ||||
-rw-r--r-- | usr.sbin/makefs/ffs/ufs_inode.h | 97 |
13 files changed, 3289 insertions, 0 deletions
diff --git a/usr.sbin/makefs/ffs/Makefile.inc b/usr.sbin/makefs/ffs/Makefile.inc new file mode 100644 index 0000000..d681c4e --- /dev/null +++ b/usr.sbin/makefs/ffs/Makefile.inc @@ -0,0 +1,9 @@ +# $FreeBSD$ +# + +.PATH: ${.CURDIR}/ffs ${.CURDIR}/../../sys/ufs/ffs + +CFLAGS+= -I${.CURDIR}/../../sys/ufs/ffs + +SRCS+= ffs_alloc.c ffs_balloc.c ffs_bswap.c ffs_subr.c ufs_bmap.c +SRCS+= buf.c mkfs.c diff --git a/usr.sbin/makefs/ffs/buf.c b/usr.sbin/makefs/ffs/buf.c new file mode 100644 index 0000000..06538f5 --- /dev/null +++ b/usr.sbin/makefs/ffs/buf.c @@ -0,0 +1,222 @@ +/* $NetBSD: buf.c,v 1.12 2004/06/20 22:20:18 jmc Exp $ */ + +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Luke Mewburn for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/time.h> + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "makefs.h" + +#include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> + +#include "ffs/buf.h" +#include "ffs/ufs_inode.h" + +extern int sectorsize; /* XXX: from ffs.c & mkfs.c */ + +TAILQ_HEAD(buftailhead,buf) buftail; + +int +bread(int fd, struct fs *fs, daddr_t blkno, int size, struct buf **bpp) +{ + off_t offset; + ssize_t rv; + + assert (fs != NULL); + assert (bpp != NULL); + + if (debug & DEBUG_BUF_BREAD) + printf("bread: fs %p blkno %lld size %d\n", + fs, (long long)blkno, size); + *bpp = getblk(fd, fs, blkno, size); + offset = (*bpp)->b_blkno * sectorsize; /* XXX */ + if (debug & DEBUG_BUF_BREAD) + printf("bread: bp %p blkno %lld offset %lld bcount %ld\n", + (*bpp), (long long)(*bpp)->b_blkno, (long long) offset, + (*bpp)->b_bcount); + if (lseek((*bpp)->b_fd, offset, SEEK_SET) == -1) + err(1, "bread: lseek %lld (%lld)", + (long long)(*bpp)->b_blkno, (long long)offset); + rv = read((*bpp)->b_fd, (*bpp)->b_data, (*bpp)->b_bcount); + if (debug & DEBUG_BUF_BREAD) + printf("bread: read %ld (%lld) returned %d\n", + (*bpp)->b_bcount, (long long)offset, (int)rv); + if (rv == -1) /* read error */ + err(1, "bread: read %ld (%lld) returned %d", + (*bpp)->b_bcount, (long long)offset, (int)rv); + else if (rv != (*bpp)->b_bcount) /* short read */ + err(1, "bread: read %ld (%lld) returned %d", + (*bpp)->b_bcount, (long long)offset, (int)rv); + else + return (0); +} + +void +brelse(struct buf *bp) +{ + + assert (bp != NULL); + assert (bp->b_data != NULL); + + if (bp->b_lblkno < 0) { + /* + * XXX don't remove any buffers with negative logical block + * numbers (lblkno), so that we retain the mapping + * of negative lblkno -> real blkno that ffs_balloc() + * sets up. + * + * if we instead released these buffers, and implemented + * ufs_strategy() (and ufs_bmaparray()) and called those + * from bread() and bwrite() to convert the lblkno to + * a real blkno, we'd add a lot more code & complexity + * and reading off disk, for little gain, because this + * simple hack works for our purpose. + */ + bp->b_bcount = 0; + return; + } + + TAILQ_REMOVE(&buftail, bp, b_tailq); + free(bp->b_data); + free(bp); +} + +int +bwrite(struct buf *bp) +{ + off_t offset; + ssize_t rv; + + assert (bp != NULL); + offset = bp->b_blkno * sectorsize; /* XXX */ + if (debug & DEBUG_BUF_BWRITE) + printf("bwrite: bp %p blkno %lld offset %lld bcount %ld\n", + bp, (long long)bp->b_blkno, (long long) offset, + bp->b_bcount); + if (lseek(bp->b_fd, offset, SEEK_SET) == -1) + return (errno); + rv = write(bp->b_fd, bp->b_data, bp->b_bcount); + if (debug & DEBUG_BUF_BWRITE) + printf("bwrite: write %ld (offset %lld) returned %lld\n", + bp->b_bcount, (long long)offset, (long long)rv); + if (rv == bp->b_bcount) + return (0); + else if (rv == -1) /* write error */ + return (errno); + else /* short write ? */ + return (EAGAIN); +} + +void +bcleanup(void) +{ + struct buf *bp; + + /* + * XXX this really shouldn't be necessary, but i'm curious to + * know why there's still some buffers lying around that + * aren't brelse()d + */ + + if (TAILQ_EMPTY(&buftail)) + return; + + printf("bcleanup: unflushed buffers:\n"); + TAILQ_FOREACH(bp, &buftail, b_tailq) { + printf("\tlblkno %10lld blkno %10lld count %6ld bufsize %6ld\n", + (long long)bp->b_lblkno, (long long)bp->b_blkno, + bp->b_bcount, bp->b_bufsize); + } + printf("bcleanup: done\n"); +} + +struct buf * +getblk(int fd, struct fs *fs, daddr_t blkno, int size) +{ + static int buftailinitted; + struct buf *bp; + void *n; + + assert (fs != NULL); + if (debug & DEBUG_BUF_GETBLK) + printf("getblk: fs %p blkno %lld size %d\n", fs, + (long long)blkno, size); + + bp = NULL; + if (!buftailinitted) { + if (debug & DEBUG_BUF_GETBLK) + printf("getblk: initialising tailq\n"); + TAILQ_INIT(&buftail); + buftailinitted = 1; + } else { + TAILQ_FOREACH(bp, &buftail, b_tailq) { + if (bp->b_lblkno != blkno) + continue; + break; + } + } + if (bp == NULL) { + if ((bp = calloc(1, sizeof(struct buf))) == NULL) + err(1, "getblk: calloc"); + + bp->b_bufsize = 0; + bp->b_blkno = bp->b_lblkno = blkno; + bp->b_fd = fd; + bp->b_fs = fs; + bp->b_data = NULL; + TAILQ_INSERT_HEAD(&buftail, bp, b_tailq); + } + bp->b_bcount = size; + if (bp->b_data == NULL || bp->b_bcount > bp->b_bufsize) { + n = realloc(bp->b_data, size); + if (n == NULL) + err(1, "getblk: realloc b_data %ld", bp->b_bcount); + bp->b_data = n; + bp->b_bufsize = size; + } + + return (bp); +} diff --git a/usr.sbin/makefs/ffs/buf.h b/usr.sbin/makefs/ffs/buf.h new file mode 100644 index 0000000..02c6713 --- /dev/null +++ b/usr.sbin/makefs/ffs/buf.h @@ -0,0 +1,67 @@ +/* $NetBSD: buf.h,v 1.2 2001/11/02 03:12:49 lukem Exp $ */ + +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Luke Mewburn for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _FFS_BUF_H +#define _FFS_BUF_H + +#include <sys/param.h> +#include <sys/queue.h> + +struct buf { + void * b_data; + long b_bufsize; + long b_bcount; + daddr_t b_blkno; + daddr_t b_lblkno; + int b_fd; + struct fs * b_fs; + + TAILQ_ENTRY(buf) b_tailq; +}; + +void bcleanup(void); +int bread(int, struct fs *, daddr_t, int, struct buf **); +void brelse(struct buf *); +int bwrite(struct buf *); +struct buf * getblk(int, struct fs *, daddr_t, int); + +#define bdwrite(bp) bwrite(bp) +#define clrbuf(bp) memset((bp)->b_data, 0, (u_int)(bp)->b_bcount) + +#endif /* _FFS_BUF_H */ diff --git a/usr.sbin/makefs/ffs/ffs_alloc.c b/usr.sbin/makefs/ffs/ffs_alloc.c new file mode 100644 index 0000000..afab869 --- /dev/null +++ b/usr.sbin/makefs/ffs/ffs_alloc.c @@ -0,0 +1,681 @@ +/* $NetBSD: ffs_alloc.c,v 1.14 2004/06/20 22:20:18 jmc Exp $ */ +/* From: NetBSD: ffs_alloc.c,v 1.50 2001/09/06 02:16:01 lukem Exp */ + +/* + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ffs_alloc.c 8.19 (Berkeley) 7/13/95 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/time.h> + +#include <errno.h> +#include <stdint.h> + +#include "makefs.h" + +#include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> + +#include "ffs/ufs_bswap.h" +#include "ffs/buf.h" +#include "ffs/ufs_inode.h" +#include "ffs/ffs_extern.h" + +static int scanc(u_int, const u_char *, const u_char *, int); + +static daddr_t ffs_alloccg(struct inode *, int, daddr_t, int); +static daddr_t ffs_alloccgblk(struct inode *, struct buf *, daddr_t); +static daddr_t ffs_hashalloc(struct inode *, int, daddr_t, int, + daddr_t (*)(struct inode *, int, daddr_t, int)); +static int32_t ffs_mapsearch(struct fs *, struct cg *, daddr_t, int); + +/* + * Allocate a block in the file system. + * + * The size of the requested block is given, which must be some + * multiple of fs_fsize and <= fs_bsize. + * A preference may be optionally specified. If a preference is given + * the following hierarchy is used to allocate a block: + * 1) allocate the requested block. + * 2) allocate a rotationally optimal block in the same cylinder. + * 3) allocate a block in the same cylinder group. + * 4) quadradically rehash into other cylinder groups, until an + * available block is located. + * If no block preference is given the following hierarchy is used + * to allocate a block: + * 1) allocate a block in the cylinder group that contains the + * inode for the file. + * 2) quadradically rehash into other cylinder groups, until an + * available block is located. + */ +int +ffs_alloc(struct inode *ip, daddr_t lbn __unused, daddr_t bpref, int size, + daddr_t *bnp) +{ + struct fs *fs = ip->i_fs; + daddr_t bno; + int cg; + + *bnp = 0; + if (size > fs->fs_bsize || fragoff(fs, size) != 0) { + errx(1, "ffs_alloc: bad size: bsize %d size %d", + fs->fs_bsize, size); + } + if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0) + goto nospace; + if (bpref >= fs->fs_size) + bpref = 0; + if (bpref == 0) + cg = ino_to_cg(fs, ip->i_number); + else + cg = dtog(fs, bpref); + bno = ffs_hashalloc(ip, cg, bpref, size, ffs_alloccg); + if (bno > 0) { + if (ip->i_fs->fs_magic == FS_UFS1_MAGIC) + ip->i_ffs1_blocks += size / DEV_BSIZE; + else + ip->i_ffs2_blocks += size / DEV_BSIZE; + *bnp = bno; + return (0); + } +nospace: + return (ENOSPC); +} + +/* + * Select the desired position for the next block in a file. The file is + * logically divided into sections. The first section is composed of the + * direct blocks. Each additional section contains fs_maxbpg blocks. + * + * If no blocks have been allocated in the first section, the policy is to + * request a block in the same cylinder group as the inode that describes + * the file. If no blocks have been allocated in any other section, the + * policy is to place the section in a cylinder group with a greater than + * average number of free blocks. An appropriate cylinder group is found + * by using a rotor that sweeps the cylinder groups. When a new group of + * blocks is needed, the sweep begins in the cylinder group following the + * cylinder group from which the previous allocation was made. The sweep + * continues until a cylinder group with greater than the average number + * of free blocks is found. If the allocation is for the first block in an + * indirect block, the information on the previous allocation is unavailable; + * here a best guess is made based upon the logical block number being + * allocated. + * + * If a section is already partially allocated, the policy is to + * contiguously allocate fs_maxcontig blocks. The end of one of these + * contiguous blocks and the beginning of the next is physically separated + * so that the disk head will be in transit between them for at least + * fs_rotdelay milliseconds. This is to allow time for the processor to + * schedule another I/O transfer. + */ +/* XXX ondisk32 */ +daddr_t +ffs_blkpref_ufs1(struct inode *ip, daddr_t lbn, int indx, int32_t *bap) +{ + struct fs *fs; + int cg; + int avgbfree, startcg; + + fs = ip->i_fs; + if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { + if (lbn < NDADDR + NINDIR(fs)) { + cg = ino_to_cg(fs, ip->i_number); + return (fs->fs_fpg * cg + fs->fs_frag); + } + /* + * Find a cylinder with greater than average number of + * unused data blocks. + */ + if (indx == 0 || bap[indx - 1] == 0) + startcg = + ino_to_cg(fs, ip->i_number) + lbn / fs->fs_maxbpg; + else + startcg = dtog(fs, + ufs_rw32(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + 1); + startcg %= fs->fs_ncg; + avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; + for (cg = startcg; cg < fs->fs_ncg; cg++) + if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) + return (fs->fs_fpg * cg + fs->fs_frag); + for (cg = 0; cg <= startcg; cg++) + if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) + return (fs->fs_fpg * cg + fs->fs_frag); + return (0); + } + /* + * We just always try to lay things out contiguously. + */ + return ufs_rw32(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + fs->fs_frag; +} + +daddr_t +ffs_blkpref_ufs2(struct inode *ip, daddr_t lbn, int indx, int64_t *bap) +{ + struct fs *fs; + int cg; + int avgbfree, startcg; + + fs = ip->i_fs; + if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { + if (lbn < NDADDR + NINDIR(fs)) { + cg = ino_to_cg(fs, ip->i_number); + return (fs->fs_fpg * cg + fs->fs_frag); + } + /* + * Find a cylinder with greater than average number of + * unused data blocks. + */ + if (indx == 0 || bap[indx - 1] == 0) + startcg = + ino_to_cg(fs, ip->i_number) + lbn / fs->fs_maxbpg; + else + startcg = dtog(fs, + ufs_rw64(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + 1); + startcg %= fs->fs_ncg; + avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; + for (cg = startcg; cg < fs->fs_ncg; cg++) + if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { + return (fs->fs_fpg * cg + fs->fs_frag); + } + for (cg = 0; cg < startcg; cg++) + if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { + return (fs->fs_fpg * cg + fs->fs_frag); + } + return (0); + } + /* + * We just always try to lay things out contiguously. + */ + return ufs_rw64(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + fs->fs_frag; +} + +/* + * Implement the cylinder overflow algorithm. + * + * The policy implemented by this algorithm is: + * 1) allocate the block in its requested cylinder group. + * 2) quadradically rehash on the cylinder group number. + * 3) brute force search for a free block. + * + * `size': size for data blocks, mode for inodes + */ +/*VARARGS5*/ +static daddr_t +ffs_hashalloc(struct inode *ip, int cg, daddr_t pref, int size, + daddr_t (*allocator)(struct inode *, int, daddr_t, int)) +{ + struct fs *fs; + daddr_t result; + int i, icg = cg; + + fs = ip->i_fs; + /* + * 1: preferred cylinder group + */ + result = (*allocator)(ip, cg, pref, size); + if (result) + return (result); + /* + * 2: quadratic rehash + */ + for (i = 1; i < fs->fs_ncg; i *= 2) { + cg += i; + if (cg >= fs->fs_ncg) + cg -= fs->fs_ncg; + result = (*allocator)(ip, cg, 0, size); + if (result) + return (result); + } + /* + * 3: brute force search + * Note that we start at i == 2, since 0 was checked initially, + * and 1 is always checked in the quadratic rehash. + */ + cg = (icg + 2) % fs->fs_ncg; + for (i = 2; i < fs->fs_ncg; i++) { + result = (*allocator)(ip, cg, 0, size); + if (result) + return (result); + cg++; + if (cg == fs->fs_ncg) + cg = 0; + } + return (0); +} + +/* + * Determine whether a block can be allocated. + * + * Check to see if a block of the appropriate size is available, + * and if it is, allocate it. + */ +static daddr_t +ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size) +{ + struct cg *cgp; + struct buf *bp; + daddr_t bno, blkno; + int error, frags, allocsiz, i; + struct fs *fs = ip->i_fs; + const int needswap = UFS_FSNEEDSWAP(fs); + + if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) + return (0); + error = bread(ip->i_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)), + (int)fs->fs_cgsize, &bp); + if (error) { + brelse(bp); + return (0); + } + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic_swap(cgp, needswap) || + (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) { + brelse(bp); + return (0); + } + if (size == fs->fs_bsize) { + bno = ffs_alloccgblk(ip, bp, bpref); + bdwrite(bp); + return (bno); + } + /* + * check to see if any fragments are already available + * allocsiz is the size which will be allocated, hacking + * it down to a smaller size if necessary + */ + frags = numfrags(fs, size); + for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++) + if (cgp->cg_frsum[allocsiz] != 0) + break; + if (allocsiz == fs->fs_frag) { + /* + * no fragments were available, so a block will be + * allocated, and hacked up + */ + if (cgp->cg_cs.cs_nbfree == 0) { + brelse(bp); + return (0); + } + bno = ffs_alloccgblk(ip, bp, bpref); + bpref = dtogd(fs, bno); + for (i = frags; i < fs->fs_frag; i++) + setbit(cg_blksfree_swap(cgp, needswap), bpref + i); + i = fs->fs_frag - frags; + ufs_add32(cgp->cg_cs.cs_nffree, i, needswap); + fs->fs_cstotal.cs_nffree += i; + fs->fs_cs(fs, cg).cs_nffree += i; + fs->fs_fmod = 1; + ufs_add32(cgp->cg_frsum[i], 1, needswap); + bdwrite(bp); + return (bno); + } + bno = ffs_mapsearch(fs, cgp, bpref, allocsiz); + for (i = 0; i < frags; i++) + clrbit(cg_blksfree_swap(cgp, needswap), bno + i); + ufs_add32(cgp->cg_cs.cs_nffree, -frags, needswap); + fs->fs_cstotal.cs_nffree -= frags; + fs->fs_cs(fs, cg).cs_nffree -= frags; + fs->fs_fmod = 1; + ufs_add32(cgp->cg_frsum[allocsiz], -1, needswap); + if (frags != allocsiz) + ufs_add32(cgp->cg_frsum[allocsiz - frags], 1, needswap); + blkno = cg * fs->fs_fpg + bno; + bdwrite(bp); + return blkno; +} + +/* + * Allocate a block in a cylinder group. + * + * This algorithm implements the following policy: + * 1) allocate the requested block. + * 2) allocate a rotationally optimal block in the same cylinder. + * 3) allocate the next available block on the block rotor for the + * specified cylinder group. + * Note that this routine only allocates fs_bsize blocks; these + * blocks may be fragmented by the routine that allocates them. + */ +static daddr_t +ffs_alloccgblk(struct inode *ip, struct buf *bp, daddr_t bpref) +{ + struct cg *cgp; + daddr_t blkno; + int32_t bno; + struct fs *fs = ip->i_fs; + const int needswap = UFS_FSNEEDSWAP(fs); + u_int8_t *blksfree_swap; + + cgp = (struct cg *)bp->b_data; + blksfree_swap = cg_blksfree_swap(cgp, needswap); + if (bpref == 0 || (uint32_t)dtog(fs, bpref) != ufs_rw32(cgp->cg_cgx, needswap)) { + bpref = ufs_rw32(cgp->cg_rotor, needswap); + } else { + bpref = blknum(fs, bpref); + bno = dtogd(fs, bpref); + /* + * if the requested block is available, use it + */ + if (ffs_isblock(fs, blksfree_swap, fragstoblks(fs, bno))) + goto gotit; + } + /* + * Take the next available one in this cylinder group. + */ + bno = ffs_mapsearch(fs, cgp, bpref, (int)fs->fs_frag); + if (bno < 0) + return (0); + cgp->cg_rotor = ufs_rw32(bno, needswap); +gotit: + blkno = fragstoblks(fs, bno); + ffs_clrblock(fs, blksfree_swap, (long)blkno); + ffs_clusteracct(fs, cgp, blkno, -1); + ufs_add32(cgp->cg_cs.cs_nbfree, -1, needswap); + fs->fs_cstotal.cs_nbfree--; + fs->fs_cs(fs, ufs_rw32(cgp->cg_cgx, needswap)).cs_nbfree--; + fs->fs_fmod = 1; + blkno = ufs_rw32(cgp->cg_cgx, needswap) * fs->fs_fpg + bno; + return (blkno); +} + +/* + * Free a block or fragment. + * + * The specified block or fragment is placed back in the + * free map. If a fragment is deallocated, a possible + * block reassembly is checked. + */ +void +ffs_blkfree(struct inode *ip, daddr_t bno, long size) +{ + struct cg *cgp; + struct buf *bp; + int32_t fragno, cgbno; + int i, error, cg, blk, frags, bbase; + struct fs *fs = ip->i_fs; + const int needswap = UFS_FSNEEDSWAP(fs); + + if (size > fs->fs_bsize || fragoff(fs, size) != 0 || + fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) { + errx(1, "blkfree: bad size: bno %lld bsize %d size %ld", + (long long)bno, fs->fs_bsize, size); + } + cg = dtog(fs, bno); + if (bno >= fs->fs_size) { + warnx("bad block %lld, ino %ju", (long long)bno, + (uintmax_t)ip->i_number); + return; + } + error = bread(ip->i_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)), + (int)fs->fs_cgsize, &bp); + if (error) { + brelse(bp); + return; + } + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic_swap(cgp, needswap)) { + brelse(bp); + return; + } + cgbno = dtogd(fs, bno); + if (size == fs->fs_bsize) { + fragno = fragstoblks(fs, cgbno); + if (!ffs_isfreeblock(fs, cg_blksfree_swap(cgp, needswap), fragno)) { + errx(1, "blkfree: freeing free block %lld", + (long long)bno); + } + ffs_setblock(fs, cg_blksfree_swap(cgp, needswap), fragno); + ffs_clusteracct(fs, cgp, fragno, 1); + ufs_add32(cgp->cg_cs.cs_nbfree, 1, needswap); + fs->fs_cstotal.cs_nbfree++; + fs->fs_cs(fs, cg).cs_nbfree++; + } else { + bbase = cgbno - fragnum(fs, cgbno); + /* + * decrement the counts associated with the old frags + */ + blk = blkmap(fs, cg_blksfree_swap(cgp, needswap), bbase); + ffs_fragacct_swap(fs, blk, cgp->cg_frsum, -1, needswap); + /* + * deallocate the fragment + */ + frags = numfrags(fs, size); + for (i = 0; i < frags; i++) { + if (isset(cg_blksfree_swap(cgp, needswap), cgbno + i)) { + errx(1, "blkfree: freeing free frag: block %lld", + (long long)(cgbno + i)); + } + setbit(cg_blksfree_swap(cgp, needswap), cgbno + i); + } + ufs_add32(cgp->cg_cs.cs_nffree, i, needswap); + fs->fs_cstotal.cs_nffree += i; + fs->fs_cs(fs, cg).cs_nffree += i; + /* + * add back in counts associated with the new frags + */ + blk = blkmap(fs, cg_blksfree_swap(cgp, needswap), bbase); + ffs_fragacct_swap(fs, blk, cgp->cg_frsum, 1, needswap); + /* + * if a complete block has been reassembled, account for it + */ + fragno = fragstoblks(fs, bbase); + if (ffs_isblock(fs, cg_blksfree_swap(cgp, needswap), fragno)) { + ufs_add32(cgp->cg_cs.cs_nffree, -fs->fs_frag, needswap); + fs->fs_cstotal.cs_nffree -= fs->fs_frag; + fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; + ffs_clusteracct(fs, cgp, fragno, 1); + ufs_add32(cgp->cg_cs.cs_nbfree, 1, needswap); + fs->fs_cstotal.cs_nbfree++; + fs->fs_cs(fs, cg).cs_nbfree++; + } + } + fs->fs_fmod = 1; + bdwrite(bp); +} + + +static int +scanc(u_int size, const u_char *cp, const u_char table[], int mask) +{ + const u_char *end = &cp[size]; + + while (cp < end && (table[*cp] & mask) == 0) + cp++; + return (end - cp); +} + +/* + * Find a block of the specified size in the specified cylinder group. + * + * It is a panic if a request is made to find a block if none are + * available. + */ +static int32_t +ffs_mapsearch(struct fs *fs, struct cg *cgp, daddr_t bpref, int allocsiz) +{ + int32_t bno; + int start, len, loc, i; + int blk, field, subfield, pos; + int ostart, olen; + const int needswap = UFS_FSNEEDSWAP(fs); + + /* + * find the fragment by searching through the free block + * map for an appropriate bit pattern + */ + if (bpref) + start = dtogd(fs, bpref) / NBBY; + else + start = ufs_rw32(cgp->cg_frotor, needswap) / NBBY; + len = howmany(fs->fs_fpg, NBBY) - start; + ostart = start; + olen = len; + loc = scanc((u_int)len, + (const u_char *)&cg_blksfree_swap(cgp, needswap)[start], + (const u_char *)fragtbl[fs->fs_frag], + (1 << (allocsiz - 1 + (fs->fs_frag % NBBY)))); + if (loc == 0) { + len = start + 1; + start = 0; + loc = scanc((u_int)len, + (const u_char *)&cg_blksfree_swap(cgp, needswap)[0], + (const u_char *)fragtbl[fs->fs_frag], + (1 << (allocsiz - 1 + (fs->fs_frag % NBBY)))); + if (loc == 0) { + errx(1, + "ffs_alloccg: map corrupted: start %d len %d offset %d %ld", + ostart, olen, + ufs_rw32(cgp->cg_freeoff, needswap), + (long)cg_blksfree_swap(cgp, needswap) - (long)cgp); + /* NOTREACHED */ + } + } + bno = (start + len - loc) * NBBY; + cgp->cg_frotor = ufs_rw32(bno, needswap); + /* + * found the byte in the map + * sift through the bits to find the selected frag + */ + for (i = bno + NBBY; bno < i; bno += fs->fs_frag) { + blk = blkmap(fs, cg_blksfree_swap(cgp, needswap), bno); + blk <<= 1; + field = around[allocsiz]; + subfield = inside[allocsiz]; + for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) { + if ((blk & field) == subfield) + return (bno + pos); + field <<= 1; + subfield <<= 1; + } + } + errx(1, "ffs_alloccg: block not in map: bno %lld", (long long)bno); + return (-1); +} + +/* + * Update the cluster map because of an allocation or free. + * + * Cnt == 1 means free; cnt == -1 means allocating. + */ +void +ffs_clusteracct(struct fs *fs, struct cg *cgp, int32_t blkno, int cnt) +{ + int32_t *sump; + int32_t *lp; + u_char *freemapp, *mapp; + int i, start, end, forw, back, map, bit; + const int needswap = UFS_FSNEEDSWAP(fs); + + if (fs->fs_contigsumsize <= 0) + return; + freemapp = cg_clustersfree_swap(cgp, needswap); + sump = cg_clustersum_swap(cgp, needswap); + /* + * Allocate or clear the actual block. + */ + if (cnt > 0) + setbit(freemapp, blkno); + else + clrbit(freemapp, blkno); + /* + * Find the size of the cluster going forward. + */ + start = blkno + 1; + end = start + fs->fs_contigsumsize; + if ((unsigned)end >= ufs_rw32(cgp->cg_nclusterblks, needswap)) + end = ufs_rw32(cgp->cg_nclusterblks, needswap); + mapp = &freemapp[start / NBBY]; + map = *mapp++; + bit = 1 << (start % NBBY); + for (i = start; i < end; i++) { + if ((map & bit) == 0) + break; + if ((i & (NBBY - 1)) != (NBBY - 1)) { + bit <<= 1; + } else { + map = *mapp++; + bit = 1; + } + } + forw = i - start; + /* + * Find the size of the cluster going backward. + */ + start = blkno - 1; + end = start - fs->fs_contigsumsize; + if (end < 0) + end = -1; + mapp = &freemapp[start / NBBY]; + map = *mapp--; + bit = 1 << (start % NBBY); + for (i = start; i > end; i--) { + if ((map & bit) == 0) + break; + if ((i & (NBBY - 1)) != 0) { + bit >>= 1; + } else { + map = *mapp--; + bit = 1 << (NBBY - 1); + } + } + back = start - i; + /* + * Account for old cluster and the possibly new forward and + * back clusters. + */ + i = back + forw + 1; + if (i > fs->fs_contigsumsize) + i = fs->fs_contigsumsize; + ufs_add32(sump[i], cnt, needswap); + if (back > 0) + ufs_add32(sump[back], -cnt, needswap); + if (forw > 0) + ufs_add32(sump[forw], -cnt, needswap); + + /* + * Update cluster summary information. + */ + lp = &sump[fs->fs_contigsumsize]; + for (i = fs->fs_contigsumsize; i > 0; i--) + if (ufs_rw32(*lp--, needswap) > 0) + break; + fs->fs_maxcluster[ufs_rw32(cgp->cg_cgx, needswap)] = i; +} diff --git a/usr.sbin/makefs/ffs/ffs_balloc.c b/usr.sbin/makefs/ffs/ffs_balloc.c new file mode 100644 index 0000000..0a048ad --- /dev/null +++ b/usr.sbin/makefs/ffs/ffs_balloc.c @@ -0,0 +1,578 @@ +/* $NetBSD: ffs_balloc.c,v 1.13 2004/06/20 22:20:18 jmc Exp $ */ +/* From NetBSD: ffs_balloc.c,v 1.25 2001/08/08 08:36:36 lukem Exp */ + +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/time.h> + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "makefs.h" + +#include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> + +#include "ffs/ufs_bswap.h" +#include "ffs/buf.h" +#include "ffs/ufs_inode.h" +#include "ffs/ffs_extern.h" + +static int ffs_balloc_ufs1(struct inode *, off_t, int, struct buf **); +static int ffs_balloc_ufs2(struct inode *, off_t, int, struct buf **); + +/* + * Balloc defines the structure of file system storage + * by allocating the physical blocks on a device given + * the inode and the logical block number in a file. + * + * Assume: flags == B_SYNC | B_CLRBUF + */ + +int +ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) +{ + if (ip->i_fs->fs_magic == FS_UFS2_MAGIC) + return ffs_balloc_ufs2(ip, offset, bufsize, bpp); + else + return ffs_balloc_ufs1(ip, offset, bufsize, bpp); +} + +static int +ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) +{ + daddr_t lbn, lastlbn; + int size; + int32_t nb; + struct buf *bp, *nbp; + struct fs *fs = ip->i_fs; + struct indir indirs[NIADDR + 2]; + daddr_t newb, pref; + int32_t *bap; + int osize, nsize, num, i, error; + int32_t *allocblk, allociblk[NIADDR + 1]; + int32_t *allocib; + const int needswap = UFS_FSNEEDSWAP(fs); + + lbn = lblkno(fs, offset); + size = blkoff(fs, offset) + bufsize; + if (bpp != NULL) { + *bpp = NULL; + } + + assert(size <= fs->fs_bsize); + if (lbn < 0) + return (EFBIG); + + /* + * If the next write will extend the file into a new block, + * and the file is currently composed of a fragment + * this fragment has to be extended to be a full block. + */ + + lastlbn = lblkno(fs, ip->i_ffs1_size); + if (lastlbn < NDADDR && lastlbn < lbn) { + nb = lastlbn; + osize = blksize(fs, ip, nb); + if (osize < fs->fs_bsize && osize > 0) { + warnx("need to ffs_realloccg; not supported!"); + abort(); + } + } + + /* + * The first NDADDR blocks are direct blocks + */ + + if (lbn < NDADDR) { + nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap); + if (nb != 0 && ip->i_ffs1_size >= lblktosize(fs, lbn + 1)) { + + /* + * The block is an already-allocated direct block + * and the file already extends past this block, + * thus this must be a whole block. + * Just read the block (if requested). + */ + + if (bpp != NULL) { + error = bread(ip->i_fd, ip->i_fs, lbn, + fs->fs_bsize, bpp); + if (error) { + brelse(*bpp); + return (error); + } + } + return (0); + } + if (nb != 0) { + + /* + * Consider need to reallocate a fragment. + */ + + osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size)); + nsize = fragroundup(fs, size); + if (nsize <= osize) { + + /* + * The existing block is already + * at least as big as we want. + * Just read the block (if requested). + */ + + if (bpp != NULL) { + error = bread(ip->i_fd, ip->i_fs, lbn, + osize, bpp); + if (error) { + brelse(*bpp); + return (error); + } + } + return 0; + } else { + warnx("need to ffs_realloccg; not supported!"); + abort(); + } + } else { + + /* + * the block was not previously allocated, + * allocate a new block or fragment. + */ + + if (ip->i_ffs1_size < lblktosize(fs, lbn + 1)) + nsize = fragroundup(fs, size); + else + nsize = fs->fs_bsize; + error = ffs_alloc(ip, lbn, + ffs_blkpref_ufs1(ip, lbn, (int)lbn, + &ip->i_ffs1_db[0]), + nsize, &newb); + if (error) + return (error); + if (bpp != NULL) { + bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize); + bp->b_blkno = fsbtodb(fs, newb); + clrbuf(bp); + *bpp = bp; + } + } + ip->i_ffs1_db[lbn] = ufs_rw32((int32_t)newb, needswap); + return (0); + } + + /* + * Determine the number of levels of indirection. + */ + + pref = 0; + if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0) + return (error); + + if (num < 1) { + warnx("ffs_balloc: ufs_getlbns returned indirect block"); + abort(); + } + + /* + * Fetch the first indirect block allocating if necessary. + */ + + --num; + nb = ufs_rw32(ip->i_ffs1_ib[indirs[0].in_off], needswap); + allocib = NULL; + allocblk = allociblk; + if (nb == 0) { + pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0); + error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); + if (error) + return error; + nb = newb; + *allocblk++ = nb; + bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize); + bp->b_blkno = fsbtodb(fs, nb); + clrbuf(bp); + /* + * Write synchronously so that indirect blocks + * never point at garbage. + */ + if ((error = bwrite(bp)) != 0) + return error; + allocib = &ip->i_ffs1_ib[indirs[0].in_off]; + *allocib = ufs_rw32((int32_t)nb, needswap); + } + + /* + * Fetch through the indirect blocks, allocating as necessary. + */ + + for (i = 1;;) { + error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn, + fs->fs_bsize, &bp); + if (error) { + brelse(bp); + return error; + } + bap = (int32_t *)bp->b_data; + nb = ufs_rw32(bap[indirs[i].in_off], needswap); + if (i == num) + break; + i++; + if (nb != 0) { + brelse(bp); + continue; + } + if (pref == 0) + pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0); + error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); + if (error) { + brelse(bp); + return error; + } + nb = newb; + *allocblk++ = nb; + nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn, + fs->fs_bsize); + nbp->b_blkno = fsbtodb(fs, nb); + clrbuf(nbp); + /* + * Write synchronously so that indirect blocks + * never point at garbage. + */ + + if ((error = bwrite(nbp)) != 0) { + brelse(bp); + return error; + } + bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap); + + bwrite(bp); + } + + /* + * Get the data block, allocating if necessary. + */ + + if (nb == 0) { + pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]); + error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); + if (error) { + brelse(bp); + return error; + } + nb = newb; + *allocblk++ = nb; + if (bpp != NULL) { + nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize); + nbp->b_blkno = fsbtodb(fs, nb); + clrbuf(nbp); + *bpp = nbp; + } + bap[indirs[num].in_off] = ufs_rw32(nb, needswap); + + /* + * If required, write synchronously, otherwise use + * delayed write. + */ + bwrite(bp); + return (0); + } + brelse(bp); + if (bpp != NULL) { + error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp); + if (error) { + brelse(nbp); + return error; + } + *bpp = nbp; + } + return (0); +} + +static int +ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) +{ + daddr_t lbn, lastlbn; + int size; + struct buf *bp, *nbp; + struct fs *fs = ip->i_fs; + struct indir indirs[NIADDR + 2]; + daddr_t newb, pref, nb; + int64_t *bap; + int osize, nsize, num, i, error; + int64_t *allocblk, allociblk[NIADDR + 1]; + int64_t *allocib; + const int needswap = UFS_FSNEEDSWAP(fs); + + lbn = lblkno(fs, offset); + size = blkoff(fs, offset) + bufsize; + if (bpp != NULL) { + *bpp = NULL; + } + + assert(size <= fs->fs_bsize); + if (lbn < 0) + return (EFBIG); + + /* + * If the next write will extend the file into a new block, + * and the file is currently composed of a fragment + * this fragment has to be extended to be a full block. + */ + + lastlbn = lblkno(fs, ip->i_ffs2_size); + if (lastlbn < NDADDR && lastlbn < lbn) { + nb = lastlbn; + osize = blksize(fs, ip, nb); + if (osize < fs->fs_bsize && osize > 0) { + warnx("need to ffs_realloccg; not supported!"); + abort(); + } + } + + /* + * The first NDADDR blocks are direct blocks + */ + + if (lbn < NDADDR) { + nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap); + if (nb != 0 && ip->i_ffs2_size >= lblktosize(fs, lbn + 1)) { + + /* + * The block is an already-allocated direct block + * and the file already extends past this block, + * thus this must be a whole block. + * Just read the block (if requested). + */ + + if (bpp != NULL) { + error = bread(ip->i_fd, ip->i_fs, lbn, + fs->fs_bsize, bpp); + if (error) { + brelse(*bpp); + return (error); + } + } + return (0); + } + if (nb != 0) { + + /* + * Consider need to reallocate a fragment. + */ + + osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size)); + nsize = fragroundup(fs, size); + if (nsize <= osize) { + + /* + * The existing block is already + * at least as big as we want. + * Just read the block (if requested). + */ + + if (bpp != NULL) { + error = bread(ip->i_fd, ip->i_fs, lbn, + osize, bpp); + if (error) { + brelse(*bpp); + return (error); + } + } + return 0; + } else { + warnx("need to ffs_realloccg; not supported!"); + abort(); + } + } else { + + /* + * the block was not previously allocated, + * allocate a new block or fragment. + */ + + if (ip->i_ffs2_size < lblktosize(fs, lbn + 1)) + nsize = fragroundup(fs, size); + else + nsize = fs->fs_bsize; + error = ffs_alloc(ip, lbn, + ffs_blkpref_ufs2(ip, lbn, (int)lbn, + &ip->i_ffs2_db[0]), + nsize, &newb); + if (error) + return (error); + if (bpp != NULL) { + bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize); + bp->b_blkno = fsbtodb(fs, newb); + clrbuf(bp); + *bpp = bp; + } + } + ip->i_ffs2_db[lbn] = ufs_rw64(newb, needswap); + return (0); + } + + /* + * Determine the number of levels of indirection. + */ + + pref = 0; + if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0) + return (error); + + if (num < 1) { + warnx("ffs_balloc: ufs_getlbns returned indirect block"); + abort(); + } + + /* + * Fetch the first indirect block allocating if necessary. + */ + + --num; + nb = ufs_rw64(ip->i_ffs2_ib[indirs[0].in_off], needswap); + allocib = NULL; + allocblk = allociblk; + if (nb == 0) { + pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0); + error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); + if (error) + return error; + nb = newb; + *allocblk++ = nb; + bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize); + bp->b_blkno = fsbtodb(fs, nb); + clrbuf(bp); + /* + * Write synchronously so that indirect blocks + * never point at garbage. + */ + if ((error = bwrite(bp)) != 0) + return error; + allocib = &ip->i_ffs2_ib[indirs[0].in_off]; + *allocib = ufs_rw64(nb, needswap); + } + + /* + * Fetch through the indirect blocks, allocating as necessary. + */ + + for (i = 1;;) { + error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn, + fs->fs_bsize, &bp); + if (error) { + brelse(bp); + return error; + } + bap = (int64_t *)bp->b_data; + nb = ufs_rw64(bap[indirs[i].in_off], needswap); + if (i == num) + break; + i++; + if (nb != 0) { + brelse(bp); + continue; + } + if (pref == 0) + pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0); + error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); + if (error) { + brelse(bp); + return error; + } + nb = newb; + *allocblk++ = nb; + nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn, + fs->fs_bsize); + nbp->b_blkno = fsbtodb(fs, nb); + clrbuf(nbp); + /* + * Write synchronously so that indirect blocks + * never point at garbage. + */ + + if ((error = bwrite(nbp)) != 0) { + brelse(bp); + return error; + } + bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap); + + bwrite(bp); + } + + /* + * Get the data block, allocating if necessary. + */ + + if (nb == 0) { + pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]); + error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); + if (error) { + brelse(bp); + return error; + } + nb = newb; + *allocblk++ = nb; + if (bpp != NULL) { + nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize); + nbp->b_blkno = fsbtodb(fs, nb); + clrbuf(nbp); + *bpp = nbp; + } + bap[indirs[num].in_off] = ufs_rw64(nb, needswap); + + /* + * If required, write synchronously, otherwise use + * delayed write. + */ + bwrite(bp); + return (0); + } + brelse(bp); + if (bpp != NULL) { + error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp); + if (error) { + brelse(nbp); + return error; + } + *bpp = nbp; + } + return (0); +} diff --git a/usr.sbin/makefs/ffs/ffs_bswap.c b/usr.sbin/makefs/ffs/ffs_bswap.c new file mode 100644 index 0000000..e62eb19 --- /dev/null +++ b/usr.sbin/makefs/ffs/ffs_bswap.c @@ -0,0 +1,260 @@ +/* $NetBSD: ffs_bswap.c,v 1.28 2004/05/25 14:54:59 hannken Exp $ */ + +/* + * Copyright (c) 1998 Manuel Bouyer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#if defined(_KERNEL) +#include <sys/systm.h> +#endif + +#include <ufs/ufs/dinode.h> +#include "ffs/ufs_bswap.h" +#include <ufs/ffs/fs.h> + +#if !defined(_KERNEL) +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#define panic(x) printf("%s\n", (x)), abort() +#endif + +#define fs_old_postbloff fs_spare5[0] +#define fs_old_rotbloff fs_spare5[1] +#define fs_old_postbl_start fs_maxbsize +#define fs_old_headswitch fs_id[0] +#define fs_old_trkseek fs_id[1] +#define fs_old_csmask fs_spare1[0] +#define fs_old_csshift fs_spare1[1] + +#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */ +#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */ + +void ffs_csum_swap(struct csum *o, struct csum *n, int size); +void ffs_csumtotal_swap(struct csum_total *o, struct csum_total *n); + +void +ffs_sb_swap(struct fs *o, struct fs *n) +{ + size_t i; + u_int32_t *o32, *n32; + + /* + * In order to avoid a lot of lines, as the first N fields (52) + * of the superblock up to fs_fmod are u_int32_t, we just loop + * here to convert them. + */ + o32 = (u_int32_t *)o; + n32 = (u_int32_t *)n; + for (i = 0; i < offsetof(struct fs, fs_fmod) / sizeof(u_int32_t); i++) + n32[i] = bswap32(o32[i]); + + n->fs_swuid = bswap64(o->fs_swuid); + n->fs_cgrotor = bswap32(o->fs_cgrotor); /* Unused */ + n->fs_old_cpc = bswap32(o->fs_old_cpc); + + /* These fields overlap with a possible location for the + * historic FS_DYNAMICPOSTBLFMT postbl table, and with the + * first half of the historic FS_42POSTBLFMT postbl table. + */ + n->fs_maxbsize = bswap32(o->fs_maxbsize); + n->fs_sblockloc = bswap64(o->fs_sblockloc); + ffs_csumtotal_swap(&o->fs_cstotal, &n->fs_cstotal); + n->fs_time = bswap64(o->fs_time); + n->fs_size = bswap64(o->fs_size); + n->fs_dsize = bswap64(o->fs_dsize); + n->fs_csaddr = bswap64(o->fs_csaddr); + n->fs_pendingblocks = bswap64(o->fs_pendingblocks); + n->fs_pendinginodes = bswap32(o->fs_pendinginodes); + + /* These fields overlap with the second half of the + * historic FS_42POSTBLFMT postbl table + */ + for (i = 0; i < FSMAXSNAP; i++) + n->fs_snapinum[i] = bswap32(o->fs_snapinum[i]); + n->fs_avgfilesize = bswap32(o->fs_avgfilesize); + n->fs_avgfpdir = bswap32(o->fs_avgfpdir); + /* fs_sparecon[28] - ignore for now */ + n->fs_flags = bswap32(o->fs_flags); + n->fs_contigsumsize = bswap32(o->fs_contigsumsize); + n->fs_maxsymlinklen = bswap32(o->fs_maxsymlinklen); + n->fs_old_inodefmt = bswap32(o->fs_old_inodefmt); + n->fs_maxfilesize = bswap64(o->fs_maxfilesize); + n->fs_qbmask = bswap64(o->fs_qbmask); + n->fs_qfmask = bswap64(o->fs_qfmask); + n->fs_state = bswap32(o->fs_state); + n->fs_old_postblformat = bswap32(o->fs_old_postblformat); + n->fs_old_nrpos = bswap32(o->fs_old_nrpos); + n->fs_old_postbloff = bswap32(o->fs_old_postbloff); + n->fs_old_rotbloff = bswap32(o->fs_old_rotbloff); + + n->fs_magic = bswap32(o->fs_magic); +} + +void +ffs_dinode1_swap(struct ufs1_dinode *o, struct ufs1_dinode *n) +{ + + n->di_mode = bswap16(o->di_mode); + n->di_nlink = bswap16(o->di_nlink); + n->di_size = bswap64(o->di_size); + n->di_atime = bswap32(o->di_atime); + n->di_atimensec = bswap32(o->di_atimensec); + n->di_mtime = bswap32(o->di_mtime); + n->di_mtimensec = bswap32(o->di_mtimensec); + n->di_ctime = bswap32(o->di_ctime); + n->di_ctimensec = bswap32(o->di_ctimensec); + memcpy(n->di_db, o->di_db, (NDADDR + NIADDR) * sizeof(u_int32_t)); + n->di_flags = bswap32(o->di_flags); + n->di_blocks = bswap32(o->di_blocks); + n->di_gen = bswap32(o->di_gen); + n->di_uid = bswap32(o->di_uid); + n->di_gid = bswap32(o->di_gid); +} + +void +ffs_dinode2_swap(struct ufs2_dinode *o, struct ufs2_dinode *n) +{ + n->di_mode = bswap16(o->di_mode); + n->di_nlink = bswap16(o->di_nlink); + n->di_uid = bswap32(o->di_uid); + n->di_gid = bswap32(o->di_gid); + n->di_blksize = bswap32(o->di_blksize); + n->di_size = bswap64(o->di_size); + n->di_blocks = bswap64(o->di_blocks); + n->di_atime = bswap64(o->di_atime); + n->di_atimensec = bswap32(o->di_atimensec); + n->di_mtime = bswap64(o->di_mtime); + n->di_mtimensec = bswap32(o->di_mtimensec); + n->di_ctime = bswap64(o->di_ctime); + n->di_ctimensec = bswap32(o->di_ctimensec); + n->di_birthtime = bswap64(o->di_ctime); + n->di_birthnsec = bswap32(o->di_ctimensec); + n->di_gen = bswap32(o->di_gen); + n->di_kernflags = bswap32(o->di_kernflags); + n->di_flags = bswap32(o->di_flags); + n->di_extsize = bswap32(o->di_extsize); + memcpy(n->di_extb, o->di_extb, (NXADDR + NDADDR + NIADDR) * 8); +} + +void +ffs_csum_swap(struct csum *o, struct csum *n, int size) +{ + size_t i; + u_int32_t *oint, *nint; + + oint = (u_int32_t*)o; + nint = (u_int32_t*)n; + + for (i = 0; i < size / sizeof(u_int32_t); i++) + nint[i] = bswap32(oint[i]); +} + +void +ffs_csumtotal_swap(struct csum_total *o, struct csum_total *n) +{ + n->cs_ndir = bswap64(o->cs_ndir); + n->cs_nbfree = bswap64(o->cs_nbfree); + n->cs_nifree = bswap64(o->cs_nifree); + n->cs_nffree = bswap64(o->cs_nffree); +} + +/* + * Note that ffs_cg_swap may be called with o == n. + */ +void +ffs_cg_swap(struct cg *o, struct cg *n, struct fs *fs) +{ + int i; + u_int32_t *n32, *o32; + u_int16_t *n16, *o16; + int32_t btotoff, boff, clustersumoff; + + n->cg_firstfield = bswap32(o->cg_firstfield); + n->cg_magic = bswap32(o->cg_magic); + n->cg_old_time = bswap32(o->cg_old_time); + n->cg_cgx = bswap32(o->cg_cgx); + n->cg_old_ncyl = bswap16(o->cg_old_ncyl); + n->cg_old_niblk = bswap16(o->cg_old_niblk); + n->cg_ndblk = bswap32(o->cg_ndblk); + n->cg_cs.cs_ndir = bswap32(o->cg_cs.cs_ndir); + n->cg_cs.cs_nbfree = bswap32(o->cg_cs.cs_nbfree); + n->cg_cs.cs_nifree = bswap32(o->cg_cs.cs_nifree); + n->cg_cs.cs_nffree = bswap32(o->cg_cs.cs_nffree); + n->cg_rotor = bswap32(o->cg_rotor); + n->cg_frotor = bswap32(o->cg_frotor); + n->cg_irotor = bswap32(o->cg_irotor); + for (i = 0; i < MAXFRAG; i++) + n->cg_frsum[i] = bswap32(o->cg_frsum[i]); + + n->cg_old_btotoff = bswap32(o->cg_old_btotoff); + n->cg_old_boff = bswap32(o->cg_old_boff); + n->cg_iusedoff = bswap32(o->cg_iusedoff); + n->cg_freeoff = bswap32(o->cg_freeoff); + n->cg_nextfreeoff = bswap32(o->cg_nextfreeoff); + n->cg_clustersumoff = bswap32(o->cg_clustersumoff); + n->cg_clusteroff = bswap32(o->cg_clusteroff); + n->cg_nclusterblks = bswap32(o->cg_nclusterblks); + n->cg_niblk = bswap32(o->cg_niblk); + n->cg_initediblk = bswap32(o->cg_initediblk); + n->cg_time = bswap64(o->cg_time); + + if (fs->fs_magic == FS_UFS2_MAGIC) + return; + + if (n->cg_magic == CG_MAGIC) { + btotoff = n->cg_old_btotoff; + boff = n->cg_old_boff; + clustersumoff = n->cg_clustersumoff; + } else { + btotoff = bswap32(n->cg_old_btotoff); + boff = bswap32(n->cg_old_boff); + clustersumoff = bswap32(n->cg_clustersumoff); + } + n32 = (u_int32_t *)((u_int8_t *)n + btotoff); + o32 = (u_int32_t *)((u_int8_t *)o + btotoff); + n16 = (u_int16_t *)((u_int8_t *)n + boff); + o16 = (u_int16_t *)((u_int8_t *)o + boff); + + for (i = 0; i < fs->fs_old_cpg; i++) + n32[i] = bswap32(o32[i]); + + for (i = 0; i < fs->fs_old_cpg * fs->fs_old_nrpos; i++) + n16[i] = bswap16(o16[i]); + + n32 = (u_int32_t *)((u_int8_t *)n + clustersumoff); + o32 = (u_int32_t *)((u_int8_t *)o + clustersumoff); + for (i = 1; i < fs->fs_contigsumsize + 1; i++) + n32[i] = bswap32(o32[i]); +} diff --git a/usr.sbin/makefs/ffs/ffs_extern.h b/usr.sbin/makefs/ffs/ffs_extern.h new file mode 100644 index 0000000..7755823 --- /dev/null +++ b/usr.sbin/makefs/ffs/ffs_extern.h @@ -0,0 +1,77 @@ +/* $NetBSD: ffs_extern.h,v 1.6 2003/08/07 11:25:33 agc Exp $ */ +/* From: NetBSD: ffs_extern.h,v 1.19 2001/08/17 02:18:48 lukem Exp */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ffs_extern.h 8.6 (Berkeley) 3/30/95 + * $FreeBSD$ + */ + +#include "ffs/buf.h" + +struct inode; + +/* + * Structure used to pass around logical block paths generated by + * ufs_getlbns and used by truncate and bmap code. + */ +struct indir { + daddr_t in_lbn; /* Logical block number. */ + int in_off; /* Offset in buffer. */ +}; + + /* ffs.c */ +_Noreturn void panic(const char *, ...) __printflike(1, 2); + + /* ffs_alloc.c */ +int ffs_alloc(struct inode *, daddr_t, daddr_t, int, daddr_t *); +daddr_t ffs_blkpref_ufs1(struct inode *, daddr_t, int, int32_t *); +daddr_t ffs_blkpref_ufs2(struct inode *, daddr_t, int, int64_t *); +void ffs_blkfree(struct inode *, daddr_t, long); +void ffs_clusteracct(struct fs *, struct cg *, int32_t, int); + + /* ffs_balloc.c */ +int ffs_balloc(struct inode *, off_t, int, struct buf **); + + /* ffs_bswap.c */ +void ffs_sb_swap(struct fs*, struct fs *); +void ffs_dinode1_swap(struct ufs1_dinode *, struct ufs1_dinode *); +void ffs_dinode2_swap(struct ufs2_dinode *, struct ufs2_dinode *); +void ffs_csum_swap(struct csum *, struct csum *, int); +void ffs_cg_swap(struct cg *, struct cg *, struct fs *); + + /* ffs_subr.c */ +void ffs_fragacct(struct fs *, int, int32_t[], int, int); +int ffs_isblock(struct fs *, u_char *, int32_t); +int ffs_isfreeblock(struct fs *, u_char *, int32_t); +void ffs_clrblock(struct fs *, u_char *, int32_t); +void ffs_setblock(struct fs *, u_char *, int32_t); + + /* ufs_bmap.c */ +int ufs_getlbns(struct inode *, daddr_t, struct indir *, int *); diff --git a/usr.sbin/makefs/ffs/ffs_subr.c b/usr.sbin/makefs/ffs/ffs_subr.c new file mode 100644 index 0000000..b55174d --- /dev/null +++ b/usr.sbin/makefs/ffs/ffs_subr.c @@ -0,0 +1,193 @@ +/* $NetBSD: ffs_subr.c,v 1.32 2003/12/30 12:33:24 pk Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ffs_subr.c 8.5 (Berkeley) 3/21/95 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> + +#include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> +#include "ffs/ffs_extern.h" +#include "ffs/ufs_bswap.h" + +/* + * Update the frsum fields to reflect addition or deletion + * of some frags. + */ +void +ffs_fragacct_swap(struct fs *fs, int fragmap, int32_t fraglist[], int cnt, int needswap) +{ + int inblk; + int field, subfield; + int siz, pos; + + inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; + fragmap <<= 1; + for (siz = 1; siz < fs->fs_frag; siz++) { + if ((inblk & (1 << (siz + (fs->fs_frag & (NBBY - 1))))) == 0) + continue; + field = around[siz]; + subfield = inside[siz]; + for (pos = siz; pos <= fs->fs_frag; pos++) { + if ((fragmap & field) == subfield) { + fraglist[siz] = ufs_rw32( + ufs_rw32(fraglist[siz], needswap) + cnt, + needswap); + pos += siz; + field <<= siz; + subfield <<= siz; + } + field <<= 1; + subfield <<= 1; + } + } +} + +/* + * block operations + * + * check if a block is available + * returns true if all the corresponding bits in the free map are 1 + * returns false if any corresponding bit in the free map is 0 + */ +int +ffs_isblock(fs, cp, h) + struct fs *fs; + u_char *cp; + int32_t h; +{ + u_char mask; + + switch ((int)fs->fs_fragshift) { + case 3: + return (cp[h] == 0xff); + case 2: + mask = 0x0f << ((h & 0x1) << 2); + return ((cp[h >> 1] & mask) == mask); + case 1: + mask = 0x03 << ((h & 0x3) << 1); + return ((cp[h >> 2] & mask) == mask); + case 0: + mask = 0x01 << (h & 0x7); + return ((cp[h >> 3] & mask) == mask); + default: + panic("ffs_isblock: unknown fs_fragshift %d", + (int)fs->fs_fragshift); + } +} + +/* + * check if a block is completely allocated + * returns true if all the corresponding bits in the free map are 0 + * returns false if any corresponding bit in the free map is 1 + */ +int +ffs_isfreeblock(fs, cp, h) + struct fs *fs; + u_char *cp; + int32_t h; +{ + + switch ((int)fs->fs_fragshift) { + case 3: + return (cp[h] == 0); + case 2: + return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0); + case 1: + return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0); + case 0: + return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0); + default: + panic("ffs_isfreeblock: unknown fs_fragshift %d", + (int)fs->fs_fragshift); + } +} + +/* + * take a block out of the map + */ +void +ffs_clrblock(fs, cp, h) + struct fs *fs; + u_char *cp; + int32_t h; +{ + + switch ((int)fs->fs_fragshift) { + case 3: + cp[h] = 0; + return; + case 2: + cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); + return; + case 1: + cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); + return; + case 0: + cp[h >> 3] &= ~(0x01 << (h & 0x7)); + return; + default: + panic("ffs_clrblock: unknown fs_fragshift %d", + (int)fs->fs_fragshift); + } +} + +/* + * put a block into the map + */ +void +ffs_setblock(fs, cp, h) + struct fs *fs; + u_char *cp; + int32_t h; +{ + + switch ((int)fs->fs_fragshift) { + case 3: + cp[h] = 0xff; + return; + case 2: + cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); + return; + case 1: + cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); + return; + case 0: + cp[h >> 3] |= (0x01 << (h & 0x7)); + return; + default: + panic("ffs_setblock: unknown fs_fragshift %d", + (int)fs->fs_fragshift); + } +} diff --git a/usr.sbin/makefs/ffs/mkfs.c b/usr.sbin/makefs/ffs/mkfs.c new file mode 100644 index 0000000..b1bdd09 --- /dev/null +++ b/usr.sbin/makefs/ffs/mkfs.c @@ -0,0 +1,839 @@ +/* $NetBSD: mkfs.c,v 1.20 2004/06/24 22:30:13 lukem Exp $ */ + +/* + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Copyright (c) 1980, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/resource.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "makefs.h" +#include "ffs.h" + +#include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> + +#include "ffs/ufs_bswap.h" +#include "ffs/ufs_inode.h" +#include "ffs/ffs_extern.h" +#include "ffs/newfs_extern.h" + +#ifndef BBSIZE +#define BBSIZE 8192 /* size of boot area, with label */ +#endif + +static void initcg(int, time_t, const fsinfo_t *); +static int ilog2(int); + +static int count_digits(int); + +/* + * make file system for cylinder-group style file systems + */ +#define UMASK 0755 +#define POWEROF2(num) (((num) & ((num) - 1)) == 0) + +union { + struct fs fs; + char pad[SBLOCKSIZE]; +} fsun; +#define sblock fsun.fs +struct csum *fscs; + +union { + struct cg cg; + char pad[FFS_MAXBSIZE]; +} cgun; +#define acg cgun.cg + +char *iobuf; +int iobufsize; + +char writebuf[FFS_MAXBSIZE]; + +static int Oflag; /* format as an 4.3BSD file system */ +static int64_t fssize; /* file system size */ +static int sectorsize; /* bytes/sector */ +static int fsize; /* fragment size */ +static int bsize; /* block size */ +static int maxbsize; /* maximum clustering */ +static int maxblkspercg; +static int minfree; /* free space threshold */ +static int opt; /* optimization preference (space or time) */ +static int density; /* number of bytes per inode */ +static int maxcontig; /* max contiguous blocks to allocate */ +static int maxbpg; /* maximum blocks per file in a cyl group */ +static int bbsize; /* boot block size */ +static int sbsize; /* superblock size */ +static int avgfilesize; /* expected average file size */ +static int avgfpdir; /* expected number of files per directory */ + +struct fs * +ffs_mkfs(const char *fsys, const fsinfo_t *fsopts) +{ + int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg; + int32_t cylno, i, csfrags; + long long sizepb; + void *space; + int size, blks; + int nprintcols, printcolwidth; + ffs_opt_t *ffs_opts = fsopts->fs_specific; + + Oflag = ffs_opts->version; + fssize = fsopts->size / fsopts->sectorsize; + sectorsize = fsopts->sectorsize; + fsize = ffs_opts->fsize; + bsize = ffs_opts->bsize; + maxbsize = ffs_opts->maxbsize; + maxblkspercg = ffs_opts->maxblkspercg; + minfree = ffs_opts->minfree; + opt = ffs_opts->optimization; + density = ffs_opts->density; + maxcontig = ffs_opts->maxcontig; + maxbpg = ffs_opts->maxbpg; + avgfilesize = ffs_opts->avgfilesize; + avgfpdir = ffs_opts->avgfpdir; + bbsize = BBSIZE; + sbsize = SBLOCKSIZE; + + strlcpy(sblock.fs_volname, ffs_opts->label, sizeof(sblock.fs_volname)); + + if (Oflag == 0) { + sblock.fs_old_inodefmt = FS_42INODEFMT; + sblock.fs_maxsymlinklen = 0; + sblock.fs_old_flags = 0; + } else { + sblock.fs_old_inodefmt = FS_44INODEFMT; + sblock.fs_maxsymlinklen = (Oflag == 1 ? MAXSYMLINKLEN_UFS1 : + MAXSYMLINKLEN_UFS2); + sblock.fs_old_flags = FS_FLAGS_UPDATED; + sblock.fs_flags = 0; + } + /* + * Validate the given file system size. + * Verify that its last block can actually be accessed. + * Convert to file system fragment sized units. + */ + if (fssize <= 0) { + printf("preposterous size %lld\n", (long long)fssize); + exit(13); + } + ffs_wtfs(fssize - 1, sectorsize, (char *)&sblock, fsopts); + + /* + * collect and verify the filesystem density info + */ + sblock.fs_avgfilesize = avgfilesize; + sblock.fs_avgfpdir = avgfpdir; + if (sblock.fs_avgfilesize <= 0) + printf("illegal expected average file size %d\n", + sblock.fs_avgfilesize), exit(14); + if (sblock.fs_avgfpdir <= 0) + printf("illegal expected number of files per directory %d\n", + sblock.fs_avgfpdir), exit(15); + /* + * collect and verify the block and fragment sizes + */ + sblock.fs_bsize = bsize; + sblock.fs_fsize = fsize; + if (!POWEROF2(sblock.fs_bsize)) { + printf("block size must be a power of 2, not %d\n", + sblock.fs_bsize); + exit(16); + } + if (!POWEROF2(sblock.fs_fsize)) { + printf("fragment size must be a power of 2, not %d\n", + sblock.fs_fsize); + exit(17); + } + if (sblock.fs_fsize < sectorsize) { + printf("fragment size %d is too small, minimum is %d\n", + sblock.fs_fsize, sectorsize); + exit(18); + } + if (sblock.fs_bsize < MINBSIZE) { + printf("block size %d is too small, minimum is %d\n", + sblock.fs_bsize, MINBSIZE); + exit(19); + } + if (sblock.fs_bsize > FFS_MAXBSIZE) { + printf("block size %d is too large, maximum is %d\n", + sblock.fs_bsize, FFS_MAXBSIZE); + exit(19); + } + if (sblock.fs_bsize < sblock.fs_fsize) { + printf("block size (%d) cannot be smaller than fragment size (%d)\n", + sblock.fs_bsize, sblock.fs_fsize); + exit(20); + } + + if (maxbsize < bsize || !POWEROF2(maxbsize)) { + sblock.fs_maxbsize = sblock.fs_bsize; + printf("Extent size set to %d\n", sblock.fs_maxbsize); + } else if (sblock.fs_maxbsize > FS_MAXCONTIG * sblock.fs_bsize) { + sblock.fs_maxbsize = FS_MAXCONTIG * sblock.fs_bsize; + printf("Extent size reduced to %d\n", sblock.fs_maxbsize); + } else { + sblock.fs_maxbsize = maxbsize; + } + sblock.fs_maxcontig = maxcontig; + if (sblock.fs_maxcontig < sblock.fs_maxbsize / sblock.fs_bsize) { + sblock.fs_maxcontig = sblock.fs_maxbsize / sblock.fs_bsize; + printf("Maxcontig raised to %d\n", sblock.fs_maxbsize); + } + + if (sblock.fs_maxcontig > 1) + sblock.fs_contigsumsize = MIN(sblock.fs_maxcontig,FS_MAXCONTIG); + + sblock.fs_bmask = ~(sblock.fs_bsize - 1); + sblock.fs_fmask = ~(sblock.fs_fsize - 1); + sblock.fs_qbmask = ~sblock.fs_bmask; + sblock.fs_qfmask = ~sblock.fs_fmask; + for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1) + sblock.fs_bshift++; + for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1) + sblock.fs_fshift++; + sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize); + for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1) + sblock.fs_fragshift++; + if (sblock.fs_frag > MAXFRAG) { + printf("fragment size %d is too small, " + "minimum with block size %d is %d\n", + sblock.fs_fsize, sblock.fs_bsize, + sblock.fs_bsize / MAXFRAG); + exit(21); + } + sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize); + sblock.fs_size = sblock.fs_providersize = fssize = + dbtofsb(&sblock, fssize); + + if (Oflag <= 1) { + sblock.fs_magic = FS_UFS1_MAGIC; + sblock.fs_sblockloc = SBLOCK_UFS1; + sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs1_daddr_t); + sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode); + sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) * + sizeof (ufs1_daddr_t)); + sblock.fs_old_inodefmt = FS_44INODEFMT; + sblock.fs_old_cgoffset = 0; + sblock.fs_old_cgmask = 0xffffffff; + sblock.fs_old_size = sblock.fs_size; + sblock.fs_old_rotdelay = 0; + sblock.fs_old_rps = 60; + sblock.fs_old_nspf = sblock.fs_fsize / sectorsize; + sblock.fs_old_cpg = 1; + sblock.fs_old_interleave = 1; + sblock.fs_old_trackskew = 0; + sblock.fs_old_cpc = 0; + sblock.fs_old_postblformat = 1; + sblock.fs_old_nrpos = 1; + } else { + sblock.fs_magic = FS_UFS2_MAGIC; + sblock.fs_sblockloc = SBLOCK_UFS2; + sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs2_daddr_t); + sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode); + sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) * + sizeof (ufs2_daddr_t)); + } + + sblock.fs_sblkno = + roundup(howmany(sblock.fs_sblockloc + SBLOCKSIZE, sblock.fs_fsize), + sblock.fs_frag); + sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno + + roundup(howmany(SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag)); + sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag; + sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1; + for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) { + sizepb *= NINDIR(&sblock); + sblock.fs_maxfilesize += sizepb; + } + + /* + * Calculate the number of blocks to put into each cylinder group. + * + * This algorithm selects the number of blocks per cylinder + * group. The first goal is to have at least enough data blocks + * in each cylinder group to meet the density requirement. Once + * this goal is achieved we try to expand to have at least + * 1 cylinder group. Once this goal is achieved, we pack as + * many blocks into each cylinder group map as will fit. + * + * We start by calculating the smallest number of blocks that we + * can put into each cylinder group. If this is too big, we reduce + * the density until it fits. + */ + origdensity = density; + for (;;) { + fragsperinode = MAX(numfrags(&sblock, density), 1); + minfpg = fragsperinode * INOPB(&sblock); + if (minfpg > sblock.fs_size) + minfpg = sblock.fs_size; + sblock.fs_ipg = INOPB(&sblock); + sblock.fs_fpg = roundup(sblock.fs_iblkno + + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); + if (sblock.fs_fpg < minfpg) + sblock.fs_fpg = minfpg; + sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), + INOPB(&sblock)); + sblock.fs_fpg = roundup(sblock.fs_iblkno + + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); + if (sblock.fs_fpg < minfpg) + sblock.fs_fpg = minfpg; + sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), + INOPB(&sblock)); + if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) + break; + density -= sblock.fs_fsize; + } + if (density != origdensity) + printf("density reduced from %d to %d\n", origdensity, density); + + if (maxblkspercg <= 0 || maxblkspercg >= fssize) + maxblkspercg = fssize - 1; + /* + * Start packing more blocks into the cylinder group until + * it cannot grow any larger, the number of cylinder groups + * drops below 1, or we reach the size requested. + */ + for ( ; sblock.fs_fpg < maxblkspercg; sblock.fs_fpg += sblock.fs_frag) { + sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), + INOPB(&sblock)); + if (sblock.fs_size / sblock.fs_fpg < 1) + break; + if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) + continue; + if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize) + break; + sblock.fs_fpg -= sblock.fs_frag; + sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), + INOPB(&sblock)); + break; + } + /* + * Check to be sure that the last cylinder group has enough blocks + * to be viable. If it is too small, reduce the number of blocks + * per cylinder group which will have the effect of moving more + * blocks into the last cylinder group. + */ + optimalfpg = sblock.fs_fpg; + for (;;) { + sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg); + lastminfpg = roundup(sblock.fs_iblkno + + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); + if (sblock.fs_size < lastminfpg) { + printf("Filesystem size %lld < minimum size of %d\n", + (long long)sblock.fs_size, lastminfpg); + exit(28); + } + if (sblock.fs_size % sblock.fs_fpg >= lastminfpg || + sblock.fs_size % sblock.fs_fpg == 0) + break; + sblock.fs_fpg -= sblock.fs_frag; + sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), + INOPB(&sblock)); + } + if (optimalfpg != sblock.fs_fpg) + printf("Reduced frags per cylinder group from %d to %d %s\n", + optimalfpg, sblock.fs_fpg, "to enlarge last cyl group"); + sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); + sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock); + if (Oflag <= 1) { + sblock.fs_old_spc = sblock.fs_fpg * sblock.fs_old_nspf; + sblock.fs_old_nsect = sblock.fs_old_spc; + sblock.fs_old_npsect = sblock.fs_old_spc; + sblock.fs_old_ncyl = sblock.fs_ncg; + } + + /* + * fill in remaining fields of the super block + */ + sblock.fs_csaddr = cgdmin(&sblock, 0); + sblock.fs_cssize = + fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); + + /* + * Setup memory for temporary in-core cylgroup summaries. + * Cribbed from ffs_mountfs(). + */ + size = sblock.fs_cssize; + blks = howmany(size, sblock.fs_fsize); + if (sblock.fs_contigsumsize > 0) + size += sblock.fs_ncg * sizeof(int32_t); + if ((space = (char *)calloc(1, size)) == NULL) + err(1, "memory allocation error for cg summaries"); + sblock.fs_csp = space; + space = (char *)space + sblock.fs_cssize; + if (sblock.fs_contigsumsize > 0) { + int32_t *lp; + + sblock.fs_maxcluster = lp = space; + for (i = 0; i < sblock.fs_ncg; i++) + *lp++ = sblock.fs_contigsumsize; + } + + sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs)); + if (sblock.fs_sbsize > SBLOCKSIZE) + sblock.fs_sbsize = SBLOCKSIZE; + sblock.fs_minfree = minfree; + sblock.fs_maxcontig = maxcontig; + sblock.fs_maxbpg = maxbpg; + sblock.fs_optim = opt; + sblock.fs_cgrotor = 0; + sblock.fs_pendingblocks = 0; + sblock.fs_pendinginodes = 0; + sblock.fs_cstotal.cs_ndir = 0; + sblock.fs_cstotal.cs_nbfree = 0; + sblock.fs_cstotal.cs_nifree = 0; + sblock.fs_cstotal.cs_nffree = 0; + sblock.fs_fmod = 0; + sblock.fs_ronly = 0; + sblock.fs_state = 0; + sblock.fs_clean = FS_ISCLEAN; + sblock.fs_ronly = 0; + sblock.fs_id[0] = start_time.tv_sec; + sblock.fs_id[1] = random(); + sblock.fs_fsmnt[0] = '\0'; + csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize); + sblock.fs_dsize = sblock.fs_size - sblock.fs_sblkno - + sblock.fs_ncg * (sblock.fs_dblkno - sblock.fs_sblkno); + sblock.fs_cstotal.cs_nbfree = + fragstoblks(&sblock, sblock.fs_dsize) - + howmany(csfrags, sblock.fs_frag); + sblock.fs_cstotal.cs_nffree = + fragnum(&sblock, sblock.fs_size) + + (fragnum(&sblock, csfrags) > 0 ? + sblock.fs_frag - fragnum(&sblock, csfrags) : 0); + sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - ROOTINO; + sblock.fs_cstotal.cs_ndir = 0; + sblock.fs_dsize -= csfrags; + sblock.fs_time = start_time.tv_sec; + if (Oflag <= 1) { + sblock.fs_old_time = start_time.tv_sec; + sblock.fs_old_dsize = sblock.fs_dsize; + sblock.fs_old_csaddr = sblock.fs_csaddr; + sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; + sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; + sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; + sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; + } + /* + * Dump out summary information about file system. + */ +#define B2MBFACTOR (1 / (1024.0 * 1024.0)) + printf("%s: %.1fMB (%lld sectors) block size %d, " + "fragment size %d\n", + fsys, (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, + (long long)fsbtodb(&sblock, sblock.fs_size), + sblock.fs_bsize, sblock.fs_fsize); + printf("\tusing %d cylinder groups of %.2fMB, %d blks, " + "%d inodes.\n", + sblock.fs_ncg, + (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, + sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg); +#undef B2MBFACTOR + /* + * Now determine how wide each column will be, and calculate how + * many columns will fit in a 76 char line. 76 is the width of the + * subwindows in sysinst. + */ + printcolwidth = count_digits( + fsbtodb(&sblock, cgsblock(&sblock, sblock.fs_ncg -1))); + nprintcols = 76 / (printcolwidth + 2); + + /* + * allocate space for superblock, cylinder group map, and + * two sets of inode blocks. + */ + if (sblock.fs_bsize < SBLOCKSIZE) + iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize; + else + iobufsize = 4 * sblock.fs_bsize; + if ((iobuf = malloc(iobufsize)) == 0) { + printf("Cannot allocate I/O buffer\n"); + exit(38); + } + memset(iobuf, 0, iobufsize); + /* + * Make a copy of the superblock into the buffer that we will be + * writing out in each cylinder group. + */ + memcpy(writebuf, &sblock, sbsize); + if (fsopts->needswap) + ffs_sb_swap(&sblock, (struct fs*)writebuf); + memcpy(iobuf, writebuf, SBLOCKSIZE); + + printf("super-block backups (for fsck -b #) at:"); + for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { + initcg(cylno, start_time.tv_sec, fsopts); + if (cylno % nprintcols == 0) + printf("\n"); + printf(" %*lld,", printcolwidth, + (long long)fsbtodb(&sblock, cgsblock(&sblock, cylno))); + fflush(stdout); + } + printf("\n"); + + /* + * Now construct the initial file system, + * then write out the super-block. + */ + sblock.fs_time = start_time.tv_sec; + if (Oflag <= 1) { + sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; + sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; + sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; + sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; + } + if (fsopts->needswap) + sblock.fs_flags |= FS_SWAPPED; + ffs_write_superblock(&sblock, fsopts); + return (&sblock); +} + +/* + * Write out the superblock and its duplicates, + * and the cylinder group summaries + */ +void +ffs_write_superblock(struct fs *fs, const fsinfo_t *fsopts) +{ + int cylno, size, blks, i, saveflag; + void *space; + char *wrbuf; + + saveflag = fs->fs_flags & FS_INTERNAL; + fs->fs_flags &= ~FS_INTERNAL; + + memcpy(writebuf, &sblock, sbsize); + if (fsopts->needswap) + ffs_sb_swap(fs, (struct fs*)writebuf); + ffs_wtfs(fs->fs_sblockloc / sectorsize, sbsize, writebuf, fsopts); + + /* Write out the duplicate super blocks */ + for (cylno = 0; cylno < fs->fs_ncg; cylno++) + ffs_wtfs(fsbtodb(fs, cgsblock(fs, cylno)), + sbsize, writebuf, fsopts); + + /* Write out the cylinder group summaries */ + size = fs->fs_cssize; + blks = howmany(size, fs->fs_fsize); + space = (void *)fs->fs_csp; + if ((wrbuf = malloc(size)) == NULL) + err(1, "ffs_write_superblock: malloc %d", size); + for (i = 0; i < blks; i+= fs->fs_frag) { + size = fs->fs_bsize; + if (i + fs->fs_frag > blks) + size = (blks - i) * fs->fs_fsize; + if (fsopts->needswap) + ffs_csum_swap((struct csum *)space, + (struct csum *)wrbuf, size); + else + memcpy(wrbuf, space, (u_int)size); + ffs_wtfs(fsbtodb(fs, fs->fs_csaddr + i), size, wrbuf, fsopts); + space = (char *)space + size; + } + free(wrbuf); + fs->fs_flags |= saveflag; +} + +/* + * Initialize a cylinder group. + */ +static void +initcg(int cylno, time_t utime, const fsinfo_t *fsopts) +{ + daddr_t cbase, dmax; + int32_t i, j, d, dlower, dupper, blkno; + struct ufs1_dinode *dp1; + struct ufs2_dinode *dp2; + int start; + + /* + * Determine block bounds for cylinder group. + * Allow space for super block summary information in first + * cylinder group. + */ + cbase = cgbase(&sblock, cylno); + dmax = cbase + sblock.fs_fpg; + if (dmax > sblock.fs_size) + dmax = sblock.fs_size; + dlower = cgsblock(&sblock, cylno) - cbase; + dupper = cgdmin(&sblock, cylno) - cbase; + if (cylno == 0) + dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); + memset(&acg, 0, sblock.fs_cgsize); + acg.cg_time = utime; + acg.cg_magic = CG_MAGIC; + acg.cg_cgx = cylno; + acg.cg_niblk = sblock.fs_ipg; + acg.cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ? + sblock.fs_ipg : 2 * INOPB(&sblock); + acg.cg_ndblk = dmax - cbase; + if (sblock.fs_contigsumsize > 0) + acg.cg_nclusterblks = acg.cg_ndblk >> sblock.fs_fragshift; + start = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield); + if (Oflag == 2) { + acg.cg_iusedoff = start; + } else { + if (cylno == sblock.fs_ncg - 1) + acg.cg_old_ncyl = howmany(acg.cg_ndblk, + sblock.fs_fpg / sblock.fs_old_cpg); + else + acg.cg_old_ncyl = sblock.fs_old_cpg; + acg.cg_old_time = acg.cg_time; + acg.cg_time = 0; + acg.cg_old_niblk = acg.cg_niblk; + acg.cg_niblk = 0; + acg.cg_initediblk = 0; + acg.cg_old_btotoff = start; + acg.cg_old_boff = acg.cg_old_btotoff + + sblock.fs_old_cpg * sizeof(int32_t); + acg.cg_iusedoff = acg.cg_old_boff + + sblock.fs_old_cpg * sizeof(u_int16_t); + } + acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); + if (sblock.fs_contigsumsize <= 0) { + acg.cg_nextfreeoff = acg.cg_freeoff + + howmany(sblock.fs_fpg, CHAR_BIT); + } else { + acg.cg_clustersumoff = acg.cg_freeoff + + howmany(sblock.fs_fpg, CHAR_BIT) - sizeof(int32_t); + acg.cg_clustersumoff = + roundup(acg.cg_clustersumoff, sizeof(int32_t)); + acg.cg_clusteroff = acg.cg_clustersumoff + + (sblock.fs_contigsumsize + 1) * sizeof(int32_t); + acg.cg_nextfreeoff = acg.cg_clusteroff + + howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); + } + if (acg.cg_nextfreeoff > sblock.fs_cgsize) { + printf("Panic: cylinder group too big\n"); + exit(37); + } + acg.cg_cs.cs_nifree += sblock.fs_ipg; + if (cylno == 0) + for (i = 0; i < ROOTINO; i++) { + setbit(cg_inosused_swap(&acg, 0), i); + acg.cg_cs.cs_nifree--; + } + if (cylno > 0) { + /* + * In cylno 0, beginning space is reserved + * for boot and super blocks. + */ + for (d = 0, blkno = 0; d < dlower;) { + ffs_setblock(&sblock, cg_blksfree_swap(&acg, 0), blkno); + if (sblock.fs_contigsumsize > 0) + setbit(cg_clustersfree_swap(&acg, 0), blkno); + acg.cg_cs.cs_nbfree++; + d += sblock.fs_frag; + blkno++; + } + } + if ((i = (dupper & (sblock.fs_frag - 1))) != 0) { + acg.cg_frsum[sblock.fs_frag - i]++; + for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) { + setbit(cg_blksfree_swap(&acg, 0), dupper); + acg.cg_cs.cs_nffree++; + } + } + for (d = dupper, blkno = dupper >> sblock.fs_fragshift; + d + sblock.fs_frag <= acg.cg_ndblk; ) { + ffs_setblock(&sblock, cg_blksfree_swap(&acg, 0), blkno); + if (sblock.fs_contigsumsize > 0) + setbit(cg_clustersfree_swap(&acg, 0), blkno); + acg.cg_cs.cs_nbfree++; + d += sblock.fs_frag; + blkno++; + } + if (d < acg.cg_ndblk) { + acg.cg_frsum[acg.cg_ndblk - d]++; + for (; d < acg.cg_ndblk; d++) { + setbit(cg_blksfree_swap(&acg, 0), d); + acg.cg_cs.cs_nffree++; + } + } + if (sblock.fs_contigsumsize > 0) { + int32_t *sump = cg_clustersum_swap(&acg, 0); + u_char *mapp = cg_clustersfree_swap(&acg, 0); + int map = *mapp++; + int bit = 1; + int run = 0; + + for (i = 0; i < acg.cg_nclusterblks; i++) { + if ((map & bit) != 0) { + run++; + } else if (run != 0) { + if (run > sblock.fs_contigsumsize) + run = sblock.fs_contigsumsize; + sump[run]++; + run = 0; + } + if ((i & (CHAR_BIT - 1)) != (CHAR_BIT - 1)) { + bit <<= 1; + } else { + map = *mapp++; + bit = 1; + } + } + if (run != 0) { + if (run > sblock.fs_contigsumsize) + run = sblock.fs_contigsumsize; + sump[run]++; + } + } + sblock.fs_cs(&sblock, cylno) = acg.cg_cs; + /* + * Write out the duplicate super block, the cylinder group map + * and two blocks worth of inodes in a single write. + */ + start = sblock.fs_bsize > SBLOCKSIZE ? sblock.fs_bsize : SBLOCKSIZE; + memcpy(&iobuf[start], &acg, sblock.fs_cgsize); + if (fsopts->needswap) + ffs_cg_swap(&acg, (struct cg*)&iobuf[start], &sblock); + start += sblock.fs_bsize; + dp1 = (struct ufs1_dinode *)(&iobuf[start]); + dp2 = (struct ufs2_dinode *)(&iobuf[start]); + for (i = 0; i < acg.cg_initediblk; i++) { + if (sblock.fs_magic == FS_UFS1_MAGIC) { + /* No need to swap, it'll stay random */ + dp1->di_gen = random(); + dp1++; + } else { + dp2->di_gen = random(); + dp2++; + } + } + ffs_wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), iobufsize, iobuf, + fsopts); + /* + * For the old file system, we have to initialize all the inodes. + */ + if (Oflag <= 1) { + for (i = 2 * sblock.fs_frag; + i < sblock.fs_ipg / INOPF(&sblock); + i += sblock.fs_frag) { + dp1 = (struct ufs1_dinode *)(&iobuf[start]); + for (j = 0; j < INOPB(&sblock); j++) { + dp1->di_gen = random(); + dp1++; + } + ffs_wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), + sblock.fs_bsize, &iobuf[start], fsopts); + } + } +} + +/* + * read a block from the file system + */ +void +ffs_rdfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts) +{ + int n; + off_t offset; + + offset = bno; + offset *= fsopts->sectorsize; + if (lseek(fsopts->fd, offset, SEEK_SET) < 0) + err(1, "ffs_rdfs: seek error for sector %lld: %s\n", + (long long)bno, strerror(errno)); + n = read(fsopts->fd, bf, size); + if (n == -1) { + abort(); + err(1, "ffs_rdfs: read error bno %lld size %d", (long long)bno, + size); + } + else if (n != size) + errx(1, "ffs_rdfs: read error for sector %lld: %s\n", + (long long)bno, strerror(errno)); +} + +/* + * write a block to the file system + */ +void +ffs_wtfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts) +{ + int n; + off_t offset; + + offset = bno; + offset *= fsopts->sectorsize; + if (lseek(fsopts->fd, offset, SEEK_SET) < 0) + err(1, "wtfs: seek error for sector %lld: %s\n", + (long long)bno, strerror(errno)); + n = write(fsopts->fd, bf, size); + if (n == -1) + err(1, "wtfs: write error for sector %lld: %s\n", + (long long)bno, strerror(errno)); + else if (n != size) + errx(1, "wtfs: write error for sector %lld: %s\n", + (long long)bno, strerror(errno)); +} + + +/* Determine how many digits are needed to print a given integer */ +static int +count_digits(int num) +{ + int ndig; + + for(ndig = 1; num > 9; num /=10, ndig++); + + return (ndig); +} + +static int +ilog2(int val) +{ + u_int n; + + for (n = 0; n < sizeof(n) * CHAR_BIT; n++) + if (1 << n == val) + return (n); + errx(1, "ilog2: %d is not a power of 2\n", val); +} diff --git a/usr.sbin/makefs/ffs/newfs_extern.h b/usr.sbin/makefs/ffs/newfs_extern.h new file mode 100644 index 0000000..a54c0e2 --- /dev/null +++ b/usr.sbin/makefs/ffs/newfs_extern.h @@ -0,0 +1,36 @@ +/* $NetBSD: newfs_extern.h,v 1.3 2009/10/21 01:07:47 snj Exp $ */ +/* From: NetBSD: extern.h,v 1.3 2000/12/01 12:03:27 simonb Exp $ */ + +/* + * Copyright (c) 1997 Christos Zoulas. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* prototypes */ +struct fs *ffs_mkfs(const char *, const fsinfo_t *); +void ffs_write_superblock(struct fs *, const fsinfo_t *); +void ffs_rdfs(daddr_t, int, void *, const fsinfo_t *); +void ffs_wtfs(daddr_t, int, void *, const fsinfo_t *); + +#define FFS_MAXBSIZE 65536 diff --git a/usr.sbin/makefs/ffs/ufs_bmap.c b/usr.sbin/makefs/ffs/ufs_bmap.c new file mode 100644 index 0000000..b65b416 --- /dev/null +++ b/usr.sbin/makefs/ffs/ufs_bmap.c @@ -0,0 +1,140 @@ +/* $NetBSD: ufs_bmap.c,v 1.14 2004/06/20 22:20:18 jmc Exp $ */ +/* From: NetBSD: ufs_bmap.c,v 1.14 2001/11/08 05:00:51 chs Exp */ + +/* + * Copyright (c) 1989, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_bmap.c 8.8 (Berkeley) 8/11/95 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/time.h> + +#include <assert.h> +#include <errno.h> +#include <strings.h> + +#include "makefs.h" + +#include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> + +#include "ffs/ufs_bswap.h" +#include "ffs/ufs_inode.h" +#include "ffs/ffs_extern.h" + +/* + * Create an array of logical block number/offset pairs which represent the + * path of indirect blocks required to access a data block. The first "pair" + * contains the logical block number of the appropriate single, double or + * triple indirect block and the offset into the inode indirect block array. + * Note, the logical block number of the inode single/double/triple indirect + * block appears twice in the array, once with the offset into the i_ffs_ib and + * once with the offset into the page itself. + */ +int +ufs_getlbns(struct inode *ip, daddr_t bn, struct indir *ap, int *nump) +{ + daddr_t metalbn, realbn; + int64_t blockcnt; + int lbc; + int i, numlevels, off; + u_long lognindir; + + lognindir = ffs(NINDIR(ip->i_fs)) - 1; + if (nump) + *nump = 0; + numlevels = 0; + realbn = bn; + if ((long)bn < 0) + bn = -(long)bn; + + assert (bn >= NDADDR); + + /* + * Determine the number of levels of indirection. After this loop + * is done, blockcnt indicates the number of data blocks possible + * at the given level of indirection, and NIADDR - i is the number + * of levels of indirection needed to locate the requested block. + */ + + bn -= NDADDR; + for (lbc = 0, i = NIADDR;; i--, bn -= blockcnt) { + if (i == 0) + return (EFBIG); + + lbc += lognindir; + blockcnt = (int64_t)1 << lbc; + + if (bn < blockcnt) + break; + } + + /* Calculate the address of the first meta-block. */ + if (realbn >= 0) + metalbn = -(realbn - bn + NIADDR - i); + else + metalbn = -(-realbn - bn + NIADDR - i); + + /* + * At each iteration, off is the offset into the bap array which is + * an array of disk addresses at the current level of indirection. + * The logical block number and the offset in that block are stored + * into the argument array. + */ + ap->in_lbn = metalbn; + ap->in_off = off = NIADDR - i; + ap++; + for (++numlevels; i <= NIADDR; i++) { + /* If searching for a meta-data block, quit when found. */ + if (metalbn == realbn) + break; + + lbc -= lognindir; + blockcnt = (int64_t)1 << lbc; + off = (bn >> lbc) & (NINDIR(ip->i_fs) - 1); + + ++numlevels; + ap->in_lbn = metalbn; + ap->in_off = off; + ++ap; + + metalbn -= -1 + (off << lbc); + } + if (nump) + *nump = numlevels; + return (0); +} diff --git a/usr.sbin/makefs/ffs/ufs_bswap.h b/usr.sbin/makefs/ffs/ufs_bswap.h new file mode 100644 index 0000000..6e7cc42 --- /dev/null +++ b/usr.sbin/makefs/ffs/ufs_bswap.h @@ -0,0 +1,90 @@ +/* $NetBSD: ufs_bswap.h,v 1.13 2003/10/05 17:48:50 bouyer Exp $ */ + +/* + * Copyright (c) 1998 Manuel Bouyer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Manuel Bouyer. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _UFS_UFS_BSWAP_H_ +#define _UFS_UFS_BSWAP_H_ + +#if defined(_KERNEL_OPT) +#include "opt_ffs.h" +#endif + +#include <sys/endian.h> + +#include "makefs.h" + +/* Macros to access UFS flags */ +#ifdef FFS_EI +#define UFS_MPNEEDSWAP(mp) (VFSTOUFS(mp)->um_flags & UFS_NEEDSWAP) +#define UFS_FSNEEDSWAP(fs) ((fs)->fs_flags & FS_SWAPPED) +#define UFS_IPNEEDSWAP(ip) UFS_MPNEEDSWAP(ITOV(ip)->v_mount) +#else +#define UFS_MPNEEDSWAP(mp) (0) +#define UFS_FSNEEDSWAP(fs) (0) +#define UFS_IPNEEDSWAP(ip) (0) +#endif + +#if !defined(_KERNEL) || defined(FFS_EI) +/* inlines for access to swapped data */ +static __inline u_int16_t ufs_rw16 __P((u_int16_t, int)); +static __inline u_int32_t ufs_rw32 __P((u_int32_t, int)); +static __inline u_int64_t ufs_rw64 __P((u_int64_t, int)); + +static __inline u_int16_t +ufs_rw16(u_int16_t a, int ns) +{ + return ((ns) ? bswap16(a) : (a)); +} +static __inline u_int32_t +ufs_rw32(u_int32_t a, int ns) +{ + return ((ns) ? bswap32(a) : (a)); +} +static __inline u_int64_t +ufs_rw64(u_int64_t a, int ns) +{ + return ((ns) ? bswap64(a) : (a)); +} +#else +#define ufs_rw16(a, ns) ((uint16_t)(a)) +#define ufs_rw32(a, ns) ((uint32_t)(a)) +#define ufs_rw64(a, ns) ((uint64_t)(a)) +#endif + +#define ufs_add16(a, b, ns) \ + (a) = ufs_rw16(ufs_rw16((a), (ns)) + (b), (ns)) +#define ufs_add32(a, b, ns) \ + (a) = ufs_rw32(ufs_rw32((a), (ns)) + (b), (ns)) +#define ufs_add64(a, b, ns) \ + (a) = ufs_rw64(ufs_rw64((a), (ns)) + (b), (ns)) + +#endif /* !_UFS_UFS_BSWAP_H_ */ diff --git a/usr.sbin/makefs/ffs/ufs_inode.h b/usr.sbin/makefs/ffs/ufs_inode.h new file mode 100644 index 0000000..8286f86 --- /dev/null +++ b/usr.sbin/makefs/ffs/ufs_inode.h @@ -0,0 +1,97 @@ +/* $NetBSD: ufs_inode.h,v 1.3 2003/08/07 11:25:34 agc Exp $ */ +/* From: NetBSD: inode.h,v 1.27 2001/12/18 10:57:23 fvdl Exp $ */ + +/* + * Copyright (c) 1982, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)inode.h 8.9 (Berkeley) 5/14/95 + * $FreeBSD$ + */ + +union dinode { + struct ufs1_dinode ffs1_din; + struct ufs2_dinode ffs2_din; +}; + +struct inode { + ino_t i_number; /* The identity of the inode. */ + struct fs *i_fs; /* File system */ + union dinode i_din; + int i_fd; /* File descriptor */ + uint64_t i_size; +}; + +#define i_ffs1_atime i_din.ffs1_din.di_atime +#define i_ffs1_atimensec i_din.ffs1_din.di_atimensec +#define i_ffs1_blocks i_din.ffs1_din.di_blocks +#define i_ffs1_ctime i_din.ffs1_din.di_ctime +#define i_ffs1_ctimensec i_din.ffs1_din.di_ctimensec +#define i_ffs1_db i_din.ffs1_din.di_db +#define i_ffs1_flags i_din.ffs1_din.di_flags +#define i_ffs1_gen i_din.ffs1_din.di_gen +#define i_ffs11_gid i_din.ffs1_din.di_gid +#define i_ffs1_ib i_din.ffs1_din.di_ib +#define i_ffs1_mode i_din.ffs1_din.di_mode +#define i_ffs1_mtime i_din.ffs1_din.di_mtime +#define i_ffs1_mtimensec i_din.ffs1_din.di_mtimensec +#define i_ffs1_nlink i_din.ffs1_din.di_nlink +#define i_ffs1_rdev i_din.ffs1_din.di_rdev +#define i_ffs1_shortlink i_din.ffs1_din.db +#define i_ffs1_size i_din.ffs1_din.di_size +#define i_ffs1_uid i_din.ffs1_din.di_uid + +#define i_ffs2_atime i_din.ffs2_din.di_atime +#define i_ffs2_atimensec i_din.ffs2_din.di_atimensec +#define i_ffs2_blocks i_din.ffs2_din.di_blocks +#define i_ffs2_ctime i_din.ffs2_din.di_ctime +#define i_ffs2_ctimensec i_din.ffs2_din.di_ctimensec +#define i_ffs2_birthtime i_din.ffs2_din.di_birthtime +#define i_ffs2_birthnsec i_din.ffs2_din.di_birthnsec +#define i_ffs2_db i_din.ffs2_din.di_db +#define i_ffs2_flags i_din.ffs2_din.di_flags +#define i_ffs2_gen i_din.ffs2_din.di_gen +#define i_ffs21_gid i_din.ffs2_din.di_gid +#define i_ffs2_ib i_din.ffs2_din.di_ib +#define i_ffs2_mode i_din.ffs2_din.di_mode +#define i_ffs2_mtime i_din.ffs2_din.di_mtime +#define i_ffs2_mtimensec i_din.ffs2_din.di_mtimensec +#define i_ffs2_nlink i_din.ffs2_din.di_nlink +#define i_ffs2_rdev i_din.ffs2_din.di_rdev +#define i_ffs2_shortlink i_din.ffs2_din.db +#define i_ffs2_size i_din.ffs2_din.di_size +#define i_ffs2_uid i_din.ffs2_din.di_uid + +#undef DIP +#define DIP(ip, field) \ + (((ip)->i_fs->fs_magic == FS_UFS1_MAGIC) ? \ + (ip)->i_ffs1_##field : (ip)->i_ffs2_##field) |