📄 lfs.c
字号:
/*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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. */#ifndef lintstatic char sccsid[] = "@(#)lfs.c 8.1 (Berkeley) 6/5/93";#endif /* not lint */#include <sys/param.h>#include <sys/disklabel.h>#include <sys/time.h>#include <sys/mount.h>#include <ufs/ufs/dir.h>#include <ufs/ufs/quota.h>#include <ufs/ufs/dinode.h>#include <ufs/lfs/lfs.h>#include <unistd.h>#include <errno.h>#include <stdlib.h>#include <string.h>#include "config.h"#include "extern.h"/* * This table is indexed by the log base 2 of the block size. * It returns the maximum file size allowed in a file system * with the specified block size. For block sizes smaller than * 8K, the size is limited by tha maximum number of blocks that * can be reached by triply indirect blocks: * NDADDR + INOPB(bsize) + INOPB(bsize)^2 + INOPB(bsize)^3 * For block size of 8K or larger, the file size is limited by the * number of blocks that can be represented in the file system. Since * we use negative block numbers to represent indirect blocks, we can * have a maximum of 2^31 blocks. */u_quad_t maxtable[] = { /* 1 */ -1, /* 2 */ -1, /* 4 */ -1, /* 8 */ -1, /* 16 */ -1, /* 32 */ -1, /* 64 */ -1, /* 128 */ -1, /* 256 */ -1, /* 512 */ NDADDR + 128 + 128 * 128 + 128 * 128 * 128, /* 1024 */ NDADDR + 256 + 256 * 256 + 256 * 256 * 256, /* 2048 */ NDADDR + 512 + 512 * 512 + 512 * 512 * 512, /* 4096 */ NDADDR + 1024 + 1024 * 1024 + 1024 * 1024 * 1024, /* 8192 */ 1 << 31, /* 16 K */ 1 << 31, /* 32 K */ 1 << 31,};static struct lfs lfs_default = { /* lfs_magic */ LFS_MAGIC, /* lfs_version */ LFS_VERSION, /* lfs_size */ 0, /* lfs_ssize */ DFL_LFSSEG/DFL_LFSBLOCK, /* lfs_dsize */ 0, /* lfs_bsize */ DFL_LFSBLOCK, /* lfs_fsize */ DFL_LFSBLOCK, /* lfs_frag */ 1, /* lfs_free */ LFS_FIRST_INUM, /* lfs_bfree */ 0, /* lfs_nfiles */ 0, /* lfs_avail */ 0, /* lfs_uinodes */ 0, /* lfs_idaddr */ 0, /* lfs_ifile */ LFS_IFILE_INUM, /* lfs_lastseg */ 0, /* lfs_nextseg */ 0, /* lfs_curseg */ 0, /* lfs_offset */ 0, /* lfs_lastpseg */ 0, /* lfs_tstamp */ 0, /* lfs_minfree */ MINFREE, /* lfs_maxfilesize */ 0, /* lfs_dbpseg */ DFL_LFSSEG/DEV_BSIZE, /* lfs_inopb */ DFL_LFSBLOCK/sizeof(struct dinode), /* lfs_ifpb */ DFL_LFSBLOCK/sizeof(IFILE), /* lfs_sepb */ DFL_LFSBLOCK/sizeof(SEGUSE), /* lfs_nindir */ DFL_LFSBLOCK/sizeof(daddr_t), /* lfs_nseg */ 0, /* lfs_nspf */ 0, /* lfs_cleansz */ 0, /* lfs_segtabsz */ 0, /* lfs_segmask */ DFL_LFSSEG_MASK, /* lfs_segshift */ DFL_LFSSEG_SHIFT, /* lfs_bmask */ DFL_LFSBLOCK_MASK, /* lfs_bshift */ DFL_LFSBLOCK_SHIFT, /* lfs_ffmask */ 0, /* lfs_ffshift */ 0, /* lfs_fbmask */ 0, /* lfs_fbshift */ 0, /* lfs_fsbtodb */ 0, /* lfs_sushift */ 0, /* lfs_sboffs */ { 0 }, /* lfs_sp */ NULL, /* lfs_ivnode */ NULL, /* lfs_seglock */ 0, /* lfs_lockpid */ 0, /* lfs_iocount */ 0, /* lfs_writer */ 0, /* lfs_dirops */ 0, /* lfs_doifile */ 0, /* lfs_nactive */ 0, /* lfs_fmod */ 0, /* lfs_clean */ 0, /* lfs_ronly */ 0, /* lfs_flags */ 0, /* lfs_fsmnt */ { 0 }, /* lfs_pad */ { 0 }, /* lfs_cksum */ 0};struct direct lfs_root_dir[] = { { ROOTINO, sizeof(struct direct), DT_DIR, 1, "."}, { ROOTINO, sizeof(struct direct), DT_DIR, 2, ".."}, { LFS_IFILE_INUM, sizeof(struct direct), DT_REG, 5, "ifile"}, { LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 10, "lost+found"},};struct direct lfs_lf_dir[] = { { LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 1, "." }, { ROOTINO, sizeof(struct direct), DT_DIR, 2, ".." },};static daddr_t make_dinode __P((ino_t, struct dinode *, int, daddr_t, struct lfs *));static void make_dir __P(( void *, struct direct *, int));static void put __P((int, off_t, void *, size_t));intmake_lfs(fd, lp, partp, minfree, block_size, seg_size) int fd; struct disklabel *lp; struct partition *partp; int minfree; int block_size; int seg_size;{ struct dinode *dip; /* Pointer to a disk inode */ struct dinode *dpagep; /* Pointer to page of disk inodes */ CLEANERINFO *cleaninfo; /* Segment cleaner information table */ FINFO file_info; /* File info structure in summary blocks */ IFILE *ifile; /* Pointer to array of ifile structures */ IFILE *ip; /* Pointer to array of ifile structures */ struct lfs *lfsp; /* Superblock */ SEGUSE *segp; /* Segment usage table */ SEGUSE *segtable; /* Segment usage table */ SEGSUM summary; /* Segment summary structure */ SEGSUM *sp; /* Segment summary pointer */ daddr_t last_sb_addr; /* Address of superblocks */ daddr_t last_addr; /* Previous segment address */ daddr_t sb_addr; /* Address of superblocks */ daddr_t seg_addr; /* Address of current segment */ void *ipagep; /* Pointer to the page we use to write stuff */ void *sump; /* Used to copy stuff into segment buffer */ u_long *block_array; /* Array of logical block nos to put in sum */ u_long blocks_used; /* Number of blocks in first segment */ u_long *dp; /* Used to computed checksum on data */ u_long *datasump; /* Used to computed checksum on data */ int block_array_size; /* How many entries in block array */ int bsize; /* Block size */ int db_per_fb; /* Disk blocks per file block */ int i, j; int off; /* Offset at which to write */ int sb_interval; /* number of segs between super blocks */ int seg_seek; /* Seek offset for a segment */ int ssize; /* Segment size */ int sum_size; /* Size of the summary block */ lfsp = &lfs_default; if (!(bsize = block_size)) bsize = DFL_LFSBLOCK; if (!(ssize = seg_size)) ssize = DFL_LFSSEG; /* Modify parts of superblock overridden by command line arguments */ if (bsize != DFL_LFSBLOCK) { lfsp->lfs_bshift = log2(bsize); if (1 << lfsp->lfs_bshift != bsize) fatal("%d: block size not a power of 2", bsize); lfsp->lfs_bsize = bsize; lfsp->lfs_fsize = bsize; lfsp->lfs_bmask = bsize - 1; lfsp->lfs_inopb = bsize / sizeof(struct dinode);/* MIS -- should I round to power of 2 */ lfsp->lfs_ifpb = bsize / sizeof(IFILE); lfsp->lfs_sepb = bsize / sizeof(SEGUSE); lfsp->lfs_nindir = bsize / sizeof(daddr_t); } if (ssize != DFL_LFSSEG) { lfsp->lfs_segshift = log2(ssize); if (1 << lfsp->lfs_segshift != ssize) fatal("%d: segment size not power of 2", ssize); lfsp->lfs_ssize = ssize; lfsp->lfs_segmask = ssize - 1; lfsp->lfs_dbpseg = ssize / DEV_BSIZE; } lfsp->lfs_ssize = ssize >> lfsp->lfs_bshift; if (minfree) lfsp->lfs_minfree = minfree; /* * Fill in parts of superblock that can be computed from file system * size, disk geometry and current time. */ db_per_fb = bsize/lp->d_secsize; lfsp->lfs_fsbtodb = log2(db_per_fb); lfsp->lfs_sushift = log2(lfsp->lfs_sepb); lfsp->lfs_size = partp->p_size >> lfsp->lfs_fsbtodb; lfsp->lfs_dsize = lfsp->lfs_size - (LFS_LABELPAD >> lfsp->lfs_bshift); lfsp->lfs_nseg = lfsp->lfs_dsize / lfsp->lfs_ssize; lfsp->lfs_maxfilesize = maxtable[lfsp->lfs_bshift] << lfsp->lfs_bshift; /* * The number of free blocks is set from the number of segments times * the segment size - 2 (that we never write because we need to make * sure the cleaner can run). Then we'll subtract off the room for the * superblocks ifile entries and segment usage table. */ lfsp->lfs_dsize = fsbtodb(lfsp, (lfsp->lfs_nseg - 2) * lfsp->lfs_ssize); lfsp->lfs_bfree = lfsp->lfs_dsize; lfsp->lfs_segtabsz = SEGTABSIZE_SU(lfsp); lfsp->lfs_cleansz = CLEANSIZE_SU(lfsp); if ((lfsp->lfs_tstamp = time(NULL)) == -1) fatal("time: %s", strerror(errno)); if ((sb_interval = lfsp->lfs_nseg / LFS_MAXNUMSB) < LFS_MIN_SBINTERVAL) sb_interval = LFS_MIN_SBINTERVAL; /* * Now, lay out the file system. We need to figure out where * the superblocks go, initialize the checkpoint information * for the first two superblocks, initialize the segment usage * information, put the segusage information in the ifile, create * the first block of IFILE structures, and link all the IFILE * structures into a free list. */ /* Figure out where the superblocks are going to live */ lfsp->lfs_sboffs[0] = LFS_LABELPAD/lp->d_secsize; for (i = 1; i < LFS_MAXNUMSB; i++) { sb_addr = ((i * sb_interval) << (lfsp->lfs_segshift - lfsp->lfs_bshift + lfsp->lfs_fsbtodb)) + lfsp->lfs_sboffs[0]; if (sb_addr > partp->p_size) break; lfsp->lfs_sboffs[i] = sb_addr; } last_sb_addr = lfsp->lfs_sboffs[i - 1]; lfsp->lfs_lastseg = lfsp->lfs_sboffs[0]; lfsp->lfs_nextseg = lfsp->lfs_sboffs[1] ? lfsp->lfs_sboffs[1] : lfsp->lfs_sboffs[0]; lfsp->lfs_curseg = lfsp->lfs_lastseg; /* * Initialize the segment usage table. The first segment will * contain the superblock, the cleanerinfo (cleansz), the segusage * table * (segtabsz), 1 block's worth of IFILE entries, the root * directory, the lost+found directory and one block's worth of * inodes (containing the ifile, root, and l+f inodes). */ if (!(cleaninfo = malloc(lfsp->lfs_cleansz << lfsp->lfs_bshift))) fatal("%s", strerror(errno)); cleaninfo->clean = lfsp->lfs_nseg - 1; cleaninfo->dirty = 1; if (!(segtable = malloc(lfsp->lfs_segtabsz << lfsp->lfs_bshift))) fatal("%s", strerror(errno)); segp = segtable; blocks_used = lfsp->lfs_segtabsz + lfsp->lfs_cleansz + 4; segp->su_nbytes = ((blocks_used - 1) << lfsp->lfs_bshift) + 3 * sizeof(struct dinode) + LFS_SUMMARY_SIZE; segp->su_lastmod = lfsp->lfs_tstamp; segp->su_nsums = 1; /* 1 summary blocks */ segp->su_ninos = 1; /* 1 inode block */ segp->su_flags = SEGUSE_SUPERBLOCK | SEGUSE_DIRTY; lfsp->lfs_bfree -= LFS_SUMMARY_SIZE / lp->d_secsize; lfsp->lfs_bfree -= fsbtodb(lfsp, lfsp->lfs_cleansz + lfsp->lfs_segtabsz + 4); /* * Now figure out the address of the ifile inode. The inode block * appears immediately after the segment summary. */ lfsp->lfs_idaddr = (LFS_LABELPAD + LFS_SBPAD + LFS_SUMMARY_SIZE) / lp->d_secsize; for (segp = segtable + 1, i = 1; i < lfsp->lfs_nseg; i++, segp++) { if ((i % sb_interval) == 0) { segp->su_flags = SEGUSE_SUPERBLOCK; lfsp->lfs_bfree -= (LFS_SBPAD / lp->d_secsize); } else segp->su_flags = 0; segp->su_lastmod = 0; segp->su_nbytes = 0; segp->su_ninos = 0; segp->su_nsums = 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -