diff -r f907de68d469 -r fb6a4db31a4e dobuild.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dobuild.sh Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,14 @@ +#!/bin/sh +# dobuild.sh - run build.sh +# usage: ./dobuild.sh machine build-sh-arguments + +MACHINE=$1 +shift + +HOSTTYPE=`uname -s`-`uname -r`-`uname -m` +TOOLDIR=`pwd`/tooldir.$HOSTTYPE + +# OBJMACHINE=yes should be equivalent to setting MAKEOBJDIR=obj.$(MACHINE) + +echo ./build.sh -m $MACHINE -V OBJMACHINE=yes -U -T $TOOLDIR "$@" +./build.sh -m $MACHINE -V OBJMACHINE=yes -U -T $TOOLDIR "$@" diff -r f907de68d469 -r fb6a4db31a4e domake.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/domake.sh Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,13 @@ +#!/bin/sh +# domake.sh - run make +# usage: ./domake.sh machine make-arguments + +MACHINE=$1 +shift + +HOSTTYPE=`uname -s`-`uname -r`-`uname -m` +TOOLDIR=`(cd $(dirname $0) && pwd)`/tooldir.$HOSTTYPE + +# the nbmake wrapper sets OBJ* and TOOLDIR; don't need to pass them + +$TOOLDIR/bin/nbmake-$MACHINE "$@" diff -r f907de68d469 -r fb6a4db31a4e libexec/lfs_cleanerd/cleansrv.c --- a/libexec/lfs_cleanerd/cleansrv.c Sun Feb 07 01:14:00 2010 -0500 +++ b/libexec/lfs_cleanerd/cleansrv.c Sun Feb 07 03:52:22 2010 -0500 @@ -39,7 +39,6 @@ #include #include #include -#include #include #include "bufcache.h" diff -r f907de68d469 -r fb6a4db31a4e libexec/lfs_cleanerd/coalesce.c --- a/libexec/lfs_cleanerd/coalesce.c Sun Feb 07 01:14:00 2010 -0500 +++ b/libexec/lfs_cleanerd/coalesce.c Sun Feb 07 03:52:22 2010 -0500 @@ -37,7 +37,6 @@ #include #include -#include #include #include @@ -104,13 +103,13 @@ "No such error" }; -static struct ufs1_dinode * +static struct lfs_dinode * get_dinode(struct clfs *fs, ino_t ino) { IFILE *ifp; daddr_t daddr; struct ubuf *bp; - struct ufs1_dinode *dip, *r; + struct lfs_dinode *dip, *r; lfs_ientry(&ifp, fs, ino, &bp); daddr = ifp->if_daddr; @@ -120,10 +119,10 @@ return NULL; bread(fs->clfs_devvp, daddr, fs->lfs_ibsize, NOCRED, 0, &bp); - for (dip = (struct ufs1_dinode *)bp->b_data; - dip < (struct ufs1_dinode *)(bp->b_data + fs->lfs_ibsize); dip++) + for (dip = (struct lfs_dinode *)bp->b_data; + dip < (struct lfs_dinode *)(bp->b_data + fs->lfs_ibsize); dip++) if (dip->di_inumber == ino) { - r = (struct ufs1_dinode *)malloc(sizeof(*r)); + r = (struct lfs_dinode *)malloc(sizeof(*r)); memcpy(r, dip, sizeof(*r)); brelse(bp, 0); return r; @@ -142,7 +141,7 @@ BLOCK_INFO *bip = NULL, *tbip; CLEANERINFO cip; struct ubuf *bp; - struct ufs1_dinode *dip; + struct lfs_dinode *dip; struct clfs_seguse *sup; struct lfs_fcntl_markv /* { BLOCK_INFO *blkiov; @@ -162,7 +161,7 @@ onb = nb = lblkno(fs, dip->di_size); /* XXX for now, don't do any file small enough to have fragments */ - if (nb < NDADDR) { + if (nb < LFS_NDIRECTBLKS) { free(dip); return COALESCE_TOOSMALL; } diff -r f907de68d469 -r fb6a4db31a4e libexec/lfs_cleanerd/lfs_cleanerd.c --- a/libexec/lfs_cleanerd/lfs_cleanerd.c Sun Feb 07 01:14:00 2010 -0500 +++ b/libexec/lfs_cleanerd/lfs_cleanerd.c Sun Feb 07 03:52:22 2010 -0500 @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -92,7 +91,7 @@ extern u_int32_t cksum(void *, size_t); extern u_int32_t lfs_sb_cksum(struct dlfs *); extern u_int32_t lfs_cksum_part(void *, size_t, u_int32_t); -extern int ufs_getlbns(struct lfs *, struct uvnode *, daddr_t, struct indir *, int *); +extern int ufs_getlbns(struct lfs *, struct uvnode *, daddr_t, struct lfs_indir *, int *); /* Compat */ void pwarn(const char *unused, ...) { /* Does nothing */ }; @@ -338,7 +337,7 @@ /* Check inode sanity */ if (bip->bi_lbn == LFS_UNUSED_LBN) { - assert(((struct ufs1_dinode *)bip->bi_bp)->di_inumber == + assert(((struct lfs_dinode *)bip->bi_bp)->di_inumber == bip->bi_inode); } @@ -367,7 +366,7 @@ int32_t *iaddrp, idaddr, odaddr; FINFO *fip; struct ubuf *ifbp; - struct ufs1_dinode *dip; + struct lfs_dinode *dip; u_int32_t ck, vers; int fic, inoc, obic; int i; @@ -433,7 +432,7 @@ if (inoc < ssp->ss_ninos && *iaddrp == daddr) { cp = fd_ptrget(fs->clfs_devvp, daddr); ck = lfs_cksum_part(cp, sizeof(u_int32_t), ck); - dip = (struct ufs1_dinode *)cp; + dip = (struct lfs_dinode *)cp; for (i = 0; i < fs->lfs_inopb; i++) { if (dip[i].di_inumber == 0) break; @@ -468,7 +467,7 @@ bip[*bic - 1].bi_segcreate = ssp->ss_create; bip[*bic - 1].bi_version = dip[i].di_gen; bip[*bic - 1].bi_bp = &(dip[i]); - bip[*bic - 1].bi_size = DINODE1_SIZE; + bip[*bic - 1].bi_size = LFS_DINODE_SIZE; } inoc += i; daddr += btofsb(fs, fs->lfs_ibsize); @@ -933,7 +932,7 @@ check_hidden_cost(struct clfs *fs, BLOCK_INFO *bip, int bic, off_t *ifc) { int start; - struct indir in[NIADDR + 1]; + struct lfs_indir in[LFS_NINDIRBLKS + 1]; int num; int i, j, ebic; BLOCK_INFO *ebip; @@ -957,7 +956,7 @@ } if (bip[i].bi_lbn == LFS_UNUSED_LBN) continue; - if (bip[i].bi_lbn < NDADDR) + if (bip[i].bi_lbn < LFS_NDIRECTBLKS) continue; ufs_getlbns((struct lfs *)fs, NULL, (daddr_t)bip[i].bi_lbn, in, &num); diff -r f907de68d469 -r fb6a4db31a4e sbin/dump_lfs/Makefile --- a/sbin/dump_lfs/Makefile Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/dump_lfs/Makefile Sun Feb 07 03:52:22 2010 -0500 @@ -15,8 +15,22 @@ CPPFLAGS+=-DRDUMP -I${.CURDIR} -I${NETBSDSRCDIR}/sbin/dump CPPFLAGS+=-DDUMP_LFS # CPPFLAGS+= -DDEBUG -DTDEBUG -DFDEBUG -DWRITEDEBUG -DSTATS -DDIAGNOSTICS -SRCS= itime.c main.c optr.c dumprmt.c rcache.c snapshot.c tape.c \ - traverse.c unctime.c ffs_bswap.c lfs_inode.c + +# from here +SRCS= lfs_inode.c + +# is this needed? (XXX) +.PATH: ${NETBSDSRCDIR}/sys/ufs/lfs + +# from sbin/dump +.PATH: ${NETBSDSRCDIR}/sbin/dump +SRCS+= itime.c main.c optr.c dumprmt.c rcache.c snapshot.c tape.c \ + traverse.c unctime.c + +# from ffs +.PATH: ${NETBSDSRCDIR}/sys/ufs/ffs +SRCS+= ffs_bswap.c + MAN= dump_lfs.8 MLINKS+=dump_lfs.8 rdump_lfs.8 #CFLAGS+=-g @@ -25,7 +39,5 @@ COPTS.lfs_inode.c+= -fno-tree-ter .endif -.PATH: ${NETBSDSRCDIR}/sbin/dump ${NETBSDSRCDIR}/sys/ufs/lfs \ - ${NETBSDSRCDIR}/sys/ufs/ffs .include diff -r f907de68d469 -r fb6a4db31a4e sbin/dump_lfs/dump.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/dump_lfs/dump.h Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,301 @@ +/* $NetBSD: dump.h,v 1.45 2008/02/16 17:58:01 matt Exp $ */ + +/*- + * Copyright (c) 1980, 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. + * + * @(#)dump.h 8.2 (Berkeley) 4/28/95 + */ + +#include + +union dinode { + // HACK + //struct ufs1_dinode dp1; + //struct ufs2_dinode dp2; + struct lfs_dinode dp1; + // END HACK +}; +#define DIP(dp, field) \ + (is_ufs2 ? (dp)->dp2.di_##field : (dp)->dp1.di_##field) + +#define DIP_SET(dp, field, val) do { \ + if (is_ufs2) \ + (dp)->dp2.di_##field = (val); \ + else \ + (dp)->dp1.di_##field = (val); \ +} while (0) + +/* + * Filestore-independent UFS data, so code can be more easily shared + * between ffs, lfs, and maybe ext2fs and others as well. + */ +struct ufsi { + int64_t ufs_dsize; /* file system size, in sectors */ + int32_t ufs_bsize; /* block size */ + int32_t ufs_bshift; /* log2(ufs_bsize) */ + int32_t ufs_fsize; /* fragment size */ + int32_t ufs_frag; /* block size / frag size */ + int32_t ufs_fsatoda; /* disk address conversion constant */ + int32_t ufs_nindir; /* disk addresses per indirect block */ + int32_t ufs_inopb; /* inodes per block */ + int32_t ufs_maxsymlinklen; /* max symlink length */ + int32_t ufs_bmask; /* block mask */ + int32_t ufs_fmask; /* frag mask */ + int64_t ufs_qbmask; /* ~ufs_bmask */ + int64_t ufs_qfmask; /* ~ufs_fmask */ +}; +#define fsatoda(u,a) ((a) << (u)->ufs_fsatoda) +#define ufs_fragroundup(u,size) /* calculates roundup(size, ufs_fsize) */ \ + (((size) + (u)->ufs_qfmask) & (u)->ufs_fmask) +#define ufs_blkoff(u,loc) /* calculates (loc % u->ufs_bsize) */ \ + ((loc) & (u)->ufs_qbmask) +#define ufs_dblksize(u,d,b) \ + ((((b) >= NDADDR || DIP((d), size) >= ((b)+1) << (u)->ufs_bshift \ + ? (u)->ufs_bsize \ + : (ufs_fragroundup((u), ufs_blkoff(u, DIP((d), size))))))) +struct ufsi *ufsib; + +/* + * Dump maps used to describe what is to be dumped. + */ +int mapsize; /* size of the state maps */ +char *usedinomap; /* map of allocated inodes */ +char *dumpdirmap; /* map of directories to be dumped */ +char *dumpinomap; /* map of files to be dumped */ +/* + * Map manipulation macros. + */ +#define SETINO(ino, map) \ + map[(u_int)((ino) - 1) / NBBY] |= 1 << ((u_int)((ino) - 1) % NBBY) +#define CLRINO(ino, map) \ + map[(u_int)((ino) - 1) / NBBY] &= ~(1 << ((u_int)((ino) - 1) % NBBY)) +#define TSTINO(ino, map) \ + (map[(u_int)((ino) - 1) / NBBY] & (1 << ((u_int)((ino) - 1) % NBBY))) + +/* + * All calculations done in 0.1" units! + */ +char *disk; /* name of the disk file */ +char *disk_dev; /* name of the raw device we are dumping */ +const char *tape; /* name of the tape file */ +const char *dumpdates; /* name of the file containing dump date information*/ +const char *temp; /* name of the file for doing rewrite of dumpdates */ +char lastlevel; /* dump level of previous dump */ +char level; /* dump level of this dump */ +int uflag; /* update flag */ +int eflag; /* eject flag */ +int lflag; /* autoload flag */ +int diskfd; /* disk file descriptor */ +int tapefd; /* tape file descriptor */ +int pipeout; /* true => output to standard output */ +ino_t curino; /* current inumber; used globally */ +int newtape; /* new tape flag */ +u_int64_t tapesize; /* estimated tape size, blocks */ +long tsize; /* tape size in 0.1" units */ +long asize; /* number of 0.1" units written on current tape */ +int etapes; /* estimated number of tapes */ +int nonodump; /* if set, do not honor UF_NODUMP user flags */ +int unlimited; /* if set, write to end of medium */ + +extern int density; /* density in 0.1" units */ +extern int notify; /* notify operator flag */ +extern int timestamp; /* timestamp messages */ +extern int blockswritten; /* number of blocks written on current tape */ +extern int tapeno; /* current tape number */ +extern int is_ufs2; + +time_t tstart_writing; /* when started writing the first tape block */ +time_t tstart_volume; /* when started writing the current volume */ +int xferrate; /* averaged transfer rate of all volumes */ +char sblock_buf[MAXBSIZE]; /* buffer to hold the superblock */ +extern long dev_bsize; /* block size of underlying disk device */ +int dev_bshift; /* log2(dev_bsize) */ +int tp_bshift; /* log2(TP_BSIZE) */ +int needswap; /* file system in swapped byte order */ + + +/* some inline functions to help the byte-swapping mess */ +static inline u_int16_t iswap16(u_int16_t); +static inline u_int32_t iswap32(u_int32_t); +static inline u_int64_t iswap64(u_int64_t); + +static inline u_int16_t iswap16(u_int16_t x) +{ + if (needswap) + return bswap16(x); + else + return x; +} + +static inline u_int32_t iswap32(u_int32_t x) +{ + if (needswap) + return bswap32(x); + else + return x; +} + +static inline u_int64_t iswap64(u_int64_t x) +{ + if (needswap) + return bswap64(x); + else + return x; +} + +/* filestore-specific hooks */ +int fs_read_sblock(char *); +struct ufsi *fs_parametrize(void); +ino_t fs_maxino(void); +void fs_mapinodes(ino_t, u_int64_t *, int *); + +/* operator interface functions */ +void broadcast(const char *); +void lastdump(char); +void msg(const char *fmt, ...) __attribute__((__format__(__printf__,1,2))); +void msgtail(const char *fmt, ...) __attribute__((__format__(__printf__,1,2))); +int query(const char *); +void quit(const char *fmt, ...) __attribute__((__format__(__printf__,1,2))); +time_t do_stats(void); +void statussig(int); +void timeest(void); +time_t unctime(char *); + +/* mapping routines */ +union dinode; +int64_t blockest(union dinode *); +void mapfileino(ino_t, u_int64_t *, int *); +int mapfiles(ino_t, u_int64_t *, char *, char * const *); +int mapdirs(ino_t, u_int64_t *); + +/* file dumping routines */ +void blksout32(int32_t *, int, ino_t); +void blksout64(int64_t *, int, ino_t); +void dumpino(union dinode *, ino_t); +#ifndef RRESTORE +void dumpmap(char *, int, ino_t); +#endif +void writeheader(ino_t); + +/* data block caching */ +void bread(daddr_t, char *, int); +void rawread(daddr_t, char *, int); +void initcache(int, int); +void printcachestats(void); + +/* tape writing routines */ +int alloctape(void); +void close_rewind(void); +void dumpblock(daddr_t, int); +void startnewtape(int); +void trewind(int); +void writerec(char *, int); + +void Exit(int); +void dumpabort(int); +void getfstab(void); + +char *rawname(char *); +union dinode *getino(ino_t); + +void *xcalloc(size_t, size_t); +void *xmalloc(size_t); +char *xstrdup(const char *); + +/* LFS snapshot hooks */ +#ifdef DUMP_LFS +int lfs_wrap_stop(char *); +void lfs_wrap_go(void); +#endif + +/* rdump routines */ +#if defined(RDUMP) || defined(RRESTORE) +void rmtclose(void); +int rmthost(const char *); +int rmtopen(const char *, int, int); +int rmtwrite(const char *, int); +int rmtioctl(int, int); +#endif /* RDUMP || RRESTORE */ + +void interrupt(int); /* in case operator bangs on console */ + +/* + * Exit status codes + */ +#define X_FINOK 0 /* normal exit */ +#define X_STARTUP 1 /* startup error */ +#define X_REWRITE 2 /* restart writing from the check point */ +#define X_ABORT 3 /* abort dump; don't attempt checkpointing */ + +#define OPGRENT "operator" /* group entry to notify */ +#define DIALUP "ttyd" /* prefix for dialups */ + +struct fstab *fstabsearch(const char *); /* search fs_file and fs_spec */ +struct statvfs *mntinfosearch(const char *key); + +#ifndef NAME_MAX +#define NAME_MAX 255 +#endif + +/* + * The contents of the file _PATH_DUMPDATES is maintained both on + * a linked list, and then (eventually) arrayified. + */ +struct dumpdates { + char dd_name[NAME_MAX+3]; + char dd_level; + time_t dd_ddate; +}; + +extern int nddates; /* number of records (might be zero) */ +extern struct dumpdates **ddatev; /* the arrayfied version */ + +void initdumptimes(void); +void getdumptime(void); +void putdumptime(void); +#define ITITERATE(i, ddp) \ + if (ddatev != NULL) \ + for (ddp = ddatev[i = 0]; i < nddates; ddp = ddatev[++i]) + +void sig(int signo); + +/* + * Compatibility with old systems. + */ +#ifdef COMPAT +#include +#define strchr(a,b) index(a,b) +#define strrchr(a,b) rindex(a,b) +extern char *strdup(), *ctime(); +extern int read(), write(); +extern int errno; +#endif + +#ifndef _PATH_FSTAB +#define _PATH_FSTAB "/etc/fstab" +#endif diff -r f907de68d469 -r fb6a4db31a4e sbin/dump_lfs/dump.h.README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/dump_lfs/dump.h.README Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,27 @@ +This is a copy of ../dump/dump.h with a HACK (q.v.) so lfs_inode.c can +compile it. Because the rest of dump_lfs is compiled against the +original, it's important that they stay in sync. + +This is gross. (Fortunately, dump doesn't get committed very often.) + +I was hoping that putting it here would cause the sources from dump/ +to find this copy, but no such luck. I could cut and paste all of +those sources here to use only this copy, but that's arguably just as +bad, and the problem should go away entirely in the near term. + +The right way to fix this is to rearrange dump a bit to improve the +abstraction for different fs types (which is probably desirable in the +long run anyway) so lfs_inode.c can include the master copy. However, +because dump is super-mission-critical I'm unwilling to do that just +for the sake of lfs, or bury the change in the middle of the big lfs +reorg. I intend to be preparing dump patches for this "soon". + +The underlying issue is that until further hacking is done it's not +safe to include both lfs.h and ufs headers at once, because there's +still a lot of symbol overlap. Everything prefixed by ufs_ or UFS_ is +ok, but lots of random stuff in UFS isn't prefixed. The LFS versions +haven't all been changed yet... and when they do get changed it's +important that any stale references to UFS symbols fail and get fixed +rather than silently doing the wrong thing. + + - dholland 2/7/2010 diff -r f907de68d469 -r fb6a4db31a4e sbin/dump_lfs/lfs_inode.c --- a/sbin/dump_lfs/lfs_inode.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/dump_lfs/lfs_inode.c Sun Feb 07 03:52:22 2010 -0500 @@ -46,12 +46,13 @@ #include #include #include -#include -#include #include #include +/* HACK until we can safely mix ufs and lfs headers */ +#define ufs1_dinode lfs_dinode #include +#undef ufs1_dinode #include #include @@ -189,15 +190,15 @@ /* * XXX KS - I know there's a better way to do this. */ -#define BASE_SINDIR (NDADDR) -#define BASE_DINDIR (NDADDR+NINDIR(fs)) -#define BASE_TINDIR (NDADDR+NINDIR(fs)+NINDIR(fs)*NINDIR(fs)) +#define BASE_SINDIR (LFS_NDIRECTBLKS) +#define BASE_DINDIR (LFS_NDIRECTBLKS+NINDIR(fs)) +#define BASE_TINDIR (LFS_NDIRECTBLKS+NINDIR(fs)+NINDIR(fs)*NINDIR(fs)) #define D_UNITS (NINDIR(fs)) #define T_UNITS (NINDIR(fs)*NINDIR(fs)) static daddr_t -lfs_bmap(struct lfs *fs, struct ufs1_dinode *idinode, daddr_t lbn) +lfs_bmap(struct lfs *fs, struct lfs_dinode *idinode, daddr_t lbn) { daddr_t residue, up; int off=0; @@ -216,7 +217,7 @@ */ if(lbn < 0) { lbn *= -1; - if(lbn == NDADDR) { + if(lbn == LFS_NDIRECTBLKS) { /* printf("lbn %d: single indir base\n", -lbn); */ return idinode->di_ib[0]; /* single indirect */ } else if(lbn == BASE_DINDIR+1) { @@ -231,7 +232,7 @@ * Find the immediate parent. This is essentially finding the * residue of modulus, and then rounding accordingly. */ - residue = (lbn-NDADDR) % NINDIR(fs); + residue = (lbn-LFS_NDIRECTBLKS) % NINDIR(fs); if(residue == 1) { /* Double indirect. Parent is the triple. */ up = idinode->di_ib[2]; @@ -260,12 +261,12 @@ } } else { /* Direct block. Its parent must be a single indirect. */ - if(lbn < NDADDR) + if(lbn < LFS_NDIRECTBLKS) return idinode->di_db[lbn]; else { /* Parent is an indirect block. */ - up = -(((lbn-NDADDR) / D_UNITS) * D_UNITS + NDADDR); - off = (lbn-NDADDR) % D_UNITS; + up = -(((lbn-LFS_NDIRECTBLKS) / D_UNITS) * D_UNITS + LFS_NDIRECTBLKS); + off = (lbn-LFS_NDIRECTBLKS) % D_UNITS; /* printf("lbn %d: parent is %d/%d\n", lbn,up,off); */ } } @@ -296,8 +297,8 @@ } /* Search a block for a specific dinode. */ -static struct ufs1_dinode * -lfs_ifind(struct lfs *fs, ino_t ino, struct ufs1_dinode *dip) +static struct lfs_dinode * +lfs_ifind(struct lfs *fs, ino_t ino, struct lfs_dinode *dip) { int cnt; @@ -312,10 +313,10 @@ { static daddr_t inoblkno; daddr_t blkno; - static struct ufs1_dinode inoblock[MAXBSIZE / sizeof (struct ufs1_dinode)]; - static struct ufs1_dinode ifile_dinode; /* XXX fill this in */ - static struct ufs1_dinode empty_dinode; /* Always stays zeroed */ - struct ufs1_dinode *dp; + static struct lfs_dinode inoblock[MAXBSIZE / sizeof (struct lfs_dinode)]; + static struct lfs_dinode ifile_dinode; /* XXX fill this in */ + static struct lfs_dinode empty_dinode; /* Always stays zeroed */ + struct lfs_dinode *dp; if(inum == sblock->lfs_ifile) { /* Load the ifile inode if not already */ diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/dir.c --- a/sbin/fsck_lfs/dir.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/dir.c Sun Feb 07 03:52:22 2010 -0500 @@ -35,9 +35,6 @@ #include #include -#include -#include -#include #include #include @@ -82,7 +79,7 @@ .dotdot_name = ".." }; -static int expanddir(struct uvnode *, struct ufs1_dinode *, char *); +static int expanddir(struct uvnode *, struct lfs_dinode *, char *); static void freedir(ino_t, ino_t); static struct direct *fsck_readdir(struct uvnode *, struct inodesc *); static int lftempname(char *, ino_t); @@ -328,7 +325,7 @@ adjust(struct inodesc *idesc, short lcnt) { struct uvnode *vp; - struct ufs1_dinode *dp; + struct lfs_dinode *dp; vp = vget(fs, idesc->id_number); dp = VTOD(vp); @@ -396,7 +393,7 @@ int linkup(ino_t orphan, ino_t parentdir) { - struct ufs1_dinode *dp; + struct lfs_dinode *dp; int lostdir; ino_t oldlfdir; struct inodesc idesc; @@ -524,7 +521,7 @@ int makeentry(ino_t parent, ino_t ino, const char *name) { - struct ufs1_dinode *dp; + struct lfs_dinode *dp; struct inodesc idesc; char pathbuf[MAXPATHLEN + 1]; struct uvnode *vp; @@ -559,14 +556,14 @@ * Attempt to expand the size of a directory */ static int -expanddir(struct uvnode *vp, struct ufs1_dinode *dp, char *name) +expanddir(struct uvnode *vp, struct lfs_dinode *dp, char *name) { daddr_t lastbn; struct ubuf *bp; char *cp, firstblk[DIRBLKSIZ]; lastbn = lblkno(fs, dp->di_size); - if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) + if (lastbn >= LFS_NDIRECTBLKS - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0) return (0); dp->di_db[lastbn + 1] = dp->di_db[lastbn]; dp->di_db[lastbn] = 0; @@ -617,7 +614,7 @@ { ino_t ino; char *cp; - struct ufs1_dinode *dp; + struct lfs_dinode *dp; struct ubuf *bp; struct dirtemplate *dirp; struct uvnode *vp; diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/extern.h --- a/sbin/fsck_lfs/extern.h Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/extern.h Sun Feb 07 03:52:22 2010 -0500 @@ -28,13 +28,13 @@ int allocblk(long); int allocdir(ino_t, ino_t, int); void blkerror(ino_t, const char *, daddr_t); -void cacheino(struct ufs1_dinode *, ino_t); +void cacheino(struct lfs_dinode *, ino_t); int changeino(ino_t, const char *, ino_t); struct fstab; void checkinode(ino_t, struct inodesc *); int chkrange(daddr_t, int); void ckfini(int); -int ckinode(struct ufs1_dinode *, struct inodesc *); +int ckinode(struct lfs_dinode *, struct inodesc *); void clri(struct inodesc *, const char *, int); int dircheck(struct inodesc *, struct direct *); void direrror(ino_t, const char *); @@ -47,10 +47,10 @@ void freeblk(daddr_t, long); void freeino(ino_t); void freeinodebuf(void); -int ftypeok(struct ufs1_dinode *); +int ftypeok(struct lfs_dinode *); void getpathname(char *, size_t, ino_t, ino_t); void inocleanup(void); -void inodirty(struct inode *); +void inodirty(struct lfs_inode *); int linkup(ino_t, ino_t); int makeentry(ino_t, ino_t, const char *); void pass0(void); diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/fsck.h --- a/sbin/fsck_lfs/fsck.h Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/fsck.h Sun Feb 07 03:52:22 2010 -0500 @@ -101,7 +101,7 @@ int32_t *b_indir; /* indirect block */ struct lfs *b_fs; /* super block */ struct cg *b_cg;/* cylinder group */ - struct ufs1_dinode *b_dinode; /* inode block */ + struct lfs_dinode *b_dinode; /* inode block */ } b_un; char b_dirty; }; @@ -206,7 +206,7 @@ ino_t allocino(ino_t, int); int ino_to_fsba(struct lfs *, ino_t); -struct ufs1_dinode *ginode(ino_t); +struct lfs_dinode *ginode(ino_t); struct inoinfo *getinoinfo(ino_t); daddr_t lfs_ino_daddr(ino_t); void clearinode(ino_t); diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/fsck_vars.h --- a/sbin/fsck_lfs/fsck_vars.h Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/fsck_vars.h Sun Feb 07 03:52:22 2010 -0500 @@ -76,6 +76,6 @@ extern daddr_t n_blks; /* number of blocks in use */ extern ino_t n_files; /* number of files in use */ -extern struct ufs1_dinode zino; +extern struct lfs_dinode zino; extern int no_roll_forward; /* Don't roll forward */ diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/inode.c --- a/sbin/fsck_lfs/inode.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/inode.c Sun Feb 07 03:52:22 2010 -0500 @@ -64,8 +64,6 @@ #include #include -#include -#include #define vnode uvnode #include #undef vnode @@ -98,7 +96,7 @@ * Get a dinode of a given inum. * XXX combine this function with vget. */ -struct ufs1_dinode * +struct lfs_dinode * ginode(ino_t ino) { struct uvnode *vp; @@ -112,21 +110,21 @@ if (din_table[ino] == 0x0) { LFS_IENTRY(ifp, fs, ino, bp); din_table[ino] = ifp->if_daddr; - seg_table[dtosn(fs, ifp->if_daddr)].su_nbytes += DINODE1_SIZE; + seg_table[dtosn(fs, ifp->if_daddr)].su_nbytes += LFS_DINODE_SIZE; brelse(bp, 0); } - return (VTOI(vp)->i_din.ffs1_din); + return (VTOI(vp)->i_ffs1_din); } /* * Check validity of held blocks in an inode, recursing through all blocks. */ int -ckinode(struct ufs1_dinode *dp, struct inodesc *idesc) +ckinode(struct lfs_dinode *dp, struct inodesc *idesc) { ufs_daddr_t *ap, lbn; long ret, n, ndb, offset; - struct ufs1_dinode dino; + struct lfs_dinode dino; u_int64_t remsize, sizepb; mode_t mode; char pathbuf[MAXPATHLEN + 1]; @@ -146,7 +144,7 @@ ndb = howmany(dino.di_size, fs->lfs_bsize); thisvp = vget(fs, idesc->id_number); - for (lbn = 0; lbn < NDADDR; lbn++) { + for (lbn = 0; lbn < LFS_NDIRECTBLKS; lbn++) { ap = dino.di_db + lbn; if (thisvp) idesc->id_numfrags = @@ -189,9 +187,9 @@ return (ret); } idesc->id_numfrags = fs->lfs_frag; - remsize = dino.di_size - fs->lfs_bsize * NDADDR; + remsize = dino.di_size - fs->lfs_bsize * LFS_NDIRECTBLKS; sizepb = fs->lfs_bsize; - for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { + for (ap = &dino.di_ib[0], n = 1; n <= LFS_NINDIRBLKS; ap++, n++) { if (*ap) { idesc->id_blkno = *ap; ret = iblock(idesc, n, remsize); @@ -350,15 +348,15 @@ * Enter inodes into the cache. */ void -cacheino(struct ufs1_dinode * dp, ino_t inumber) +cacheino(struct lfs_dinode * dp, ino_t inumber) { struct inoinfo *inp; struct inoinfo **inpp, **ninpsort; unsigned int blks; blks = howmany(dp->di_size, fs->lfs_bsize); - if (blks > NDADDR) - blks = NDADDR + NIADDR; + if (blks > LFS_NDIRECTBLKS) + blks = LFS_NDIRECTBLKS + LFS_NINDIRBLKS; inp = emalloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t)); inpp = &inphead[inumber % numdirs]; inp->i_nexthash = *inpp; @@ -418,7 +416,7 @@ } void -inodirty(struct inode *ip) +inodirty(struct lfs_inode *ip) { ip->i_flag |= IN_MODIFIED; } @@ -475,9 +473,9 @@ SEGUSE *sup; u_int32_t oldsn = dtosn(fs, daddr); - seg_table[oldsn].su_nbytes -= DINODE1_SIZE; + seg_table[oldsn].su_nbytes -= LFS_DINODE_SIZE; LFS_SEGENTRY(sup, fs, oldsn, bp); - sup->su_nbytes -= DINODE1_SIZE; + sup->su_nbytes -= LFS_DINODE_SIZE; LFS_WRITESEGENTRY(sup, fs, oldsn, bp); /* Ifile */ } } @@ -519,7 +517,7 @@ void pinode(ino_t ino) { - struct ufs1_dinode *dp; + struct lfs_dinode *dp; struct passwd *pw; printf(" I=%llu ", (unsigned long long)ino); @@ -578,7 +576,7 @@ allocino(ino_t request, int type) { ino_t ino; - struct ufs1_dinode *dp; + struct lfs_dinode *dp; time_t t; struct uvnode *vp; struct ubuf *bp; @@ -607,7 +605,7 @@ vp = lfs_valloc(fs, ino); if (vp == NULL) return (0); - dp = (VTOI(vp)->i_din.ffs1_din); + dp = (VTOI(vp)->i_ffs1_din); bp = getblk(vp, 0, fs->lfs_fsize); VOP_BWRITE(bp); dp->di_mode = type; diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/lfs.c --- a/sbin/fsck_lfs/lfs.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/lfs.c Sun Feb 07 03:52:22 2010 -0500 @@ -70,8 +70,6 @@ #include #include -#include -#include #define vnode uvnode #include #undef vnode @@ -157,18 +155,18 @@ * next block and the disk address of the block (if it is assigned). */ int -ufs_bmaparray(struct lfs * fs, struct uvnode * vp, daddr_t bn, daddr_t * bnp, struct indir * ap, int *nump) +ufs_bmaparray(struct lfs * fs, struct uvnode * vp, daddr_t bn, daddr_t * bnp, struct lfs_indir * ap, int *nump) { - struct inode *ip; + struct lfs_inode *ip; struct ubuf *bp; - struct indir a[NIADDR + 1], *xap; + struct lfs_indir a[LFS_NINDIRBLKS + 1], *xap; daddr_t daddr; daddr_t metalbn; int error, num; ip = VTOI(vp); - if (bn >= 0 && bn < NDADDR) { + if (bn >= 0 && bn < LFS_NDIRECTBLKS) { if (nump != NULL) *nump = 0; *bnp = fsbtodb(fs, ip->i_ffs1_db[bn]); @@ -230,7 +228,7 @@ * once with the offset into the page itself. */ int -ufs_getlbns(struct lfs * fs, struct uvnode * vp, daddr_t bn, struct indir * ap, int *nump) +ufs_getlbns(struct lfs * fs, struct uvnode * vp, daddr_t bn, struct lfs_indir * ap, int *nump) { daddr_t metalbn, realbn; int64_t blockcnt; @@ -251,13 +249,16 @@ for (indir = fs->lfs_nindir; indir; indir >>= 1) ++lognindir; - /* 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. */ + /* + * 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 + * LFS_NINDIRBLKS - i is the number of levels of indirection + * needed to locate the requested block. + */ - bn -= NDADDR; - for (lbc = 0, i = NIADDR;; i--, bn -= blockcnt) { + bn -= LFS_NDIRECTBLKS; + for (lbc = 0, i = LFS_NINDIRBLKS;; i--, bn -= blockcnt) { if (i == 0) return (EFBIG); @@ -269,17 +270,17 @@ } /* Calculate the address of the first meta-block. */ - metalbn = -((realbn >= 0 ? realbn : -realbn) - bn + NIADDR - i); + metalbn = -((realbn >= 0 ? realbn : -realbn) - bn + LFS_NINDIRBLKS - 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->in_off = off = LFS_NINDIRBLKS - i; ap->in_exists = 0; ap++; - for (++numlevels; i <= NIADDR; i++) { + for (++numlevels; i <= LFS_NINDIRBLKS; i++) { /* If searching for a meta-data block, quit when found. */ if (metalbn == realbn) break; @@ -308,11 +309,11 @@ } /* Search a block for a specific dinode. */ -struct ufs1_dinode * +struct lfs_dinode * lfs_ifind(struct lfs * fs, ino_t ino, struct ubuf * bp) { - struct ufs1_dinode *dip = (struct ufs1_dinode *) bp->b_data; - struct ufs1_dinode *ldip, *fin; + struct lfs_dinode *dip = (struct lfs_dinode *) bp->b_data; + struct lfs_dinode *ldip, *fin; fin = dip + INOPB(fs); @@ -335,8 +336,8 @@ lfs_raw_vget(struct lfs * fs, ino_t ino, int fd, ufs_daddr_t daddr) { struct uvnode *vp; - struct inode *ip; - struct ufs1_dinode *dip; + struct lfs_inode *ip; + struct lfs_dinode *dip; struct ubuf *bp; int i, hash; @@ -352,7 +353,7 @@ ip = ecalloc(1, sizeof(*ip)); - ip->i_din.ffs1_din = ecalloc(1, sizeof(*ip->i_din.ffs1_din)); + ip->i_ffs1_din = ecalloc(1, sizeof(*ip->i_ffs1_din)); /* Initialize the inode -- from lfs_vcreate. */ ip->inode_ext.lfs = ecalloc(1, sizeof(*ip->inode_ext.lfs)); @@ -376,7 +377,7 @@ free(vp); return NULL; } - memcpy(ip->i_din.ffs1_din, dip, sizeof(*dip)); + memcpy(ip->i_ffs1_din, dip, sizeof(*dip)); brelse(bp, 0); } ip->i_number = ino; @@ -392,8 +393,8 @@ } #endif - memset(ip->i_lfs_fragsize, 0, NDADDR * sizeof(*ip->i_lfs_fragsize)); - for (i = 0; i < NDADDR; i++) + memset(ip->i_lfs_fragsize, 0, LFS_NDIRECTBLKS * sizeof(*ip->i_lfs_fragsize)); + for (i = 0; i < LFS_NDIRECTBLKS; i++) if (ip->i_ffs1_db[i] != 0) ip->i_lfs_fragsize[i] = blksize(fs, ip, i); @@ -903,7 +904,7 @@ extend_ifile(struct lfs *fs) { struct uvnode *vp; - struct inode *ip; + struct lfs_inode *ip; IFILE *ifp; IFILE_V1 *ifp_v1; struct ubuf *bp, *cbp; @@ -973,9 +974,9 @@ int offset; daddr_t daddr, idaddr; struct ubuf *ibp, *bp; - struct inode *ip; + struct lfs_inode *ip; struct lfs *fs; - struct indir indirs[NIADDR+2], *idp; + struct lfs_indir indirs[LFS_NINDIRBLKS+2], *idp; daddr_t lbn, lastblock; int bb, bcount; int error, frags, i, nsize, osize, num; @@ -1006,7 +1007,7 @@ /* Check for block beyond end of file and fragment extension needed. */ lastblock = lblkno(fs, ip->i_ffs1_size); - if (lastblock < NDADDR && lastblock < lbn) { + if (lastblock < LFS_NDIRECTBLKS && lastblock < lbn) { osize = blksize(fs, ip, lastblock); if (osize < fs->lfs_bsize && osize > 0) { if ((error = lfs_fragextend(vp, osize, fs->lfs_bsize, @@ -1029,7 +1030,7 @@ * size or it already exists and contains some fragments and * may need to extend it. */ - if (lbn < NDADDR && lblkno(fs, ip->i_ffs1_size) <= lbn) { + if (lbn < LFS_NDIRECTBLKS && lblkno(fs, ip->i_ffs1_size) <= lbn) { osize = blksize(fs, ip, lbn); nsize = fragroundup(fs, offset + iosize); if (lblktosize(fs, lbn) >= ip->i_ffs1_size) { @@ -1189,7 +1190,7 @@ lfs_fragextend(struct uvnode *vp, int osize, int nsize, daddr_t lbn, struct ubuf **bpp) { - struct inode *ip; + struct lfs_inode *ip; struct lfs *fs; long bb; int error; diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/lfs_user.h --- a/sbin/fsck_lfs/lfs_user.h Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/lfs_user.h Sun Feb 07 03:52:22 2010 -0500 @@ -53,7 +53,7 @@ * Structure used to pass around logical block paths generated by * ufs_getlbns and used by truncate and bmap code. */ -struct indir { +struct lfs_indir { daddr_t in_lbn; /* Logical block number. */ int in_off; /* Offset in buffer. */ int in_exists; /* Flag if the block exists. */ @@ -62,8 +62,8 @@ typedef int32_t ufs_daddr_t; /* Convert between inode pointers and vnode pointers. */ -#define VTOI(vp) ((struct inode *)(vp)->v_data) -#define VTOD(vp) (VTOI(vp)->i_din.ffs1_din) +#define VTOI(vp) ((struct lfs_inode *)(vp)->v_data) +#define VTOD(vp) (VTOI(vp)->i_ffs1_din) #define sbdirty() ++fsdirty @@ -79,7 +79,7 @@ struct lfs *lfs_verify(struct lfs *, struct lfs *, struct uvnode *, int); int check_summary(struct lfs *, struct segsum *, ufs_daddr_t, int, struct uvnode *, void (*)(ufs_daddr_t, struct finfo *)); ufs_daddr_t try_verify(struct lfs *, struct uvnode *, ufs_daddr_t, int); -struct ufs1_dinode *lfs_ifind(struct lfs *, ino_t, struct ubuf *); +struct lfs_dinode *lfs_ifind(struct lfs *, ino_t, struct ubuf *); void call_panic(const char *, ...); void my_vpanic(int, const char *, va_list); int extend_ifile(struct lfs *); diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/main.c --- a/sbin/fsck_lfs/main.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/main.c Sun Feb 07 03:52:22 2010 -0500 @@ -32,8 +32,6 @@ #include #include #include -#include -#include #include #include @@ -306,7 +304,7 @@ */ if (statvfs("/", &stfs_buf) == 0) { long flags = stfs_buf.f_flag; - struct ufs_args args; + struct lfs_args args; if (flags & MNT_RDONLY) { args.fspec = 0; diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/pass0.c --- a/sbin/fsck_lfs/pass0.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/pass0.c Sun Feb 07 03:52:22 2010 -0500 @@ -63,8 +63,6 @@ #include #include -#include -#include #define vnode uvnode #include #undef vnode diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/pass1.c --- a/sbin/fsck_lfs/pass1.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/pass1.c Sun Feb 07 03:52:22 2010 -0500 @@ -34,8 +34,6 @@ #include #include -#include -#include #define vnode uvnode #include #undef vnode @@ -90,7 +88,7 @@ ino_t inumber; int i; struct inodesc idesc; - struct ufs1_dinode *tinode; + struct lfs_dinode *tinode; struct ifile *ifp; struct ubuf *bp; struct ino_daddr **dins; @@ -162,7 +160,7 @@ void checkinode(ino_t inumber, struct inodesc * idesc) { - struct ufs1_dinode *dp; + struct lfs_dinode *dp; struct uvnode *vp; struct zlncnt *zlnp; struct ubuf *bp; @@ -184,8 +182,8 @@ /* XXX - LFS doesn't have this particular problem (?) */ if (mode == 0) { - if (memcmp(dp->di_db, zino.di_db, NDADDR * sizeof(ufs_daddr_t)) || - memcmp(dp->di_ib, zino.di_ib, NIADDR * sizeof(ufs_daddr_t)) || + if (memcmp(dp->di_db, zino.di_db, LFS_NDIRECTBLKS * sizeof(ufs_daddr_t)) || + memcmp(dp->di_ib, zino.di_ib, LFS_NINDIRBLKS * sizeof(ufs_daddr_t)) || dp->di_mode || dp->di_size) { pwarn("mode=o%o, ifmt=o%o\n", dp->di_mode, mode); pfatal("PARTIALLY ALLOCATED INODE I=%llu", @@ -231,24 +229,24 @@ if (dp->di_size < fs->lfs_maxsymlinklen || (fs->lfs_maxsymlinklen == 0 && dp->di_blocks == 0)) { ndb = howmany(dp->di_size, sizeof(ufs_daddr_t)); - if (ndb > NDADDR) { - j = ndb - NDADDR; + if (ndb > LFS_NDIRECTBLKS) { + j = ndb - LFS_NDIRECTBLKS; for (ndb = 1; j > 1; j--) ndb *= NINDIR(fs); - ndb += NDADDR; + ndb += LFS_NDIRECTBLKS; } } } - for (j = ndb; j < NDADDR; j++) + for (j = ndb; j < LFS_NDIRECTBLKS; j++) if (dp->di_db[j] != 0) { if (debug) printf("bad direct addr for size %lld lbn %d: 0x%x\n", (long long)dp->di_size, j, (unsigned)dp->di_db[j]); goto unknown; } - for (j = 0, ndb -= NDADDR; ndb > 0; j++) + for (j = 0, ndb -= LFS_NDIRECTBLKS; ndb > 0; j++) ndb /= NINDIR(fs); - for (; j < NIADDR; j++) + for (; j < LFS_NINDIRBLKS; j++) if (dp->di_ib[j] != 0) { if (debug) printf("bad indirect addr for size %lld # %d: 0x%x\n", diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/pass2.c --- a/sbin/fsck_lfs/pass2.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/pass2.c Sun Feb 07 03:52:22 2010 -0500 @@ -35,8 +35,6 @@ #include #include -#include -#include #include #include @@ -60,12 +58,12 @@ void pass2(void) { - struct ufs1_dinode *dp; + struct lfs_dinode *dp; struct uvnode *vp; struct inoinfo **inpp, *inp; struct inoinfo **inpend; struct inodesc curino; - struct ufs1_dinode dino; + struct lfs_dinode dino; char pathbuf[MAXPATHLEN + 1]; switch (statemap[ROOTINO]) { @@ -155,7 +153,7 @@ inodirty(VTOI(vp)); } } - memset(&dino, 0, sizeof(struct ufs1_dinode)); + memset(&dino, 0, sizeof(struct lfs_dinode)); dino.di_mode = IFDIR; dino.di_size = inp->i_isize; memcpy(&dino.di_db[0], &inp->i_blks[0], (size_t) inp->i_numblks); @@ -204,7 +202,7 @@ struct direct *dirp = idesc->id_dirp; struct inoinfo *inp; int n, entrysize, ret = 0; - struct ufs1_dinode *dp; + struct lfs_dinode *dp; const char *errmsg; struct direct proto; char namebuf[MAXPATHLEN + 1]; diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/pass3.c --- a/sbin/fsck_lfs/pass3.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/pass3.c Sun Feb 07 03:52:22 2010 -0500 @@ -31,7 +31,6 @@ #include #include -#include #include #include #include "fsck.h" diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/pass4.c --- a/sbin/fsck_lfs/pass4.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/pass4.c Sun Feb 07 03:52:22 2010 -0500 @@ -32,7 +32,6 @@ #include #include #include -#include #define vnode uvnode #define buf ubuf @@ -81,7 +80,7 @@ { ino_t inumber; struct zlncnt *zlnp; - struct ufs1_dinode *dp; + struct lfs_dinode *dp; struct inodesc idesc; int n; diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/pass5.c --- a/sbin/fsck_lfs/pass5.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/pass5.c Sun Feb 07 03:52:22 2010 -0500 @@ -35,9 +35,6 @@ #include #include -#include -#include -#include #define vnode uvnode #include #undef vnode diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/pass6.c --- a/sbin/fsck_lfs/pass6.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/pass6.c Sun Feb 07 03:52:22 2010 -0500 @@ -34,10 +34,8 @@ #include #include #include +#include -#include -#include -#include #define vnode uvnode #include #undef vnode @@ -82,8 +80,8 @@ { SEGUSE *sup; struct ubuf *bp; - struct indir a[NIADDR + 2], *ap; - struct inode *ip; + struct lfs_indir a[LFS_NINDIRBLKS + 2], *ap; + struct lfs_inode *ip; daddr_t daddr, ooff; int num, error; int i, bb, osize = 0, obb = 0; @@ -137,7 +135,7 @@ */ if (daddr > 0) { oldsn = dtosn(fs, daddr); - if (lbn >= 0 && lbn < NDADDR) + if (lbn >= 0 && lbn < LFS_NDIRECTBLKS) osize = ip->i_lfs_fragsize[lbn]; else osize = fs->lfs_bsize; @@ -157,7 +155,7 @@ } /* If block frag size is too large for old EOF, update size */ - if (lbn < NDADDR) { + if (lbn < LFS_NDIRECTBLKS) { off_t minsize; minsize = (lbn << fs->lfs_bshift); @@ -196,7 +194,7 @@ * segment no longer owns it, we can forget about its * old size. */ - if (lbn >= 0 && lbn < NDADDR) + if (lbn >= 0 && lbn < LFS_NDIRECTBLKS) ip->i_lfs_fragsize[lbn] = size; } @@ -234,9 +232,9 @@ vp = lfs_raw_vget(fs, ino, fs->lfs_ivnode->v_fd, daddr); LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp); - sup->su_nbytes -= DINODE1_SIZE; + sup->su_nbytes -= LFS_DINODE_SIZE; VOP_BWRITE(sbp); - seg_table[dtosn(fs, daddr)].su_nbytes -= DINODE1_SIZE; + seg_table[dtosn(fs, daddr)].su_nbytes -= LFS_DINODE_SIZE; } else brelse(bp, 0); @@ -328,7 +326,7 @@ } static void -account_indir(struct uvnode *vp, struct ufs1_dinode *dp, daddr_t ilbn, daddr_t daddr, int lvl) +account_indir(struct uvnode *vp, struct lfs_dinode *dp, daddr_t ilbn, daddr_t daddr, int lvl) { struct ubuf *bp; int32_t *dap, *odap, *buf, *obuf; @@ -375,18 +373,18 @@ * Account block changes between new found inode and existing inode. */ static void -account_block_changes(struct ufs1_dinode *dp) +account_block_changes(struct lfs_dinode *dp) { int i; daddr_t lbn, off, odaddr; struct uvnode *vp; - struct inode *ip; + struct lfs_inode *ip; vp = vget(fs, dp->di_inumber); ip = (vp ? VTOI(vp) : NULL); /* Check direct block holdings between existing and new */ - for (i = 0; i < NDADDR; i++) { + for (i = 0; i < LFS_NDIRECTBLKS; i++) { odaddr = (ip ? ip->i_ffs1_db[i] : 0x0); if (dp->di_db[i] > 0 && dp->di_db[i] != odaddr) rfw_update_single(vp, i, dp->di_db[i], @@ -395,10 +393,10 @@ /* Check indirect block holdings between existing and new */ off = 0; - for (i = 0; i < NIADDR; i++) { + for (i = 0; i < LFS_NINDIRBLKS; i++) { odaddr = (ip ? ip->i_ffs1_ib[i] : 0x0); if (dp->di_ib[i] > 0 && dp->di_ib[i] != odaddr) { - lbn = -(NDADDR + off + i); + lbn = -(LFS_NDIRECTBLKS + off + i); rfw_update_single(vp, i, dp->di_ib[i], fs->lfs_bsize); account_indir(vp, dp, lbn, dp->di_ib[i], i); } @@ -417,7 +415,7 @@ * free list accounting is done. */ static void -readdress_inode(struct ufs1_dinode *dp, ufs_daddr_t daddr) +readdress_inode(struct lfs_dinode *dp, ufs_daddr_t daddr) { IFILE *ifp; SEGUSE *sup; @@ -446,20 +444,20 @@ /* Copy over preexisting in-core inode, if any */ vp = vget(fs, thisino); - memcpy(VTOI(vp)->i_din.ffs1_din, dp, sizeof(*dp)); + memcpy(VTOI(vp)->i_ffs1_din, dp, sizeof(*dp)); /* Finally account the inode itself */ sn = dtosn(fs, odaddr); LFS_SEGENTRY(sup, fs, sn, bp); - sup->su_nbytes -= DINODE1_SIZE; + sup->su_nbytes -= LFS_DINODE_SIZE; VOP_BWRITE(bp); - seg_table[sn].su_nbytes -= DINODE1_SIZE; + seg_table[sn].su_nbytes -= LFS_DINODE_SIZE; sn = dtosn(fs, daddr); LFS_SEGENTRY(sup, fs, sn, bp); - sup->su_nbytes += DINODE1_SIZE; + sup->su_nbytes += LFS_DINODE_SIZE; VOP_BWRITE(bp); - seg_table[sn].su_nbytes += DINODE1_SIZE; + seg_table[sn].su_nbytes += LFS_DINODE_SIZE; } /* @@ -518,9 +516,9 @@ /* Account for new location */ LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), bp); - sup->su_nbytes += DINODE1_SIZE; + sup->su_nbytes += LFS_DINODE_SIZE; VOP_BWRITE(bp); - seg_table[dtosn(fs, daddr)].su_nbytes += DINODE1_SIZE; + seg_table[dtosn(fs, daddr)].su_nbytes += LFS_DINODE_SIZE; } /* @@ -549,7 +547,7 @@ SEGUSE *sup; SEGSUM *sp; struct ubuf *bp, *ibp, *sbp, *cbp; - struct ufs1_dinode *dp; + struct lfs_dinode *dp; struct inodesc idesc; int i, j, bc, hassuper; int nnewfiles, ndelfiles, nmvfiles; @@ -659,8 +657,8 @@ brelse(ibp, 0); j = 0; - for (dp = (struct ufs1_dinode *)ibbuf; - dp < (struct ufs1_dinode *)ibbuf + INOPB(fs); + for (dp = (struct lfs_dinode *)ibbuf; + dp < (struct lfs_dinode *)ibbuf + INOPB(fs); ++dp) { if (dp->di_u.inumber == 0 || dp->di_u.inumber == fs->lfs_ifile) @@ -758,7 +756,7 @@ if (debug) pwarn("alloc ino %d nlink %d\n", (int)inums[j], VTOD(vp)->di_nlink); - memset(VTOD(vp)->di_db, 0, (NDADDR + NIADDR) * + memset(VTOD(vp)->di_db, 0, (LFS_NDIRECTBLKS + LFS_NINDIRBLKS) * sizeof(ufs_daddr_t)); VTOD(vp)->di_blocks = 0; diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/segwrite.c --- a/sbin/fsck_lfs/segwrite.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/segwrite.c Sun Feb 07 03:52:22 2010 -0500 @@ -66,9 +66,7 @@ #include #include #include - -#include -#include +#include /* Override certain things to make work */ #define vnode uvnode @@ -122,7 +120,7 @@ daddr_t lbn; lbn = bp->b_lblkno; - return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 0); + return (lbn < 0 && (-lbn - LFS_NDIRECTBLKS) % NINDIR(fs) == 0); } int @@ -131,7 +129,7 @@ daddr_t lbn; lbn = bp->b_lblkno; - return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 1); + return (lbn < 0 && (-lbn - LFS_NDIRECTBLKS) % NINDIR(fs) == 1); } int @@ -140,7 +138,7 @@ daddr_t lbn; lbn = bp->b_lblkno; - return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 2); + return (lbn < 0 && (-lbn - LFS_NDIRECTBLKS) % NINDIR(fs) == 2); } /* @@ -149,7 +147,7 @@ int lfs_segwrite(struct lfs * fs, int flags) { - struct inode *ip; + struct lfs_inode *ip; struct segment *sp; struct uvnode *vp; int redo; @@ -197,7 +195,7 @@ { struct ubuf *bp; struct finfo *fip; - struct inode *ip; + struct lfs_inode *ip; IFILE *ifp; ip = VTOI(vp); @@ -236,10 +234,10 @@ } int -lfs_writeinode(struct lfs * fs, struct segment * sp, struct inode * ip) +lfs_writeinode(struct lfs * fs, struct segment * sp, struct lfs_inode * ip) { struct ubuf *bp, *ibp; - struct ufs1_dinode *cdp; + struct lfs_dinode *cdp; IFILE *ifp; SEGUSE *sup; daddr_t daddr; @@ -268,7 +266,7 @@ /* Zero out inode numbers */ for (i = 0; i < INOPB(fs); ++i) - ((struct ufs1_dinode *) sp->ibp->b_data)[i].di_inumber = 0; + ((struct lfs_dinode *) sp->ibp->b_data)[i].di_inumber = 0; ++sp->start_bpp; fs->lfs_avail -= btofsb(fs, fs->lfs_ibsize); @@ -295,19 +293,19 @@ * already been gathered. */ if (ip->i_number == LFS_IFILE_INUM && sp->idp) { - *(sp->idp) = *ip->i_din.ffs1_din; + *(sp->idp) = *ip->i_ffs1_din; ip->i_lfs_osize = ip->i_ffs1_size; return 0; } bp = sp->ibp; - cdp = ((struct ufs1_dinode *) bp->b_data) + (sp->ninodes % INOPB(fs)); - *cdp = *ip->i_din.ffs1_din; + cdp = ((struct lfs_dinode *) bp->b_data) + (sp->ninodes % INOPB(fs)); + *cdp = *ip->i_ffs1_din; /* If all blocks are goig to disk, update the "size on disk" */ ip->i_lfs_osize = ip->i_ffs1_size; if (ip->i_number == LFS_IFILE_INUM) /* We know sp->idp == NULL */ - sp->idp = ((struct ufs1_dinode *) bp->b_data) + + sp->idp = ((struct lfs_dinode *) bp->b_data) + (sp->ninodes % INOPB(fs)); if (gotblk) { LFS_LOCK_BUF(bp); @@ -345,7 +343,7 @@ if (daddr != LFS_UNUSED_DADDR) { u_int32_t oldsn = dtosn(fs, daddr); LFS_SEGENTRY(sup, fs, oldsn, bp); - sup->su_nbytes -= DINODE1_SIZE; + sup->su_nbytes -= LFS_DINODE_SIZE; redo_ifile = (ino == LFS_IFILE_INUM && !(bp->b_flags & B_GATHERED)); if (redo_ifile) @@ -435,8 +433,8 @@ { SEGUSE *sup; struct ubuf *bp; - struct indir a[NIADDR + 2], *ap; - struct inode *ip; + struct lfs_indir a[LFS_NINDIRBLKS + 2], *ap; + struct lfs_inode *ip; struct uvnode *vp; daddr_t daddr, ooff; int num, error; @@ -489,7 +487,7 @@ */ if (daddr > 0) { u_int32_t oldsn = dtosn(fs, daddr); - if (lbn >= 0 && lbn < NDADDR) + if (lbn >= 0 && lbn < LFS_NDIRECTBLKS) osize = ip->i_lfs_fragsize[lbn]; else osize = fs->lfs_bsize; @@ -504,7 +502,7 @@ * segment no longer owns it, we can forget about its * old size. */ - if (lbn >= 0 && lbn < NDADDR) + if (lbn >= 0 && lbn < LFS_NDIRECTBLKS) ip->i_lfs_fragsize[lbn] = size; } @@ -767,7 +765,7 @@ ssp->ss_flags |= SS_RFW; ninos = (ssp->ss_ninos + INOPB(fs) - 1) / INOPB(fs); - sup->su_nbytes += ssp->ss_ninos * DINODE1_SIZE; + sup->su_nbytes += ssp->ss_ninos * LFS_DINODE_SIZE; if (fs->lfs_version == 1) sup->su_olastmod = write_time; @@ -963,7 +961,7 @@ int lfs_writevnodes(struct lfs *fs, struct segment *sp, int op) { - struct inode *ip; + struct lfs_inode *ip; struct uvnode *vp; int inodes_written = 0; diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/segwrite.h --- a/sbin/fsck_lfs/segwrite.h Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/segwrite.h Sun Feb 07 03:52:22 2010 -0500 @@ -41,7 +41,7 @@ int lfs_segwrite(struct lfs *, int); void lfs_writefile(struct lfs *, struct segment *, struct uvnode *); -int lfs_writeinode(struct lfs *, struct segment *, struct inode *); +int lfs_writeinode(struct lfs *, struct segment *, struct lfs_inode *); int lfs_gatherblock(struct segment *, struct ubuf *); int lfs_gather(struct lfs *, struct segment *, struct uvnode *, int (*match) (struct lfs *, struct ubuf *)); @@ -59,8 +59,8 @@ void lfs_shellsort(struct ubuf **, int32_t *, int, int); -int ufs_getlbns(struct lfs *, struct uvnode *, daddr_t, struct indir *, int *); -int ufs_bmaparray(struct lfs *, struct uvnode *, daddr_t, daddr_t *, struct indir *, int *); +int ufs_getlbns(struct lfs *, struct uvnode *, daddr_t, struct lfs_indir *, int *); +int ufs_bmaparray(struct lfs *, struct uvnode *, daddr_t, daddr_t *, struct lfs_indir *, int *); int lfs_seglock(struct lfs *, unsigned long); void lfs_segunlock(struct lfs *); diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/setup.c --- a/sbin/fsck_lfs/setup.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/setup.c Sun Feb 07 03:52:22 2010 -0500 @@ -70,8 +70,6 @@ #include #include -#include -#include #define vnode uvnode #include #undef vnode @@ -123,7 +121,7 @@ uint64_t maxblock; nptr = (1 << bshift) / sizeof(uint32_t); - maxblock = NDADDR + nptr + nptr * nptr + nptr * nptr * nptr; + maxblock = LFS_NDIRECTBLKS + nptr + nptr * nptr + nptr * nptr * nptr; return maxblock << bshift; } @@ -392,10 +390,10 @@ sbdirty(); } } - if (fs->lfs_maxsymlinklen != MAXSYMLINKLEN_UFS1) { + if (fs->lfs_maxsymlinklen != LFS_MAXSYMLINKLEN) { pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK", fs->lfs_maxsymlinklen); - fs->lfs_maxsymlinklen = MAXSYMLINKLEN_UFS1; + fs->lfs_maxsymlinklen = LFS_MAXSYMLINKLEN; if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { @@ -437,7 +435,7 @@ /* Initialize Ifile entry */ din_table[fs->lfs_ifile] = fs->lfs_idaddr; - seg_table[dtosn(fs, fs->lfs_idaddr)].su_nbytes += DINODE1_SIZE; + seg_table[dtosn(fs, fs->lfs_idaddr)].su_nbytes += LFS_DINODE_SIZE; #ifndef VERBOSE_BLOCKMAP bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/utilities.c --- a/sbin/fsck_lfs/utilities.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/utilities.c Sun Feb 07 03:52:22 2010 -0500 @@ -33,8 +33,6 @@ #include #include -#include -#include #define buf ubuf #define vnode uvnode #include @@ -65,7 +63,7 @@ extern off_t locked_queue_bytes; int -ftypeok(struct ufs1_dinode * dp) +ftypeok(struct lfs_dinode * dp) { switch (dp->di_mode & IFMT) { diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/vars.c --- a/sbin/fsck_lfs/vars.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/vars.c Sun Feb 07 03:52:22 2010 -0500 @@ -30,8 +30,6 @@ #include #include -#include -#include #include /* XXX */ #include #include "fsck.h" @@ -81,6 +79,6 @@ daddr_t n_blks; /* number of blocks in use */ ino_t n_files; /* number of files in use */ -struct ufs1_dinode zino; +struct lfs_dinode zino; int no_roll_forward = 0; /* don't roll forward */ diff -r f907de68d469 -r fb6a4db31a4e sbin/fsck_lfs/vnode.c --- a/sbin/fsck_lfs/vnode.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/fsck_lfs/vnode.c Sun Feb 07 03:52:22 2010 -0500 @@ -33,10 +33,9 @@ #include #include #include +#include #include -#include -#include #define vnode uvnode #include #undef vnode @@ -63,7 +62,7 @@ /* Convert between inode pointers and vnode pointers. */ #ifndef VTOI -#define VTOI(vp) ((struct inode *)(vp)->v_data) +#define VTOI(vp) ((struct lfs_inode *)(vp)->v_data) #endif /* @@ -141,8 +140,8 @@ buf_destroy(bp); } free(VTOI(tossvp)->inode_ext.lfs); - free(VTOI(tossvp)->i_din.ffs1_din); - memset(VTOI(tossvp), 0, sizeof(struct inode)); + free(VTOI(tossvp)->i_ffs1_din); + memset(VTOI(tossvp), 0, sizeof(struct lfs_inode)); free(tossvp->v_data); memset(tossvp, 0, sizeof(*tossvp)); free(tossvp); diff -r f907de68d469 -r fb6a4db31a4e sbin/mount_lfs/mount_lfs.c --- a/sbin/mount_lfs/mount_lfs.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/mount_lfs/mount_lfs.c Sun Feb 07 03:52:22 2010 -0500 @@ -46,7 +46,7 @@ #include #include -#include +#include #include #include @@ -94,7 +94,7 @@ void mount_lfs_parseargs(int argc, char *argv[], - struct ufs_args *args, int *mntflags, + struct lfs_args *args, int *mntflags, char *canon_dev, char *canon_dir) { int ch; @@ -151,7 +151,7 @@ int mount_lfs(int argc, char *argv[]) { - struct ufs_args args; + struct lfs_args args; int mntflags; int mntsize, oldflags, i; char fs_name[MAXPATHLEN], canon_dev[MAXPATHLEN]; diff -r f907de68d469 -r fb6a4db31a4e sbin/mount_lfs/mount_lfs.h --- a/sbin/mount_lfs/mount_lfs.h Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/mount_lfs/mount_lfs.h Sun Feb 07 03:52:22 2010 -0500 @@ -28,10 +28,10 @@ #ifndef _SBIN_MOUNT_LFS_MOUNT_LFS_H_ #define _SBIN_MOUNT_LFS_MOUNT_LFS_H_ -#include +#include int mount_lfs(int, char **); -void mount_lfs_parseargs(int, char **, struct ufs_args *, int *, +void mount_lfs_parseargs(int, char **, struct lfs_args *, int *, char *, char *); int lfs_cleaner_main(int, char **); diff -r f907de68d469 -r fb6a4db31a4e sbin/newfs_lfs/make_lfs.c --- a/sbin/newfs_lfs/make_lfs.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/newfs_lfs/make_lfs.c Sun Feb 07 03:52:22 2010 -0500 @@ -72,9 +72,7 @@ #include #include -#include #include -#include /* Override certain things to make work */ # undef simple_lock @@ -137,7 +135,7 @@ /* dlfs_minfree */ MINFREE, /* dlfs_maxfilesize */ 0, /* dlfs_fsbpseg */ 0, - /* dlfs_inopb */ DFL_LFSBLOCK/sizeof(struct ufs1_dinode), + /* dlfs_inopb */ DFL_LFSBLOCK/sizeof(struct lfs_dinode), /* dlfs_ifpb */ DFL_LFSBLOCK/sizeof(IFILE), /* dlfs_sepb */ DFL_LFSBLOCK/sizeof(SEGUSE), /* XXX ondisk32 */ @@ -156,7 +154,7 @@ /* dlfs_fbmask */ DFL_LFS_FBMASK, /* dlfs_blktodb */ 0, /* dlfs_sushift */ 0, - /* dlfs_maxsymlinklen */ MAXSYMLINKLEN_UFS1, + /* dlfs_maxsymlinklen */ LFS_MAXSYMLINKLEN, /* dlfs_sboffs */ { 0 }, /* dlfs_nclean */ 0, /* dlfs_fsmnt */ { 0 }, @@ -198,7 +196,7 @@ #endif void pwarn(const char *, ...); -static void make_dinode(ino_t, struct ufs1_dinode *, int, struct lfs *); +static void make_dinode(ino_t, struct lfs_dinode *, int, struct lfs *); static void make_dir( void *, struct direct *, int); static uint64_t maxfilesize(int); @@ -212,7 +210,7 @@ uint64_t maxblock; nptr = (1 << bshift) / sizeof(uint32_t); - maxblock = NDADDR + nptr + nptr * nptr + nptr * nptr * nptr; + maxblock = LFS_NDIRECTBLKS + nptr + nptr * nptr + nptr * nptr * nptr; return maxblock << bshift; } @@ -222,13 +220,13 @@ * directory. */ static void -make_dinode(ino_t ino, struct ufs1_dinode *dip, int nfrags, struct lfs *fs) +make_dinode(ino_t ino, struct lfs_dinode *dip, int nfrags, struct lfs *fs) { int fsb_per_blk, i; int nblocks, bb, base, factor, lvl; nblocks = howmany(nfrags, fs->lfs_frag); - if(nblocks >= NDADDR) + if(nblocks >= LFS_NDIRECTBLKS) nfrags = roundup(nfrags, fs->lfs_frag); dip->di_nlink = 1; @@ -242,10 +240,10 @@ fsb_per_blk = fragstofsb(fs, blkstofrags(fs, 1)); - if (NDADDR < nblocks) { + if (LFS_NDIRECTBLKS < nblocks) { /* Count up how many indirect blocks we need, recursively */ /* XXX We are only called with nblocks > 1 for Ifile */ - bb = nblocks - NDADDR; + bb = nblocks - LFS_NDIRECTBLKS; while (bb > 0) { bb = howmany(bb, NINDIR(fs)); ifibc += bb; @@ -255,14 +253,14 @@ } /* Assign the block addresses for the ifile */ - for (i = 0; i < MIN(nblocks,NDADDR); i++) { + for (i = 0; i < MIN(nblocks,LFS_NDIRECTBLKS); i++) { dip->di_db[i] = 0x0; } - if(nblocks > NDADDR) { + if(nblocks > LFS_NDIRECTBLKS) { dip->di_ib[0] = 0x0; - bb = howmany(nblocks - NDADDR, NINDIR(fs)) - 1; + bb = howmany(nblocks - LFS_NDIRECTBLKS, NINDIR(fs)) - 1; factor = NINDIR(fs); - base = -NDADDR - factor; + base = -LFS_NDIRECTBLKS - factor; lvl = 1; while (bb > 0) { dip->di_ib[lvl] = 0x0; @@ -303,7 +301,7 @@ int resvseg, int version, daddr_t start, int ibsize, int interleave, u_int32_t roll_id) { - struct ufs1_dinode *dip; /* Pointer to a disk inode */ + struct lfs_dinode *dip; /* Pointer to a disk inode */ CLEANERINFO *cip; /* Segment cleaner information table */ IFILE *ip; /* Pointer to array of ifile structures */ IFILE_V1 *ip_v1 = NULL; @@ -440,11 +438,11 @@ fs->lfs_ssize = ssize; fs->lfs_ibsize = ibsize; } - fs->lfs_inopb = fs->lfs_ibsize / sizeof(struct ufs1_dinode); + fs->lfs_inopb = fs->lfs_ibsize / sizeof(struct lfs_dinode); fs->lfs_minfree = minfree; if (version > 1) { - fs->lfs_inopf = secsize/DINODE1_SIZE; + fs->lfs_inopf = secsize/LFS_DINODE_SIZE; fs->lfs_interleave = interleave; if (roll_id == 0) roll_id = arc4random(); @@ -600,7 +598,7 @@ * Initialize the Ifile inode. Do this before we do anything * with the Ifile or segment tables. */ - dip = VTOI(fs->lfs_ivnode)->i_din.ffs1_din = (struct ufs1_dinode *) + dip = VTOI(fs->lfs_ivnode)->i_ffs1_din = (struct lfs_dinode *) malloc(sizeof(*dip)); if (dip == NULL) err(1, NULL); @@ -610,7 +608,7 @@ make_dinode(LFS_IFILE_INUM, dip, blkstofrags(fs, fs->lfs_cleansz + fs->lfs_segtabsz + 1), fs); dip->di_size = (fs->lfs_cleansz + fs->lfs_segtabsz + 1) << fs->lfs_bshift; - for (i = 0; i < NDADDR && i < (dip->di_size >> fs->lfs_bshift); i++) + for (i = 0; i < LFS_NDIRECTBLKS && i < (dip->di_size >> fs->lfs_bshift); i++) VTOI(fs->lfs_ivnode)->i_lfs_fragsize[i] = fs->lfs_bsize; /* @@ -668,7 +666,7 @@ /* Initialize root directory */ vp = lfs_raw_vget(fs, ROOTINO, devfd, 0x0); - dip = VTOI(vp)->i_din.ffs1_din; + dip = VTOI(vp)->i_ffs1_din; make_dinode(ROOTINO, dip, howmany(DIRBLKSIZ,fs->lfs_fsize), fs); dip->di_mode = IFDIR | UMASK; VTOI(vp)->i_lfs_osize = dip->di_size = DIRBLKSIZ; @@ -679,7 +677,7 @@ #endif VTOI(vp)->i_lfs_effnblks = dip->di_blocks = btofsb(fs, roundup(DIRBLKSIZ,fs->lfs_fsize)); - for (i = 0; i < NDADDR && i < howmany(DIRBLKSIZ, fs->lfs_bsize); i++) + for (i = 0; i < LFS_NDIRECTBLKS && i < howmany(DIRBLKSIZ, fs->lfs_bsize); i++) VTOI(vp)->i_lfs_fragsize[i] = fs->lfs_bsize; if (DIRBLKSIZ < fs->lfs_bsize) VTOI(vp)->i_lfs_fragsize[i - 1] = @@ -699,7 +697,7 @@ VTOI(vp)->i_nlink = dip->di_nlink = 2; VTOI(vp)->i_lfs_effnblks = dip->di_blocks = btofsb(fs, roundup(DIRBLKSIZ,fs->lfs_fsize)); - for (i = 0; i < NDADDR && i < howmany(DIRBLKSIZ, fs->lfs_bsize); i++) + for (i = 0; i < LFS_NDIRECTBLKS && i < howmany(DIRBLKSIZ, fs->lfs_bsize); i++) VTOI(vp)->i_lfs_fragsize[i] = fs->lfs_bsize; if (DIRBLKSIZ < fs->lfs_bsize) VTOI(vp)->i_lfs_fragsize[i - 1] = diff -r f907de68d469 -r fb6a4db31a4e sbin/newfs_lfs/newfs.c --- a/sbin/newfs_lfs/newfs.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/newfs_lfs/newfs.c Sun Feb 07 03:52:22 2010 -0500 @@ -56,8 +56,6 @@ #include #include -#include -#include #include #include diff -r f907de68d469 -r fb6a4db31a4e sbin/resize_lfs/resize_lfs.c --- a/sbin/resize_lfs/resize_lfs.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sbin/resize_lfs/resize_lfs.c Sun Feb 07 03:52:22 2010 -0500 @@ -38,7 +38,6 @@ #include #include -#include #include #include diff -r f907de68d469 -r fb6a4db31a4e sys/arch/amd64/conf/LFSONLY --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/arch/amd64/conf/LFSONLY Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,1141 @@ +# $NetBSD: GENERIC,v 1.245 2009/07/19 06:28:08 kiyohara Exp $ +# +# GENERIC machine description file +# +# This machine description file is used to generate the default NetBSD +# kernel. The generic kernel does not include all options, subsystems +# and device drivers, but should be useful for most applications. +# +# The machine description file can be customised for your specific +# machine to reduce the kernel size and improve its performance. +# +# For further information on compiling NetBSD kernels, see the config(8) +# man page. +# +# For further information on hardware support for this architecture, see +# the intro(4) man page. For further information about kernel options +# for this architecture, see the options(4) man page. For an explanation +# of each device driver in this file see the section 4 man page for the +# device. + +include "arch/amd64/conf/std.amd64" + +options INCLUDE_CONFIG_FILE # embed config file in kernel binary + +#ident "GENERIC-$Revision: 1.245 $" + +maxusers 64 # estimated number of users + +# delay between "rebooting ..." message and hardware reset, in milliseconds +#options CPURESET_DELAY=2000 + +# This option allows you to force a serial console at the specified +# I/O address. see console(4) for details. +#options CONSDEVNAME="\"com\"",CONADDR=0x2f8,CONSPEED=57600 +# you don't want the option below ON iff you are using the +# serial console option of the new boot strap code. +#options CONS_OVERRIDE # Always use above! independent of boot info + +# The following options override the memory sizes passed in from the boot +# block. Use them *only* if the boot block is unable to determine the correct +# values. Note that the BIOS may *correctly* report less than 640k of base +# memory if the extended BIOS data area is located at the top of base memory +# (as is the case on most recent systems). +#options REALBASEMEM=639 # size of base memory (in KB) +#options REALEXTMEM=15360 # size of extended memory (in KB) + +# The following options limit the overall size of physical memory +# and/or the maximum address used by the system. +# Contrary to REALBASEMEM and REALEXTMEM, they still use the BIOS memory map +# and can deal with holes in the memory layout. +#options PHYSMEM_MAX_SIZE=64 # max size of physical memory (in MB) +#options PHYSMEM_MAX_ADDR=2048 # don't use memory above this (in MB) + +# Standard system options + +options INSECURE # disable kernel security levels - X needs this + +options RTC_OFFSET=0 # hardware clock is this many mins. west of GMT +options NTP # NTP phase/frequency locked loop + +options KTRACE # system call tracing via ktrace(1) + +# Note: SysV IPC parameters could be changed dynamically, see sysctl(8). +options SYSVMSG # System V-like message queues +options SYSVSEM # System V-like semaphores +options SYSVSHM # System V-like memory sharing +#options P1003_1B_SEMAPHORE # p1003.1b semaphore support + +options MODULAR # new style module framework +options USERCONF # userconf(4) support +#options PIPE_SOCKETPAIR # smaller, but slower pipe(2) +options SYSCTL_INCLUDE_DESCR # Include sysctl descriptions in kernel + +# Intel Enhanced Speedstep for EM64T CPUs +options ENHANCED_SPEEDSTEP +#options EST_FREQ_USERWRITE # any user can set frequency + +# AMD PowerNow! and Cool`n'Quiet technology +options POWERNOW_K8 + +# Intel(R) On Demand Clock Modulation (aka ODCM) +# options INTEL_ONDEMAND_CLOCKMOD + +# Alternate buffer queue strategies for better responsiveness under high +# disk I/O load. +#options BUFQ_READPRIO +options BUFQ_PRIOCSCAN + +# Diagnostic/debugging support options +#options DIAGNOSTIC # expensive kernel consistency checks +#options DEBUG # expensive debugging checks/support +#options LOCKDEBUG # expensive locking checks/support +#options KMEMSTATS # kernel memory statistics (vmstat -m) + +# +# Because gcc omits the frame pointer for any -O level, the line below +# is needed to make backtraces in DDB work. +# +makeoptions COPTS="-O2 -fno-omit-frame-pointer" +options DDB # in-kernel debugger +#options DDB_ONPANIC=1 # see also sysctl(8): `ddb.onpanic' +options DDB_HISTORY_SIZE=512 # enable history editing in DDB +#options KGDB # remote debugger +#options KGDB_DEVNAME="\"com\"",KGDB_DEVADDR=0x3f8,KGDB_DEVRATE=9600 +#makeoptions DEBUG="-g" # compile full symbol table +#options SYSCALL_STATS # per syscall counts +#options SYSCALL_TIMES # per syscall times +#options SYSCALL_TIMES_HASCOUNTER # use 'broken' rdtsc (soekris) + +# Compatibility options +options COMPAT_15 # compatibility with NetBSD 1.5, +options COMPAT_16 # NetBSD 1.6, +options COMPAT_20 # NetBSD 2.0, +options COMPAT_30 # NetBSD 3.0, +options COMPAT_40 # NetBSD 4.0 compatibility. +options COMPAT_43 # and 4.3BSD +options COMPAT_50 # NetBSD 5.0 +#options COMPAT_386BSD_MBRPART # recognize old partition ID + +options COMPAT_OSSAUDIO +options COMPAT_NETBSD32 +options COMPAT_LINUX +options COMPAT_LINUX32 # req. COMPAT_LINUX and COMPAT_NETBSD32 +options EXEC_ELF32 +options COMPAT_BSDPTY # /dev/[pt]ty?? ptys. + +# Wedge support +options DKWEDGE_AUTODISCOVER # Automatically add dk(4) instances +options DKWEDGE_METHOD_GPT # Supports GPT partitions as wedges +# The following two options can break /etc/fstab, so handle with care +#options DKWEDGE_METHOD_BSDLABEL # Support disklabel entries as wedges +#options DKWEDGE_METHOD_MBR # Support MBR partitions as wedges + +# File systems +#file-system FFS # UFS +#file-system EXT2FS # second extended file system (linux) +file-system LFS # log-structured file system +options LFS_KERNEL_RFW # kernel rollforward support +options LFS_DIRHASH # large directory hashing for LFS +#file-system MFS # memory file system +file-system NFS # Network File System client +#file-system NTFS # Windows/NT file system (experimental) +#file-system CD9660 # ISO 9660 + Rock Ridge file system +#file-system MSDOSFS # MS-DOS file system +#file-system FDESC # /dev/fd +#file-system KERNFS # /kern +#file-system NULLFS # loopback file system +#file-system OVERLAY # overlay file system +#file-system PORTAL # portal filesystem (still experimental) +#file-system PROCFS # /proc +#file-system SMBFS # experimental - SMB/CIFS file-system +#file-system UMAPFS # NULLFS + uid and gid remapping +#file-system UNION # union file system +#file-system CODA # Coda File System; also needs vcoda (below) +#file-system PTYFS # /dev/pts/N support +#file-system TMPFS # Efficient memory file-system +##file-system UDF # experimental - OSTA UDF CD/DVD file-system +##file-system HFS # experimental - Apple HFS+ (read-only) + +# File system options +options QUOTA # UFS quotas +#options FFS_EI # FFS Endian Independent support +#options WAPBL # File system journaling support - Experimental +# Note that UFS_DIRHASH is suspected of causing kernel memory corruption. +# It is not recommended for general use. +#options UFS_DIRHASH # UFS Large Directory Hashing - Experimental +options NFSSERVER # Network File System server +#options EXT2FS_SYSTEM_FLAGS # makes ext2fs file flags (append and + # immutable) behave as system flags. +#options FFS_NO_SNAPSHOT # No FFS snapshot support + +# Networking options +#options GATEWAY # packet forwarding +options INET # IP + ICMP + TCP + UDP +options INET6 # IPV6 +#options IPSEC # IP security +#options IPSEC_ESP # IP security (encryption part; define w/IPSEC) +#options IPSEC_NAT_T # IPsec NAT traversal (NAT-T) +#options IPSEC_DEBUG # debug for IP security +#options MROUTING # IP multicast routing +#options PIM # Protocol Independent Multicast +#options ISO,TPIP # OSI +#options EON # OSI tunneling over IP +options NETATALK # AppleTalk networking protocols +options PPP_BSDCOMP # BSD-Compress compression support for PPP +options PPP_DEFLATE # Deflate compression support for PPP +options PPP_FILTER # Active filter support for PPP (requires bpf) +options PFIL_HOOKS # pfil(9) packet filter hooks +options IPFILTER_LOG # ipmon(8) log support +options IPFILTER_LOOKUP # ippool(8) support +#options IPFILTER_DEFAULT_BLOCK # block all packets by default +#options TCP_DEBUG # Record last TCP_NDEBUG packets with SO_DEBUG + +#options ALTQ # Manipulate network interfaces' output queues +#options ALTQ_BLUE # Stochastic Fair Blue +#options ALTQ_CBQ # Class-Based Queueing +#options ALTQ_CDNR # Diffserv Traffic Conditioner +#options ALTQ_FIFOQ # First-In First-Out Queue +#options ALTQ_FLOWVALVE # RED/flow-valve (red-penalty-box) +#options ALTQ_HFSC # Hierarchical Fair Service Curve +#options ALTQ_LOCALQ # Local queueing discipline +#options ALTQ_PRIQ # Priority Queueing +#options ALTQ_RED # Random Early Detection +#options ALTQ_RIO # RED with IN/OUT +#options ALTQ_WFQ # Weighted Fair Queueing + +# These options enable verbose messages for several subsystems. +# Warning, these may compile large string tables into the kernel! +#options ACPIVERBOSE # verbose ACPI configuration messages +#options MIIVERBOSE # verbose PHY autoconfig messages +#options PCIVERBOSE # verbose PCI device autoconfig messages +#options PCI_CONFIG_DUMP # verbosely dump PCI config space +#options PCMCIAVERBOSE # verbose PCMCIA configuration messages +options SCSIVERBOSE # human readable SCSI error messages +#options USBVERBOSE # verbose USB device autoconfig messages + +options NFS_BOOT_DHCP,NFS_BOOT_BOOTPARAM + +# +# wscons options +# +# builtin terminal emulations +#options WSEMUL_SUN # sun terminal emulation +options WSEMUL_VT100 # VT100 / VT220 emulation +# different kernel output - see dev/wscons/wsdisplayvar.h +options WS_KERNEL_FG=WSCOL_GREEN +#options WS_KERNEL_BG=WSCOL_BLACK +# compatibility to other console drivers +options WSDISPLAY_COMPAT_PCVT # emulate some ioctls +options WSDISPLAY_COMPAT_SYSCONS # emulate some ioctls +options WSDISPLAY_COMPAT_USL # VT handling +options WSDISPLAY_COMPAT_RAWKBD # can get raw scancodes +# see dev/pckbport/wskbdmap_mfii.c for implemented layouts +#options PCKBD_LAYOUT="(KB_DE | KB_NODEAD)" +# allocate a number of virtual screens at autoconfiguration time +#options WSDISPLAY_DEFAULTSCREENS=4 +# use a large software cursor that doesn't blink +options PCDISPLAY_SOFTCURSOR +# modify the screen type of the console; defaults to "80x25" +#options VGA_CONSOLE_SCREENTYPE="\"80x24\"" +# work around a hardware bug that loaded fonts don't work; found on ATI cards +#options VGA_CONSOLE_ATI_BROKEN_FONTSEL +# console scrolling support. +options WSDISPLAY_SCROLLSUPPORT +# enable VGA raster mode capable of displaying multilingual text on console +#options VGA_RASTERCONSOLE + +# Kernel root file system and dump configuration. +config netbsd root on ? type ? +#config netbsd root on sd0a type ffs +#config netbsd root on ? type nfs + +# +# Device configuration +# + +#IPMI support +ipmi0 at mainbus? + +# ACPI will be used if present. If not it will fall back to MPBIOS +acpi0 at mainbus0 +options ACPI_SCANPCI # find PCI roots using ACPI +options MPBIOS # configure CPUs and APICs using MPBIOS +options MPBIOS_SCANPCI # MPBIOS configures PCI roots +#options PCI_INTR_FIXUP # PCI interrupt routing via ACPI +#options PCI_BUS_FIXUP # fixup PCI bus numbering +#options PCI_ADDR_FIXUP # fixup PCI I/O addresses +#options ACPI_ACTIVATE_DEV # If set, activate inactive devices +#options ACPICA_PEDANTIC # force strict conformance to the Spec. +options VGA_POST # in-kernel support for VGA POST + +# ACPI devices +#acpiacad* at acpi? # ACPI AC Adapter +#acpibat* at acpi? # ACPI Battery +#acpibut* at acpi? # ACPI Button +#acpidalb* at acpi? # Direct Application Launch Button +# The ACPI Embedded Controller is generally configured via the special ECDT. +# This is required as parts of the DSDT can reference the EC before the normal +# attach phase. +#acpiec* at acpi? # ACPI Embedded Controller (late binding) +#acpiecdt* at acpi? # ACPI Embedded Controller (early binding) +#acpilid* at acpi? # ACPI Lid Switch +#acpitz* at acpi? # ACPI Thermal Zone + +# Mainboard devices +#aiboost* at acpi? # ASUS AI Booster Hardware monitor +#asus* at acpi? # ASUS hotkeys +#attimer* at acpi? # AT Timer +##com* at acpi? # Serial communications interface +##fdc* at acpi? # Floppy disk controller +#hpqlb* at acpi? # HP Quick Launch Buttons +#hpet* at acpi? # High Precision Event Timer +#joy* at acpi? # Joystick/Game port +##lpt* at acpi? # Parallel port +#mpu* at acpi? # Roland MPU-401 MIDI UART +#pckbc* at acpi? # PC keyboard controller +#pcppi* at acpi? # AT-style speaker sound +#sony* at acpi? # Sony Notebook Controller +#thinkpad* at acpi? # IBM/Lenovo Thinkpad hotkeys +#ug* at acpi? # Abit uGuru Hardware monitor +#wss* at acpi? # NeoMagic 256AV in wss mode + +#apm0 at mainbus0 # Advanced power management + +# Tuning for power management, see apm(4) for more details. +#options APM_NO_IDLE # Don't call BIOS CPU idle function +#options APM_V10_ONLY # Use only the APM 1.0 calls +#options APM_NO_POWEROFF # Don't power off on halt(8) +#options APM_POWER_PRINT # Print stats on the console +#options APM_DISABLE_INTERRUPTS=0 # Don't disable interrupts + + +# Basic Bus Support + +# PCI bus support +pci* at mainbus? bus ? +pci* at pchb? bus ? +pci* at ppb? bus ? + +# PCI bridges +pchb* at pci? dev ? function ? # PCI-Host bridges +pcib* at pci? dev ? function ? # PCI-ISA bridges +ppb* at pci? dev ? function ? # PCI-PCI bridges +# XXX 'puc's aren't really bridges, but there's no better place for them here +#puc* at pci? dev ? function ? # PCI "universal" comm. cards + +#amdpcib* at pci? dev ? function ? # AMD 8111 PCI-ISA w/ HPET +#hpet* at amdpcib? + +#ichlpcib* at pci? dev ? function ? # Intel ICH PCI-ISA w/ timecounter, + # watchdog and Speedstep support. +#hpet* at ichlpcib? + +#aapic* at pci? dev ? function ? # AMD 8131 IO apic + +#agp* at pchb? + +# ISA bus support +#isa0 at mainbus? +isa0 at pcib? +#isa0 at amdpcib? +#isa0 at ichlpcib? + +# CardBus bridge support +#cbb* at pci? dev ? function ? +#cardslot* at cbb? + +# CardBus bus support +#cardbus* at cardslot? +#pcmcia* at cardslot? + +# Console Devices + +# wscons +pckbc0 at isa? # pc keyboard controller +pckbd* at pckbc? # PC keyboard +pms* at pckbc? # PS/2 mouse for wsmouse +#options PMS_DISABLE_POWERHOOK # Disable PS/2 reset on resume +#options PMS_SYNAPTICS_TOUCHPAD # Enable support for Synaptics Touchpads +#options PMS_ELANTECH_TOUCHPAD # Enable support for Elantech Touchpads +vga* at pci? dev ? function ? +#genfb* at pci? dev ? function ? +wsdisplay* at vga? console ? +#wsdisplay* at wsemuldisplaydev? +wskbd* at pckbd? console ? +wsmouse* at pms? mux 0 + +attimer0 at isa? +pcppi0 at isa? +sysbeep0 at pcppi? + +# Cryptographic Devices + +# PCI cryptographic devices +#hifn* at pci? dev ? function ? # Hifn 7755/7811/795x +#ubsec* at pci? dev ? function ? # Broadcom 5501/5601/580x/582x + +# Serial Devices + +# PCI serial interfaces +#com* at puc? port ? # 16x50s on "universal" comm boards +#cy* at pci? dev ? function ? # Cyclades Cyclom-Y serial boards +#cz* at pci? dev ? function ? # Cyclades-Z multi-port serial boards + +# PCMCIA serial interfaces +#com* at pcmcia? function ? # Modems and serial cards + +#pcmcom* at pcmcia? function ? # PCMCIA multi-port serial cards +#com* at pcmcom? slave ? # ...and the slave devices + +# CardBus serial interfaces +#com* at cardbus? function ? # Modems and serial cards + +# ISA serial interfaces +#options COM_HAYESP # adds Hayes ESP serial board support +#com0 at isa? port 0x3f8 irq 4 # Standard PC serial ports +#com1 at isa? port 0x2f8 irq 3 + +# Parallel Printer Interfaces + +# PCI parallel printer interfaces +#lpt* at puc? port ? # || ports on "universal" comm boards + +# ISA parallel printer interfaces +#lpt0 at isa? port 0x378 irq 7 # standard PC parallel ports +#lpt1 at isa? port 0x278 + +# Hardware monitors + +#amdtemp* at pci? dev ? function ? # AMD CPU Temperature sensors + +# LM7[89] and compatible hardware monitors +#lm0 at isa? port 0x290 # other common ports: 0x280, 0x310 + +# SMSC LPC47B397 hardware monitor functions +#smsc0 at isa? port 0x02e + +# AMD 768 and 8111 power/ACPI controllers +#amdpm* at pci? dev ? function ? # RNG and SMBus 1.0 interface +#iic* at amdpm? # sensors below are on this bus + +# NVIDIA nForce2/3/4 SMBus controller +#nfsmbc* at pci? dev ? function ? +#nfsmb* at nfsmbc? +#iic* at nfsmb? + +# Intel PIIX4 power management controllers +#piixpm* at pci? dev ? function ? # PIIX4 compatible PM controller +#iic* at piixpm? # SMBus on PIIX4 + +# Intel Core's on-die Thermal sensor +#options INTEL_CORETEMP + +# Intel ICH SMBus controller +#ichsmb* at pci? dev ? function ? +#iic* at ichsmb? + +# Thermal monitor and fan controller +#dbcool* at iic? addr 0x2C # Unknown other motherboard(s) +#dbcool* at iic? addr 0x2D # Tyan S2881 +#dbcool* at iic? addr 0x2E # Tyan S2882-D + +# Fintek Super I/O with hardware monitor +#finsio0 at isa? port 0x4e + +# iTE IT87xxF Super I/O with watchdog and sensors support +#itesio0 at isa? port 0x2e + +# Abit uGuru Hardware system monitor +#ug0 at isa? port 0xe0 + +# Serial Presence Detect capable memory modules +#spdmem* at iic? addr 0x50 +#spdmem* at iic? addr 0x51 +#spdmem* at iic? addr 0x52 +#spdmem* at iic? addr 0x53 + +# I2O devices +#iop* at pci? dev ? function ? # I/O processor +#iopsp* at iop? tid ? # SCSI/FC-AL ports +#ld* at iop? tid ? # block devices +# XXX dpti.c wants a processor type that is not assigned for x86-64 +#dpti* at iop? tid 0 # DPT/Adaptec control interface + + +# SCSI Controllers and Devices + +# PCI SCSI controllers +#adv* at pci? dev ? function ? # AdvanSys 1200[A,B], 9xx[U,UA] SCSI +#adw* at pci? dev ? function ? # AdvanSys 9x0UW[D], 3940U[2,3]W SCSI +#ahc* at pci? dev ? function ? # Adaptec [23]94x, aic78x0 SCSI +#ahd* at pci? dev ? function ? # Adaptec aic790x SCSI +#bha* at pci? dev ? function ? # BusLogic 9xx SCSI +#dpt* at pci? dev ? function ? # DPT SmartCache/SmartRAID +#iha* at pci? dev ? function ? # Initio INIC-940/950 SCSI +#isp* at pci? dev ? function ? # Qlogic ISP [12]0x0 SCSI/FibreChannel +#mfi* at pci? dev ? function ? # LSI MegaRAID SAS +#mly* at pci? dev ? function ? # Mylex AcceleRAID and eXtremeRAID +#mpt* at pci? dev ? function ? # LSILogic 9x9 and 53c1030 +#pcscp* at pci? dev ? function ? # AMD 53c974 PCscsi-PCI SCSI +#siop* at pci? dev ? function ? # Symbios 53c8xx SCSI +#esiop* at pci? dev ? function ? # Symbios 53c875 and newer SCSI +#options SIOP_SYMLED # drive the act. LED in software +#trm* at pci? dev ? function ? # Tekram DC-395U/UW/F, DC-315/U SCSI + +# PCMCIA SCSI controllers +#aic* at pcmcia? function ? # Adaptec APA-1460 SCSI +#esp* at pcmcia? function ? # Qlogic ESP406/FAS408 SCSI +#spc* at pcmcia? function ? # Fujitsu MB87030/MB89352 SCSI + +# CardBus SCSI cards +#adv* at cardbus? function ? # AdvanSys 1200[A,B], 9xx[U,UA] SCSI +#ahc* at cardbus? function ? # Adaptec ADP-1480 + +# SCSI bus support +#scsibus* at scsi? + +# SCSI devices +#sd* at scsibus? target ? lun ? # SCSI disk drives +#st* at scsibus? target ? lun ? # SCSI tape drives +#cd* at scsibus? target ? lun ? # SCSI CD-ROM drives +#ch* at scsibus? target ? lun ? # SCSI autochangers +#ses* at scsibus? target ? lun ? # SCSI Enclosure Services devices +#ss* at scsibus? target ? lun ? # SCSI scanners +#uk* at scsibus? target ? lun ? # SCSI unknown + + +# RAID controllers and devices +#aac* at pci? dev ? function ? # Adaptec AAC family +#amr* at pci? dev ? function ? # AMI/LSI Logic MegaRAID +#arcmsr* at pci? dev ? function ? # Areca SATA RAID controllers +#cac* at pci? dev ? function ? # Compaq PCI array controllers +#ciss* at pci? dev ? function ? # HP Smart Array controllers +#icp* at pci? dev ? function ? # ICP-Vortex GDT & Intel RAID +#mlx* at pci? dev ? function ? # Mylex DAC960 & DEC SWXCR family +#twe* at pci? dev ? function ? # 3ware Escalade RAID controllers +#twa* at pci? dev ? function ? # 3ware Escalade 9xxx RAID controllers + +#ld* at aac? unit ? +#ld* at amr? unit ? +#ld* at cac? unit ? +#ld* at icp? unit ? +#ld* at twe? unit ? +#ld* at twa? unit ? +#ld* at mlx? unit ? + +#icpsp* at icp? unit ? # SCSI pass-through + +# IDE and related devices +# PCI IDE controllers - see pciide(4) for supported hardware. +# The 0x0001 flag force the driver to use DMA, even if the driver doesn't know +# how to set up DMA modes for this chip. This may work, or may cause +# a machine hang with some controllers. +pciide* at pci? dev ? function ? flags 0x0000 # GENERIC pciide driver +#acardide* at pci? dev ? function ? # Acard IDE controllers +#aceride* at pci? dev ? function ? # Acer Lab IDE controllers +#ahcisata* at pci? dev ? function ? # AHCI SATA controllers +#artsata* at pci? dev ? function ? # Intel i31244 SATA controller +#cmdide* at pci? dev ? function ? # CMD tech IDE controllers +#cypide* at pci? dev ? function ? # Cypress IDE controllers +#hptide* at pci? dev ? function ? # Triones/HighPoint IDE controllers +#iteide* at pci? dev ? function ? # IT Express IDE controllers +#ixpide* at pci? dev ? function ? # ATI IXP IDE controllers +#jmide* at pci? dev ? function ? # JMicron PCI-e PATA/SATA controllers +#ahcisata* at jmide? +#optiide* at pci? dev ? function ? # Opti IDE controllers +#piixide* at pci? dev ? function ? # Intel IDE controllers +#pdcide* at pci? dev ? function ? # Promise IDE controllers +#pdcsata* at pci? dev ? function ? # Promise SATA150 controllers +#satalink* at pci? dev ? function ? # SiI SATALink controllers +#siisata* at pci? dev ? function ? # SiI SteelVine controllers +#siside* at pci? dev ? function ? # SiS IDE controllers +#slide* at pci? dev ? function ? # Symphony Labs IDE controllers +#svwsata* at pci? dev ? function ? # ServerWorks SATA controllers +#viaide* at pci? dev ? function ? # VIA/AMD/Nvidia IDE controllers + +# PCMCIA IDE controllers +#wdc* at pcmcia? function ? + +# CardBus IDE controllers +#njata* at cardbus? function ? flags 0x01 # Workbit NinjaATA-32 +#siisata* at cardbus? function ? # SiI SteelVine controllers + +# ISA ST506, ESDI, and IDE controllers +# Use flags 0x01 if you want to try to use 32bits data I/O (the driver will +# fall back to 16bits I/O if 32bits I/O are not functional). +# Some controllers pass the initial 32bit test, but will fail later. +#wdc0 at isa? port 0x1f0 irq 14 flags 0x00 +#wdc1 at isa? port 0x170 irq 15 flags 0x00 + +# ATA (IDE) bus support +atabus* at ata? +options ATADEBUG + +# IDE drives +# Flags are used only with controllers that support DMA operations +# and mode settings (e.g. some pciide controllers) +# The lowest order four bits (rightmost digit) of the flags define the PIO +# mode to use, the next set of four bits the DMA mode and the third set the +# UltraDMA mode. For each set of four bits, the 3 lower bits define the mode +# to use, and the last bit must be 1 for this setting to be used. +# For DMA and UDMA, 0xf (1111) means 'disable'. +# 0x0fac means 'use PIO mode 4, DMA mode 2, disable UltraDMA'. +# (0xc=1100, 0xa=1010, 0xf=1111) +# 0x0000 means "use whatever the drive claims to support". +wd* at atabus? drive ? flags 0x0000 + +# ATAPI bus support +atapibus* at atapi? + + +# ATA RAID configuration support, as found on some Promise controllers. +pseudo-device ataraid +#ld* at ataraid? vendtype ? unit ? + +# ATAPI devices +# flags have the same meaning as for IDE drives. +#cd* at atapibus? drive ? flags 0x0000 # ATAPI CD-ROM drives +#sd* at atapibus? drive ? flags 0x0000 # ATAPI disk drives +#st* at atapibus? drive ? flags 0x0000 # ATAPI tape drives +#uk* at atapibus? drive ? flags 0x0000 # ATAPI unknown + + +# Miscellaneous mass storage devices + +# ISA floppy +#fdc0 at isa? port 0x3f0 irq 6 drq 2 # standard PC floppy controllers +#fdc1 at isa? port 0x370 irq ? drq ? +#fd* at fdc? drive ? # the drives themselves +# some machines need you to do this instead of fd* +#fd0 at fdc0 drive 0 + +# Network Interfaces + +# PCI network interfaces +#age* at pci? dev ? function ? # Attansic/Atheros L1 Gigabit Ethernet +#an* at pci? dev ? function ? # Aironet PC4500/PC4800 (802.11) +#ale* at pci? dev ? function ? # Attansic/Atheros L1E Ethernet +#ath* at pci? dev ? function ? # Atheros 5210/5211/5212 802.11 +#atw* at pci? dev ? function ? # ADMtek ADM8211 (802.11) +#bce* at pci? dev ? function ? # Broadcom 440x 10/100 Ethernet +#bge* at pci? dev ? function ? # Broadcom 570x gigabit Ethernet +#bnx* at pci? dev ? function ? # Broadcom NetXtremeII gigabit Ethernet +#dge* at pci? dev ? function ? # Intel 82597 10GbE LR +#en* at pci? dev ? function ? # ENI/Adaptec ATM +#ep* at pci? dev ? function ? # 3Com 3c59x +#epic* at pci? dev ? function ? # SMC EPIC/100 Ethernet +#esh* at pci? dev ? function ? # Essential HIPPI card +#ex* at pci? dev ? function ? # 3Com 90x[BC] +#fpa* at pci? dev ? function ? # DEC DEFPA FDDI +fxp* at pci? dev ? function ? # Intel EtherExpress PRO 10+/100B +#gsip* at pci? dev ? function ? # NS83820 Gigabit Ethernet +#ipw* at pci? dev ? function ? # Intel PRO/Wireless 2100 +#iwi* at pci? dev ? function ? # Intel PRO/Wireless 2200BG +#iwn* at pci? dev ? function ? # Intel PRO/Wireless 4965AGN +#jme* at pci? dev ? function ? # JMicron JMC2[56]0 ethernet +#hme* at pci? dev ? function ? # Sun Microelectronics STP2002-STQ +#le* at pci? dev ? function ? # PCnet-PCI Ethernet +#lii* at pci? dev ? function ? # Atheros L2 Fast-Ethernet +#lmc* at pci? dev ? function ? # Lan Media Corp SSI/HSSI/DS3 +#mskc* at pci? dev ? function ? # Marvell Yukon 2 Gigabit Ethernet +#msk* at mskc? # Marvell Yukon 2 Gigabit Ethernet +#mtd* at pci? dev ? function ? # Myson MTD803 3-in-1 Ethernet +#ne* at pci? dev ? function ? # NE2000-compatible Ethernet +#nfe* at pci? dev ? function ? # NVIDIA nForce Ethernet +#ntwoc* at pci? dev ? function ? # Riscom/N2 PCI Sync Serial +#pcn* at pci? dev ? function ? # AMD PCnet-PCI Ethernet +#ral* at pci? dev ? function ? # Ralink Technology RT25x0 802.11a/b/g +#re* at pci? dev ? function ? # Realtek 8139C+/8169/8169S/8110S +#rtk* at pci? dev ? function ? # Realtek 8129/8139 +#rtw* at pci? dev ? function ? # Realtek 8180L (802.11) +#sf* at pci? dev ? function ? # Adaptec AIC-6915 Ethernet +#sip* at pci? dev ? function ? # SiS 900/DP83815 Ethernet +#skc* at pci? dev ? function ? # SysKonnect SK9821 Gigabit Ethernet +#sk* at skc? # SysKonnect SK9821 Gigabit Ethernet +#ste* at pci? dev ? function ? # Sundance ST-201 Ethernet +#stge* at pci? dev ? function ? # Sundance/Tamarack TC9021 Gigabit +#ti* at pci? dev ? function ? # Alteon ACEnic gigabit Ethernet +#tl* at pci? dev ? function ? # ThunderLAN-based Ethernet +#tlp* at pci? dev ? function ? # DECchip 21x4x and clones +#txp* at pci? dev ? function ? # 3com 3cr990 +#vge* at pci? dev ? function ? # VIATech VT612X Gigabit Ethernet +#vr* at pci? dev ? function ? # VIA Rhine Fast Ethernet +#wi* at pci? dev ? function ? # Intersil Prism Mini-PCI (802.11b) +#wm* at pci? dev ? function ? # Intel 82543/82544 gigabit +#wpi* at pci? dev ? function ? # Intel PRO/Wireless 3945ABG +#xge* at pci? dev ? function ? # Neterion (S2io) Xframe-I 10GbE + +# PCMCIA network interfaces +#an* at pcmcia? function ? # Aironet PC4500/PC4800 (802.11) +#awi* at pcmcia? function ? # BayStack 650/660 (802.11FH/DS) +#cnw* at pcmcia? function ? # Xircom/Netwave AirSurfer +#cs* at pcmcia? function ? # CS89xx Ethernet +#ep* at pcmcia? function ? # 3Com 3c589 and 3c562 Ethernet +#mbe* at pcmcia? function ? # MB8696x based Ethernet +#ne* at pcmcia? function ? # NE2000-compatible Ethernet +#ray* at pcmcia? function ? # Raytheon Raylink (802.11) +#sm* at pcmcia? function ? # Megahertz Ethernet +# tr at pcmcia has problems with Cardbus bridges +#tr* at pcmcia? function ? # TROPIC based Token-Ring +#wi* at pcmcia? function ? # Lucent/Intersil WaveLan IEEE (802.11) +#xirc* at pcmcia? function ? # Xircom CreditCard Ethernet +#com* at xirc? +#xi* at xirc? + +#mhzc* at pcmcia? function ? # Megahertz Ethernet/Modem combo cards +#com* at mhzc? +#sm* at mhzc? + +# CardBus network cards +#ath* at cardbus? function ? # Atheros 5210/5211/5212 802.11 +#atw* at cardbus? function ? # ADMtek ADM8211 (802.11) +#ex* at cardbus? function ? # 3Com 3C575TX +#fxp* at cardbus? function ? # Intel i8255x +#ral* at cardbus? function ? # Ralink Technology RT25x0 802.11a/b/g +#re* at cardbus? function ? # Realtek 8139C+/8169/8169S/8110S +#rtk* at cardbus? function ? # Realtek 8129/8139 +#rtw* at cardbus? function ? # Realtek 8180L (802.11) +#tlp* at cardbus? function ? # DECchip 21143 + +# MII/PHY support +#acphy* at mii? phy ? # DAltima AC101 and AMD Am79c874 PHYs +#amhphy* at mii? phy ? # AMD 79c901 Ethernet PHYs +#atphy* at mii? phy ? # Attansic/Atheros PHYs +#bmtphy* at mii? phy ? # Broadcom BCM5201 and BCM5202 PHYs +#brgphy* at mii? phy ? # Broadcom BCM5400-family PHYs +#ciphy* at mii? phy ? # Cicada CS8201 Gig-E PHYs +#dmphy* at mii? phy ? # Davicom DM9101 PHYs +#exphy* at mii? phy ? # 3Com internal PHYs +#gentbi* at mii? phy ? # Generic Ten-Bit 1000BASE-[CLS]X PHYs +#glxtphy* at mii? phy ? # Level One LXT-1000 PHYs +#gphyter* at mii? phy ? # NS83861 Gig-E PHY +#icsphy* at mii? phy ? # Integrated Circuit Systems ICS189x +#igphy* at mii? phy ? # Intel IGP01E1000 +#ikphy* at mii? phy ? # Intel 82563 PHYs +#inphy* at mii? phy ? # Intel 82555 PHYs +#iophy* at mii? phy ? # Intel 82553 PHYs +#lxtphy* at mii? phy ? # Level One LXT-970 PHYs +#makphy* at mii? phy ? # Marvell Semiconductor 88E1000 PHYs +#nsphy* at mii? phy ? # NS83840 PHYs +#nsphyter* at mii? phy ? # NS83843 PHYs +#pnaphy* at mii? phy ? # generic HomePNA PHYs +#qsphy* at mii? phy ? # Quality Semiconductor QS6612 PHYs +#rgephy* at mii? phy ? # Realtek 8169S/8110 internal PHYs +#rlphy* at mii? phy ? # Realtek 8139/8201L PHYs +#sqphy* at mii? phy ? # Seeq 80220/80221/80223 PHYs +#tlphy* at mii? phy ? # ThunderLAN PHYs +#tqphy* at mii? phy ? # TDK Semiconductor PHYs +ukphy* at mii? phy ? # generic unknown PHYs +#urlphy* at mii? phy ? # Realtek RTL8150L internal PHYs + + +# USB Controller and Devices + +# PCI USB controllers +#ehci* at pci? dev ? function ? # Enhanced Host Controller +#ohci* at pci? dev ? function ? # Open Host Controller +#uhci* at pci? dev ? function ? # Universal Host Controller (Intel) + +# CardBus USB controllers +#ehci* at cardbus? function ? # Enhanced Host Controller +#ohci* at cardbus? function ? # Open Host Controller +#uhci* at cardbus? function ? # Universal Host Controller (Intel) + +# ISA USB controllers +#slhci0 at isa? port 0x300 irq 5 # ScanLogic SL811HS + +# PCMCIA USB controllers +#slhci* at pcmcia? function ? # ScanLogic SL811HS + +# USB bus support +#usb* at ehci? +#usb* at ohci? +#usb* at uhci? +#usb* at slhci? + +# USB Hubs +#uhub* at usb? +#uhub* at uhub? port ? + +# USB HID device +#uhidev* at uhub? port ? configuration ? interface ? + +# USB Mice +#ums* at uhidev? reportid ? +#wsmouse* at ums? mux 0 + +# USB eGalax touch-panel +#uep* at uhub? port ? +#wsmouse* at uep? mux 0 + +# USB Keyboards +#ukbd* at uhidev? reportid ? +#wskbd* at ukbd? console ? mux 1 + +# USB serial adapter +#ucycom* at uhidev? reportid ? + +# USB Generic HID devices +#uhid* at uhidev? reportid ? + +# USB Printer +#ulpt* at uhub? port ? configuration ? interface ? + +# USB Modem +#umodem* at uhub? port ? configuration ? +#ucom* at umodem? + +# Huawei E220 3G/HSDPA modem +#uhmodem* at uhub? port ? configuration ? interface ? +#ucom* at uhmodem? portno ? + +# USB Mass Storage +#umass* at uhub? port ? configuration ? interface ? +#wd* at umass? + +# USB audio +#uaudio* at uhub? port ? configuration ? + +# USB MIDI +#umidi* at uhub? port ? configuration ? + +# USB IrDA +# USB-IrDA bridge spec +#uirda* at uhub? port ? configuration ? interface ? +#irframe* at uirda? + +#stuirda* at uhub? port ? configuration ? interface ? +#irframe* at stuirda? + +# SigmaTel STIr4200 USB/IrDA Bridge +#ustir* at uhub? port ? +#irframe* at ustir? + +# USB Ethernet adapters +#aue* at uhub? port ? # ADMtek AN986 Pegasus based adapters +#axe* at uhub? port ? # ASIX AX88172 based adapters +#cdce* at uhub? port ? # CDC, Ethernet Networking Control Model +#cue* at uhub? port ? # CATC USB-EL1201A based adapters +#kue* at uhub? port ? # Kawasaki LSI KL5KUSB101B based adapters +#url* at uhub? port ? # Realtek RTL8150L based adapters +#udav* at uhub? port ? # Davicom DM9601 based adapters + +# Prolific PL2301/PL2302 host-to-host adapter +#upl* at uhub? port ? + +# Serial adapters +#ubsa* at uhub? port ? # Belkin serial adapter +#ucom* at ubsa? portno ? + +#uchcom* at uhub? port ? # WinChipHead CH341/CH340 serial adapter +#ucom* at uchcom? portno ? + +#uftdi* at uhub? port ? # FTDI FT8U100AX serial adapter +#ucom* at uftdi? portno ? + +#uipaq* at uhub? port ? # iPAQ PDAs +#ucom* at uipaq? portno ? + +#umct* at uhub? port ? # MCT USB-RS232 serial adapter +#ucom* at umct? portno ? + +#uplcom* at uhub? port ? # I/O DATA USB-RSAQ2 serial adapter +#ucom* at uplcom? portno ? + +#uslsa* at uhub? port ? # Silicon Labs USB-RS232 serial adapter +#ucom* at uslsa? portno ? + +#uvscom* at uhub? port ? # SUNTAC Slipper U VS-10U serial adapter +#ucom* at uvscom? portno ? + +# RIM BlackBerry +#uberry* at uhub? port ? + +# Diamond Multimedia Rio 500 +#urio* at uhub? port ? + +# USB Handspring Visor +#uvisor* at uhub? port ? +#ucom* at uvisor? + +# Kyocera AIR-EDGE PHONE +#ukyopon* at uhub? port ? +#ucom* at ukyopon? portno ? + +# USB scanners +#uscanner* at uhub? port ? + +# USB 802.11 adapters +#atu* at uhub? port ? # Atmel at76c50x 802.11b +#ral* at uhub? port ? # Ralink Technology RT25x0 802.11a/b/g +#rum* at uhub? port ? # Ralink Technology RT2501/RT2601 802.11a/b/g +#zyd* at uhub? port ? # Zydas ZD1211 + +# USB scanners that use SCSI emulation, e.g., HP5300 +#usscanner* at uhub? port ? + +# Topfield TF5000PVR range of DVB recorders +#utoppy* at uhub? port ? + +# Y@P firmware loader +#uyap* at uhub? port ? + +# D-Link DSB-R100 USB radio +#udsbr* at uhub? port ? +#radio* at udsbr? + +# USB Generic driver +#ugen* at uhub? port ? +# On ugen bulk endpoints, perform read-ahead and write-behind. +#options UGEN_BULK_RA_WB + +# USB 3G datacards +#u3g* at uhub? port ? +#ucom* at u3g? + +# USB generic serial port (e.g., data over cellular) +#ugensa* at uhub? port ? +#ucom* at ugensa? + +# IrDA and Consumer Ir devices + +# Toshiba Oboe +#oboe* at pci? dev ? function ? # broken -- vtophys +#irframe* at oboe? + +# PCI IEEE1394 controllers +#fwohci* at pci? dev ? function ? # IEEE1394 Open Host Controller + +# CardBus IEEE1394 controllers +#fwohci* at cardbus? function ? # IEEE1394 Open Host Controller + +#ieee1394if* at fwohci? +#fwip* at ieee1394if? # IP over IEEE1394 +#sbp* at ieee1394if? euihi ? euilo ? + +# Audio Devices + +# PCI audio devices +#auacer* at pci? dev ? function ? # ALi M5455 integrated AC'97 Audio +#auich* at pci? dev ? function ? # Intel/AMD/nVidia AC'97 Audio +#auixp* at pci? dev ? function ? # ATI IXP AC'97 Audio +#autri* at pci? dev ? function ? # Trident 4DWAVE based AC'97 Audio +#auvia* at pci? dev ? function ? # VIA AC'97 audio +#azalia* at pci? dev ? function ? # High Definition Audio +#clcs* at pci? dev ? function ? # Cirrus Logic CS4280 +#clct* at pci? dev ? function ? # Cirrus Logic CS4281 +#cmpci* at pci? dev ? function ? # C-Media CMI8338/8738 +#eap* at pci? dev ? function ? # Ensoniq AudioPCI +#emuxki* at pci? dev ? function ? # Creative SBLive! and PCI512 +#esa* at pci? dev ? function ? # ESS Allegro-1 / Maestro-3 PCI Audio +#esm* at pci? dev ? function ? # ESS Maestro-1/2/2e PCI Audio Accelerator +#eso* at pci? dev ? function ? # ESS Solo-1 PCI AudioDrive +#fms* at pci? dev ? function ? # Forte Media FM801 +#neo* at pci? dev ? function ? # NeoMagic 256 AC'97 Audio +#sv* at pci? dev ? function ? # S3 SonicVibes +#yds* at pci? dev ? function ? # Yamaha DS-1 PCI Audio + +# OPL[23] FM synthesizers +#opl0 at isa? port 0x388 # use only if not attached to sound card +#opl* at cmpci? flags 1 +#opl* at eso? +#opl* at fms? +#opl* at sv? + +# Audio support +#audio* at audiobus? + +# MPU 401 UARTs +#mpu* at isa? port 0x330 irq 9 # MPU401 or compatible card +#mpu* at cmpci? +#mpu* at eso? +#mpu* at yds? + +# MIDI support +#midi* at midibus? +#midi* at pcppi? # MIDI interface to the PC speaker + +# The spkr driver provides a simple tone interface to the built in speaker. +#spkr0 at pcppi? # PC speaker + + +# FM-Radio devices +# PCI radio devices +#gtp* at pci? dev ? function ? # Guillemot Maxi Radio FM 2000 Radio Card + +# Radio support +#radio* at gtp? + + +# Video capture devices + +#pseye* at uhub? # Sony PLAYSTATION(R) Eye webcam +#uvideo* at uhub? # USB Video Class capture devices +#video* at videobus? + + +# TV cards + +# Brooktree 848/849/878/879 based TV cards +#bktr* at pci? dev ? function ? +#radio* at bktr? + + +# Bluetooth Controller and Device support + +# Bluetooth PCMCIA Controllers +#bt3c* at pcmcia? function ? # 3Com 3CRWB6096-A +#btbc* at pcmcia? function ? # AnyCom BlueCard LSE041/039/139 + +# Bluetooth SDIO Controllers +#sbt* at sdmmc? + +# Bluetooth USB Controllers +#ubt* at uhub? port ? + +# Bluetooth Device Hub +#bthub* at bcsp? +#bthub* at bt3c? +#bthub* at btbc? +#bthub* at btuart? +#bthub* at sbt? +#bthub* at ubt? + +# Bluetooth HID support +#bthidev* at bthub? + +# Bluetooth Mouse +#btms* at bthidev? reportid ? +#wsmouse* at btms? mux 0 + +# Bluetooth Keyboard +#btkbd* at bthidev? reportid ? +#wskbd* at btkbd? console ? mux 1 + +# Bluetooth Audio support +#btsco* at bthub? + + +# SD/MMC/SDIO Controller and Device support + +# SD/MMC controller +#sdhc* at pci? # SD Host Controller +#sdmmc* at sdhc? # SD/MMC bus + +#ld* at sdmmc? + + +# Mice + +# Middle Digital, Inc. PCI-Weasel serial console board control +# devices (watchdog timer, etc.) +#weasel* at pci? + +# Pull in optional local configuration +cinclude "arch/amd64/conf/GENERIC.local" + +# Pseudo-Devices + +pseudo-device crypto # /dev/crypto device +pseudo-device swcrypto # software crypto implementation + +# disk/mass storage pseudo-devices +#pseudo-device bio # RAID control device driver +#pseudo-device ccd 4 # concatenated/striped disk devices +#pseudo-device cgd 4 # cryptographic disk devices +#pseudo-device raid 8 # RAIDframe disk driver +#options RAID_AUTOCONFIG # auto-configuration of RAID components +#Options to enable various other RAIDframe RAID types. +#options RF_INCLUDE_EVENODD=1 +#options RF_INCLUDE_RAID5_RS=1 +#options RF_INCLUDE_PARITYLOGGING=1 +#options RF_INCLUDE_CHAINDECLUSTER=1 +#options RF_INCLUDE_INTERDECLUSTER=1 +#options RF_INCLUDE_PARITY_DECLUSTERING=1 +#options RF_INCLUDE_PARITY_DECLUSTERING_DS=1 +pseudo-device fss 4 # file system snapshot device + +#pseudo-device md 1 # memory disk device (ramdisk) +#options MEMORY_DISK_HOOKS # enable root ramdisk +#options MEMORY_DISK_DYNAMIC # loaded via kernel module + +pseudo-device vnd # disk-like interface to files +#options VND_COMPRESSION # compressed vnd(4) + +# network pseudo-devices +pseudo-device bpfilter # Berkeley packet filter +#pseudo-device carp # Common Address Redundancy Protocol +pseudo-device ipfilter # IP filter (firewall) and NAT +pseudo-device loop # network loopback +#pseudo-device ppp # Point-to-Point Protocol +#pseudo-device pppoe # PPP over Ethernet (RFC 2516) +#pseudo-device sl # Serial Line IP +#pseudo-device strip # Starmode Radio IP (Metricom) +#pseudo-device irframetty # IrDA frame line discipline +#pseudo-device tun # network tunneling over tty +#pseudo-device tap # virtual Ethernet +#pseudo-device gre # generic L3 over IP tunnel +#pseudo-device gif # IPv[46] over IPv[46] tunnel (RFC1933) +#pseudo-device faith # IPv[46] tcp relay translation i/f +#pseudo-device stf # 6to4 IPv6 over IPv4 encapsulation +#pseudo-device vlan # IEEE 802.1q encapsulation +#pseudo-device bridge # simple inter-network bridging +#options BRIDGE_IPF # bridge uses IP/IPv6 pfil hooks too +#pseudo-device agr # IEEE 802.3ad link aggregation + +# +# accept filters +pseudo-device accf_data # "dataready" accept filter +pseudo-device accf_http # "httpready" accept filter + +# miscellaneous pseudo-devices +pseudo-device pty # pseudo-terminals +#pseudo-device sequencer 1 # MIDI sequencer +# rnd works; RND_COM does not on port i386 yet. +pseudo-device rnd # /dev/random and in-kernel generator +#options RND_COM # use "com" randomness as well (BROKEN) +pseudo-device clockctl # user control of clock subsystem +pseudo-device ksyms # /dev/ksyms +#pseudo-device pf # PF packet filter +#pseudo-device pflog # PF log if +pseudo-device lockstat # lock profiling +#pseudo-device bcsp # BlueCore Serial Protocol +#pseudo-device btuart # Bluetooth HCI UART (H4) + +# a pseudo device needed for Coda # also needs CODA (above) +#pseudo-device vcoda 4 # coda minicache <-> venus comm. + +# a pseudo device needed for SMBFS +#pseudo-device nsmb # experimental - SMB requester + +# wscons pseudo-devices +pseudo-device wsmux # mouse & keyboard multiplexor +pseudo-device wsfont + +# pseudo audio device driver +#pseudo-device pad + +# userland interface to drivers, including autoconf and properties retrieval +pseudo-device drvctl + +#options FILEASSOC # fileassoc(9) - required for Veriexec + +# Veriexec +# +# a pseudo device needed for veriexec +#pseudo-device veriexec 1 +# +# Uncomment the fingerprint methods below that are desired. Note that +# removing fingerprint methods will have almost no impact on the kernel +# code size. +# +#options VERIFIED_EXEC_FP_RMD160 +#options VERIFIED_EXEC_FP_SHA256 +#options VERIFIED_EXEC_FP_SHA384 +#options VERIFIED_EXEC_FP_SHA512 +#options VERIFIED_EXEC_FP_SHA1 +#options VERIFIED_EXEC_FP_MD5 + +options PAX_MPROTECT=0 # PaX mprotect(2) restrictions +options PAX_ASLR=0 # PaX Address Space Layout Randomization diff -r f907de68d469 -r fb6a4db31a4e sys/arch/i386/conf/ALL --- a/sys/arch/i386/conf/ALL Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/arch/i386/conf/ALL Sun Feb 07 03:52:22 2010 -0500 @@ -205,6 +205,8 @@ options WAPBL # File system journaling support - Experimental options UFS_DIRHASH # UFS Large Directory Hashing - Experimental options UFS_EXTATTR +options LFS_KERNEL_RFW # Kernel roll-forward support +options LFS_DIRHASH # like UFS_DIRHASH but for lfs options NFSSERVER # Network File System server options FFS_NO_SNAPSHOT # No FFS snapshot support options EXT2FS_SYSTEM_FLAGS # makes ext2fs file flags (append and diff -r f907de68d469 -r fb6a4db31a4e sys/lib/libsa/lfsv1.c --- a/sys/lib/libsa/lfsv1.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/lib/libsa/lfsv1.c Sun Feb 07 03:52:22 2010 -0500 @@ -10,13 +10,17 @@ #define ufs_seek lfsv1_seek #define ufs_stat lfsv1_stat +#define ufs_dinode lfs_dinode + #define fs_bsize lfs_ibsize #define IFILE_Vx IFILE_V1 #define FSBTODB(fs, daddr) (daddr) /* LFSv1 uses sectors for addresses */ #define INOPBx(fs) INOPB(fs) +#define NDADDR LFS_NDIRECTBLKS +#define NIADDR LFS_NINDIRBLKS + #define FSMOD "lfs" -#define FSMOD2 "ffs" #include "lib/libsa/ufs.c" diff -r f907de68d469 -r fb6a4db31a4e sys/lib/libsa/lfsv2.c --- a/sys/lib/libsa/lfsv2.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/lib/libsa/lfsv2.c Sun Feb 07 03:52:22 2010 -0500 @@ -10,6 +10,8 @@ #define ufs_seek lfsv2_seek #define ufs_stat lfsv2_stat +#define ufs_dinode lfs_dinode + #define fs_bsize lfs_bsize #define IFILE_Vx IFILE @@ -19,7 +21,9 @@ #define INOPBx(fs) INOPB(fs) #endif +#define NDADDR LFS_NDIRECTBLKS +#define NIADDR LFS_NINDIRBLKS + #define FSMOD "lfs" -#define FSMOD2 "ffs" #include "lib/libsa/ufs.c" diff -r f907de68d469 -r fb6a4db31a4e sys/lib/libsa/ufs.c --- a/sys/lib/libsa/ufs.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/lib/libsa/ufs.c Sun Feb 07 03:52:22 2010 -0500 @@ -64,14 +64,15 @@ #include #include -#include -#include #ifdef LIBSA_LFS #include #include #include /* XXX for MNAMELEN */ +#define __LFS_LIBSA /* avoid including things we choke on*/ #include #else +#include +#include #include #endif #ifdef _STANDALONE diff -r f907de68d469 -r fb6a4db31a4e sys/modules/lfs/Makefile --- a/sys/modules/lfs/Makefile Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/modules/lfs/Makefile Sun Feb 07 03:52:22 2010 -0500 @@ -2,17 +2,17 @@ .include "../Makefile.inc" -.PATH: ${S}/ufs/lfs ${S}/ufs/ufs +.PATH: ${S}/ufs/lfs -lfs_vnops.o: ufs_readwrite.c +lfs_vnops.o: ulfs_readwrite.c -COPTS+= -DLFS -Dufs_mkdir=lfs_ufs_mkdir -Dufs_makeinode=lfs_ufs_makeinode \ - -Dufs_strategy=lfs_ufs_strategy -Dufs_whiteout=lfs_ufs_whiteout \ - -Dufs_link=lfs_ufs_link -Dufs_rename=lfs_ufs_rename +COPTS+=-DLFS KMOD= lfs SRCS= lfs_vfsops.c lfs_vnops.c lfs_subr.c lfs_alloc.c lfs_balloc.c \ lfs_bio.c lfs_cksum.c lfs_debug.c lfs_inode.c lfs_segment.c \ - lfs_syscalls.c ufs_vnops.c lfs_itimes.c + lfs_syscalls.c lfs_itimes.c +SRCS+= ulfs_bmap.c ulfs_dirhash.c ulfs_ihash.c ulfs_inode.c ulfs_lookup.c \ + ulfs_quota.c ulfs_vfsops.c ulfs_vnops.c .include diff -r f907de68d469 -r fb6a4db31a4e sys/rump/fs/lib/liblfs/Makefile --- a/sys/rump/fs/lib/liblfs/Makefile Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/rump/fs/lib/liblfs/Makefile Sun Feb 07 03:52:22 2010 -0500 @@ -5,10 +5,16 @@ LIB= rumpfs_lfs +lfs_vnops.o: ulfs_readwrite.c + SRCS= lfs_alloc.c lfs_balloc.c lfs_bio.c lfs_cksum.c lfs_debug.c \ lfs_inode.c lfs_itimes.c lfs_rfw.c lfs_segment.c lfs_subr.c \ lfs_syscalls.c lfs_vfsops.c lfs_vnops.c +SRCS+= ulfs_bmap.c ulfs_dirhash.c ulfs_ihash.c ulfs_inode.c ulfs_lookup.c \ + ulfs_quota.c ulfs_vfsops.c ulfs_vnops.c + + CFLAGS+= -Wno-pointer-sign -DLFS_KERNEL_RFW .include diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/files.ufs --- a/sys/ufs/files.ufs Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/files.ufs Sun Feb 07 03:52:22 2010 -0500 @@ -10,6 +10,7 @@ UFS_EXTATTR UFS_EXTATTR_AUTOSTART defflag opt_lfs.h LFS_KERNEL_RFW +defflag opt_lfs.h LFS_DIRHASH file ufs/ext2fs/ext2fs_alloc.c ext2fs file ufs/ext2fs/ext2fs_balloc.c ext2fs @@ -34,6 +35,21 @@ file ufs/ffs/ffs_wapbl.c ffs & wapbl file ufs/ffs/ffs_appleufs.c ffs & apple_ufs +file ufs/mfs/mfs_vfsops.c mfs +file ufs/mfs/mfs_vnops.c mfs + +file ufs/ufs/ufs_bmap.c ffs | mfs | ext2fs +file ufs/ufs/ufs_dirhash.c (ffs | mfs | ext2fs) & ufs_dirhash +file ufs/ufs/ufs_extattr.c (ffs | mfs) & ufs_extattr +file ufs/ufs/ufs_ihash.c ffs | mfs | ext2fs +file ufs/ufs/ufs_inode.c ffs | mfs | ext2fs +file ufs/ufs/ufs_lookup.c ffs | mfs | ext2fs +file ufs/ufs/ufs_quota.c quota & (ffs | mfs | ext2fs) +file ufs/ufs/ufs_vfsops.c ffs | mfs | ext2fs +file ufs/ufs/ufs_vnops.c ffs | mfs | ext2fs +file ufs/ufs/ufs_wapbl.c ffs & wapbl + + file ufs/lfs/lfs_alloc.c lfs file ufs/lfs/lfs_balloc.c lfs file ufs/lfs/lfs_bio.c lfs @@ -47,17 +63,11 @@ file ufs/lfs/lfs_syscalls.c lfs file ufs/lfs/lfs_vfsops.c lfs file ufs/lfs/lfs_vnops.c lfs - -file ufs/mfs/mfs_vfsops.c mfs -file ufs/mfs/mfs_vnops.c mfs - -file ufs/ufs/ufs_bmap.c ffs | lfs | mfs | ext2fs -file ufs/ufs/ufs_dirhash.c (ffs | lfs | mfs | ext2fs) & ufs_dirhash -file ufs/ufs/ufs_extattr.c (ffs | mfs) & ufs_extattr -file ufs/ufs/ufs_ihash.c ffs | lfs | mfs | ext2fs -file ufs/ufs/ufs_inode.c ffs | lfs | mfs | ext2fs -file ufs/ufs/ufs_lookup.c ffs | lfs | mfs | ext2fs -file ufs/ufs/ufs_quota.c quota & (ffs | lfs | mfs | ext2fs) -file ufs/ufs/ufs_vfsops.c ffs | lfs | mfs | ext2fs -file ufs/ufs/ufs_vnops.c ffs | lfs | mfs | ext2fs -file ufs/ufs/ufs_wapbl.c ffs & wapbl +file ufs/lfs/ulfs_bmap.c lfs +file ufs/lfs/ulfs_dirhash.c lfs & lfs_dirhash +file ufs/lfs/ulfs_ihash.c lfs +file ufs/lfs/ulfs_inode.c lfs +file ufs/lfs/ulfs_lookup.c lfs +file ufs/lfs/ulfs_quota.c quota & lfs +file ufs/lfs/ulfs_vfsops.c lfs +file ufs/lfs/ulfs_vnops.c lfs diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs.h --- a/sys/ufs/lfs/lfs.h Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs.h Sun Feb 07 03:52:22 2010 -0500 @@ -28,6 +28,51 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +/* + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Copyright (c) 1982, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)dinode.h 8.9 (Berkeley) 3/29/95 + * NetBSD: dinode.h,v 1.21 2009/06/28 09:26:18 ad Exp + */ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. @@ -58,6 +103,44 @@ * * @(#)lfs.h 8.9 (Berkeley) 5/8/95 */ +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)inode.h 8.9 (Berkeley) 5/14/95 + * @(#)dir.h 8.5 (Berkeley) 4/27/95 + * NetBSD: inode.h,v 1.56 2009/02/22 20:28:07 ad Exp + * NetBSD: dir.h,v 1.21 2009/07/22 04:49:19 dholland Exp + */ #ifndef _UFS_LFS_LFS_H_ #define _UFS_LFS_LFS_H_ @@ -66,6 +149,13 @@ #include #include #include +#include + +#ifndef __LFS_LIBSA +#include +#endif + +#include /* for MAXQUOTAS */ /* * Compile-time options for LFS. @@ -91,6 +181,27 @@ #define LFS_MAX_DADDR 0x7fffffff /* Highest addressable fsb */ +/* + * The root inode is the root of the file system. Inode 0 can't be used for + * normal purposes and historically bad blocks were linked to inode 1, thus + * the root inode is 2. (Inode 1 is no longer used for this purpose, however + * numerous dump tapes make this assumption, so we are stuck with it). + */ +#define ROOTINO ((ino_t)2) + +/* + * The Whiteout inode# is a dummy non-zero inode number which will + * never be allocated to a real file. It is used as a place holder + * in the directory entry which has been tagged as a DT_W entry. + * See the comments about ROOTINO above. + */ +#define WINO ((ino_t)1) + + +/* XXX these are currently repeated as NDADDR/NIADDR in ulfs_inode.h */ +#define LFS_NDIRECTBLKS 12 /* # of direct blocks in inode */ +#define LFS_NINDIRBLKS 3 /* # of indirect blocks in inode */ + #define LFS_MAXNAMLEN 255 /* maximum name length in a dir */ /* Adjustable filesystem parameters */ @@ -116,7 +227,7 @@ #define LFS_INVERSE_MAX_BYTES(n) LFS_INVERSE_MAX_RESOURCE(n, PAGE_SIZE) #define LFS_WAIT_BYTES LFS_WAIT_RESOURCE(bufmem_lowater, PAGE_SIZE) #define LFS_MAX_DIROP ((desiredvnodes >> 2) + (desiredvnodes >> 3)) -#define SIZEOF_DIROP(fs) (2 * ((fs)->lfs_bsize + DINODE1_SIZE)) +#define SIZEOF_DIROP(fs) (2 * ((fs)->lfs_bsize + LFS_DINODE_SIZE)) #define LFS_MAX_FSDIROP(fs) \ ((fs)->lfs_nclean <= (fs)->lfs_resvseg ? 0 : \ (((fs)->lfs_nclean - (fs)->lfs_resvseg) * (fs)->lfs_ssize) / \ @@ -288,22 +399,26 @@ #endif /* _KERNEL */ #ifdef _KERNEL -/* Filehandle structure for exported LFSes */ +/* + * Filehandle structure for exported LFSes. + * + * This is a superset of struct fid from sys/fstypes.h. + */ struct lfid { - struct ufid lfid_ufid; -#define lfid_len lfid_ufid.ufid_len -#define lfid_ino lfid_ufid.ufid_ino -#define lfid_gen lfid_ufid.ufid_gen + u_int16_t lfid_len; /* Length of structure. */ + u_int16_t lfid_pad; /* Force 32-bit alignment. */ + u_int32_t lfid_ino; /* File number (ino). */ + int32_t lfid_gen; /* Generation number. */ uint32_t lfid_ident; }; #endif /* _KERNEL */ /* - * "struct inode" associated definitions + * "struct lfs_inode" associated definitions */ /* Address calculations for metadata located in the inode */ -#define S_INDIR(fs) -NDADDR +#define S_INDIR(fs) (-LFS_NDIRECTBLKS) #define D_INDIR(fs) (S_INDIR(fs) - NINDIR(fs) - 1) #define T_INDIR(fs) (D_INDIR(fs) - NINDIR(fs) * NINDIR(fs) - 1) @@ -820,8 +935,8 @@ long lfs_ravail; /* blocks pre-reserved for writing */ long lfs_favail; /* blocks pre-reserved for writing */ res_t *lfs_resblk; /* Reserved memory for pageout */ - TAILQ_HEAD(, inode) lfs_dchainhd; /* dirop vnodes */ - TAILQ_HEAD(, inode) lfs_pchainhd; /* paging vnodes */ + TAILQ_HEAD(, lfs_inode) lfs_dchainhd; /* dirop vnodes */ + TAILQ_HEAD(, lfs_inode) lfs_pchainhd; /* paging vnodes */ #define LFS_RESHASH_WIDTH 17 LIST_HEAD(, lfs_res_blk) lfs_reshash[LFS_RESHASH_WIDTH]; int lfs_pdflush; /* pagedaemon wants us to flush */ @@ -852,7 +967,7 @@ #define INOPF(fs) ((fs)->lfs_inopf) #define blksize(fs, ip, lbn) \ - (((lbn) >= NDADDR || (ip)->i_ffs1_size >= ((lbn) + 1) << (fs)->lfs_bshift) \ + (((lbn) >= LFS_NDIRECTBLKS || (ip)->i_ffs1_size >= ((lbn) + 1) << (fs)->lfs_bshift) \ ? (fs)->lfs_bsize \ : (fragroundup(fs, blkoff(fs, (ip)->i_ffs1_size)))) #define blkoff(fs, loc) ((int)((loc) & (fs)->lfs_bmask)) @@ -889,7 +1004,7 @@ #define blknum(fs, fsb) /* calculates rounddown(fsb, fs->lfs_frag) */ \ ((fsb) &~ ((fs)->lfs_frag - 1)) #define dblksize(fs, dp, lbn) \ - (((lbn) >= NDADDR || (dp)->di_size >= ((lbn) + 1) << (fs)->lfs_bshift)\ + (((lbn) >= LFS_NDIRECTBLKS || (dp)->di_size >= ((lbn) + 1) << (fs)->lfs_bshift)\ ? (fs)->lfs_bsize \ : (fragroundup(fs, blkoff(fs, (dp)->di_size)))) @@ -936,7 +1051,7 @@ struct buf **cbpp; /* pointer to next available bp */ struct buf **start_bpp; /* pointer to first bp in this set */ struct buf *ibp; /* buffer pointer to inode page */ - struct ufs1_dinode *idp; /* pointer to ifile dinode */ + struct lfs_dinode *idp; /* pointer to ifile dinode */ struct finfo *fip; /* current fileinfo pointer */ struct vnode *vp; /* vnode being gathered */ void *segsum; /* segment summary info */ @@ -981,14 +1096,130 @@ #endif /* _KERNEL */ /* + * Theoretically, directories can be more than 2Gb in length; however, + * in practice this seems unlikely. So, we define the type lfs_doff_t + * as a 32-bit quantity to keep down the cost of doing lookup on a + * 32-bit machine. + */ +#define lfs_doff_t int32_t +#define MAXDIRSIZE (0x7fffffff) + +#ifndef __LFS_LIBSA +/* + * In-memory inode. + */ + +/* + * The inode is used to describe each active (or recently active) file in the + * LFS filesystem. It is composed of two types of information. The first part + * is the information that is needed only while the file is active (such as + * the identity of the file and linkage to speed its lookup). The second part + * is the permanent meta-data associated with the file which is read in + * from the permanent dinode from long term storage when the file becomes + * active, and is put back when the file is no longer being used. + */ +struct lfs_inode { + struct genfs_node i_gnode; + LIST_ENTRY(lfs_inode) i_hash;/* Hash chain. */ + TAILQ_ENTRY(lfs_inode) i_nextsnap; /* snapshot file list. */ + struct vnode *i_vnode; /* Vnode associated with this inode. */ + struct ulfsmount *i_ump; /* Mount point associated with this inode. */ + struct vnode *i_devvp; /* Vnode for block I/O. */ + u_int32_t i_flag; /* flags, see below */ + dev_t i_dev; /* Device associated with the inode. */ + ino_t i_number; /* The identity of the inode. */ + + struct lfs *i_lfs; /* LFS */ + + void *i_unused1; /* Unused. */ + struct ulfs_dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ + u_quad_t i_modrev; /* Revision level for NFS lease. */ + struct lockf *i_lockf;/* Head of byte-level lock list. */ + + /* + * Side effects; used during directory lookup. + */ + int32_t i_count; /* Size of free slot in directory. */ + lfs_doff_t i_endoff; /* End of useful stuff in directory. */ + lfs_doff_t i_diroff; /* Offset in dir, where we found last entry. */ + lfs_doff_t i_offset; /* Offset of free space in directory. */ + u_int32_t i_reclen; /* Size of found directory entry. */ + int i_unused; /* was for softdep, now unused */ + /* + * Inode extensions + */ + union { + struct lfs_inode_ext *lfs; + } inode_ext; +//#define i_snapblklist inode_ext.ffs.ffs_snapblklist + /* + * Copies from the on-disk dinode itself. + * + * These fields are currently only used by FFS and LFS, + * do NOT use them with ext2fs. + */ + u_int16_t i_mode; /* IFMT, permissions; see below. */ + int16_t i_nlink; /* File link count. */ + u_int64_t i_size; /* File byte count. */ + u_int32_t i_flags; /* Status flags (chflags). */ + int32_t i_gen; /* Generation number. */ + u_int32_t i_uid; /* File owner. */ + u_int32_t i_gid; /* File group. */ + + struct ulfs_dirhash *i_dirhash; /* Hashing for large directories */ + + /* + * The on-disk dinode itself. + */ + struct lfs_dinode *i_ffs1_din; /* 128 bytes of the on-disk dinode. */ +}; + +#define i_ffs1_atime i_ffs1_din->di_atime +#define i_ffs1_atimensec i_ffs1_din->di_atimensec +#define i_ffs1_blocks i_ffs1_din->di_blocks +#define i_ffs1_ctime i_ffs1_din->di_ctime +#define i_ffs1_ctimensec i_ffs1_din->di_ctimensec +#define i_ffs1_db i_ffs1_din->di_db +#define i_ffs1_flags i_ffs1_din->di_flags +#define i_ffs1_gen i_ffs1_din->di_gen +#define i_ffs1_gid i_ffs1_din->di_gid +#define i_ffs1_ib i_ffs1_din->di_ib +#define i_ffs1_mode i_ffs1_din->di_mode +#define i_ffs1_mtime i_ffs1_din->di_mtime +#define i_ffs1_mtimensec i_ffs1_din->di_mtimensec +#define i_ffs1_nlink i_ffs1_din->di_nlink +#define i_ffs1_rdev i_ffs1_din->di_rdev +#define i_ffs1_size i_ffs1_din->di_size +#define i_ffs1_uid i_ffs1_din->di_uid +#define i_ffs1_ouid i_ffs1_din->di_u.oldids[0] +#define i_ffs1_ogid i_ffs1_din->di_u.oldids[1] + +/* + * Flags for lfs_inode->i_flag. + */ +#define IN_ACCESS 0x0001 /* Access time update request. */ +#define IN_CHANGE 0x0002 /* Inode change time update request. */ +#define IN_UPDATE 0x0004 /* Inode was written to; update mtime. */ +#define IN_MODIFY 0x2000 /* Modification time update request. */ +#define IN_MODIFIED 0x0008 /* Inode has been modified. */ +#define IN_ACCESSED 0x0010 /* Inode has been accessed. */ +#define IN_RENAME 0x0020 /* Inode is being renamed. */ +#define IN_SHLOCK 0x0040 /* File has shared lock. */ +#define IN_EXLOCK 0x0080 /* File has exclusive lock. */ +#define IN_CLEANING 0x0100 /* LFS: file is being cleaned */ +#define IN_ADIROP 0x0200 /* LFS: dirop in progress */ +#define IN_SPACECOUNTED 0x0400 /* Blocks to be freed in free count. */ +#define IN_PAGING 0x1000 /* LFS: file is on paging queue */ + +/* * LFS inode extensions. */ struct lfs_inode_ext { off_t lfs_osize; /* size of file on disk */ u_int32_t lfs_effnblocks; /* number of blocks when i/o completes */ - size_t lfs_fragsize[NDADDR]; /* size of on-disk direct blocks */ - TAILQ_ENTRY(inode) lfs_dchain; /* Dirop chain. */ - TAILQ_ENTRY(inode) lfs_pchain; /* Paging chain. */ + size_t lfs_fragsize[LFS_NDIRECTBLKS]; /* size of on-disk direct blocks */ + TAILQ_ENTRY(lfs_inode) lfs_dchain; /* Dirop chain. */ + TAILQ_ENTRY(lfs_inode) lfs_pchain; /* Paging chain. */ #define LFSI_NO_GOP_WRITE 0x01 #define LFSI_DELETED 0x02 #define LFSI_WRAPBLOCK 0x04 @@ -1014,6 +1245,192 @@ #define i_lfs_segdhd inode_ext.lfs->lfs_segdhd #define i_lfs_odnlink inode_ext.lfs->lfs_odnlink +#endif /* __LFS_LIBSA */ + +/* + * On-disk inode. + */ + +/* + * A dinode contains all the meta-data associated with a ULFS file. + * This structure defines the on-disk format of a dinode. Since + * this structure describes an on-disk structure, all its fields + * are defined by types with precise widths. + */ + +struct lfs_dinode { + u_int16_t di_mode; /* 0: IFMT, permissions; see below. */ + int16_t di_nlink; /* 2: File link count. */ + union { + u_int16_t oldids[2]; /* 4: Ffs: old user and group ids. */ + u_int32_t inumber; /* 4: Lfs: inode number. */ + } di_u; + u_int64_t di_size; /* 8: File byte count. */ + int32_t di_atime; /* 16: Last access time. */ + int32_t di_atimensec; /* 20: Last access time. */ + int32_t di_mtime; /* 24: Last modified time. */ + int32_t di_mtimensec; /* 28: Last modified time. */ + int32_t di_ctime; /* 32: Last inode change time. */ + int32_t di_ctimensec; /* 36: Last inode change time. */ + int32_t di_db[LFS_NDIRECTBLKS]; /* 40: Direct disk blocks. */ + int32_t di_ib[LFS_NINDIRBLKS]; /* 88: Indirect disk blocks. */ + u_int32_t di_flags; /* 100: Status flags (chflags). */ + u_int32_t di_blocks; /* 104: Blocks actually held. */ + int32_t di_gen; /* 108: Generation number. */ + u_int32_t di_uid; /* 112: File owner. */ + u_int32_t di_gid; /* 116: File group. */ + u_int64_t di_modrev; /* 120: i_modrev for NFSv4 */ +}; + +/* + * The di_db fields may be overlaid with other information for + * file types that do not have associated disk storage. Block + * and character devices overlay the first data block with their + * dev_t value. Short symbolic links place their path in the + * di_db area. + */ +#define di_inumber di_u.inumber +#define di_ogid di_u.oldids[1] +#define di_ouid di_u.oldids[0] +#define di_rdev di_db[0] + +/* File permissions. */ +#define IEXEC 0000100 /* Executable. */ +#define IWRITE 0000200 /* Writable. */ +#define IREAD 0000400 /* Readable. */ +#define ISVTX 0001000 /* Sticky bit. */ +#define ISGID 0002000 /* Set-gid. */ +#define ISUID 0004000 /* Set-uid. */ + +/* File types. */ +#define IFMT 0170000 /* Mask of file type. */ +#define IFIFO 0010000 /* Named pipe (fifo). */ +#define IFCHR 0020000 /* Character device. */ +#define IFDIR 0040000 /* Directory file. */ +#define IFBLK 0060000 /* Block device. */ +#define IFREG 0100000 /* Regular file. */ +#define IFLNK 0120000 /* Symbolic link. */ +#define IFSOCK 0140000 /* UNIX domain socket. */ +#define IFWHT 0160000 /* Whiteout. */ + +#define LFS_MAXSYMLINKLEN ((LFS_NDIRECTBLKS + LFS_NINDIRBLKS) * sizeof(int32_t)) + +/* Size of the on-disk inode. */ +#define LFS_DINODE_SIZE (sizeof(struct lfs_dinode)) /* 128 */ + + +/* + * On-disk directory entry. + * + * A directory consists of some number of blocks of DIRBLKSIZ + * bytes, where DIRBLKSIZ is chosen such that it can be transferred + * to disk in a single atomic operation (e.g. 512 bytes on most machines). + * + * Each DIRBLKSIZ byte block contains some number of directory entry + * structures, which are of variable length. Each directory entry has + * a struct direct at the front of it, containing its inode number, + * the length of the entry, and the length of the name contained in + * the entry. These are followed by the name padded to a 4 byte boundary. + * All names are guaranteed null terminated. + * The maximum length of a name in a directory is LFS_MAXNAMLEN. + * + * The macro DIRSIZ(fmt, dp) gives the amount of space required to represent + * a directory entry. Free space in a directory is represented by + * entries which have dp->d_reclen > DIRSIZ(fmt, dp). All DIRBLKSIZ bytes + * in a directory block are claimed by the directory entries. This + * usually results in the last entry in a directory having a large + * dp->d_reclen. When entries are deleted from a directory, the + * space is returned to the previous entry in the same directory + * block by increasing its dp->d_reclen. If the first entry of + * a directory block is free, then its dp->d_ino is set to 0. + * Entries other than the first in a directory do not normally have + * dp->d_ino set to 0. + */ +#undef DIRBLKSIZ +#define DIRBLKSIZ DEV_BSIZE +#define LFS_MAXNAMLEN 255 + +#define d_ino d_fileno +struct direct { + u_int32_t d_fileno; /* inode number of entry */ + u_int16_t d_reclen; /* length of this record */ + u_int8_t d_type; /* file type, see below */ + u_int8_t d_namlen; /* length of string in d_name */ + char d_name[LFS_MAXNAMLEN + 1];/* name with length <= LFS_MAXNAMLEN */ +}; + +/* + * File types + */ +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + +/* + * Convert between stat structure types and directory types. + */ +#define IFTODT(mode) (((mode) & 0170000) >> 12) +#define DTTOIF(dirtype) ((dirtype) << 12) + +/* + * The DIRSIZ macro gives the minimum record length which will hold + * the directory entry. This requires the amount of space in struct direct + * without the d_name field, plus enough space for the name with a terminating + * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. + */ +#define DIRECTSIZ(namlen) \ + ((sizeof(struct direct) - (LFS_MAXNAMLEN+1)) + (((namlen)+1 + 3) &~ 3)) + +#if (BYTE_ORDER == LITTLE_ENDIAN) +#define DIRSIZ(oldfmt, dp, needswap) \ + (((oldfmt) && !(needswap)) ? \ + DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen)) +#else +#define DIRSIZ(oldfmt, dp, needswap) \ + (((oldfmt) && (needswap)) ? \ + DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen)) +#endif + +#define OLDDIRFMT 1 +#define NEWDIRFMT 0 + +/* + * Template for manipulating directories. Should use struct direct's, + * but the name field is LFS_MAXNAMLEN - 1, and this just won't do. + */ +struct dirtemplate { + u_int32_t dot_ino; + int16_t dot_reclen; + u_int8_t dot_type; + u_int8_t dot_namlen; + char dot_name[4]; /* must be multiple of 4 */ + u_int32_t dotdot_ino; + int16_t dotdot_reclen; + u_int8_t dotdot_type; + u_int8_t dotdot_namlen; + char dotdot_name[4]; /* ditto */ +}; + +/* + * This is the old format of directories, sans type element. + */ +struct odirtemplate { + u_int32_t dot_ino; + int16_t dot_reclen; + u_int16_t dot_namlen; + char dot_name[4]; /* must be multiple of 4 */ + u_int32_t dotdot_ino; + int16_t dotdot_reclen; + u_int16_t dotdot_namlen; + char dotdot_name[4]; /* ditto */ +}; + /* * Macros for determining free space on the disk, with the variable metadata * of segment summaries and inode blocks taken into account. @@ -1149,8 +1566,16 @@ # define ASSERT_MAYBE_SEGLOCK(x) #endif /* !notyet */ +/* + * Arguments to mount LFS filesystems + */ +struct lfs_args { + char *fspec; /* block special device to mount */ +}; + + __BEGIN_DECLS -void lfs_itimes(struct inode *, const struct timespec *, +void lfs_itimes(struct lfs_inode *, const struct timespec *, const struct timespec *, const struct timespec *); __END_DECLS diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_alloc.c --- a/sys/ufs/lfs/lfs_alloc.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_alloc.c Sun Feb 07 03:52:22 2010 -0500 @@ -80,13 +80,12 @@ #include #include -#include -#include -#include -#include - #include #include +#include +#include +#include +#include /* Constants for inode free bitmap */ #define BMSHIFT 5 /* 2 ** 5 = 32 */ @@ -113,7 +112,7 @@ lfs_extend_ifile(struct lfs *fs, kauth_cred_t cred) { struct vnode *vp; - struct inode *ip; + struct lfs_inode *ip; IFILE *ifp; IFILE_V1 *ifp_v1; struct buf *bp, *cbp; @@ -265,13 +264,13 @@ lfs_ialloc(struct lfs *fs, struct vnode *pvp, ino_t new_ino, int new_gen, struct vnode **vpp) { - struct inode *ip; + struct lfs_inode *ip; struct vnode *vp; ASSERT_NO_SEGLOCK(fs); vp = *vpp; - mutex_enter(&ufs_hashlock); + mutex_enter(&ulfs_hashlock); /* Create an inode to associate with the vnode. */ lfs_vcreate(pvp->v_mount, new_ino, vp); @@ -280,7 +279,7 @@ LFS_SET_UINO(ip, IN_CHANGE); mutex_exit(&lfs_lock); /* on-disk structure has been zeroed out by lfs_vcreate */ - ip->i_din.ffs1_din->di_inumber = new_ino; + ip->i_ffs1_din->di_inumber = new_ino; /* Note no blocks yet */ ip->i_lfs_hiblk = -1; @@ -292,10 +291,10 @@ } /* Insert into the inode hash table. */ - ufs_ihashins(ip); - mutex_exit(&ufs_hashlock); + ulfs_ihashins(ip); + mutex_exit(&ulfs_hashlock); - ufs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, vpp); + ulfs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, vpp); vp = *vpp; ip = VTOI(vp); @@ -312,12 +311,12 @@ void lfs_vcreate(struct mount *mp, ino_t ino, struct vnode *vp) { - struct inode *ip; - struct ufs1_dinode *dp; - struct ufsmount *ump; + struct lfs_inode *ip; + struct lfs_dinode *dp; + struct ulfsmount *ump; /* Get a pointer to the private mount structure. */ - ump = VFSTOUFS(mp); + ump = VFSTOULFS(mp); ASSERT_NO_SEGLOCK(ump->um_lfs); @@ -329,7 +328,7 @@ ip->inode_ext.lfs = pool_get(&lfs_inoext_pool, PR_WAITOK); memset(ip->inode_ext.lfs, 0, sizeof(*ip->inode_ext.lfs)); vp->v_data = ip; - ip->i_din.ffs1_din = dp; + ip->i_ffs1_din = dp; ip->i_ump = ump; ip->i_vnode = vp; ip->i_devvp = ump->um_devvp; @@ -341,7 +340,7 @@ ip->i_lfs_nbtree = 0; LIST_INIT(&ip->i_lfs_segdhd); #ifdef QUOTA - ufsquota_init(ip); + ulfsquota_init(ip); #endif } @@ -419,7 +418,7 @@ CLEANERINFO *cip; struct buf *cbp, *bp; struct ifile *ifp; - struct inode *ip; + struct lfs_inode *ip; struct lfs *fs; daddr_t old_iaddr; ino_t otail; @@ -555,17 +554,17 @@ if (old_iaddr != LFS_UNUSED_DADDR) { LFS_SEGENTRY(sup, fs, dtosn(fs, old_iaddr), bp); #ifdef DIAGNOSTIC - if (sup->su_nbytes < sizeof (struct ufs1_dinode)) { + if (sup->su_nbytes < sizeof (struct lfs_dinode)) { printf("lfs_vfree: negative byte count" " (segment %" PRIu32 " short by %d)\n", dtosn(fs, old_iaddr), - (int)sizeof (struct ufs1_dinode) - + (int)sizeof (struct lfs_dinode) - sup->su_nbytes); panic("lfs_vfree: negative byte count"); - sup->su_nbytes = sizeof (struct ufs1_dinode); + sup->su_nbytes = sizeof (struct lfs_dinode); } #endif - sup->su_nbytes -= sizeof (struct ufs1_dinode); + sup->su_nbytes -= sizeof (struct lfs_dinode); LFS_WRITESEGENTRY(sup, fs, dtosn(fs, old_iaddr), bp); /* Ifile */ } diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_balloc.c --- a/sys/ufs/lfs/lfs_balloc.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_balloc.c Sun Feb 07 03:52:22 2010 -0500 @@ -79,13 +79,12 @@ #include -#include -#include -#include -#include - #include #include +#include +#include +#include +#include #include @@ -99,8 +98,8 @@ * this block to be created. * * Blocks which have never been accounted for (i.e., which "do not exist") - * have disk address 0, which is translated by ufs_bmap to the special value - * UNASSIGNED == -1, as in the historical UFS. + * have disk address 0, which is translated by ulfs_bmap to the special value + * UNASSIGNED == -1, as in the historical ULFS. * * Blocks which have been accounted for but which have not yet been written * to disk are given the new special disk address UNWRITTEN == -2, so that @@ -114,9 +113,9 @@ int offset; daddr_t daddr, idaddr; struct buf *ibp, *bp; - struct inode *ip; + struct lfs_inode *ip; struct lfs *fs; - struct indir indirs[NIADDR+2], *idp; + struct lfs_indir indirs[NIADDR+2], *idp; daddr_t lbn, lastblock; int bb, bcount; int error, frags, i, nsize, osize, num; @@ -214,7 +213,7 @@ return 0; } - error = ufs_bmaparray(vp, lbn, &daddr, &indirs[0], &num, NULL, NULL); + error = ulfs_bmaparray(vp, lbn, &daddr, &indirs[0], &num, NULL, NULL); if (error) return (error); @@ -225,7 +224,7 @@ * Do byte accounting all at once, so we can gracefully fail *before* * we start assigning blocks. */ - bb = VFSTOUFS(vp->v_mount)->um_seqinc; + bb = VFSTOULFS(vp->v_mount)->um_seqinc; bcount = 0; if (daddr == UNASSIGNED) { bcount = bb; @@ -308,7 +307,7 @@ * The block we are writing may be a brand new block * in which case we need to do accounting. * - * We can tell a truly new block because ufs_bmaparray will say + * We can tell a truly new block because ulfs_bmaparray will say * it is UNASSIGNED. Once we allocate it we will assign it the * disk address UNWRITTEN. */ @@ -373,7 +372,7 @@ lfs_fragextend(struct vnode *vp, int osize, int nsize, daddr_t lbn, struct buf **bpp, kauth_cred_t cred) { - struct inode *ip; + struct lfs_inode *ip; struct lfs *fs; long bb; int error; @@ -415,7 +414,7 @@ goto out; } #ifdef QUOTA - if ((error = chkdq(ip, bb, cred, 0))) { + if ((error = lfs_chkdq(ip, bb, cred, 0))) { if (bpp) brelse(*bpp, 0); goto out; @@ -433,7 +432,7 @@ if (bpp) brelse(*bpp, 0); #ifdef QUOTA - chkdq(ip, -bb, cred, 0); + lfs_chkdq(ip, -bb, cred, 0); #endif rw_exit(&fs->lfs_fraglock); lfs_availwait(fs, bb); @@ -489,7 +488,7 @@ lfs_register_block(struct vnode *vp, daddr_t lbn) { struct lfs *fs; - struct inode *ip; + struct lfs_inode *ip; struct lbnentry *lbp; ip = VTOI(vp); @@ -524,7 +523,7 @@ } static void -lfs_do_deregister(struct lfs *fs, struct inode *ip, struct lbnentry *lbp) +lfs_do_deregister(struct lfs *fs, struct lfs_inode *ip, struct lbnentry *lbp) { ASSERT_MAYBE_SEGLOCK(fs); @@ -546,7 +545,7 @@ lfs_deregister_block(struct vnode *vp, daddr_t lbn) { struct lfs *fs; - struct inode *ip; + struct lfs_inode *ip; struct lbnentry *lbp; struct lbnentry tmp; @@ -571,7 +570,7 @@ struct lbnentry *lbp, *nlbp; struct lfs_splay *hd; struct lfs *fs; - struct inode *ip; + struct lfs_inode *ip; ip = VTOI(vp); fs = ip->i_lfs; diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_bio.c --- a/sys/ufs/lfs/lfs_bio.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_bio.c Sun Feb 07 03:52:22 2010 -0500 @@ -72,12 +72,11 @@ #include #include -#include -#include -#include - #include #include +#include +#include +#include #include @@ -436,12 +435,12 @@ lfs_bwrite_ext(struct buf *bp, int flags) { struct lfs *fs; - struct inode *ip; + struct lfs_inode *ip; struct vnode *vp; int fsb; vp = bp->b_vp; - fs = VFSTOUFS(vp->v_mount)->um_lfs; + fs = VFSTOULFS(vp->v_mount)->um_lfs; ASSERT_MAYBE_SEGLOCK(fs); KASSERT(bp->b_cflags & BC_BUSY); @@ -591,7 +590,7 @@ } if (strncmp(&mp->mnt_stat.f_fstypename[0], MOUNT_LFS, sizeof(mp->mnt_stat.f_fstypename)) == 0) { - tfs = VFSTOUFS(mp)->um_lfs; + tfs = VFSTOULFS(mp)->um_lfs; mutex_enter(&lfs_lock); lfs_flush_fs(tfs, flags); mutex_exit(&lfs_lock); @@ -611,7 +610,7 @@ } #define INOCOUNT(fs) howmany((fs)->lfs_uinodes, INOPB(fs)) -#define INOBYTES(fs) ((fs)->lfs_uinodes * sizeof (struct ufs1_dinode)) +#define INOBYTES(fs) ((fs)->lfs_uinodes * sizeof (struct lfs_dinode)) /* * make sure that we don't have too many locked buffers. @@ -622,7 +621,7 @@ { int error; struct lfs *fs; - struct inode *ip; + struct lfs_inode *ip; extern pid_t lfs_writer_daemon; error = 0; diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_cksum.c --- a/sys/ufs/lfs/lfs_cksum.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_cksum.c Sun Feb 07 03:52:22 2010 -0500 @@ -70,7 +70,7 @@ # include #endif #include -#include + #include #include diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_debug.c --- a/sys/ufs/lfs/lfs_debug.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_debug.c Sun Feb 07 03:52:22 2010 -0500 @@ -75,7 +75,7 @@ #include #include -#include +#include #include #include @@ -190,7 +190,7 @@ } void -lfs_dump_dinode(struct ufs1_dinode *dip) +lfs_dump_dinode(struct lfs_dinode *dip) { int i; diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_extern.h --- a/sys/ufs/lfs/lfs_extern.h Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_extern.h Sun Feb 07 03:52:22 2010 -0500 @@ -65,6 +65,7 @@ #ifdef _KERNEL #include +MALLOC_DECLARE(M_ULFSMOUNT); MALLOC_DECLARE(M_SEGMENT); #endif @@ -91,10 +92,10 @@ struct proc; struct statvfs; struct timeval; -struct inode; +struct lfs_inode; struct uio; struct mbuf; -struct ufs1_dinode; +struct lfs_dinode; struct buf; struct vnode; struct dlfs; @@ -152,7 +153,7 @@ int lfs_bwrite_log(struct buf *, const char *, int); void lfs_dumplog(void); void lfs_dump_super(struct lfs *); -void lfs_dump_dinode(struct ufs1_dinode *); +void lfs_dump_dinode(struct lfs_dinode *); void lfs_check_bpp(struct lfs *, struct segment *, char *, int); void lfs_check_segsum(struct lfs *, struct segment *, char *, int); void lfs_debug_log(int, const char *, ...); @@ -162,8 +163,8 @@ int lfs_update(struct vnode *, const struct timespec *, const struct timespec *, int); int lfs_truncate(struct vnode *, off_t, int, kauth_cred_t); -struct ufs1_dinode *lfs_ifind(struct lfs *, ino_t, struct buf *); -void lfs_finalize_ino_seguse(struct lfs *, struct inode *); +struct lfs_dinode *lfs_ifind(struct lfs *, ino_t, struct buf *); +void lfs_finalize_ino_seguse(struct lfs *, struct lfs_inode *); void lfs_finalize_fs_seguse(struct lfs *); /* lfs_rfw.c */ @@ -175,7 +176,7 @@ int lfs_vflush(struct vnode *); int lfs_segwrite(struct mount *, int); int lfs_writefile(struct lfs *, struct segment *, struct vnode *); -int lfs_writeinode(struct lfs *, struct segment *, struct inode *); +int lfs_writeinode(struct lfs *, struct segment *, struct lfs_inode *); int lfs_gatherblock(struct segment *, struct buf *, kmutex_t *); int lfs_gather(struct lfs *, struct segment *, struct vnode *, int (*match )(struct lfs *, struct buf *)); void lfs_update_single(struct lfs *, struct segment *, struct vnode *, @@ -211,7 +212,7 @@ void lfs_wakeup_cleaner(struct lfs *); /* lfs_syscalls.c */ -int lfs_fastvget(struct mount *, ino_t, daddr_t, struct vnode **, struct ufs1_dinode *); +int lfs_fastvget(struct mount *, ino_t, daddr_t, struct vnode **, struct lfs_dinode *); struct buf *lfs_fakebuf(struct lfs *, struct vnode *, int, size_t, void *); int lfs_do_segclean(struct lfs *, unsigned long); int lfs_segwait(fsid_t *, struct timeval *); diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_inode.c --- a/sys/ufs/lfs/lfs_inode.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_inode.c Sun Feb 07 03:52:22 2010 -0500 @@ -79,26 +79,25 @@ #include #include -#include -#include -#include -#include - #include #include +#include +#include +#include +#include -static int lfs_update_seguse(struct lfs *, struct inode *ip, long, size_t); -static int lfs_indirtrunc (struct inode *, daddr_t, daddr_t, +static int lfs_update_seguse(struct lfs *, struct lfs_inode *ip, long, size_t); +static int lfs_indirtrunc (struct lfs_inode *, daddr_t, daddr_t, daddr_t, int, long *, long *, long *, size_t *); -static int lfs_blkfree (struct lfs *, struct inode *, daddr_t, size_t, long *, size_t *); +static int lfs_blkfree (struct lfs *, struct lfs_inode *, daddr_t, size_t, long *, size_t *); static int lfs_vtruncbuf(struct vnode *, daddr_t, bool, int); /* Search a block for a specific dinode. */ -struct ufs1_dinode * +struct lfs_dinode * lfs_ifind(struct lfs *fs, ino_t ino, struct buf *bp) { - struct ufs1_dinode *dip = (struct ufs1_dinode *)bp->b_data; - struct ufs1_dinode *ldip, *fin; + struct lfs_dinode *dip = (struct lfs_dinode *)bp->b_data; + struct lfs_dinode *ldip, *fin; ASSERT_NO_SEGLOCK(fs); /* @@ -125,8 +124,8 @@ lfs_update(struct vnode *vp, const struct timespec *acc, const struct timespec *mod, int updflags) { - struct inode *ip; - struct lfs *fs = VFSTOUFS(vp->v_mount)->um_lfs; + struct lfs_inode *ip; + struct lfs *fs = VFSTOULFS(vp->v_mount)->um_lfs; int flags; ASSERT_NO_SEGLOCK(fs); @@ -197,7 +196,7 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred) { daddr_t lastblock; - struct inode *oip = VTOI(ovp); + struct lfs_inode *oip = VTOI(ovp); daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR]; /* XXX ondisk32 */ int32_t newblks[NDADDR + NIADDR]; @@ -212,7 +211,7 @@ size_t bc; int obufsize, odb; int usepc; - struct ufsmount *ump = oip->i_ump; + struct ulfsmount *ump = oip->i_ump; if (ovp->v_type == VCHR || ovp->v_type == VBLK || ovp->v_type == VFIFO || ovp->v_type == VSOCK) { @@ -271,7 +270,7 @@ eob = blkroundup(fs, osize); uvm_vnp_setwritesize(ovp, eob); - error = ufs_balloc_range(ovp, osize, + error = ulfs_balloc_range(ovp, osize, eob - osize, cred, aflags); if (error) return error; @@ -284,7 +283,7 @@ } } uvm_vnp_setwritesize(ovp, length); - error = ufs_balloc_range(ovp, length - 1, 1, cred, + error = ulfs_balloc_range(ovp, length - 1, 1, cred, aflags); if (error) { (void) lfs_truncate(ovp, osize, @@ -379,7 +378,7 @@ voff_t eoz; aflags = ioflag & IO_SYNC ? B_SYNC : 0; - error = ufs_balloc_range(ovp, length - 1, 1, cred, aflags); + error = ulfs_balloc_range(ovp, length - 1, 1, cred, aflags); if (error) { lfs_reserve(fs, ovp, NULL, -btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift)); @@ -579,7 +578,7 @@ oip->i_flag |= IN_CHANGE; #ifdef QUOTA - (void) chkdq(oip, -blocksreleased, NOCRED, 0); + (void) lfs_chkdq(oip, -blocksreleased, NOCRED, 0); #endif lfs_reserve(fs, ovp, NULL, -btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift)); @@ -593,7 +592,7 @@ /* Update segment and avail usage information when removing a block. */ static int -lfs_blkfree(struct lfs *fs, struct inode *ip, daddr_t daddr, +lfs_blkfree(struct lfs *fs, struct lfs_inode *ip, daddr_t daddr, size_t bsize, long *lastseg, size_t *num) { long seg; @@ -615,7 +614,7 @@ /* Finish the accounting updates for a segment. */ static int -lfs_update_seguse(struct lfs *fs, struct inode *ip, long lastseg, size_t num) +lfs_update_seguse(struct lfs *fs, struct lfs_inode *ip, long lastseg, size_t num) { struct segdelta *sd; struct vnode *vp; @@ -665,7 +664,7 @@ /* Finish the accounting updates for a segment. */ void -lfs_finalize_ino_seguse(struct lfs *fs, struct inode *ip) +lfs_finalize_ino_seguse(struct lfs *fs, struct lfs_inode *ip) { ASSERT_SEGLOCK(fs); lfs_finalize_seguse(fs, &ip->i_lfs_segdhd); @@ -689,7 +688,7 @@ * NB: triple indirect blocks are untested. */ static int -lfs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, +lfs_indirtrunc(struct lfs_inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn, int level, long *countp, long *rcountp, long *lastsegp, size_t *bcp) { diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_itimes.c --- a/sys/ufs/lfs/lfs_itimes.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_itimes.c Sun Feb 07 03:52:22 2010 -0500 @@ -36,8 +36,6 @@ #include #include -#include - #ifndef _KERNEL #include "bufcache.h" #include "vnode.h" @@ -47,13 +45,14 @@ #define panic call_panic #else #include +#include #include #endif #include void -lfs_itimes(struct inode *ip, const struct timespec *acc, +lfs_itimes(struct lfs_inode *ip, const struct timespec *acc, const struct timespec *mod, const struct timespec *cre) { #ifdef _KERNEL diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_rfw.c --- a/sys/ufs/lfs/lfs_rfw.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_rfw.c Sun Feb 07 03:52:22 2010 -0500 @@ -62,11 +62,6 @@ #include -#include -#include -#include -#include - #include #include #include @@ -74,6 +69,10 @@ #include #include +#include +#include +#include +#include #include #include @@ -103,7 +102,7 @@ IFILE *ifp; struct buf *bp, *cbp; struct vnode *vp; - struct inode *ip; + struct lfs_inode *ip; ino_t tino, oldnext; int error; CLEANERINFO *cip; @@ -182,7 +181,7 @@ ip = VTOI(vp); ip->i_mode = ip->i_ffs1_mode = IFREG; ip->i_nlink = ip->i_ffs1_nlink = 1; - ufs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, &vp); + ulfs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, &vp); ip = VTOI(vp); DLOG((DLOG_RF, "lfs_rf_valloc: ino %d vp %p\n", ino, vp)); @@ -213,10 +212,10 @@ { int error; struct vnode *vp; - struct inode *ip; + struct lfs_inode *ip; #ifdef DEBUG daddr_t odaddr; - struct indir a[NIADDR]; + struct lfs_indir a[NIADDR]; int num; int i; #endif /* DEBUG */ @@ -282,7 +281,7 @@ #ifdef DEBUG /* Now look again to make sure it worked */ - ufs_bmaparray(vp, lbn, &odaddr, &a[0], &num, NULL, NULL); + ulfs_bmaparray(vp, lbn, &odaddr, &a[0], &num, NULL, NULL); for (i = num; i > 0; i--) { if (!a[i].in_exists) panic("update_meta: absent %d lv indirect block", i); @@ -300,8 +299,8 @@ struct lwp *l) { struct vnode *devvp, *vp; - struct inode *ip; - struct ufs1_dinode *dip; + struct lfs_inode *ip; + struct lfs_dinode *dip; struct buf *dbp, *ibp; int error; daddr_t daddr; @@ -320,8 +319,8 @@ DLOG((DLOG_RF, "update_inoblk: bread returned %d\n", error)); return error; } - dip = ((struct ufs1_dinode *)(dbp->b_data)) + INOPB(fs); - while (--dip >= (struct ufs1_dinode *)dbp->b_data) { + dip = ((struct lfs_dinode *)(dbp->b_data)) + INOPB(fs); + while (--dip >= (struct lfs_dinode *)dbp->b_data) { if (dip->di_inumber > LFS_IFILE_INUM) { error = lfs_rf_valloc(fs, dip->di_inumber, dip->di_gen, l, &vp); @@ -334,8 +333,8 @@ if (dip->di_size != ip->i_size) lfs_truncate(vp, dip->di_size, 0, NOCRED); /* Get mode, link count, size, and times */ - memcpy(ip->i_din.ffs1_din, dip, - offsetof(struct ufs1_dinode, di_db[0])); + memcpy(ip->i_ffs1_din, dip, + offsetof(struct lfs_dinode, di_db[0])); /* Then the rest, except di_blocks */ ip->i_flags = ip->i_ffs1_flags = dip->di_flags; @@ -350,7 +349,7 @@ LFS_SET_UINO(ip, IN_CHANGE | IN_UPDATE); /* Re-initialize to get type right */ - ufs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, + ulfs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, &vp); vput(vp); @@ -364,14 +363,14 @@ if (daddr > 0) { LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), ibp); - sup->su_nbytes -= sizeof (struct ufs1_dinode); + sup->su_nbytes -= sizeof (struct lfs_dinode); LFS_WRITESEGENTRY(sup, fs, dtosn(fs, daddr), ibp); } LFS_SEGENTRY(sup, fs, dtosn(fs, dbtofsb(fs, dbp->b_blkno)), ibp); - sup->su_nbytes += sizeof (struct ufs1_dinode); + sup->su_nbytes += sizeof (struct lfs_dinode); LFS_WRITESEGENTRY(sup, fs, dtosn(fs, dbtofsb(fs, dbp->b_blkno)), ibp); diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_segment.c --- a/sys/ufs/lfs/lfs_segment.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_segment.c Sun Feb 07 03:52:22 2010 -0500 @@ -95,17 +95,16 @@ #include #include -#include -#include -#include -#include - #include #include +#include +#include +#include #include #include +MALLOC_JUSTDEFINE(M_ULFSMOUNT, "ULFS mount", "Mount structure for LFS"); MALLOC_JUSTDEFINE(M_SEGMENT, "LFS segment", "Segment for LFS"); extern int count_lock_queue(void); @@ -170,7 +169,7 @@ lfs_imtime(struct lfs *fs) { struct timespec ts; - struct inode *ip; + struct lfs_inode *ip; ASSERT_MAYBE_SEGLOCK(fs); vfs_timestamp(&ts); @@ -191,7 +190,7 @@ int lfs_vflush(struct vnode *vp) { - struct inode *ip; + struct lfs_inode *ip; struct lfs *fs; struct segment *sp; struct buf *bp, *nbp, *tbp, *tnbp; @@ -201,7 +200,7 @@ int loopcount; ip = VTOI(vp); - fs = VFSTOUFS(vp->v_mount)->um_lfs; + fs = VFSTOULFS(vp->v_mount)->um_lfs; relock = 0; top: @@ -469,7 +468,7 @@ int lfs_writevnodes(struct lfs *fs, struct mount *mp, struct segment *sp, int op) { - struct inode *ip; + struct lfs_inode *ip; struct vnode *vp; int inodes_written = 0, only_cleaning; int error = 0; @@ -601,7 +600,7 @@ lfs_segwrite(struct mount *mp, int flags) { struct buf *bp; - struct inode *ip; + struct lfs_inode *ip; struct lfs *fs; struct segment *sp; struct vnode *vp; @@ -614,7 +613,7 @@ int um_error; int loopcount; - fs = VFSTOUFS(mp)->um_lfs; + fs = VFSTOULFS(mp)->um_lfs; ASSERT_MAYBE_SEGLOCK(fs); if (fs->lfs_ronly) @@ -827,7 +826,7 @@ lfs_writefile(struct lfs *fs, struct segment *sp, struct vnode *vp) { struct finfo *fip; - struct inode *ip; + struct lfs_inode *ip; int i, frag; int error; @@ -915,7 +914,7 @@ * Update segment accounting to reflect this inode's change of address. */ static int -lfs_update_iaddr(struct lfs *fs, struct segment *sp, struct inode *ip, daddr_t ndaddr) +lfs_update_iaddr(struct lfs *fs, struct segment *sp, struct lfs_inode *ip, daddr_t ndaddr) { struct buf *bp; daddr_t daddr; @@ -988,26 +987,26 @@ LFS_SEGENTRY(sup, fs, oldsn, bp); #ifdef DIAGNOSTIC if (sup->su_nbytes + - sizeof (struct ufs1_dinode) * ndupino - < sizeof (struct ufs1_dinode)) { + sizeof (struct lfs_dinode) * ndupino + < sizeof (struct lfs_dinode)) { printf("lfs_writeinode: negative bytes " "(segment %" PRIu32 " short by %d, " "oldsn=%" PRIu32 ", cursn=%" PRIu32 ", daddr=%" PRId64 ", su_nbytes=%u, " "ndupino=%d)\n", dtosn(fs, daddr), - (int)sizeof (struct ufs1_dinode) * + (int)sizeof (struct lfs_dinode) * (1 - sp->ndupino) - sup->su_nbytes, oldsn, sp->seg_number, daddr, (unsigned int)sup->su_nbytes, sp->ndupino); panic("lfs_writeinode: negative bytes"); - sup->su_nbytes = sizeof (struct ufs1_dinode); + sup->su_nbytes = sizeof (struct lfs_dinode); } #endif DLOG((DLOG_SU, "seg %d -= %d for ino %d inode\n", - dtosn(fs, daddr), sizeof (struct ufs1_dinode), ino)); - sup->su_nbytes -= sizeof (struct ufs1_dinode); + dtosn(fs, daddr), sizeof (struct lfs_dinode), ino)); + sup->su_nbytes -= sizeof (struct lfs_dinode); redo_ifile |= (ino == LFS_IFILE_INUM && !(bp->b_flags & B_GATHERED)); if (redo_ifile) { @@ -1024,10 +1023,10 @@ } int -lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip) +lfs_writeinode(struct lfs *fs, struct segment *sp, struct lfs_inode *ip) { struct buf *bp; - struct ufs1_dinode *cdp; + struct lfs_dinode *cdp; daddr_t daddr; int32_t *daddrp; /* XXX ondisk32 */ int i, ndx; @@ -1101,7 +1100,7 @@ /* Zero out inode numbers */ for (i = 0; i < INOPB(fs); ++i) - ((struct ufs1_dinode *)sp->ibp->b_data)[i].di_inumber = + ((struct lfs_dinode *)sp->ibp->b_data)[i].di_inumber = 0; ++sp->start_bpp; @@ -1132,14 +1131,14 @@ * already been gathered. */ if (ip->i_number == LFS_IFILE_INUM && sp->idp) { - *(sp->idp) = *ip->i_din.ffs1_din; + *(sp->idp) = *ip->i_ffs1_din; ip->i_lfs_osize = ip->i_size; return 0; } bp = sp->ibp; - cdp = ((struct ufs1_dinode *)bp->b_data) + (sp->ninodes % INOPB(fs)); - *cdp = *ip->i_din.ffs1_din; + cdp = ((struct lfs_dinode *)bp->b_data) + (sp->ninodes % INOPB(fs)); + *cdp = *ip->i_ffs1_din; /* * If cleaning, link counts and directory file sizes cannot change, @@ -1236,7 +1235,7 @@ if (ip->i_number == LFS_IFILE_INUM) { /* We know sp->idp == NULL */ - sp->idp = ((struct ufs1_dinode *)bp->b_data) + + sp->idp = ((struct lfs_dinode *)bp->b_data) + (sp->ninodes % INOPB(fs)); /* Not dirty any more */ @@ -1417,7 +1416,7 @@ /* * Change the given block's address to ndaddr, finding its previous - * location using ufs_bmaparray(). + * location using ulfs_bmaparray(). * * Account for this change in the segment table. * @@ -1429,8 +1428,8 @@ { SEGUSE *sup; struct buf *bp; - struct indir a[NIADDR + 2], *ap; - struct inode *ip; + struct lfs_indir a[NIADDR + 2], *ap; + struct lfs_inode *ip; daddr_t daddr, ooff; int num, error; int bb, osize, obb; @@ -1439,9 +1438,9 @@ KASSERT(sp == NULL || sp->vp == vp); ip = VTOI(vp); - error = ufs_bmaparray(vp, lbn, &daddr, a, &num, NULL, NULL); + error = ulfs_bmaparray(vp, lbn, &daddr, a, &num, NULL, NULL); if (error) - panic("lfs_updatemeta: ufs_bmaparray returned %d", error); + panic("lfs_updatemeta: ulfs_bmaparray returned %d", error); daddr = (daddr_t)((int32_t)daddr); /* XXX ondisk32 */ KASSERT(daddr <= LFS_MAX_DADDR); @@ -1520,13 +1519,13 @@ osize = fs->lfs_bsize; LFS_SEGENTRY(sup, fs, oldsn, bp); #ifdef DIAGNOSTIC - if (sup->su_nbytes + sizeof (struct ufs1_dinode) * ndupino + if (sup->su_nbytes + sizeof (struct lfs_dinode) * ndupino < osize) { printf("lfs_updatemeta: negative bytes " "(segment %" PRIu32 " short by %" PRId64 ")\n", dtosn(fs, daddr), (int64_t)osize - - (sizeof (struct ufs1_dinode) * ndupino + + (sizeof (struct lfs_dinode) * ndupino + sup->su_nbytes)); printf("lfs_updatemeta: ino %llu, lbn %" PRId64 ", addr = 0x%" PRIx64 "\n", @@ -1534,7 +1533,7 @@ printf("lfs_updatemeta: ndupino=%d\n", ndupino); panic("lfs_updatemeta: negative bytes"); sup->su_nbytes = osize - - sizeof (struct ufs1_dinode) * ndupino; + sizeof (struct lfs_dinode) * ndupino; } #endif DLOG((DLOG_SU, "seg %" PRIu32 " -= %d for ino %d lbn %" PRId64 @@ -2021,9 +2020,9 @@ ninos = (ssp->ss_ninos + INOPB(fs) - 1) / INOPB(fs); DLOG((DLOG_SU, "seg %d += %d for %d inodes\n", - sp->seg_number, ssp->ss_ninos * sizeof (struct ufs1_dinode), + sp->seg_number, ssp->ss_ninos * sizeof (struct lfs_dinode), ssp->ss_ninos)); - sup->su_nbytes += ssp->ss_ninos * sizeof (struct ufs1_dinode); + sup->su_nbytes += ssp->ss_ninos * sizeof (struct lfs_dinode); /* sup->su_nbytes += fs->lfs_sumsize; */ if (fs->lfs_version == 1) sup->su_olastmod = time_second; @@ -2478,7 +2477,7 @@ struct lfs *fs; struct buf *tbp, *fbp; struct vnode *vp, *devvp, *ovp; - struct inode *ip; + struct lfs_inode *ip; int error; KERNEL_LOCK(1, curlwp); diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_subr.c --- a/sys/ufs/lfs/lfs_subr.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_subr.c Sun Feb 07 03:52:22 2010 -0500 @@ -72,7 +72,7 @@ #include #include -#include +#include #include #include @@ -344,7 +344,7 @@ static void lfs_unmark_dirop(struct lfs *fs) { - struct inode *ip, *nip; + struct lfs_inode *ip, *nip; struct vnode *vp; int doit; diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_syscalls.c --- a/sys/ufs/lfs/lfs_syscalls.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_syscalls.c Sun Feb 07 03:52:22 2010 -0500 @@ -77,12 +77,11 @@ #include #include -#include -#include -#include - #include #include +#include +#include +#include struct buf *lfs_fakebuf(struct lfs *, struct vnode *, int, size_t, void *); int lfs_fasthashget(dev_t, ino_t, struct vnode **); @@ -126,7 +125,7 @@ if ((mntp = vfs_getvfs(fsidp)) == NULL) return (ENOENT); - fs = VFSTOUFS(mntp)->um_lfs; + fs = VFSTOULFS(mntp)->um_lfs; blkcnt = SCARG(uap, blkcnt); if ((u_int) blkcnt > LFS_MARKV_MAXBLKCNT) @@ -171,7 +170,7 @@ if ((mntp = vfs_getvfs(&fsid)) == NULL) return (ENOENT); - fs = VFSTOUFS(mntp)->um_lfs; + fs = VFSTOULFS(mntp)->um_lfs; blkcnt = SCARG(uap, blkcnt); if ((u_int) blkcnt > LFS_MARKV_MAXBLKCNT) @@ -224,7 +223,7 @@ BLOCK_INFO *blkp; IFILE *ifp; struct buf *bp; - struct inode *ip = NULL; + struct lfs_inode *ip = NULL; struct lfs *fs; struct mount *mntp; struct vnode *vp = NULL; @@ -242,7 +241,7 @@ if ((mntp = vfs_getvfs(fsidp)) == NULL) return (ENOENT); - fs = VFSTOUFS(mntp)->um_lfs; + fs = VFSTOULFS(mntp)->um_lfs; if (fs->lfs_ronly) return EROFS; @@ -469,7 +468,7 @@ /* * XXX should account indirect blocks and ifile pages as well */ - if (nblkwritten + lblkno(fs, ninowritten * sizeof (struct ufs1_dinode)) + if (nblkwritten + lblkno(fs, ninowritten * sizeof (struct lfs_dinode)) > LFS_MARKV_MAX_BLOCKS) { DLOG((DLOG_CLEAN, "lfs_markv: writing %d blks %d inos\n", nblkwritten, ninowritten)); @@ -573,7 +572,7 @@ if ((mntp = vfs_getvfs(&fsid)) == NULL) return (ENOENT); - fs = VFSTOUFS(mntp)->um_lfs; + fs = VFSTOULFS(mntp)->um_lfs; blkcnt = SCARG(uap, blkcnt); if ((u_int) blkcnt > SIZE_T_MAX / sizeof(BLOCK_INFO)) @@ -617,7 +616,7 @@ if ((mntp = vfs_getvfs(&fsid)) == NULL) return (ENOENT); - fs = VFSTOUFS(mntp)->um_lfs; + fs = VFSTOULFS(mntp)->um_lfs; blkcnt = SCARG(uap, blkcnt); if ((size_t) blkcnt > SIZE_T_MAX / sizeof(BLOCK_INFO)) @@ -666,10 +665,10 @@ BLOCK_INFO *blkp; IFILE *ifp; struct buf *bp; - struct inode *ip = NULL; + struct lfs_inode *ip = NULL; struct lfs *fs; struct mount *mntp; - struct ufsmount *ump; + struct ulfsmount *ump; struct vnode *vp; ino_t lastino; daddr_t v_daddr; @@ -681,13 +680,13 @@ if ((mntp = vfs_getvfs(fsidp)) == NULL) return (ENOENT); - ump = VFSTOUFS(mntp); + ump = VFSTOULFS(mntp); if ((error = vfs_busy(mntp, NULL)) != 0) return (error); cnt = blkcnt; - fs = VFSTOUFS(mntp)->um_lfs; + fs = VFSTOULFS(mntp)->um_lfs; error = 0; @@ -730,19 +729,19 @@ * A regular call to VFS_VGET could deadlock * here. Instead, we try an unlocked access. */ - mutex_enter(&ufs_ihash_lock); - vp = ufs_ihashlookup(ump->um_dev, blkp->bi_inode); + mutex_enter(&ulfs_ihash_lock); + vp = ulfs_ihashlookup(ump->um_dev, blkp->bi_inode); if (vp != NULL && !(vp->v_iflag & VI_XLOCK)) { ip = VTOI(vp); mutex_enter(&vp->v_interlock); - mutex_exit(&ufs_ihash_lock); + mutex_exit(&ulfs_ihash_lock); if (lfs_vref(vp)) { v_daddr = LFS_UNUSED_DADDR; continue; } numrefed++; } else { - mutex_exit(&ufs_ihash_lock); + mutex_exit(&ulfs_ihash_lock); /* * Don't VFS_VGET if we're being unmounted, * since we hold vfs_busy(). @@ -857,7 +856,7 @@ if ((mntp = vfs_getvfs(&fsid)) == NULL) return (ENOENT); - fs = VFSTOUFS(mntp)->um_lfs; + fs = VFSTOULFS(mntp)->um_lfs; segnum = SCARG(uap, segment); if ((error = vfs_busy(mntp, NULL)) != 0) @@ -959,7 +958,7 @@ if (fsidp == NULL || (mntp = vfs_getvfs(fsidp)) == NULL) addr = &lfs_allclean_wakeup; else - addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; + addr = &VFSTOULFS(mntp)->um_lfs->lfs_nextseg; /* * XXX THIS COULD SLEEP FOREVER IF TIMEOUT IS {0,0}! * XXX IS THAT WHAT IS INTENDED? @@ -1024,10 +1023,10 @@ { struct vnode *vp; - mutex_enter(&ufs_ihash_lock); - if ((vp = ufs_ihashlookup(dev, ino)) != NULL) { + mutex_enter(&ulfs_ihash_lock); + if ((vp = ulfs_ihashlookup(dev, ino)) != NULL) { mutex_enter(&vp->v_interlock); - mutex_exit(&ufs_ihash_lock); + mutex_exit(&ulfs_ihash_lock); if (vp->v_iflag & VI_XLOCK) { DLOG((DLOG_CLEAN, "lfs_fastvget: ino %d VI_XLOCK\n", ino)); @@ -1042,7 +1041,7 @@ return EAGAIN; } } else { - mutex_exit(&ufs_ihash_lock); + mutex_exit(&ulfs_ihash_lock); } *vpp = vp; @@ -1051,18 +1050,18 @@ int lfs_fastvget(struct mount *mp, ino_t ino, daddr_t daddr, struct vnode **vpp, - struct ufs1_dinode *dinp) + struct lfs_dinode *dinp) { - struct inode *ip; - struct ufs1_dinode *dip; + struct lfs_inode *ip; + struct lfs_dinode *dip; struct vnode *vp; - struct ufsmount *ump; + struct ulfsmount *ump; dev_t dev; int error, retries; struct buf *bp; struct lfs *fs; - ump = VFSTOUFS(mp); + ump = VFSTOULFS(mp); dev = ump->um_dev; fs = ump->um_lfs; @@ -1102,10 +1101,10 @@ return (error); } - mutex_enter(&ufs_hashlock); + mutex_enter(&ulfs_hashlock); error = lfs_fasthashget(dev, ino, vpp); if (error != 0 || *vpp != NULL) { - mutex_exit(&ufs_hashlock); + mutex_exit(&ulfs_hashlock); ungetnewvnode(vp); return (error); } @@ -1120,8 +1119,8 @@ * disk portion of this inode to be read. */ ip = VTOI(vp); - ufs_ihashins(ip); - mutex_exit(&ufs_hashlock); + ulfs_ihashins(ip); + mutex_exit(&ulfs_hashlock); /* * XXX @@ -1133,11 +1132,11 @@ /* Read in the disk contents for the inode, copy into the inode. */ if (dinp) { - error = copyin(dinp, ip->i_din.ffs1_din, sizeof (struct ufs1_dinode)); + error = copyin(dinp, ip->i_ffs1_din, sizeof (struct lfs_dinode)); if (error) { DLOG((DLOG_CLEAN, "lfs_fastvget: dinode copyin failed" " for ino %d\n", ino)); - ufs_ihashrem(ip); + ulfs_ihashrem(ip); /* Unlock and discard unneeded inode. */ vlockmgr(&vp->v_lock, LK_RELEASE); @@ -1160,7 +1159,7 @@ * would be misleading to leave it on its hash chain. * Iput() will return it to the free list. */ - ufs_ihashrem(ip); + ulfs_ihashrem(ip); /* Unlock and discard unneeded inode. */ vlockmgr(&vp->v_lock, LK_RELEASE); @@ -1180,7 +1179,7 @@ " retrying...\n")); goto again; } - *ip->i_din.ffs1_din = *dip; + *ip->i_ffs1_din = *dip; brelse(bp, 0); } lfs_vinit(mp, &vp); diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_vfsops.c --- a/sys/ufs/lfs/lfs_vfsops.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_vfsops.c Sun Feb 07 03:52:22 2010 -0500 @@ -95,11 +95,6 @@ #include -#include -#include -#include -#include - #include #include #include @@ -107,6 +102,10 @@ #include #include +#include +#include +#include +#include #include #include @@ -114,7 +113,7 @@ MODULE(MODULE_CLASS_VFS, lfs, "ffs"); static int lfs_gop_write(struct vnode *, struct vm_page **, int, int); -static bool lfs_issequential_hole(const struct ufsmount *, +static bool lfs_issequential_hole(const struct ulfsmount *, daddr_t, daddr_t); static int lfs_mountfs(struct vnode *, struct mount *, struct lwp *); @@ -140,12 +139,12 @@ struct vfsops lfs_vfsops = { MOUNT_LFS, - sizeof (struct ufs_args), + sizeof (struct lfs_args), lfs_mount, - ufs_start, + ulfs_start, lfs_unmount, - ufs_root, - ufs_quotactl, + ulfs_root, + ulfs_quotactl, lfs_statvfs, lfs_sync, lfs_vget, @@ -168,12 +167,12 @@ const struct genfs_ops lfs_genfsops = { .gop_size = lfs_gop_size, - .gop_alloc = ufs_gop_alloc, + .gop_alloc = ulfs_gop_alloc, .gop_write = lfs_gop_write, - .gop_markupdate = ufs_gop_markupdate, + .gop_markupdate = ulfs_gop_markupdate, }; -static const struct ufs_ops lfs_ufsops = { +static const struct ulfs_ops lfs_ulfsops = { .uo_itimes = NULL, .uo_update = lfs_update, .uo_truncate = lfs_truncate, @@ -406,7 +405,7 @@ } if (strncmp(mp->mnt_stat.f_fstypename, MOUNT_LFS, sizeof(mp->mnt_stat.f_fstypename)) == 0) { - fs = VFSTOUFS(mp)->um_lfs; + fs = VFSTOULFS(mp)->um_lfs; mutex_enter(&lfs_lock); fsflags = 0; if ((fs->lfs_dirvcount > LFS_MAX_FSDIROP(fs) || @@ -464,22 +463,23 @@ } /* - * Initialize the filesystem, most work done by ufs_init. + * Initialize the filesystem, most work done by ulfs_init. */ void lfs_init(void) { + malloc_type_attach(M_ULFSMOUNT); malloc_type_attach(M_SEGMENT); - pool_init(&lfs_inode_pool, sizeof(struct inode), 0, 0, 0, + pool_init(&lfs_inode_pool, sizeof(struct lfs_inode), 0, 0, 0, "lfsinopl", &pool_allocator_nointr, IPL_NONE); - pool_init(&lfs_dinode_pool, sizeof(struct ufs1_dinode), 0, 0, 0, + pool_init(&lfs_dinode_pool, sizeof(struct lfs_dinode), 0, 0, 0, "lfsdinopl", &pool_allocator_nointr, IPL_NONE); pool_init(&lfs_inoext_pool, sizeof(struct lfs_inode_ext), 8, 0, 0, "lfsinoextpl", &pool_allocator_nointr, IPL_NONE); pool_init(&lfs_lbnentry_pool, sizeof(struct lbnentry), 0, 0, 0, "lfslbnpool", &pool_allocator_nointr, IPL_NONE); - ufs_init(); + ulfs_init(); #ifdef DEBUG memset(lfs_log, 0, sizeof(lfs_log)); @@ -492,13 +492,13 @@ void lfs_reinit(void) { - ufs_reinit(); + ulfs_reinit(); } void lfs_done(void) { - ufs_done(); + ulfs_done(); mutex_destroy(&lfs_lock); cv_destroy(&locked_queue_cv); cv_destroy(&lfs_writing_cv); @@ -507,10 +507,11 @@ pool_destroy(&lfs_inoext_pool); pool_destroy(&lfs_lbnentry_pool); malloc_type_detach(M_SEGMENT); + malloc_type_detach(M_ULFSMOUNT); } /* - * Called by main() when ufs is going to be mounted as root. + * Called by main() when lfs is going to be mounted as root. */ int lfs_mountroot(void) @@ -539,7 +540,7 @@ mutex_exit(&mountlist_lock); (void)lfs_statvfs(mp, &mp->mnt_stat); vfs_unbusy(mp, false, NULL); - setrootfstime((time_t)(VFSTOUFS(mp)->um_lfs->lfs_tstamp)); + setrootfstime((time_t)(VFSTOULFS(mp)->um_lfs->lfs_tstamp)); return (0); } @@ -553,8 +554,8 @@ { struct lwp *l = curlwp; struct vnode *devvp; - struct ufs_args *args = data; - struct ufsmount *ump = NULL; + struct lfs_args *args = data; + struct ulfsmount *ump = NULL; struct lfs *fs = NULL; /* LFS */ int error = 0, update; mode_t accessmode; @@ -563,7 +564,7 @@ return EINVAL; if (mp->mnt_flag & MNT_GETARGS) { - ump = VFSTOUFS(mp); + ump = VFSTOULFS(mp); if (ump == NULL) return EIO; args->fspec = NULL; @@ -596,7 +597,7 @@ * Be sure we're still naming the same device * used for our initial mount */ - ump = VFSTOUFS(mp); + ump = VFSTOULFS(mp); if (devvp != ump->um_devvp) error = EINVAL; } @@ -606,7 +607,7 @@ return (EINVAL); } else { /* Use the extant mount */ - ump = VFSTOUFS(mp); + ump = VFSTOULFS(mp); devvp = ump->um_devvp; vref(devvp); } @@ -651,7 +652,7 @@ goto fail; } - ump = VFSTOUFS(mp); + ump = VFSTOULFS(mp); fs = ump->um_lfs; } else { /* @@ -665,7 +666,7 @@ */ vrele(devvp); - ump = VFSTOUFS(mp); + ump = VFSTOULFS(mp); fs = ump->um_lfs; if (fs->lfs_ronly && (mp->mnt_iflag & IMNT_WANTRDWR)) { /* @@ -705,7 +706,7 @@ { struct dlfs *tdfs, *dfs, *adfs; struct lfs *fs; - struct ufsmount *ump; + struct ulfsmount *ump; struct vnode *vp; struct buf *bp, *abp; struct partinfo dpart; @@ -834,7 +835,7 @@ } /* Allocate the mount structure, copy the superblock into it. */ - fs = malloc(sizeof(struct lfs), M_UFSMNT, M_WAITOK | M_ZERO); + fs = malloc(sizeof(struct lfs), M_ULFSMOUNT, M_WAITOK | M_ZERO); memcpy(&fs->lfs_dlfs, tdfs, sizeof(struct dlfs)); /* Compatibility */ @@ -859,7 +860,7 @@ (long long)((bufmem_hiwater / bufmem_lowater) * LFS_INVERSE_MAX_BYTES( fsbtob(fs, LFS_NRESERVE(fs))) >> PAGE_SHIFT))); - free(fs, M_UFSMNT); + free(fs, M_ULFSMOUNT); error = EFBIG; /* XXX needs translation */ goto out; } @@ -870,10 +871,9 @@ fs->lfs_rfpid = l->l_proc->p_pid; } - ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO); + ump = malloc(sizeof *ump, M_ULFSMOUNT, M_WAITOK | M_ZERO); ump->um_lfs = fs; - ump->um_ops = &lfs_ufsops; - ump->um_fstype = UFS1; + ump->um_ops = &lfs_ulfsops; if (sizeof(struct lfs) < LFS_SBPAD) { /* XXX why? */ brelse(bp, BC_INVAL); brelse(abp, BC_INVAL); @@ -1055,8 +1055,8 @@ if (abp) brelse(abp, 0); if (ump) { - free(ump->um_lfs, M_UFSMNT); - free(ump, M_UFSMNT); + free(ump->um_lfs, M_ULFSMOUNT); + free(ump, M_ULFSMOUNT); mp->mnt_data = NULL; } @@ -1070,7 +1070,7 @@ lfs_unmount(struct mount *mp, int mntflags) { struct lwp *l = curlwp; - struct ufsmount *ump; + struct ulfsmount *ump; struct lfs *fs; int error, flags, ronly; vnode_t *vp; @@ -1079,7 +1079,7 @@ if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - ump = VFSTOUFS(mp); + ump = VFSTOULFS(mp); fs = ump->um_lfs; /* Two checkpoints */ @@ -1103,7 +1103,7 @@ for (i = 0; i < MAXQUOTAS; i++) { if (ump->um_quotas[i] == NULLVP) continue; - quotaoff(l, mp, i); + lfs_quotaoff(l, mp, i); } /* * Here we fall through to vflush again to ensure @@ -1156,8 +1156,8 @@ cv_destroy(&fs->lfs_stopcv); rw_destroy(&fs->lfs_fraglock); rw_destroy(&fs->lfs_iflock); - free(fs, M_UFSMNT); - free(ump, M_UFSMNT); + free(fs, M_ULFSMOUNT); + free(ump, M_ULFSMOUNT); mp->mnt_data = NULL; mp->mnt_flag &= ~MNT_LOCAL; @@ -1174,9 +1174,9 @@ lfs_statvfs(struct mount *mp, struct statvfs *sbp) { struct lfs *fs; - struct ufsmount *ump; + struct ulfsmount *ump; - ump = VFSTOUFS(mp); + ump = VFSTOULFS(mp); fs = ump->um_lfs; if (fs->lfs_magic != LFS_MAGIC) panic("lfs_statvfs: magic"); @@ -1220,7 +1220,7 @@ int error; struct lfs *fs; - fs = VFSTOUFS(mp)->um_lfs; + fs = VFSTOULFS(mp)->um_lfs; if (fs->lfs_ronly) return 0; @@ -1245,7 +1245,7 @@ error = lfs_segwrite(mp, SEGM_CKP | (waitfor ? SEGM_SYNC : 0)); lfs_writer_leave(fs); #ifdef QUOTA - qsync(mp); + lfs_qsync(mp); #endif return (error); } @@ -1259,12 +1259,12 @@ lfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) { struct lfs *fs; - struct ufs1_dinode *dip; - struct inode *ip; + struct lfs_dinode *dip; + struct lfs_inode *ip; struct buf *bp; struct ifile *ifp; struct vnode *vp; - struct ufsmount *ump; + struct ulfsmount *ump; daddr_t daddr; dev_t dev; int error, retries; @@ -1272,7 +1272,7 @@ memset(&ts, 0, sizeof ts); /* XXX gcc */ - ump = VFSTOUFS(mp); + ump = VFSTOULFS(mp); dev = ump->um_dev; fs = ump->um_lfs; @@ -1287,7 +1287,7 @@ mutex_exit(&lfs_lock); retry: - if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) + if ((*vpp = ulfs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) return (0); if ((error = getnewvnode(VT_LFS, mp, lfs_vnodeop_p, &vp)) != 0) { @@ -1295,9 +1295,9 @@ return (error); } - mutex_enter(&ufs_hashlock); - if (ufs_ihashget(dev, ino, 0) != NULL) { - mutex_exit(&ufs_hashlock); + mutex_enter(&ulfs_hashlock); + if (ulfs_ihashget(dev, ino, 0) != NULL) { + mutex_exit(&ulfs_hashlock); ungetnewvnode(vp); goto retry; } @@ -1317,7 +1317,7 @@ brelse(bp, 0); if (daddr == LFS_UNUSED_DADDR) { *vpp = NULLVP; - mutex_exit(&ufs_hashlock); + mutex_exit(&ulfs_hashlock); ungetnewvnode(vp); return (ENOENT); } @@ -1333,8 +1333,8 @@ * disk portion of this inode to be read. */ ip = VTOI(vp); - ufs_ihashins(ip); - mutex_exit(&ufs_hashlock); + ulfs_ihashins(ip); + mutex_exit(&ulfs_hashlock); /* * XXX @@ -1375,7 +1375,7 @@ mutex_enter(&lfs_lock); if (fs->lfs_seglock > 0) { struct buf **bpp; - struct ufs1_dinode *dp; + struct lfs_dinode *dp; int i; for (bpp = fs->lfs_sp->bpp; @@ -1385,7 +1385,7 @@ /* Inode block */ printf("lfs_vget: block 0x%" PRIx64 ": ", (*bpp)->b_blkno); - dp = (struct ufs1_dinode *)(*bpp)->b_data; + dp = (struct lfs_dinode *)(*bpp)->b_data; for (i = 0; i < INOPB(fs); i++) if (dp[i].di_u.inumber) printf("%d ", dp[i].di_u.inumber); @@ -1407,7 +1407,7 @@ mutex_exit(&lfs_lock); goto again; } - *ip->i_din.ffs1_din = *dip; + *ip->i_ffs1_din = *dip; brelse(bp, 0); if (fs->lfs_version > 1) { @@ -1444,7 +1444,7 @@ if (lfh.lfid_ino < LFS_IFILE_INUM) return ESTALE; - fs = VFSTOUFS(mp)->um_lfs; + fs = VFSTOULFS(mp)->um_lfs; if (lfh.lfid_ident != fs->lfs_ident) return ESTALE; @@ -1453,9 +1453,9 @@ fs->lfs_cleansz - fs->lfs_segtabsz) * fs->lfs_ifpb) return ESTALE; - mutex_enter(&ufs_ihash_lock); - vp = ufs_ihashlookup(VFSTOUFS(mp)->um_dev, lfh.lfid_ino); - mutex_exit(&ufs_ihash_lock); + mutex_enter(&ulfs_ihash_lock); + vp = ulfs_ihashlookup(VFSTOULFS(mp)->um_dev, lfh.lfid_ino); + mutex_exit(&ulfs_ihash_lock); if (vp == NULL) { LFS_IENTRY(ifp, fs, lfh.lfid_ino, bp); daddr = ifp->if_daddr; @@ -1464,7 +1464,7 @@ return ESTALE; } - return (ufs_fhtovp(mp, &lfh.lfid_ufid, vpp)); + return (ulfs_fhtovp(mp, &lfh, vpp)); } /* @@ -1474,7 +1474,7 @@ int lfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size) { - struct inode *ip; + struct lfs_inode *ip; struct lfid lfh; if (*fh_size < sizeof(struct lfid)) { @@ -1493,13 +1493,13 @@ } /* - * ufs_bmaparray callback function for writing. + * ulfs_bmaparray callback function for writing. * * Since blocks will be written to the new segment anyway, * we don't care about current daddr of them. */ static bool -lfs_issequential_hole(const struct ufsmount *ump, +lfs_issequential_hole(const struct ulfsmount *ump, daddr_t daddr0, daddr_t daddr1) { daddr0 = (daddr_t)((int32_t)daddr0); /* XXX ondisk32 */ @@ -1511,7 +1511,7 @@ (0 <= daddr1 && daddr1 <= LFS_MAX_DADDR)); /* NOTE: all we want to know here is 'hole or not'. */ - /* NOTE: UNASSIGNED is converted to 0 by ufs_bmaparray. */ + /* NOTE: UNASSIGNED is converted to 0 by ulfs_bmaparray. */ /* * treat UNWRITTENs and all resident blocks as 'contiguous' @@ -1554,7 +1554,7 @@ struct vm_page *pg; struct buf *mbp, *bp; struct vnode *devvp = VTOI(vp)->i_devvp; - struct inode *ip = VTOI(vp); + struct lfs_inode *ip = VTOI(vp); struct lfs *fs = ip->i_lfs; struct segment *sp = fs->lfs_sp; UVMHIST_FUNC("lfs_gop_write"); UVMHIST_CALLED(ubchist); @@ -1692,10 +1692,10 @@ bytes > 0; offset += iobytes, bytes -= iobytes) { lbn = offset >> fs_bshift; - error = ufs_bmaparray(vp, lbn, &blkno, NULL, NULL, &run, + error = ulfs_bmaparray(vp, lbn, &blkno, NULL, NULL, &run, lfs_issequential_hole); if (error) { - UVMHIST_LOG(ubchist, "ufs_bmaparray() -> %d", + UVMHIST_LOG(ubchist, "ulfs_bmaparray() -> %d", error,0,0,0); skipbytes += bytes; bytes = 0; @@ -1848,8 +1848,8 @@ lfs_vinit(struct mount *mp, struct vnode **vpp) { struct vnode *vp = *vpp; - struct inode *ip = VTOI(vp); - struct ufsmount *ump = VFSTOUFS(mp); + struct lfs_inode *ip = VTOI(vp); + struct ulfsmount *ump = VFSTOULFS(mp); struct lfs *fs = ump->um_lfs; int i; @@ -1868,7 +1868,7 @@ * Initialize the vnode from the inode, check for aliases. In all * cases re-init ip, the underlying vnode/inode may have changed. */ - ufs_vinit(mp, lfs_specop_p, lfs_fifoop_p, &vp); + ulfs_vinit(mp, lfs_specop_p, lfs_fifoop_p, &vp); ip = VTOI(vp); memset(ip->i_lfs_fragsize, 0, NDADDR * sizeof(*ip->i_lfs_fragsize)); @@ -1881,7 +1881,7 @@ continue; if (ip->i_ffs1_db[i] != 0) { inconsistent: - lfs_dump_dinode(ip->i_din.ffs1_din); + lfs_dump_dinode(ip->i_ffs1_din); panic("inconsistent inode"); } } @@ -1899,7 +1899,7 @@ #ifdef DIAGNOSTIC if (vp->v_type == VNON) { # ifdef DEBUG - lfs_dump_dinode(ip->i_din.ffs1_din); + lfs_dump_dinode(ip->i_ffs1_din); # endif panic("lfs_vinit: ino %llu is type VNON! (ifmt=%o)\n", (unsigned long long)ip->i_number, @@ -1932,7 +1932,7 @@ struct buf *bp, *obp; daddr_t olast, nlast, ilast, noff, start, end; struct vnode *ivp; - struct inode *ip; + struct lfs_inode *ip; int error, badnews, inc, oldnsegs; int sbbytes, csbbytes, gain, cgain; int i; diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/lfs_vnops.c --- a/sys/ufs/lfs/lfs_vnops.c Sun Feb 07 01:14:00 2010 -0500 +++ b/sys/ufs/lfs/lfs_vnops.c Sun Feb 07 03:52:22 2010 -0500 @@ -87,11 +87,6 @@ #include #include -#include -#include -#include -#include - #include #include #include @@ -99,6 +94,9 @@ #include #include +#include +#include +#include extern pid_t lfs_writer_daemon; int lfs_ignore_lazy_sync = 1; @@ -107,44 +105,44 @@ int (**lfs_vnodeop_p)(void *); const struct vnodeopv_entry_desc lfs_vnodeop_entries[] = { { &vop_default_desc, vn_default_error }, - { &vop_lookup_desc, ufs_lookup }, /* lookup */ + { &vop_lookup_desc, ulfs_lookup }, /* lookup */ { &vop_create_desc, lfs_create }, /* create */ - { &vop_whiteout_desc, ufs_whiteout }, /* whiteout */ + { &vop_whiteout_desc, ulfs_whiteout }, /* whiteout */ { &vop_mknod_desc, lfs_mknod }, /* mknod */ - { &vop_open_desc, ufs_open }, /* open */ + { &vop_open_desc, ulfs_open }, /* open */ { &vop_close_desc, lfs_close }, /* close */ - { &vop_access_desc, ufs_access }, /* access */ + { &vop_access_desc, ulfs_access }, /* access */ { &vop_getattr_desc, lfs_getattr }, /* getattr */ { &vop_setattr_desc, lfs_setattr }, /* setattr */ { &vop_read_desc, lfs_read }, /* read */ { &vop_write_desc, lfs_write }, /* write */ - { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ + { &vop_ioctl_desc, ulfs_ioctl }, /* ioctl */ { &vop_fcntl_desc, lfs_fcntl }, /* fcntl */ - { &vop_poll_desc, ufs_poll }, /* poll */ + { &vop_poll_desc, ulfs_poll }, /* poll */ { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ - { &vop_revoke_desc, ufs_revoke }, /* revoke */ + { &vop_revoke_desc, ulfs_revoke }, /* revoke */ { &vop_mmap_desc, lfs_mmap }, /* mmap */ { &vop_fsync_desc, lfs_fsync }, /* fsync */ - { &vop_seek_desc, ufs_seek }, /* seek */ + { &vop_seek_desc, ulfs_seek }, /* seek */ { &vop_remove_desc, lfs_remove }, /* remove */ { &vop_link_desc, lfs_link }, /* link */ { &vop_rename_desc, lfs_rename }, /* rename */ { &vop_mkdir_desc, lfs_mkdir }, /* mkdir */ { &vop_rmdir_desc, lfs_rmdir }, /* rmdir */ { &vop_symlink_desc, lfs_symlink }, /* symlink */ - { &vop_readdir_desc, ufs_readdir }, /* readdir */ - { &vop_readlink_desc, ufs_readlink }, /* readlink */ - { &vop_abortop_desc, ufs_abortop }, /* abortop */ + { &vop_readdir_desc, ulfs_readdir }, /* readdir */ + { &vop_readlink_desc, ulfs_readlink }, /* readlink */ + { &vop_abortop_desc, ulfs_abortop }, /* abortop */ { &vop_inactive_desc, lfs_inactive }, /* inactive */ { &vop_reclaim_desc, lfs_reclaim }, /* reclaim */ - { &vop_lock_desc, ufs_lock }, /* lock */ - { &vop_unlock_desc, ufs_unlock }, /* unlock */ - { &vop_bmap_desc, ufs_bmap }, /* bmap */ + { &vop_lock_desc, ulfs_lock }, /* lock */ + { &vop_unlock_desc, ulfs_unlock }, /* unlock */ + { &vop_bmap_desc, ulfs_bmap }, /* bmap */ { &vop_strategy_desc, lfs_strategy }, /* strategy */ - { &vop_print_desc, ufs_print }, /* print */ - { &vop_islocked_desc, ufs_islocked }, /* islocked */ - { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */ - { &vop_advlock_desc, ufs_advlock }, /* advlock */ + { &vop_print_desc, ulfs_print }, /* print */ + { &vop_islocked_desc, ulfs_islocked }, /* islocked */ + { &vop_pathconf_desc, ulfs_pathconf }, /* pathconf */ + { &vop_advlock_desc, ulfs_advlock }, /* advlock */ { &vop_bwrite_desc, lfs_bwrite }, /* bwrite */ { &vop_getpages_desc, lfs_getpages }, /* getpages */ { &vop_putpages_desc, lfs_putpages }, /* putpages */ @@ -161,13 +159,13 @@ { &vop_mknod_desc, spec_mknod }, /* mknod */ { &vop_open_desc, spec_open }, /* open */ { &vop_close_desc, lfsspec_close }, /* close */ - { &vop_access_desc, ufs_access }, /* access */ + { &vop_access_desc, ulfs_access }, /* access */ { &vop_getattr_desc, lfs_getattr }, /* getattr */ { &vop_setattr_desc, lfs_setattr }, /* setattr */ - { &vop_read_desc, ufsspec_read }, /* read */ - { &vop_write_desc, ufsspec_write }, /* write */ + { &vop_read_desc, ulfsspec_read }, /* read */ + { &vop_write_desc, ulfsspec_write }, /* write */ { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ - { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ + { &vop_fcntl_desc, ulfs_fcntl }, /* fcntl */ { &vop_poll_desc, spec_poll }, /* poll */ { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ { &vop_revoke_desc, spec_revoke }, /* revoke */ @@ -185,12 +183,12 @@ { &vop_abortop_desc, spec_abortop }, /* abortop */ { &vop_inactive_desc, lfs_inactive }, /* inactive */ { &vop_reclaim_desc, lfs_reclaim }, /* reclaim */ - { &vop_lock_desc, ufs_lock }, /* lock */ - { &vop_unlock_desc, ufs_unlock }, /* unlock */ + { &vop_lock_desc, ulfs_lock }, /* lock */ + { &vop_unlock_desc, ulfs_unlock }, /* unlock */ { &vop_bmap_desc, spec_bmap }, /* bmap */ { &vop_strategy_desc, spec_strategy }, /* strategy */ - { &vop_print_desc, ufs_print }, /* print */ - { &vop_islocked_desc, ufs_islocked }, /* islocked */ + { &vop_print_desc, ulfs_print }, /* print */ + { &vop_islocked_desc, ulfs_islocked }, /* islocked */ { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ { &vop_advlock_desc, spec_advlock }, /* advlock */ { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ @@ -209,13 +207,13 @@ { &vop_mknod_desc, fifo_mknod }, /* mknod */ { &vop_open_desc, fifo_open }, /* open */ { &vop_close_desc, lfsfifo_close }, /* close */ - { &vop_access_desc, ufs_access }, /* access */ + { &vop_access_desc, ulfs_access }, /* access */ { &vop_getattr_desc, lfs_getattr }, /* getattr */ { &vop_setattr_desc, lfs_setattr }, /* setattr */ - { &vop_read_desc, ufsfifo_read }, /* read */ - { &vop_write_desc, ufsfifo_write }, /* write */ + { &vop_read_desc, ulfsfifo_read }, /* read */ + { &vop_write_desc, ulfsfifo_write }, /* write */ { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ - { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ + { &vop_fcntl_desc, ulfs_fcntl }, /* fcntl */ { &vop_poll_desc, fifo_poll }, /* poll */ { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ { &vop_revoke_desc, fifo_revoke }, /* revoke */ @@ -233,12 +231,12 @@ { &vop_abortop_desc, fifo_abortop }, /* abortop */ { &vop_inactive_desc, lfs_inactive }, /* inactive */ { &vop_reclaim_desc, lfs_reclaim }, /* reclaim */ - { &vop_lock_desc, ufs_lock }, /* lock */ - { &vop_unlock_desc, ufs_unlock }, /* unlock */ + { &vop_lock_desc, ulfs_lock }, /* lock */ + { &vop_unlock_desc, ulfs_unlock }, /* unlock */ { &vop_bmap_desc, fifo_bmap }, /* bmap */ { &vop_strategy_desc, fifo_strategy }, /* strategy */ - { &vop_print_desc, ufs_print }, /* print */ - { &vop_islocked_desc, ufs_islocked }, /* islocked */ + { &vop_print_desc, ulfs_print }, /* print */ + { &vop_islocked_desc, ulfs_islocked }, /* islocked */ { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ { &vop_advlock_desc, fifo_advlock }, /* advlock */ { &vop_bwrite_desc, lfs_bwrite }, /* bwrite */ @@ -251,7 +249,7 @@ static int check_dirty(struct lfs *, struct vnode *, off_t, off_t, off_t, int, int, struct vm_page **); #define LFS_READWRITE -#include +#include #undef LFS_READWRITE /* @@ -270,7 +268,7 @@ } */ *ap = v; struct vnode *vp = ap->a_vp; int error, wait; - struct inode *ip = VTOI(vp); + struct lfs_inode *ip = VTOI(vp); struct lfs *fs = ip->i_lfs; /* If we're mounted read-only, don't try to sync. */ @@ -335,7 +333,7 @@ } /* - * Take IN_ADIROP off, then call ufs_inactive. + * Take IN_ADIROP off, then call ulfs_inactive. */ int lfs_inactive(void *v) @@ -358,11 +356,11 @@ return 0; } - return ufs_inactive(v); + return ulfs_inactive(v); } /* - * These macros are used to bracket UFS directory ops, so that we can + * These macros are used to bracket ULFS directory ops, so that we can * identify all the pages touched during directory ops which need to * be ordered and flushed atomically, so that they may be recovered. * @@ -465,7 +463,7 @@ int error; struct lfs *fs; - fs = VFSTOUFS(dvp->v_mount)->um_lfs; + fs = VFSTOULFS(dvp->v_mount)->um_lfs; ASSERT_NO_SEGLOCK(fs); if (fs->lfs_ronly) return EROFS; @@ -530,7 +528,7 @@ void lfs_mark_vnode(struct vnode *vp) { - struct inode *ip = VTOI(vp); + struct lfs_inode *ip = VTOI(vp); struct lfs *fs = ip->i_lfs; mutex_enter(&lfs_lock); @@ -553,7 +551,7 @@ void lfs_unmark_vnode(struct vnode *vp) { - struct inode *ip = VTOI(vp); + struct lfs_inode *ip = VTOI(vp); if (ip && (ip->i_flag & IN_ADIROP)) { KASSERT(vp->v_uflag & VU_DIROP); @@ -580,7 +578,7 @@ vput(ap->a_dvp); return error; } - error = ufs_symlink(ap); + error = ulfs_symlink(ap); SET_ENDOP_CREATE_AP(ap, "symlink"); return (error); } @@ -596,7 +594,7 @@ } */ *ap = v; struct vattr *vap = ap->a_vap; struct vnode **vpp = ap->a_vpp; - struct inode *ip; + struct lfs_inode *ip; int error; struct mount *mp; ino_t ino; @@ -605,7 +603,7 @@ vput(ap->a_dvp); return error; } - error = ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode), + error = ulfs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode), ap->a_dvp, vpp, ap->a_cnp); /* Either way we're done with the dirop at this point */ @@ -624,8 +622,8 @@ * inodes, so don't truncate the dev number. */ #if 0 - ip->i_ffs1_rdev = ufs_rw32(vap->va_rdev, - UFS_MPNEEDSWAP((*vpp)->v_mount)); + ip->i_ffs1_rdev = ulfs_rw32(vap->va_rdev, + ULFS_MPNEEDSWAP((*vpp)->v_mount)); #else ip->i_ffs1_rdev = vap->va_rdev; #endif @@ -678,7 +676,7 @@ vput(ap->a_dvp); return error; } - error = ufs_create(ap); + error = ulfs_create(ap); SET_ENDOP_CREATE_AP(ap, "create"); return (error); } @@ -698,7 +696,7 @@ vput(ap->a_dvp); return error; } - error = ufs_mkdir(ap); + error = ulfs_mkdir(ap); SET_ENDOP_CREATE_AP(ap, "mkdir"); return (error); } @@ -712,7 +710,7 @@ struct componentname *a_cnp; } */ *ap = v; struct vnode *dvp, *vp; - struct inode *ip; + struct lfs_inode *ip; int error; dvp = ap->a_dvp; @@ -726,7 +724,7 @@ vput(dvp); return error; } - error = ufs_remove(ap); + error = ulfs_remove(ap); if (ip->i_nlink == 0) lfs_orphan(ip->i_lfs, ip->i_number); SET_ENDOP_REMOVE(ip->i_lfs, dvp, ap->a_vp, "remove"); @@ -743,7 +741,7 @@ struct componentname *a_cnp; } */ *ap = v; struct vnode *vp; - struct inode *ip; + struct lfs_inode *ip; int error; vp = ap->a_vp; @@ -756,7 +754,7 @@ vput(vp); return error; } - error = ufs_rmdir(ap); + error = ulfs_rmdir(ap); if (ip->i_nlink == 0) lfs_orphan(ip->i_lfs, ip->i_number); SET_ENDOP_REMOVE(ip->i_lfs, ap->a_dvp, ap->a_vp, "rmdir"); @@ -778,7 +776,7 @@ vput(ap->a_dvp); return error; } - error = ufs_link(ap); + error = ulfs_link(ap); SET_ENDOP_CREATE(VTOI(ap->a_dvp)->i_lfs, ap->a_dvp, vpp, "link"); return (error); } @@ -813,7 +811,7 @@ * (In particular note that MARK_VNODE(tdvp) will DTWT on * a cross-device rename.) * - * Copied from ufs_rename. + * Copied from ulfs_rename. */ if ((fvp->v_mount != tdvp->v_mount) || (tvp && (fvp->v_mount != tvp->v_mount))) { @@ -827,7 +825,7 @@ * if we are we can't recursively call VOP_REMOVE since that * would leave us with an unaccounted-for number of live dirops. * - * Inline the relevant section of ufs_rename here, *before* + * Inline the relevant section of ulfs_rename here, *before* * calling SET_DIROP_REMOVE. */ if (tvp && ((VTOI(tvp)->i_flags & (IMMUTABLE | APPEND)) || @@ -864,7 +862,7 @@ MARK_VNODE(fdvp); MARK_VNODE(fvp); - error = ufs_rename(ap); + error = ulfs_rename(ap); UNMARK_VNODE(fdvp); UNMARK_VNODE(fvp); SET_ENDOP_REMOVE(fs, tdvp, tvp, "rename"); @@ -894,7 +892,7 @@ kauth_cred_t a_cred; } */ *ap = v; struct vnode *vp = ap->a_vp; - struct inode *ip = VTOI(vp); + struct lfs_inode *ip = VTOI(vp); struct vattr *vap = ap->a_vap; struct lfs *fs = ip->i_lfs; /* @@ -931,7 +929,7 @@ /* * Check to make sure the inode blocks won't choke the buffer - * cache, then call ufs_setattr as usual. + * cache, then call ulfs_setattr as usual. */ int lfs_setattr(void *v) @@ -944,7 +942,7 @@ struct vnode *vp = ap->a_vp; lfs_check(vp, LFS_UNUSED_LBN, 0); - return ufs_setattr(v); + return ulfs_setattr(v); } /* @@ -952,7 +950,7 @@ * or explicitly from LFCNWRAPGO. Called with the interlock held. */ static int -lfs_wrapgo(struct lfs *fs, struct inode *ip, int waitfor) +lfs_wrapgo(struct lfs *fs, struct lfs_inode *ip, int waitfor) { if (fs->lfs_stoplwp != curlwp) return EBUSY; @@ -991,7 +989,7 @@ kauth_cred_t a_cred; } */ *ap = v; struct vnode *vp = ap->a_vp; - struct inode *ip = VTOI(vp); + struct lfs_inode *ip = VTOI(vp); struct lfs *fs = ip->i_lfs; if ((ip->i_number == ROOTINO || ip->i_number == LFS_IFILE_INUM) && @@ -1026,7 +1024,7 @@ kauth_cred_t a_cred; } */ *ap = v; struct vnode *vp; - struct inode *ip; + struct lfs_inode *ip; vp = ap->a_vp; ip = VTOI(vp); @@ -1050,7 +1048,7 @@ kauth_cred_ a_cred; } */ *ap = v; struct vnode *vp; - struct inode *ip; + struct lfs_inode *ip; vp = ap->a_vp; ip = VTOI(vp); @@ -1071,14 +1069,14 @@ struct vnode *a_vp; } */ *ap = v; struct vnode *vp = ap->a_vp; - struct inode *ip = VTOI(vp); + struct lfs_inode *ip = VTOI(vp); struct lfs *fs = ip->i_lfs; int error; mutex_enter(&lfs_lock); LFS_CLR_UINO(ip, IN_ALLMOD); mutex_exit(&lfs_lock); - if ((error = ufs_reclaim(vp))) + if ((error = ulfs_reclaim(vp))) return (error); /* @@ -1099,7 +1097,7 @@ } mutex_exit(&lfs_lock); - pool_put(&lfs_dinode_pool, ip->i_din.ffs1_din); + pool_put(&lfs_dinode_pool, ip->i_ffs1_din); lfs_deregister_all(vp); pool_put(&lfs_inoext_pool, ip->inode_ext.lfs); ip->inode_ext.lfs = NULL; @@ -1116,7 +1114,7 @@ * buffer cache / page cache mechanisms---check for collisions before * reading. * - * We inline ufs_strategy to make sure that the VOP_BMAP occurs *before* + * We inline ulfs_strategy to make sure that the VOP_BMAP occurs *before* * the active cleaner test. * * XXX This code assumes that lfs_markv makes synchronous checkpoints. @@ -1131,7 +1129,7 @@ struct buf *bp; struct lfs *fs; struct vnode *vp; - struct inode *ip; + struct lfs_inode *ip; daddr_t tbn; int i, sn, error, slept; @@ -1223,7 +1221,7 @@ void lfs_flush_dirops(struct lfs *fs) { - struct inode *ip, *nip; + struct lfs_inode *ip, *nip; struct vnode *vp; extern int lfs_dostats; struct segment *sp; @@ -1324,7 +1322,7 @@ void lfs_flush_pchain(struct lfs *fs) { - struct inode *ip, *nip; + struct lfs_inode *ip, *nip; struct vnode *vp; extern int lfs_dostats; struct segment *sp; @@ -1444,7 +1442,7 @@ /* Only respect LFS fcntls on fs root or Ifile */ if (VTOI(ap->a_vp)->i_number != ROOTINO && VTOI(ap->a_vp)->i_number != LFS_IFILE_INUM) { - return ufs_fcntl(v); + return ulfs_fcntl(v); } /* Avoid locking a draining lock */ @@ -1675,7 +1673,7 @@ return 0; default: - return ufs_fcntl(v); + return ulfs_fcntl(v); } return 0; } @@ -1761,7 +1759,7 @@ int seglocked, const char *label) { #ifndef BUSYWAIT - struct inode *ip = VTOI(vp); + struct lfs_inode *ip = VTOI(vp); struct segment *sp = fs->lfs_sp; int count = 0; @@ -2012,7 +2010,7 @@ int a_flags; } */ *ap = v; struct vnode *vp; - struct inode *ip; + struct lfs_inode *ip; struct lfs *fs; struct segment *sp; off_t origoffset, startoffset, endoffset, origendoffset, blkeof; @@ -2396,7 +2394,7 @@ void lfs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags) { - struct inode *ip = VTOI(vp); + struct lfs_inode *ip = VTOI(vp); struct lfs *fs = ip->i_lfs; daddr_t olbn, nlbn; @@ -2425,7 +2423,7 @@ #ifdef DDB vfs_vnode_print(ap->a_vp, 0, printf); #endif - lfs_dump_dinode(VTOI(ap->a_vp)->i_din.ffs1_din); + lfs_dump_dinode(VTOI(ap->a_vp)->i_ffs1_din); } #endif @@ -2441,5 +2439,5 @@ if (VTOI(ap->a_vp)->i_number == LFS_IFILE_INUM) return EOPNOTSUPP; - return ufs_mmap(v); + return ulfs_mmap(v); } diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_bmap.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_bmap.c Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,372 @@ +/* $NetBSD: ulfs_bmap.c,v 1.48 2008/03/27 19:06:52 ad Exp $ */ +/* from NetBSD: ufs_bmap.c,v 1.48 2008/03/27 19:06:52 ad 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. + * + * @(#)ulfs_bmap.c 8.8 (Berkeley) 8/11/95 + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: ulfs_bmap.c,v 1.48 2008/03/27 19:06:52 ad Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +static bool +ulfs_issequential(const struct ulfsmount *ump, daddr_t daddr0, daddr_t daddr1) +{ + + /* for ulfs, blocks in a hole is not 'contiguous'. */ + if (daddr0 == 0) + return false; + + return (daddr0 + ump->um_seqinc == daddr1); +} + +/* + * Bmap converts the logical block number of a file to its physical block + * number on the disk. The conversion is done by using the logical block + * number to index into the array of block pointers described by the dinode. + */ +int +ulfs_bmap(void *v) +{ + struct vop_bmap_args /* { + struct vnode *a_vp; + daddr_t a_bn; + struct vnode **a_vpp; + daddr_t *a_bnp; + int *a_runp; + } */ *ap = v; + int error; + + /* + * Check for underlying vnode requests and ensure that logical + * to physical mapping is requested. + */ + if (ap->a_vpp != NULL) + *ap->a_vpp = VTOI(ap->a_vp)->i_devvp; + if (ap->a_bnp == NULL) + return (0); + + fstrans_start(ap->a_vp->v_mount, FSTRANS_SHARED); + error = ulfs_bmaparray(ap->a_vp, ap->a_bn, ap->a_bnp, NULL, NULL, + ap->a_runp, ulfs_issequential); + fstrans_done(ap->a_vp->v_mount); + return error; +} + +/* + * Indirect blocks are now on the vnode for the file. They are given negative + * logical block numbers. Indirect blocks are addressed by the negative + * address of the first data block to which they point. Double indirect blocks + * are addressed by one less than the address of the first indirect block to + * which they point. Triple indirect blocks are addressed by one less than + * the address of the first double indirect block to which they point. + * + * ulfs_bmaparray does the bmap conversion, and if requested returns the + * array of logical blocks which must be traversed to get to a block. + * Each entry contains the offset into that block that gets you to the + * next block and the disk address of the block (if it is assigned). + */ + +int +ulfs_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, struct lfs_indir *ap, + int *nump, int *runp, ulfs_issequential_callback_t is_sequential) +{ + struct lfs_inode *ip; + struct buf *bp, *cbp; + struct ulfsmount *ump; + struct mount *mp; + struct lfs_indir a[NIADDR + 1], *xap; + daddr_t daddr; + daddr_t metalbn; + int error, maxrun = 0, num; + + ip = VTOI(vp); + mp = vp->v_mount; + ump = ip->i_ump; +#ifdef DIAGNOSTIC + if ((ap != NULL && nump == NULL) || (ap == NULL && nump != NULL)) + panic("ulfs_bmaparray: invalid arguments"); +#endif + + if (runp) { + /* + * XXX + * If MAXBSIZE is the largest transfer the disks can handle, + * we probably want maxrun to be 1 block less so that we + * don't create a block larger than the device can handle. + */ + *runp = 0; + maxrun = MAXPHYS / mp->mnt_stat.f_iosize - 1; + } + + if (bn >= 0 && bn < NDADDR) { + if (nump != NULL) + *nump = 0; + daddr = ulfs_rw32(ip->i_ffs1_db[bn], + ULFS_MPNEEDSWAP(ump)); + *bnp = blkptrtodb(ump, daddr); + /* + * Since this is FFS independent code, we are out of + * scope for the definitions of BLK_NOCOPY and + * BLK_SNAP, but we do know that they will fall in + * the range 1..um_seqinc, so we use that test and + * return a request for a zeroed out buffer if attempts + * are made to read a BLK_NOCOPY or BLK_SNAP block. + */ + if ((ip->i_flags & SF_SNAPSHOT) && daddr > 0 && + daddr < ump->um_seqinc) { + *bnp = -1; + } else if (*bnp == 0) { + if (ip->i_flags & SF_SNAPSHOT) { + *bnp = blkptrtodb(ump, bn * ump->um_seqinc); + } else { + *bnp = -1; + } + } else if (runp) { + for (++bn; bn < NDADDR && *runp < maxrun && + is_sequential(ump, + ulfs_rw32(ip->i_ffs1_db[bn - 1], + ULFS_MPNEEDSWAP(ump)), + ulfs_rw32(ip->i_ffs1_db[bn], + ULFS_MPNEEDSWAP(ump))); + ++bn, ++*runp); + } + return (0); + } + + xap = ap == NULL ? a : ap; + if (!nump) + nump = # + if ((error = ulfs_getlbns(vp, bn, xap, nump)) != 0) + return (error); + + num = *nump; + + /* Get disk address out of indirect block array */ + daddr = ulfs_rw32(ip->i_ffs1_ib[xap->in_off], + ULFS_MPNEEDSWAP(ump)); + + for (bp = NULL, ++xap; --num; ++xap) { + /* + * Exit the loop if there is no disk address assigned yet and + * the indirect block isn't in the cache, or if we were + * looking for an indirect block and we've found it. + */ + + metalbn = xap->in_lbn; + if (metalbn == bn) + break; + if (daddr == 0) { + mutex_enter(&bufcache_lock); + cbp = incore(vp, metalbn); + mutex_exit(&bufcache_lock); + if (cbp == NULL) + break; + } + + /* + * If we get here, we've either got the block in the cache + * or we have a disk address for it, go fetch it. + */ + if (bp) + brelse(bp, 0); + + xap->in_exists = 1; + bp = getblk(vp, metalbn, mp->mnt_stat.f_iosize, 0, 0); + if (bp == NULL) { + + /* + * getblk() above returns NULL only iff we are + * pagedaemon. See the implementation of getblk + * for detail. + */ + + return (ENOMEM); + } + if (bp->b_oflags & (BO_DONE | BO_DELWRI)) { + trace(TR_BREADHIT, pack(vp, size), metalbn); + } +#ifdef DIAGNOSTIC + else if (!daddr) + panic("ulfs_bmaparray: indirect block not in cache"); +#endif + else { + trace(TR_BREADMISS, pack(vp, size), metalbn); + bp->b_blkno = blkptrtodb(ump, daddr); + bp->b_flags |= B_READ; + BIO_SETPRIO(bp, BPRIO_TIMECRITICAL); + VOP_STRATEGY(vp, bp); + curlwp->l_ru.ru_inblock++; /* XXX */ + if ((error = biowait(bp)) != 0) { + brelse(bp, 0); + return (error); + } + } + daddr = ulfs_rw32(((u_int32_t *)bp->b_data)[xap->in_off], + ULFS_MPNEEDSWAP(ump)); + if (num == 1 && daddr && runp) { + for (bn = xap->in_off + 1; + bn < MNINDIR(ump) && *runp < maxrun && + is_sequential(ump, + ulfs_rw32(((int32_t *)bp->b_data)[bn-1], + ULFS_MPNEEDSWAP(ump)), + ulfs_rw32(((int32_t *)bp->b_data)[bn], + ULFS_MPNEEDSWAP(ump))); + ++bn, ++*runp); + } + } + if (bp) + brelse(bp, 0); + + /* + * Since this is FFS independent code, we are out of scope for the + * definitions of BLK_NOCOPY and BLK_SNAP, but we do know that they + * will fall in the range 1..um_seqinc, so we use that test and + * return a request for a zeroed out buffer if attempts are made + * to read a BLK_NOCOPY or BLK_SNAP block. + */ + if ((ip->i_flags & SF_SNAPSHOT) && daddr > 0 && + daddr < ump->um_seqinc) { + *bnp = -1; + return (0); + } + *bnp = blkptrtodb(ump, daddr); + if (*bnp == 0) { + if (ip->i_flags & SF_SNAPSHOT) { + *bnp = blkptrtodb(ump, bn * ump->um_seqinc); + } else { + *bnp = -1; + } + } + return (0); +} + +/* + * 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_ffs1_ib and + * once with the offset into the page itself. + */ +int +ulfs_getlbns(struct vnode *vp, daddr_t bn, struct lfs_indir *ap, int *nump) +{ + daddr_t metalbn, realbn; + struct ulfsmount *ump; + int64_t blockcnt; + int lbc; + int i, numlevels, off; + + ump = VFSTOULFS(vp->v_mount); + if (nump) + *nump = 0; + numlevels = 0; + realbn = bn; + if (bn < 0) + bn = -bn; + KASSERT(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 += ump->um_lognindir; + blockcnt = (int64_t)1 << lbc; + + if (bn < blockcnt) + break; + } + + /* Calculate the address of the first meta-block. */ + metalbn = -((realbn >= 0 ? realbn : -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->in_exists = 0; + ap++; + for (++numlevels; i <= NIADDR; i++) { + /* If searching for a meta-data block, quit when found. */ + if (metalbn == realbn) + break; + + lbc -= ump->um_lognindir; + off = (bn >> lbc) & (MNINDIR(ump) - 1); + + ++numlevels; + ap->in_lbn = metalbn; + ap->in_off = off; + ap->in_exists = 0; + ++ap; + + metalbn -= -1 + ((int64_t)off << lbc); + } + if (nump) + *nump = numlevels; + return (0); +} diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_bswap.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_bswap.h Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,82 @@ +/* $NetBSD: ulfs_bswap.h,v 1.1 2009/11/16 01:00:00 dholland Exp $ */ +/* from NetBSD: ufs_bswap.h,v 1.19 2009/10/19 18:41:17 bouyer Exp */ + +/* + * Copyright (c) 1998 Manuel Bouyer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _UFS_LFS_ULFS_BSWAP_H_ +#define _UFS_LFS_ULFS_BSWAP_H_ + +#if defined(_KERNEL_OPT) +#include "opt_lfs.h" +#include "opt_ffs.h" /* XXX */ +#endif + +#include + +/* Macros to access ULFS flags */ +#ifdef LFS_EI +#define ULFS_MPNEEDSWAP(ump) ((ump)->um_flags & ULFS_NEEDSWAP) +#define ULFS_FSNEEDSWAP(fs) ((fs)->fs_flags & FS_SWAPPED) +#define ULFS_IPNEEDSWAP(ip) ULFS_MPNEEDSWAP((ip)->i_ump) +#else +#define ULFS_MPNEEDSWAP(ump) (0) +#define ULFS_FSNEEDSWAP(fs) (0) +#define ULFS_IPNEEDSWAP(ip) (0) +#endif + +#if !defined(_KERNEL) || defined(LFS_EI) +/* inlines for access to swapped data */ +static inline u_int16_t +ulfs_rw16(uint16_t a, int ns) +{ + return ((ns) ? bswap16(a) : (a)); +} + +static inline u_int32_t +ulfs_rw32(uint32_t a, int ns) +{ + return ((ns) ? bswap32(a) : (a)); +} + +static inline u_int64_t +ulfs_rw64(uint64_t a, int ns) +{ + return ((ns) ? bswap64(a) : (a)); +} +#else +#define ulfs_rw16(a, ns) ((uint16_t)(a)) +#define ulfs_rw32(a, ns) ((uint32_t)(a)) +#define ulfs_rw64(a, ns) ((uint64_t)(a)) +#endif + +#define ulfs_add16(a, b, ns) \ + (a) = ulfs_rw16(ulfs_rw16((a), (ns)) + (b), (ns)) +#define ulfs_add32(a, b, ns) \ + (a) = ulfs_rw32(ulfs_rw32((a), (ns)) + (b), (ns)) +#define ulfs_add64(a, b, ns) \ + (a) = ulfs_rw64(ulfs_rw64((a), (ns)) + (b), (ns)) + +#endif /* !_UFS_LFS_ULFS_BSWAP_H_ */ diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_dinode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_dinode.h Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,71 @@ +/* $NetBSD: dinode.h,v 1.21 2009/06/28 09:26:18 ad Exp $ */ +/* from NetBSD: dinode.h,v 1.21 2009/06/28 09:26:18 ad Exp */ + +/* + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Copyright (c) 1982, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)dinode.h 8.9 (Berkeley) 3/29/95 + */ + +/* + * NOTE: COORDINATE ON-DISK FORMAT CHANGES WITH THE FREEBSD PROJECT. + */ + +#ifndef _UFS_LFS_ULFS_DINODE_H_ +#define _UFS_LFS_ULFS_DINODE_H_ + +/* + * XXX: NDADDR should be replaced with LFS_NDIRECTBLKS + * and NIADDR with LFS_NINDIRECTBLKS (these from lfs.h) + */ +#define NXADDR 2 /* Extended attribute addrs in inode */ +#define NDADDR 12 /* Direct addresses in inode. */ +#define NIADDR 3 /* Indirect addresses in inode. */ + +#define MAXSYMLINKLEN_ULFS1 LFS_MAXSYMLINKLEN +#define MAXSYMLINKLEN_ULFS2 ( not valid ; not valid ) // XXX + +#define MAXSYMLINKLEN(ip) \ + ((ip)->i_ump->um_fstype == ULFS1) ? \ + MAXSYMLINKLEN_ULFS1 : MAXSYMLINKLEN_ULFS2 + +#endif /* !_UFS_LFS_ULFS_DINODE_H_ */ diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_dirhash.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_dirhash.c Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,1172 @@ +/* $NetBSD: ulfs_dirhash.c,v 1.1 2009/11/16 01:00:00 dholland Exp $ */ +/* from NetBSD: ufs_dirhash.c,v 1.34 2009/10/05 23:48:08 rmind Exp */ + +/* + * Copyright (c) 2001, 2002 Ian Dowse. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/ufs/ufs/ufs_dirhash.c,v 1.3.2.8 2004/12/08 11:54:13 dwmalone Exp $ + */ + +#include +__KERNEL_RCSID(0, "$NetBSD$"); + +/* + * This implements a hash-based lookup scheme for ULFS directories. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define WRAPINCR(val, limit) (((val) + 1 == (limit)) ? 0 : ((val) + 1)) +#define WRAPDECR(val, limit) (((val) == 0) ? ((limit) - 1) : ((val) - 1)) +#define OFSFMT(ip) ((ip)->i_ump->um_maxsymlinklen <= 0) +#define BLKFREE2IDX(n) ((n) > DH_NFSTATS ? DH_NFSTATS : (n)) + +static u_int ulfs_dirhashminblks = 5; +static u_int ulfs_dirhashmaxmem = 2 * 1024 * 1024; +static u_int ulfs_dirhashmem; +static u_int ulfs_dirhashcheck = 0; + +static int ulfsdirhash_hash(struct ulfs_dirhash *dh, const char *name, int namelen); +static void ulfsdirhash_adjfree(struct ulfs_dirhash *dh, lfs_doff_t offset, int diff, + int dirblksiz); +static void ulfsdirhash_delslot(struct ulfs_dirhash *dh, int slot); +static int ulfsdirhash_findslot(struct ulfs_dirhash *dh, const char *name, + int namelen, lfs_doff_t offset); +static lfs_doff_t ulfsdirhash_getprev(struct direct *dp, lfs_doff_t offset, + int dirblksiz); +static int ulfsdirhash_recycle(int wanted); + +static pool_cache_t ulfsdirhashblk_cache; +static pool_cache_t ulfsdirhash_cache; + +#define DIRHASHLIST_LOCK() mutex_enter(&ulfsdirhash_lock) +#define DIRHASHLIST_UNLOCK() mutex_exit(&ulfsdirhash_lock) +#define DIRHASH_LOCK(dh) mutex_enter(&(dh)->dh_lock) +#define DIRHASH_UNLOCK(dh) mutex_exit(&(dh)->dh_lock) +#define DIRHASH_BLKALLOC() \ + pool_cache_get(ulfsdirhashblk_cache, PR_NOWAIT) +#define DIRHASH_BLKFREE(ptr) \ + pool_cache_put(ulfsdirhashblk_cache, ptr) + +/* Dirhash list; recently-used entries are near the tail. */ +static TAILQ_HEAD(, ulfs_dirhash) ulfsdirhash_list; + +/* Protects: ulfsdirhash_list, `dh_list' field, ulfs_dirhashmem. */ +static kmutex_t ulfsdirhash_lock; + +static struct sysctllog *ulfsdirhash_sysctl_log; + +/* + * Locking order: + * ulfsdirhash_lock + * dh_lock + * + * The dh_lock mutex should be acquired either via the inode lock, or via + * ulfsdirhash_lock. Only the owner of the inode may free the associated + * dirhash, but anything can steal its memory and set dh_hash to NULL. + */ + +/* + * Attempt to build up a hash table for the directory contents in + * inode 'ip'. Returns 0 on success, or -1 of the operation failed. + */ +int +ulfsdirhash_build(struct lfs_inode *ip) +{ + struct ulfs_dirhash *dh; + struct buf *bp = NULL; + struct direct *ep; + struct vnode *vp; + lfs_doff_t bmask, pos; + int dirblocks, i, j, memreqd, nblocks, narrays, nslots, slot; + const int needswap = ULFS_MPNEEDSWAP(ip->i_ump); + int dirblksiz = ip->i_ump->um_dirblksiz; + + /* Check if we can/should use dirhash. */ + if (ip->i_dirhash == NULL) { + if (ip->i_size < (ulfs_dirhashminblks * dirblksiz) || OFSFMT(ip)) + return (-1); + } else { + /* Hash exists, but sysctls could have changed. */ + if (ip->i_size < (ulfs_dirhashminblks * dirblksiz) || + ulfs_dirhashmem > ulfs_dirhashmaxmem) { + ulfsdirhash_free(ip); + return (-1); + } + /* Check if hash exists and is intact (note: unlocked read). */ + if (ip->i_dirhash->dh_hash != NULL) + return (0); + /* Free the old, recycled hash and build a new one. */ + ulfsdirhash_free(ip); + } + + /* Don't hash removed directories. */ + if (ip->i_nlink == 0) + return (-1); + + vp = ip->i_vnode; + /* Allocate 50% more entries than this dir size could ever need. */ + KASSERT(ip->i_size >= dirblksiz); + nslots = ip->i_size / DIRECTSIZ(1); + nslots = (nslots * 3 + 1) / 2; + narrays = howmany(nslots, DH_NBLKOFF); + nslots = narrays * DH_NBLKOFF; + dirblocks = howmany(ip->i_size, dirblksiz); + nblocks = (dirblocks * 3 + 1) / 2; + + memreqd = sizeof(*dh) + narrays * sizeof(*dh->dh_hash) + + narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) + + nblocks * sizeof(*dh->dh_blkfree); + + while (atomic_add_int_nv(&ulfs_dirhashmem, memreqd) > + ulfs_dirhashmaxmem) { + atomic_add_int(&ulfs_dirhashmem, -memreqd); + if (memreqd > ulfs_dirhashmaxmem / 2) + return (-1); + /* Try to free some space. */ + if (ulfsdirhash_recycle(memreqd) != 0) + return (-1); + else + DIRHASHLIST_UNLOCK(); + } + + /* + * Use non-blocking mallocs so that we will revert to a linear + * lookup on failure rather than potentially blocking forever. + */ + dh = pool_cache_get(ulfsdirhash_cache, PR_NOWAIT); + if (dh == NULL) { + atomic_add_int(&ulfs_dirhashmem, -memreqd); + return (-1); + } + memset(dh, 0, sizeof(*dh)); + mutex_init(&dh->dh_lock, MUTEX_DEFAULT, IPL_NONE); + DIRHASH_LOCK(dh); + dh->dh_hashsz = narrays * sizeof(dh->dh_hash[0]); + dh->dh_hash = kmem_zalloc(dh->dh_hashsz, KM_NOSLEEP); + dh->dh_blkfreesz = nblocks * sizeof(dh->dh_blkfree[0]); + dh->dh_blkfree = kmem_zalloc(dh->dh_blkfreesz, KM_NOSLEEP); + if (dh->dh_hash == NULL || dh->dh_blkfree == NULL) + goto fail; + for (i = 0; i < narrays; i++) { + if ((dh->dh_hash[i] = DIRHASH_BLKALLOC()) == NULL) + goto fail; + for (j = 0; j < DH_NBLKOFF; j++) + dh->dh_hash[i][j] = DIRHASH_EMPTY; + } + + /* Initialise the hash table and block statistics. */ + dh->dh_narrays = narrays; + dh->dh_hlen = nslots; + dh->dh_nblk = nblocks; + dh->dh_dirblks = dirblocks; + for (i = 0; i < dirblocks; i++) + dh->dh_blkfree[i] = dirblksiz / DIRALIGN; + for (i = 0; i < DH_NFSTATS; i++) + dh->dh_firstfree[i] = -1; + dh->dh_firstfree[DH_NFSTATS] = 0; + dh->dh_seqopt = 0; + dh->dh_seqoff = 0; + dh->dh_score = DH_SCOREINIT; + ip->i_dirhash = dh; + + bmask = VFSTOULFS(vp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; + pos = 0; + while (pos < ip->i_size) { + if ((curcpu()->ci_schedstate.spc_flags & SPCF_SHOULDYIELD) + != 0) { + preempt(); + } + /* If necessary, get the next directory block. */ + if ((pos & bmask) == 0) { + if (bp != NULL) + brelse(bp, 0); + if (ulfs_blkatoff(vp, (off_t)pos, NULL, &bp, false) != 0) + goto fail; + } + + /* Add this entry to the hash. */ + ep = (struct direct *)((char *)bp->b_data + (pos & bmask)); + if (ep->d_reclen == 0 || ep->d_reclen > + dirblksiz - (pos & (dirblksiz - 1))) { + /* Corrupted directory. */ + brelse(bp, 0); + goto fail; + } + if (ep->d_ino != 0) { + /* Add the entry (simplified ulfsdirhash_add). */ + slot = ulfsdirhash_hash(dh, ep->d_name, ep->d_namlen); + while (DH_ENTRY(dh, slot) != DIRHASH_EMPTY) + slot = WRAPINCR(slot, dh->dh_hlen); + dh->dh_hused++; + DH_ENTRY(dh, slot) = pos; + ulfsdirhash_adjfree(dh, pos, -DIRSIZ(0, ep, needswap), + dirblksiz); + } + pos += ep->d_reclen; + } + + if (bp != NULL) + brelse(bp, 0); + DIRHASHLIST_LOCK(); + TAILQ_INSERT_TAIL(&ulfsdirhash_list, dh, dh_list); + dh->dh_onlist = 1; + DIRHASH_UNLOCK(dh); + DIRHASHLIST_UNLOCK(); + return (0); + +fail: + DIRHASH_UNLOCK(dh); + if (dh->dh_hash != NULL) { + for (i = 0; i < narrays; i++) + if (dh->dh_hash[i] != NULL) + DIRHASH_BLKFREE(dh->dh_hash[i]); + kmem_free(dh->dh_hash, dh->dh_hashsz); + } + if (dh->dh_blkfree != NULL) + kmem_free(dh->dh_blkfree, dh->dh_blkfreesz); + mutex_destroy(&dh->dh_lock); + pool_cache_put(ulfsdirhash_cache, dh); + ip->i_dirhash = NULL; + atomic_add_int(&ulfs_dirhashmem, -memreqd); + return (-1); +} + +/* + * Free any hash table associated with inode 'ip'. + */ +void +ulfsdirhash_free(struct lfs_inode *ip) +{ + struct ulfs_dirhash *dh; + int i, mem; + + if ((dh = ip->i_dirhash) == NULL) + return; + + if (dh->dh_onlist) { + DIRHASHLIST_LOCK(); + if (dh->dh_onlist) + TAILQ_REMOVE(&ulfsdirhash_list, dh, dh_list); + DIRHASHLIST_UNLOCK(); + } + + /* The dirhash pointed to by 'dh' is exclusively ours now. */ + mem = sizeof(*dh); + if (dh->dh_hash != NULL) { + for (i = 0; i < dh->dh_narrays; i++) + DIRHASH_BLKFREE(dh->dh_hash[i]); + kmem_free(dh->dh_hash, dh->dh_hashsz); + kmem_free(dh->dh_blkfree, dh->dh_blkfreesz); + mem += dh->dh_hashsz; + mem += dh->dh_narrays * DH_NBLKOFF * sizeof(**dh->dh_hash); + mem += dh->dh_nblk * sizeof(*dh->dh_blkfree); + } + mutex_destroy(&dh->dh_lock); + pool_cache_put(ulfsdirhash_cache, dh); + ip->i_dirhash = NULL; + + atomic_add_int(&ulfs_dirhashmem, -mem); +} + +/* + * Find the offset of the specified name within the given inode. + * Returns 0 on success, ENOENT if the entry does not exist, or + * EJUSTRETURN if the caller should revert to a linear search. + * + * If successful, the directory offset is stored in *offp, and a + * pointer to a struct buf containing the entry is stored in *bpp. If + * prevoffp is non-NULL, the offset of the previous entry within + * the DIRBLKSIZ-sized block is stored in *prevoffp (if the entry + * is the first in a block, the start of the block is used). + */ +int +ulfsdirhash_lookup(struct lfs_inode *ip, const char *name, int namelen, lfs_doff_t *offp, + struct buf **bpp, lfs_doff_t *prevoffp) +{ + struct ulfs_dirhash *dh, *dh_next; + struct direct *dp; + struct vnode *vp; + struct buf *bp; + lfs_doff_t blkoff, bmask, offset, prevoff; + int i, slot; + const int needswap = ULFS_MPNEEDSWAP(ip->i_ump); + int dirblksiz = ip->i_ump->um_dirblksiz; + + if ((dh = ip->i_dirhash) == NULL) + return (EJUSTRETURN); + + /* + * Move this dirhash towards the end of the list if it has a + * score higher than the next entry, and acquire the dh_lock. + * Optimise the case where it's already the last by performing + * an unlocked read of the TAILQ_NEXT pointer. + * + * In both cases, end up holding just dh_lock. + */ + if (TAILQ_NEXT(dh, dh_list) != NULL) { + DIRHASHLIST_LOCK(); + DIRHASH_LOCK(dh); + /* + * If the new score will be greater than that of the next + * entry, then move this entry past it. With both mutexes + * held, dh_next won't go away, but its dh_score could + * change; that's not important since it is just a hint. + */ + if (dh->dh_hash != NULL && + (dh_next = TAILQ_NEXT(dh, dh_list)) != NULL && + dh->dh_score >= dh_next->dh_score) { + KASSERT(dh->dh_onlist); + TAILQ_REMOVE(&ulfsdirhash_list, dh, dh_list); + TAILQ_INSERT_AFTER(&ulfsdirhash_list, dh_next, dh, + dh_list); + } + DIRHASHLIST_UNLOCK(); + } else { + /* Already the last, though that could change as we wait. */ + DIRHASH_LOCK(dh); + } + if (dh->dh_hash == NULL) { + DIRHASH_UNLOCK(dh); + ulfsdirhash_free(ip); + return (EJUSTRETURN); + } + + /* Update the score. */ + if (dh->dh_score < DH_SCOREMAX) + dh->dh_score++; + + vp = ip->i_vnode; + bmask = VFSTOULFS(vp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; + blkoff = -1; + bp = NULL; +restart: + slot = ulfsdirhash_hash(dh, name, namelen); + + if (dh->dh_seqopt) { + /* + * Sequential access optimisation. dh_seqoff contains the + * offset of the directory entry immediately following + * the last entry that was looked up. Check if this offset + * appears in the hash chain for the name we are looking for. + */ + for (i = slot; (offset = DH_ENTRY(dh, i)) != DIRHASH_EMPTY; + i = WRAPINCR(i, dh->dh_hlen)) + if (offset == dh->dh_seqoff) + break; + if (offset == dh->dh_seqoff) { + /* + * We found an entry with the expected offset. This + * is probably the entry we want, but if not, the + * code below will turn off seqoff and retry. + */ + slot = i; + } else + dh->dh_seqopt = 0; + } + + for (; (offset = DH_ENTRY(dh, slot)) != DIRHASH_EMPTY; + slot = WRAPINCR(slot, dh->dh_hlen)) { + if (offset == DIRHASH_DEL) + continue; + + if (offset < 0 || offset >= ip->i_size) + panic("ulfsdirhash_lookup: bad offset in hash array"); + if ((offset & ~bmask) != blkoff) { + if (bp != NULL) + brelse(bp, 0); + blkoff = offset & ~bmask; + if (ulfs_blkatoff(vp, (off_t)blkoff, + NULL, &bp, false) != 0) { + DIRHASH_UNLOCK(dh); + return (EJUSTRETURN); + } + } + dp = (struct direct *)((char *)bp->b_data + (offset & bmask)); + if (dp->d_reclen == 0 || dp->d_reclen > + dirblksiz - (offset & (dirblksiz - 1))) { + /* Corrupted directory. */ + DIRHASH_UNLOCK(dh); + brelse(bp, 0); + return (EJUSTRETURN); + } + if (dp->d_namlen == namelen && + memcmp(dp->d_name, name, namelen) == 0) { + /* Found. Get the prev offset if needed. */ + if (prevoffp != NULL) { + if (offset & (dirblksiz - 1)) { + prevoff = ulfsdirhash_getprev(dp, + offset, dirblksiz); + if (prevoff == -1) { + brelse(bp, 0); + return (EJUSTRETURN); + } + } else + prevoff = offset; + *prevoffp = prevoff; + } + + /* Check for sequential access, and update offset. */ + if (dh->dh_seqopt == 0 && dh->dh_seqoff == offset) + dh->dh_seqopt = 1; + dh->dh_seqoff = offset + DIRSIZ(0, dp, needswap); + DIRHASH_UNLOCK(dh); + + *bpp = bp; + *offp = offset; + return (0); + } + + if (dh->dh_hash == NULL) { + DIRHASH_UNLOCK(dh); + if (bp != NULL) + brelse(bp, 0); + ulfsdirhash_free(ip); + return (EJUSTRETURN); + } + /* + * When the name doesn't match in the seqopt case, go back + * and search normally. + */ + if (dh->dh_seqopt) { + dh->dh_seqopt = 0; + goto restart; + } + } + DIRHASH_UNLOCK(dh); + if (bp != NULL) + brelse(bp, 0); + return (ENOENT); +} + +/* + * Find a directory block with room for 'slotneeded' bytes. Returns + * the offset of the directory entry that begins the free space. + * This will either be the offset of an existing entry that has free + * space at the end, or the offset of an entry with d_ino == 0 at + * the start of a DIRBLKSIZ block. + * + * To use the space, the caller may need to compact existing entries in + * the directory. The total number of bytes in all of the entries involved + * in the compaction is stored in *slotsize. In other words, all of + * the entries that must be compacted are exactly contained in the + * region beginning at the returned offset and spanning *slotsize bytes. + * + * Returns -1 if no space was found, indicating that the directory + * must be extended. + */ +lfs_doff_t +ulfsdirhash_findfree(struct lfs_inode *ip, int slotneeded, int *slotsize) +{ + struct direct *dp; + struct ulfs_dirhash *dh; + struct buf *bp; + lfs_doff_t pos, slotstart; + int dirblock, error, freebytes, i; + const int needswap = ULFS_MPNEEDSWAP(ip->i_ump); + int dirblksiz = ip->i_ump->um_dirblksiz; + + if ((dh = ip->i_dirhash) == NULL) + return (-1); + + DIRHASH_LOCK(dh); + if (dh->dh_hash == NULL) { + DIRHASH_UNLOCK(dh); + ulfsdirhash_free(ip); + return (-1); + } + + /* Find a directory block with the desired free space. */ + dirblock = -1; + for (i = howmany(slotneeded, DIRALIGN); i <= DH_NFSTATS; i++) + if ((dirblock = dh->dh_firstfree[i]) != -1) + break; + if (dirblock == -1) { + DIRHASH_UNLOCK(dh); + return (-1); + } + + KASSERT(dirblock < dh->dh_nblk && + dh->dh_blkfree[dirblock] >= howmany(slotneeded, DIRALIGN)); + pos = dirblock * dirblksiz; + error = ulfs_blkatoff(ip->i_vnode, (off_t)pos, (void *)&dp, &bp, false); + if (error) { + DIRHASH_UNLOCK(dh); + return (-1); + } + /* Find the first entry with free space. */ + for (i = 0; i < dirblksiz; ) { + if (dp->d_reclen == 0) { + DIRHASH_UNLOCK(dh); + brelse(bp, 0); + return (-1); + } + if (dp->d_ino == 0 || dp->d_reclen > DIRSIZ(0, dp, needswap)) + break; + i += dp->d_reclen; + dp = (struct direct *)((char *)dp + dp->d_reclen); + } + if (i > dirblksiz) { + DIRHASH_UNLOCK(dh); + brelse(bp, 0); + return (-1); + } + slotstart = pos + i; + + /* Find the range of entries needed to get enough space */ + freebytes = 0; + while (i < dirblksiz && freebytes < slotneeded) { + freebytes += dp->d_reclen; + if (dp->d_ino != 0) + freebytes -= DIRSIZ(0, dp, needswap); + if (dp->d_reclen == 0) { + DIRHASH_UNLOCK(dh); + brelse(bp, 0); + return (-1); + } + i += dp->d_reclen; + dp = (struct direct *)((char *)dp + dp->d_reclen); + } + if (i > dirblksiz) { + DIRHASH_UNLOCK(dh); + brelse(bp, 0); + return (-1); + } + if (freebytes < slotneeded) + panic("ulfsdirhash_findfree: free mismatch"); + DIRHASH_UNLOCK(dh); + brelse(bp, 0); + *slotsize = pos + i - slotstart; + return (slotstart); +} + +/* + * Return the start of the unused space at the end of a directory, or + * -1 if there are no trailing unused blocks. + */ +lfs_doff_t +ulfsdirhash_enduseful(struct lfs_inode *ip) +{ + struct ulfs_dirhash *dh; + int i; + int dirblksiz = ip->i_ump->um_dirblksiz; + + if ((dh = ip->i_dirhash) == NULL) + return (-1); + + DIRHASH_LOCK(dh); + if (dh->dh_hash == NULL) { + DIRHASH_UNLOCK(dh); + ulfsdirhash_free(ip); + return (-1); + } + + if (dh->dh_blkfree[dh->dh_dirblks - 1] != dirblksiz / DIRALIGN) { + DIRHASH_UNLOCK(dh); + return (-1); + } + + for (i = dh->dh_dirblks - 1; i >= 0; i--) + if (dh->dh_blkfree[i] != dirblksiz / DIRALIGN) + break; + DIRHASH_UNLOCK(dh); + return ((lfs_doff_t)(i + 1) * dirblksiz); +} + +/* + * Insert information into the hash about a new directory entry. dirp + * points to a struct direct containing the entry, and offset specifies + * the offset of this entry. + */ +void +ulfsdirhash_add(struct lfs_inode *ip, struct direct *dirp, lfs_doff_t offset) +{ + struct ulfs_dirhash *dh; + int slot; + const int needswap = ULFS_MPNEEDSWAP(ip->i_ump); + int dirblksiz = ip->i_ump->um_dirblksiz; + + if ((dh = ip->i_dirhash) == NULL) + return; + + DIRHASH_LOCK(dh); + if (dh->dh_hash == NULL) { + DIRHASH_UNLOCK(dh); + ulfsdirhash_free(ip); + return; + } + + KASSERT(offset < dh->dh_dirblks * dirblksiz); + /* + * Normal hash usage is < 66%. If the usage gets too high then + * remove the hash entirely and let it be rebuilt later. + */ + if (dh->dh_hused >= (dh->dh_hlen * 3) / 4) { + DIRHASH_UNLOCK(dh); + ulfsdirhash_free(ip); + return; + } + + /* Find a free hash slot (empty or deleted), and add the entry. */ + slot = ulfsdirhash_hash(dh, dirp->d_name, dirp->d_namlen); + while (DH_ENTRY(dh, slot) >= 0) + slot = WRAPINCR(slot, dh->dh_hlen); + if (DH_ENTRY(dh, slot) == DIRHASH_EMPTY) + dh->dh_hused++; + DH_ENTRY(dh, slot) = offset; + + /* Update the per-block summary info. */ + ulfsdirhash_adjfree(dh, offset, -DIRSIZ(0, dirp, needswap), dirblksiz); + DIRHASH_UNLOCK(dh); +} + +/* + * Remove the specified directory entry from the hash. The entry to remove + * is defined by the name in `dirp', which must exist at the specified + * `offset' within the directory. + */ +void +ulfsdirhash_remove(struct lfs_inode *ip, struct direct *dirp, lfs_doff_t offset) +{ + struct ulfs_dirhash *dh; + int slot; + const int needswap = ULFS_MPNEEDSWAP(ip->i_ump); + int dirblksiz = ip->i_ump->um_dirblksiz; + + if ((dh = ip->i_dirhash) == NULL) + return; + + DIRHASH_LOCK(dh); + if (dh->dh_hash == NULL) { + DIRHASH_UNLOCK(dh); + ulfsdirhash_free(ip); + return; + } + + KASSERT(offset < dh->dh_dirblks * dirblksiz); + /* Find the entry */ + slot = ulfsdirhash_findslot(dh, dirp->d_name, dirp->d_namlen, offset); + + /* Remove the hash entry. */ + ulfsdirhash_delslot(dh, slot); + + /* Update the per-block summary info. */ + ulfsdirhash_adjfree(dh, offset, DIRSIZ(0, dirp, needswap), dirblksiz); + DIRHASH_UNLOCK(dh); +} + +/* + * Change the offset associated with a directory entry in the hash. Used + * when compacting directory blocks. + */ +void +ulfsdirhash_move(struct lfs_inode *ip, struct direct *dirp, lfs_doff_t oldoff, + lfs_doff_t newoff) +{ + struct ulfs_dirhash *dh; + int slot; + + if ((dh = ip->i_dirhash) == NULL) + return; + DIRHASH_LOCK(dh); + if (dh->dh_hash == NULL) { + DIRHASH_UNLOCK(dh); + ulfsdirhash_free(ip); + return; + } + + KASSERT(oldoff < dh->dh_dirblks * ip->i_ump->um_dirblksiz && + newoff < dh->dh_dirblks * ip->i_ump->um_dirblksiz); + /* Find the entry, and update the offset. */ + slot = ulfsdirhash_findslot(dh, dirp->d_name, dirp->d_namlen, oldoff); + DH_ENTRY(dh, slot) = newoff; + DIRHASH_UNLOCK(dh); +} + +/* + * Inform dirhash that the directory has grown by one block that + * begins at offset (i.e. the new length is offset + DIRBLKSIZ). + */ +void +ulfsdirhash_newblk(struct lfs_inode *ip, lfs_doff_t offset) +{ + struct ulfs_dirhash *dh; + int block; + int dirblksiz = ip->i_ump->um_dirblksiz; + + if ((dh = ip->i_dirhash) == NULL) + return; + DIRHASH_LOCK(dh); + if (dh->dh_hash == NULL) { + DIRHASH_UNLOCK(dh); + ulfsdirhash_free(ip); + return; + } + + KASSERT(offset == dh->dh_dirblks * dirblksiz); + block = offset / dirblksiz; + if (block >= dh->dh_nblk) { + /* Out of space; must rebuild. */ + DIRHASH_UNLOCK(dh); + ulfsdirhash_free(ip); + return; + } + dh->dh_dirblks = block + 1; + + /* Account for the new free block. */ + dh->dh_blkfree[block] = dirblksiz / DIRALIGN; + if (dh->dh_firstfree[DH_NFSTATS] == -1) + dh->dh_firstfree[DH_NFSTATS] = block; + DIRHASH_UNLOCK(dh); +} + +/* + * Inform dirhash that the directory is being truncated. + */ +void +ulfsdirhash_dirtrunc(struct lfs_inode *ip, lfs_doff_t offset) +{ + struct ulfs_dirhash *dh; + int block, i; + int dirblksiz = ip->i_ump->um_dirblksiz; + + if ((dh = ip->i_dirhash) == NULL) + return; + + DIRHASH_LOCK(dh); + if (dh->dh_hash == NULL) { + DIRHASH_UNLOCK(dh); + ulfsdirhash_free(ip); + return; + } + + KASSERT(offset <= dh->dh_dirblks * dirblksiz); + block = howmany(offset, dirblksiz); + /* + * If the directory shrinks to less than 1/8 of dh_nblk blocks + * (about 20% of its original size due to the 50% extra added in + * ulfsdirhash_build) then free it, and let the caller rebuild + * if necessary. + */ + if (block < dh->dh_nblk / 8 && dh->dh_narrays > 1) { + DIRHASH_UNLOCK(dh); + ulfsdirhash_free(ip); + return; + } + + /* + * Remove any `first free' information pertaining to the + * truncated blocks. All blocks we're removing should be + * completely unused. + */ + if (dh->dh_firstfree[DH_NFSTATS] >= block) + dh->dh_firstfree[DH_NFSTATS] = -1; + for (i = block; i < dh->dh_dirblks; i++) + if (dh->dh_blkfree[i] != dirblksiz / DIRALIGN) + panic("ulfsdirhash_dirtrunc: blocks in use"); + for (i = 0; i < DH_NFSTATS; i++) + if (dh->dh_firstfree[i] >= block) + panic("ulfsdirhash_dirtrunc: first free corrupt"); + dh->dh_dirblks = block; + DIRHASH_UNLOCK(dh); +} + +/* + * Debugging function to check that the dirhash information about + * a directory block matches its actual contents. Panics if a mismatch + * is detected. + * + * On entry, `sbuf' should point to the start of an in-core + * DIRBLKSIZ-sized directory block, and `offset' should contain the + * offset from the start of the directory of that block. + */ +void +ulfsdirhash_checkblock(struct lfs_inode *ip, char *sbuf, lfs_doff_t offset) +{ + struct ulfs_dirhash *dh; + struct direct *dp; + int block, ffslot, i, nfree; + const int needswap = ULFS_MPNEEDSWAP(ip->i_ump); + int dirblksiz = ip->i_ump->um_dirblksiz; + + if (!ulfs_dirhashcheck) + return; + if ((dh = ip->i_dirhash) == NULL) + return; + + DIRHASH_LOCK(dh); + if (dh->dh_hash == NULL) { + DIRHASH_UNLOCK(dh); + ulfsdirhash_free(ip); + return; + } + + block = offset / dirblksiz; + if ((offset & (dirblksiz - 1)) != 0 || block >= dh->dh_dirblks) + panic("ulfsdirhash_checkblock: bad offset"); + + nfree = 0; + for (i = 0; i < dirblksiz; i += dp->d_reclen) { + dp = (struct direct *)(sbuf + i); + if (dp->d_reclen == 0 || i + dp->d_reclen > dirblksiz) + panic("ulfsdirhash_checkblock: bad dir"); + + if (dp->d_ino == 0) { +#if 0 + /* + * XXX entries with d_ino == 0 should only occur + * at the start of a DIRBLKSIZ block. However the + * ulfs code is tolerant of such entries at other + * offsets, and fsck does not fix them. + */ + if (i != 0) + panic("ulfsdirhash_checkblock: bad dir inode"); +#endif + nfree += dp->d_reclen; + continue; + } + + /* Check that the entry exists (will panic if it doesn't). */ + ulfsdirhash_findslot(dh, dp->d_name, dp->d_namlen, offset + i); + + nfree += dp->d_reclen - DIRSIZ(0, dp, needswap); + } + if (i != dirblksiz) + panic("ulfsdirhash_checkblock: bad dir end"); + + if (dh->dh_blkfree[block] * DIRALIGN != nfree) + panic("ulfsdirhash_checkblock: bad free count"); + + ffslot = BLKFREE2IDX(nfree / DIRALIGN); + for (i = 0; i <= DH_NFSTATS; i++) + if (dh->dh_firstfree[i] == block && i != ffslot) + panic("ulfsdirhash_checkblock: bad first-free"); + if (dh->dh_firstfree[ffslot] == -1) + panic("ulfsdirhash_checkblock: missing first-free entry"); + DIRHASH_UNLOCK(dh); +} + +/* + * Hash the specified filename into a dirhash slot. + */ +static int +ulfsdirhash_hash(struct ulfs_dirhash *dh, const char *name, int namelen) +{ + u_int32_t hash; + + /* + * We hash the name and then some other bit of data that is + * invariant over the dirhash's lifetime. Otherwise names + * differing only in the last byte are placed close to one + * another in the table, which is bad for linear probing. + */ + hash = hash32_buf(name, namelen, HASH32_BUF_INIT); + hash = hash32_buf(&dh, sizeof(dh), hash); + return (hash % dh->dh_hlen); +} + +/* + * Adjust the number of free bytes in the block containing `offset' + * by the value specified by `diff'. + * + * The caller must ensure we have exclusive access to `dh'; normally + * that means that dh_lock should be held, but this is also called + * from ulfsdirhash_build() where exclusive access can be assumed. + */ +static void +ulfsdirhash_adjfree(struct ulfs_dirhash *dh, lfs_doff_t offset, int diff, int dirblksiz) +{ + int block, i, nfidx, ofidx; + + KASSERT(mutex_owned(&dh->dh_lock)); + + /* Update the per-block summary info. */ + block = offset / dirblksiz; + KASSERT(block < dh->dh_nblk && block < dh->dh_dirblks); + ofidx = BLKFREE2IDX(dh->dh_blkfree[block]); + dh->dh_blkfree[block] = (int)dh->dh_blkfree[block] + (diff / DIRALIGN); + nfidx = BLKFREE2IDX(dh->dh_blkfree[block]); + + /* Update the `first free' list if necessary. */ + if (ofidx != nfidx) { + /* If removing, scan forward for the next block. */ + if (dh->dh_firstfree[ofidx] == block) { + for (i = block + 1; i < dh->dh_dirblks; i++) + if (BLKFREE2IDX(dh->dh_blkfree[i]) == ofidx) + break; + dh->dh_firstfree[ofidx] = (i < dh->dh_dirblks) ? i : -1; + } + + /* Make this the new `first free' if necessary */ + if (dh->dh_firstfree[nfidx] > block || + dh->dh_firstfree[nfidx] == -1) + dh->dh_firstfree[nfidx] = block; + } +} + +/* + * Find the specified name which should have the specified offset. + * Returns a slot number, and panics on failure. + * + * `dh' must be locked on entry and remains so on return. + */ +static int +ulfsdirhash_findslot(struct ulfs_dirhash *dh, const char *name, int namelen, + lfs_doff_t offset) +{ + int slot; + + KASSERT(mutex_owned(&dh->dh_lock)); + + /* Find the entry. */ + KASSERT(dh->dh_hused < dh->dh_hlen); + slot = ulfsdirhash_hash(dh, name, namelen); + while (DH_ENTRY(dh, slot) != offset && + DH_ENTRY(dh, slot) != DIRHASH_EMPTY) + slot = WRAPINCR(slot, dh->dh_hlen); + if (DH_ENTRY(dh, slot) != offset) + panic("ulfsdirhash_findslot: '%.*s' not found", namelen, name); + + return (slot); +} + +/* + * Remove the entry corresponding to the specified slot from the hash array. + * + * `dh' must be locked on entry and remains so on return. + */ +static void +ulfsdirhash_delslot(struct ulfs_dirhash *dh, int slot) +{ + int i; + + KASSERT(mutex_owned(&dh->dh_lock)); + + /* Mark the entry as deleted. */ + DH_ENTRY(dh, slot) = DIRHASH_DEL; + + /* If this is the end of a chain of DIRHASH_DEL slots, remove them. */ + for (i = slot; DH_ENTRY(dh, i) == DIRHASH_DEL; ) + i = WRAPINCR(i, dh->dh_hlen); + if (DH_ENTRY(dh, i) == DIRHASH_EMPTY) { + i = WRAPDECR(i, dh->dh_hlen); + while (DH_ENTRY(dh, i) == DIRHASH_DEL) { + DH_ENTRY(dh, i) = DIRHASH_EMPTY; + dh->dh_hused--; + i = WRAPDECR(i, dh->dh_hlen); + } + KASSERT(dh->dh_hused >= 0); + } +} + +/* + * Given a directory entry and its offset, find the offset of the + * previous entry in the same DIRBLKSIZ-sized block. Returns an + * offset, or -1 if there is no previous entry in the block or some + * other problem occurred. + */ +static lfs_doff_t +ulfsdirhash_getprev(struct direct *dirp, lfs_doff_t offset, int dirblksiz) +{ + struct direct *dp; + char *blkbuf; + lfs_doff_t blkoff, prevoff; + int entrypos, i; + + blkoff = offset & ~(dirblksiz - 1); /* offset of start of block */ + entrypos = offset & (dirblksiz - 1); /* entry relative to block */ + blkbuf = (char *)dirp - entrypos; + prevoff = blkoff; + + /* If `offset' is the start of a block, there is no previous entry. */ + if (entrypos == 0) + return (-1); + + /* Scan from the start of the block until we get to the entry. */ + for (i = 0; i < entrypos; i += dp->d_reclen) { + dp = (struct direct *)(blkbuf + i); + if (dp->d_reclen == 0 || i + dp->d_reclen > entrypos) + return (-1); /* Corrupted directory. */ + prevoff = blkoff + i; + } + return (prevoff); +} + +/* + * Try to free up `wanted' bytes by stealing memory from existing + * dirhashes. Returns zero with list locked if successful. + */ +static int +ulfsdirhash_recycle(int wanted) +{ + struct ulfs_dirhash *dh; + lfs_doff_t **hash; + u_int8_t *blkfree; + int i, mem, narrays; + size_t hashsz, blkfreesz; + + DIRHASHLIST_LOCK(); + while (wanted + ulfs_dirhashmem > ulfs_dirhashmaxmem) { + /* Find a dirhash, and lock it. */ + if ((dh = TAILQ_FIRST(&ulfsdirhash_list)) == NULL) { + DIRHASHLIST_UNLOCK(); + return (-1); + } + DIRHASH_LOCK(dh); + KASSERT(dh->dh_hash != NULL); + + /* Decrement the score; only recycle if it becomes zero. */ + if (--dh->dh_score > 0) { + DIRHASH_UNLOCK(dh); + DIRHASHLIST_UNLOCK(); + return (-1); + } + + /* Remove it from the list and detach its memory. */ + TAILQ_REMOVE(&ulfsdirhash_list, dh, dh_list); + dh->dh_onlist = 0; + hash = dh->dh_hash; + hashsz = dh->dh_hashsz; + dh->dh_hash = NULL; + blkfree = dh->dh_blkfree; + blkfreesz = dh->dh_blkfreesz; + dh->dh_blkfree = NULL; + narrays = dh->dh_narrays; + mem = narrays * sizeof(*dh->dh_hash) + + narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) + + dh->dh_nblk * sizeof(*dh->dh_blkfree); + + /* Unlock everything, free the detached memory. */ + DIRHASH_UNLOCK(dh); + DIRHASHLIST_UNLOCK(); + + for (i = 0; i < narrays; i++) + DIRHASH_BLKFREE(hash[i]); + kmem_free(hash, hashsz); + kmem_free(blkfree, blkfreesz); + + /* Account for the returned memory, and repeat if necessary. */ + DIRHASHLIST_LOCK(); + atomic_add_int(&ulfs_dirhashmem, -mem); + } + /* Success. */ + return (0); +} + +static void +ulfsdirhash_sysctl_init(void) +{ + const struct sysctlnode *rnode, *cnode; + + sysctl_createv(&ulfsdirhash_sysctl_log, 0, NULL, &rnode, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "vfs", NULL, + NULL, 0, NULL, 0, + CTL_VFS, CTL_EOL); + + sysctl_createv(&ulfsdirhash_sysctl_log, 0, &rnode, &rnode, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "ulfs", + SYSCTL_DESCR("ulfs"), + NULL, 0, NULL, 0, + CTL_CREATE, CTL_EOL); + + sysctl_createv(&ulfsdirhash_sysctl_log, 0, &rnode, &rnode, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "dirhash", + SYSCTL_DESCR("dirhash"), + NULL, 0, NULL, 0, + CTL_CREATE, CTL_EOL); + + sysctl_createv(&ulfsdirhash_sysctl_log, 0, &rnode, &cnode, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "minblocks", + SYSCTL_DESCR("minimum hashed directory size in blocks"), + NULL, 0, &ulfs_dirhashminblks, 0, + CTL_CREATE, CTL_EOL); + + sysctl_createv(&ulfsdirhash_sysctl_log, 0, &rnode, &cnode, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "maxmem", + SYSCTL_DESCR("maximum dirhash memory usage"), + NULL, 0, &ulfs_dirhashmaxmem, 0, + CTL_CREATE, CTL_EOL); + + sysctl_createv(&ulfsdirhash_sysctl_log, 0, &rnode, &cnode, + CTLFLAG_PERMANENT|CTLFLAG_READONLY, + CTLTYPE_INT, "memused", + SYSCTL_DESCR("current dirhash memory usage"), + NULL, 0, &ulfs_dirhashmem, 0, + CTL_CREATE, CTL_EOL); + + sysctl_createv(&ulfsdirhash_sysctl_log, 0, &rnode, &cnode, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "docheck", + SYSCTL_DESCR("enable extra sanity checks"), + NULL, 0, &ulfs_dirhashcheck, 0, + CTL_CREATE, CTL_EOL); +} + +void +ulfsdirhash_init(void) +{ + + mutex_init(&ulfsdirhash_lock, MUTEX_DEFAULT, IPL_NONE); + ulfsdirhashblk_cache = pool_cache_init(DH_NBLKOFF * sizeof(daddr_t), 0, + 0, 0, "dirhashblk", NULL, IPL_NONE, NULL, NULL, NULL); + ulfsdirhash_cache = pool_cache_init(sizeof(struct ulfs_dirhash), 0, + 0, 0, "dirhash", NULL, IPL_NONE, NULL, NULL, NULL); + TAILQ_INIT(&ulfsdirhash_list); + ulfsdirhash_sysctl_init(); +} + +void +ulfsdirhash_done(void) +{ + + KASSERT(TAILQ_EMPTY(&ulfsdirhash_list)); + pool_cache_destroy(ulfsdirhashblk_cache); + pool_cache_destroy(ulfsdirhash_cache); + mutex_destroy(&ulfsdirhash_lock); + sysctl_teardown(&ulfsdirhash_sysctl_log); +} diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_dirhash.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_dirhash.h Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,130 @@ +/* $NetBSD: dirhash.h,v 1.6 2008/06/04 11:33:19 ad Exp $ */ +/* from NetBSD: dirhash.h,v 1.6 2008/06/04 11:33:19 ad Exp */ + +/* + * Copyright (c) 2001 Ian Dowse. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/ufs/ufs/dirhash.h,v 1.2.2.2 2004/12/08 11:54:13 dwmalone Exp $ + */ + +#ifndef _UFS_LFS_ULFS_DIRHASH_H_ +#define _UFS_LFS_ULFS_DIRHASH_H_ + +/* + * For fast operations on large directories, we maintain a hash + * that maps the file name to the offset of the directory entry within + * the directory file. + * + * The hashing uses a dumb spillover to the next free slot on + * collisions, so we must keep the utilisation low to avoid + * long linear searches. Deleted entries that are not the last + * in a chain must be marked DIRHASH_DEL. + * + * We also maintain information about free space in each block + * to speed up creations. + */ +#define DIRHASH_EMPTY (-1) /* entry unused */ +#define DIRHASH_DEL (-2) /* deleted entry; may be part of chain */ + +#define DIRALIGN 4 +#define DH_NFSTATS (DIRECTSIZ(LFS_MAXNAMLEN + 1) / DIRALIGN) + /* max DIRALIGN words in a directory entry */ + +/* + * Dirhash uses a score mechanism to achieve a hybrid between a + * least-recently-used and a least-often-used algorithm for entry + * recycling. The score is incremented when a directory is used, and + * decremented when the directory is a candidate for recycling. When + * the score reaches zero, the hash is recycled. Hashes are linked + * together on a TAILQ list, and hashes with higher scores filter + * towards the tail (most recently used) end of the list. + * + * New hash entries are given an inital score of DH_SCOREINIT and are + * placed at the most-recently-used end of the list. This helps a lot + * in the worst-case case scenario where every directory access is + * to a directory that is not hashed (i.e. the working set of hash + * candidates is much larger than the configured memry limit). In this + * case it limits the number of hash builds to 1/DH_SCOREINIT of the + * number of accesses. + */ +#define DH_SCOREINIT 8 /* initial dh_score when dirhash built */ +#define DH_SCOREMAX 64 /* max dh_score value */ + +/* + * The main hash table has 2 levels. It is an array of pointers to + * blocks of DH_NBLKOFF offsets. + */ +#define DH_BLKOFFSHIFT 8 +#define DH_NBLKOFF (1 << DH_BLKOFFSHIFT) +#define DH_BLKOFFMASK (DH_NBLKOFF - 1) + +#define DH_ENTRY(dh, slot) \ + ((dh)->dh_hash[(slot) >> DH_BLKOFFSHIFT][(slot) & DH_BLKOFFMASK]) + +struct ulfs_dirhash { + kmutex_t dh_lock; /* protects all fields except dh_list */ + + lfs_doff_t **dh_hash; /* the hash array (2-level) */ + size_t dh_hashsz; + int dh_narrays; /* number of entries in dh_hash */ + int dh_hlen; /* total slots in the 2-level hash array */ + int dh_hused; /* entries in use */ + + u_int8_t *dh_blkfree; /* free DIRALIGN words in each dir block */ + size_t dh_blkfreesz; + int dh_nblk; /* size of dh_blkfree array */ + int dh_dirblks; /* number of DIRBLKSIZ blocks in dir */ + int dh_firstfree[DH_NFSTATS + 1]; /* first blk with N words free */ + + int dh_seqopt; /* sequential access optimisation enabled */ + lfs_doff_t dh_seqoff; /* sequential access optimisation offset */ + + int dh_score; /* access count for this dirhash */ + + int dh_onlist; /* true if on the ulfsdirhash_list chain */ + + /* Protected by ulfsdirhash_lock. */ + TAILQ_ENTRY(ulfs_dirhash) dh_list; /* chain of all dirhashes */ +}; + + +/* + * Dirhash functions. + */ +int ulfsdirhash_build(struct lfs_inode *); +lfs_doff_t ulfsdirhash_findfree(struct lfs_inode *, int, int *); +lfs_doff_t ulfsdirhash_enduseful(struct lfs_inode *); +int ulfsdirhash_lookup(struct lfs_inode *, const char *, int, lfs_doff_t *, + struct buf **, lfs_doff_t *); +void ulfsdirhash_newblk(struct lfs_inode *, lfs_doff_t); +void ulfsdirhash_add(struct lfs_inode *, struct direct *, lfs_doff_t); +void ulfsdirhash_remove(struct lfs_inode *, struct direct *, lfs_doff_t); +void ulfsdirhash_move(struct lfs_inode *, struct direct *, lfs_doff_t, lfs_doff_t); +void ulfsdirhash_dirtrunc(struct lfs_inode *, lfs_doff_t); +void ulfsdirhash_free(struct lfs_inode *); +void ulfsdirhash_checkblock(struct lfs_inode *, char *, lfs_doff_t); +void ulfsdirhash_init(void); +void ulfsdirhash_done(void); + +#endif /* !_UFS_LFS_ULFS_DIRHASH_H_ */ diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_extattr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_extattr.h Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,125 @@ +/* $NetBSD: extattr.h,v 1.8 2008/01/30 14:54:01 ad Exp $ */ +/* from NetBSD: extattr.h,v 1.8 2008/01/30 14:54:01 ad Exp */ + +/*- + * Copyright (c) 1999-2001 Robert N. M. Watson + * All rights reserved. + * + * This software was developed by Robert Watson for the TrustedBSD Project. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/ufs/ufs/extattr.h,v 1.20 2005/01/31 08:16:45 imp Exp $ + */ + +/* + * Support for file system extended attributes on the ULFS1 file system. + * Developed by the TrustedBSD Project. + */ + +#ifndef _UFS_LFS_ULFS_EXTATTR_H_ +#define _UFS_LFS_ULFS_EXTATTR_H_ + +#define ULFS_EXTATTR_MAGIC 0x00b5d5ec +#define ULFS_EXTATTR_VERSION 0x00000003 +#define ULFS_EXTATTR_FSROOTSUBDIR ".attribute" +#define ULFS_EXTATTR_SUBDIR_SYSTEM "system" +#define ULFS_EXTATTR_SUBDIR_USER "user" +#define ULFS_EXTATTR_MAXEXTATTRNAME 65 /* including null */ + +#define ULFS_EXTATTR_ATTR_FLAG_INUSE 0x00000001 /* attr has been set */ +#define ULFS_EXTATTR_PERM_KERNEL 0x00000000 +#define ULFS_EXTATTR_PERM_ROOT 0x00000001 +#define ULFS_EXTATTR_PERM_OWNER 0x00000002 +#define ULFS_EXTATTR_PERM_ANYONE 0x00000003 + +#define ULFS_EXTATTR_UEPM_INITIALIZED 0x00000001 +#define ULFS_EXTATTR_UEPM_STARTED 0x00000002 + +#define ULFS_EXTATTR_CMD_START 0x00000001 +#define ULFS_EXTATTR_CMD_STOP 0x00000002 +#define ULFS_EXTATTR_CMD_ENABLE 0x00000003 +#define ULFS_EXTATTR_CMD_DISABLE 0x00000004 + +struct ulfs_extattr_fileheader { + uint32_t uef_magic; /* magic number for sanity checking */ + uint32_t uef_version; /* version of attribute file */ + uint32_t uef_size; /* size of attributes, w/o header */ +}; + +struct ulfs_extattr_header { + uint32_t ueh_flags; /* flags for attribute */ + uint32_t ueh_len; /* local defined length; <= uef_size */ + uint32_t ueh_i_gen; /* generation number for sanity */ + /* data follows the header */ +}; + +#ifdef _KERNEL + +#ifdef MALLOC_DECLARE +MALLOC_DECLARE(M_EXTATTR); +#endif + +struct vnode; +LIST_HEAD(ulfs_extattr_list_head, ulfs_extattr_list_entry); +struct ulfs_extattr_list_entry { + LIST_ENTRY(ulfs_extattr_list_entry) uele_entries; + struct ulfs_extattr_fileheader uele_fileheader; + int uele_attrnamespace; + char uele_attrname[ULFS_EXTATTR_MAXEXTATTRNAME]; + struct vnode *uele_backing_vnode; + int uele_flags; +}; + +/* uele_flags */ +#define UELE_F_NEEDSWAP 0x01 /* needs byte swap */ + +#define UELE_NEEDSWAP(uele) ((uele)->uele_flags & UELE_F_NEEDSWAP) + +struct lock; +struct ulfs_extattr_per_mount { + kmutex_t uepm_lock; + struct ulfs_extattr_list_head uepm_list; + kauth_cred_t uepm_ucred; + int uepm_lockcnt; + int uepm_flags; +}; + +void ulfs_extattr_uepm_init(struct ulfs_extattr_per_mount *uepm); +void ulfs_extattr_uepm_destroy(struct ulfs_extattr_per_mount *uepm); +int ulfs_extattr_start(struct mount *mp, struct lwp *l); +int ulfs_extattr_autostart(struct mount *mp, struct lwp *l); +void ulfs_extattr_stop(struct mount *mp, struct lwp *l); +int ulfs_extattrctl(struct mount *mp, int cmd, struct vnode *filename, + int attrnamespace, const char *attrname); +int ulfs_getextattr(struct vop_getextattr_args *ap); +int ulfs_deleteextattr(struct vop_deleteextattr_args *ap); +int ulfs_setextattr(struct vop_setextattr_args *ap); +int ulfs_listextattr(struct vop_listextattr_args *ap); +void ulfs_extattr_vnode_inactive(struct vnode *vp, struct lwp *l); + +void ulfs_extattr_init(void); +void ulfs_extattr_done(void); + +#endif /* !_KERNEL */ + +#endif /* !_UFS_LFS_ULFS_EXTATTR_H_ */ diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_extern.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_extern.h Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,182 @@ +/* $NetBSD: ulfs_extern.h,v 1.1 2009/11/16 01:00:00 dholland Exp $ */ +/* from NetBSD: ufs_extern.h,v 1.62 2009/09/13 05:17:37 tsutsui Exp */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_extern.h 8.10 (Berkeley) 5/14/95 + */ + +#ifndef _UFS_LFS_ULFS_EXTERN_H_ +#define _UFS_LFS_ULFS_EXTERN_H_ + +#include + +struct buf; +struct componentname; +struct direct; +struct disklabel; +struct dquot; +struct fid; +struct flock; +struct lfs_indir; +struct lfs_inode; +struct mbuf; +struct mount; +struct nameidata; +struct lfid; +struct lwp; +struct ulfs_args; +struct ulfsmount; +struct uio; +struct vattr; +struct vnode; + +extern pool_cache_t ulfs_direct_cache; /* memory pool for directs */ + +__BEGIN_DECLS +#define ulfs_abortop genfs_abortop +int ulfs_access(void *); +int ulfs_advlock(void *); +int ulfs_bmap(void *); +int ulfs_close(void *); +int ulfs_create(void *); +int ulfs_getattr(void *); +int ulfs_inactive(void *); +#define ulfs_fcntl genfs_fcntl +#define ulfs_ioctl genfs_enoioctl +#define ulfs_islocked genfs_islocked +int ulfs_link(void *); +#define ulfs_lock genfs_lock +int ulfs_lookup(void *); +int ulfs_mkdir(void *); +int ulfs_mknod(void *); +#define ulfs_mmap genfs_mmap +#define ulfs_revoke genfs_revoke +int ulfs_open(void *); +int ulfs_pathconf(void *); +int ulfs_print(void *); +int ulfs_readdir(void *); +int ulfs_readlink(void *); +int ulfs_remove(void *); +int ulfs_rename(void *); +int ulfs_rmdir(void *); +#define ulfs_seek genfs_seek +#define ulfs_poll genfs_poll +int ulfs_setattr(void *); +int ulfs_strategy(void *); +int ulfs_symlink(void *); +#define ulfs_unlock genfs_unlock +int ulfs_whiteout(void *); +int ulfsspec_close(void *); +int ulfsspec_read(void *); +int ulfsspec_write(void *); + +int ulfsfifo_read(void *); +int ulfsfifo_write(void *); +int ulfsfifo_close(void *); + +/* ulfs_bmap.c */ +typedef bool (*ulfs_issequential_callback_t)(const struct ulfsmount *, + daddr_t, daddr_t); +int ulfs_bmaparray(struct vnode *, daddr_t, daddr_t *, struct lfs_indir *, + int *, int *, ulfs_issequential_callback_t); +int ulfs_getlbns(struct vnode *, daddr_t, struct lfs_indir *, int *); + +/* ulfs_ihash.c */ +void ulfs_ihashinit(void); +void ulfs_ihashreinit(void); +void ulfs_ihashdone(void); +struct vnode *ulfs_ihashlookup(dev_t, ino_t); +struct vnode *ulfs_ihashget(dev_t, ino_t, int); +void ulfs_ihashins(struct lfs_inode *); +void ulfs_ihashrem(struct lfs_inode *); + +/* ulfs_inode.c */ +int ulfs_reclaim(struct vnode *); +int ulfs_balloc_range(struct vnode *, off_t, off_t, kauth_cred_t, int); + +/* ulfs_lookup.c */ +void ulfs_dirbad(struct lfs_inode *, lfs_doff_t, const char *); +int ulfs_dirbadentry(struct vnode *, struct direct *, int); +void ulfs_makedirentry(struct lfs_inode *, struct componentname *, + struct direct *); +int ulfs_direnter(struct vnode *, struct vnode *, struct direct *, + struct componentname *, struct buf *); +int ulfs_dirremove(struct vnode *, struct lfs_inode *, int, int); +int ulfs_dirrewrite(struct lfs_inode *, struct lfs_inode *, ino_t, int, int, int); +int ulfs_dirempty(struct lfs_inode *, ino_t, kauth_cred_t); +int ulfs_checkpath(struct lfs_inode *, struct lfs_inode *, kauth_cred_t); +int ulfs_blkatoff(struct vnode *, off_t, char **, struct buf **, bool); + +/* ulfs_quota.c */ +/* + * Flags to lfs_chkdq() and lfs_chkiq() + */ +#define FORCE 0x01 /* force usage changes independent of limits */ +void ulfsquota_init(struct lfs_inode *); +void ulfsquota_free(struct lfs_inode *); +int lfs_getinoquota(struct lfs_inode *); +int lfs_chkdq(struct lfs_inode *, int64_t, kauth_cred_t, int); +int lfs_chkiq(struct lfs_inode *, int32_t, kauth_cred_t, int); +int lfs_quotaon(struct lwp *, struct mount *, int, void *); +int lfs_quotaoff(struct lwp *, struct mount *, int); +int lfs_getquota(struct mount *, u_long, int, void *); +int lfs_setquota(struct mount *, u_long, int, void *); +int lfs_setuse(struct mount *, u_long, int, void *); +int lfs_qsync(struct mount *); + +/* ulfs_vfsops.c */ +void ulfs_init(void); +void ulfs_reinit(void); +void ulfs_done(void); +int ulfs_start(struct mount *, int); +int ulfs_root(struct mount *, struct vnode **); +int ulfs_quotactl(struct mount *, int, uid_t, void *); +int ulfs_fhtovp(struct mount *, struct lfid *, struct vnode **); + +/* ulfs_vnops.c */ +void ulfs_vinit(struct mount *, int (**)(void *), + int (**)(void *), struct vnode **); +int ulfs_makeinode(int, struct vnode *, struct vnode **, + struct componentname *); +int ulfs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t); +void ulfs_gop_markupdate(struct vnode *, int); + +/* + * Snapshot function prototypes. + */ + +void ffs_snapgone(struct lfs_inode *); + +__END_DECLS + +extern kmutex_t ulfs_ihash_lock; +extern kmutex_t ulfs_hashlock; + +#endif /* !_UFS_LFS_ULFS_EXTERN_H_ */ diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_ihash.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_ihash.c Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,193 @@ +/* $NetBSD: ulfs_ihash.c,v 1.1 2008/11/16 01:00:00 dholland Exp $ */ +/* from NetBSD: ufs_ihash.c,v 1.28 2009/11/05 08:18:02 ad Exp */ + +/* + * Copyright (c) 1982, 1986, 1989, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95 + */ + +#include +__KERNEL_RCSID(0, "$NetBSD$"); + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * Structures associated with inode cacheing. + */ +static LIST_HEAD(ihashhead, lfs_inode) *ihashtbl; +static u_long ihash; /* size of hash table - 1 */ +#define INOHASH(device, inum) (((device) + (inum)) & ihash) + +kmutex_t ulfs_ihash_lock; +kmutex_t ulfs_hashlock; + +/* + * Initialize inode hash table. + */ +void +ulfs_ihashinit(void) +{ + + mutex_init(&ulfs_hashlock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&ulfs_ihash_lock, MUTEX_DEFAULT, IPL_NONE); + ihashtbl = hashinit(desiredvnodes, HASH_LIST, true, &ihash); +} + +/* + * Reinitialize inode hash table. + */ + +void +ulfs_ihashreinit(void) +{ + struct lfs_inode *ip; + struct ihashhead *oldhash, *hash; + u_long oldmask, mask, val; + int i; + + hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); + mutex_enter(&ulfs_ihash_lock); + oldhash = ihashtbl; + oldmask = ihash; + ihashtbl = hash; + ihash = mask; + for (i = 0; i <= oldmask; i++) { + while ((ip = LIST_FIRST(&oldhash[i])) != NULL) { + LIST_REMOVE(ip, i_hash); + val = INOHASH(ip->i_dev, ip->i_number); + LIST_INSERT_HEAD(&hash[val], ip, i_hash); + } + } + mutex_exit(&ulfs_ihash_lock); + hashdone(oldhash, HASH_LIST, oldmask); +} + +/* + * Free inode hash table. + */ +void +ulfs_ihashdone(void) +{ + + hashdone(ihashtbl, HASH_LIST, ihash); + mutex_destroy(&ulfs_hashlock); + mutex_destroy(&ulfs_ihash_lock); +} + +/* + * Use the device/inum pair to find the incore inode, and return a pointer + * to it. If it is in core, return it, even if it is locked. + */ +struct vnode * +ulfs_ihashlookup(dev_t dev, ino_t inum) +{ + struct lfs_inode *ip; + struct ihashhead *ipp; + + KASSERT(mutex_owned(&ulfs_ihash_lock)); + + ipp = &ihashtbl[INOHASH(dev, inum)]; + LIST_FOREACH(ip, ipp, i_hash) { + if (inum == ip->i_number && dev == ip->i_dev) + break; + } + if (ip) + return (ITOV(ip)); + return (NULLVP); +} + +/* + * Use the device/inum pair to find the incore inode, and return a pointer + * to it. If it is in core, but locked, wait for it. + */ +struct vnode * +ulfs_ihashget(dev_t dev, ino_t inum, int flags) +{ + struct ihashhead *ipp; + struct lfs_inode *ip; + struct vnode *vp; + + loop: + mutex_enter(&ulfs_ihash_lock); + ipp = &ihashtbl[INOHASH(dev, inum)]; + LIST_FOREACH(ip, ipp, i_hash) { + if (inum == ip->i_number && dev == ip->i_dev) { + vp = ITOV(ip); + if (flags == 0) { + mutex_exit(&ulfs_ihash_lock); + } else { + mutex_enter(&vp->v_interlock); + mutex_exit(&ulfs_ihash_lock); + if (vget(vp, flags | LK_INTERLOCK)) + goto loop; + } + return (vp); + } + } + mutex_exit(&ulfs_ihash_lock); + return (NULL); +} + +/* + * Insert the inode into the hash table, and return it locked. + */ +void +ulfs_ihashins(struct lfs_inode *ip) +{ + struct ihashhead *ipp; + + KASSERT(mutex_owned(&ulfs_hashlock)); + + /* lock the inode, then put it on the appropriate hash list */ + vlockmgr(&ip->i_vnode->v_lock, LK_EXCLUSIVE); + + mutex_enter(&ulfs_ihash_lock); + ipp = &ihashtbl[INOHASH(ip->i_dev, ip->i_number)]; + LIST_INSERT_HEAD(ipp, ip, i_hash); + mutex_exit(&ulfs_ihash_lock); +} + +/* + * Remove the inode from the hash table. + */ +void +ulfs_ihashrem(struct lfs_inode *ip) +{ + mutex_enter(&ulfs_ihash_lock); + LIST_REMOVE(ip, i_hash); + mutex_exit(&ulfs_ihash_lock); +} diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_inode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_inode.c Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,296 @@ +/* $NetBSD: ulfs_inode.c,v 1.78 2009/02/22 20:28:07 ad Exp $ */ +/* from NetBSD: ufs_inode.c,v 1.78 2009/02/22 20:28:07 ad Exp */ + +/* + * Copyright (c) 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_inode.c 8.9 (Berkeley) 5/14/95 + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: ulfs_inode.c,v 1.78 2009/02/22 20:28:07 ad Exp $"); + +#if defined(_KERNEL_OPT) +#include "opt_ffs.h" /* XXX */ +#include "opt_lfs.h" +#include "opt_quota.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef LFS_DIRHASH +#include +#endif +#ifdef LFS_EXTATTR +#include +#endif + +#include + +extern int prtactive; + +/* + * Last reference to an inode. If necessary, write or delete it. + */ +int +ulfs_inactive(void *v) +{ + struct vop_inactive_args /* { + struct vnode *a_vp; + struct bool *a_recycle; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct lfs_inode *ip = VTOI(vp); + struct mount *transmp; + mode_t mode; + int error = 0; + + transmp = vp->v_mount; + fstrans_start(transmp, FSTRANS_SHARED); + /* + * Ignore inodes related to stale file handles. + */ + if (ip->i_mode == 0) + goto out; + if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { + error = 0; +#ifdef QUOTA + (void)lfs_chkiq(ip, -1, NOCRED, 0); +#endif +#ifdef LFS_EXTATTR + ulfs_extattr_vnode_inactive(vp, curlwp); +#endif + if (ip->i_size != 0) { + error = ULFS_TRUNCATE(vp, (off_t)0, 0, NOCRED); + } + DIP_ASSIGN(ip, rdev, 0); + mode = ip->i_mode; + ip->i_mode = 0; + DIP_ASSIGN(ip, mode, 0); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + mutex_enter(&vp->v_interlock); + vp->v_iflag |= VI_FREEING; + mutex_exit(&vp->v_interlock); + ULFS_VFREE(vp, ip->i_number, mode); + } + + if (ip->i_flag & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) { + ULFS_UPDATE(vp, NULL, NULL, 0); + } + +out: + /* + * If we are done with the inode, reclaim it + * so that it can be reused immediately. + */ + *ap->a_recycle = (ip->i_mode == 0); + VOP_UNLOCK(vp, 0); + fstrans_done(transmp); + return (error); +} + +/* + * Reclaim an inode so that it can be used for other purposes. + */ +int +ulfs_reclaim(struct vnode *vp) +{ + struct lfs_inode *ip = VTOI(vp); + + if (prtactive && vp->v_usecount > 1) + vprint("ulfs_reclaim: pushing active", vp); + + /* XXX: do we need both of these? seems to be a WAPBL artifact */ + ULFS_UPDATE(vp, NULL, NULL, UPDATE_CLOSE); + ULFS_UPDATE(vp, NULL, NULL, UPDATE_CLOSE); + + /* + * Remove the inode from its hash chain. + */ + ulfs_ihashrem(ip); + /* + * Purge old data structures associated with the inode. + */ + cache_purge(vp); + if (ip->i_devvp) { + vrele(ip->i_devvp); + ip->i_devvp = 0; + } +#ifdef QUOTA + ulfsquota_free(ip); +#endif +#ifdef LFS_DIRHASH + if (ip->i_dirhash != NULL) + ulfsdirhash_free(ip); +#endif + return (0); +} + +/* + * allocate a range of blocks in a file. + * after this function returns, any page entirely contained within the range + * will map to invalid data and thus must be overwritten before it is made + * accessible to others. + */ + +int +ulfs_balloc_range(struct vnode *vp, off_t off, off_t len, kauth_cred_t cred, + int flags) +{ + off_t neweof; /* file size after the operation */ + off_t neweob; /* offset next to the last block after the operation */ + off_t pagestart; /* starting offset of range covered by pgs */ + off_t eob; /* offset next to allocated blocks */ + struct uvm_object *uobj; + int i, delta, error, npages; + int bshift = vp->v_mount->mnt_fs_bshift; + int bsize = 1 << bshift; + int ppb = MAX(bsize >> PAGE_SHIFT, 1); + struct vm_page **pgs; + size_t pgssize; + UVMHIST_FUNC("ulfs_balloc_range"); UVMHIST_CALLED(ubchist); + UVMHIST_LOG(ubchist, "vp %p off 0x%x len 0x%x u_size 0x%x", + vp, off, len, vp->v_size); + + neweof = MAX(vp->v_size, off + len); + GOP_SIZE(vp, neweof, &neweob, 0); + + error = 0; + uobj = &vp->v_uobj; + + /* + * read or create pages covering the range of the allocation and + * keep them locked until the new block is allocated, so there + * will be no window where the old contents of the new block are + * visible to racing threads. + */ + + pagestart = trunc_page(off) & ~(bsize - 1); + npages = MIN(ppb, (round_page(neweob) - pagestart) >> PAGE_SHIFT); + pgssize = npages * sizeof(struct vm_page *); + pgs = kmem_zalloc(pgssize, KM_SLEEP); + + /* + * adjust off to be block-aligned. + */ + + delta = off & (bsize - 1); + off -= delta; + len += delta; + + retry: + mutex_enter(&uobj->vmobjlock); + error = VOP_GETPAGES(vp, pagestart, pgs, &npages, 0, + VM_PROT_WRITE, 0, + PGO_SYNCIO|PGO_PASTEOF|PGO_NOBLOCKALLOC|PGO_NOTIMESTAMP); + if (error) { + goto out; + } + mutex_enter(&uobj->vmobjlock); + mutex_enter(&uvm_pageqlock); + for (i = 0; i < npages; i++) { + UVMHIST_LOG(ubchist, "got pgs[%d] %p", i, pgs[i],0,0); + KASSERT((pgs[i]->flags & PG_RELEASED) == 0); + pgs[i]->flags &= ~PG_CLEAN; + uvm_pageactivate(pgs[i]); + } + mutex_exit(&uvm_pageqlock); + mutex_exit(&uobj->vmobjlock); + + /* + * now allocate the range. + */ + + /* + * XXX: Hack around deadlock with pagebusy and genfs node lock. + * This should be properly fixed. PR kern/40389 + */ + { + struct genfs_node *gp = VTOG(vp); /* XXX */ + + if (!rw_tryenter(&gp->g_glock, RW_WRITER)) { + mutex_enter(&uobj->vmobjlock); + for (i = 0; i < npages; i++) + pgs[i]->flags |= PG_RELEASED | PG_CLEAN; + mutex_enter(&uvm_pageqlock); + uvm_page_unbusy(pgs, npages); + mutex_exit(&uvm_pageqlock); + mutex_exit(&uobj->vmobjlock); + kpause("uballo", false, 1, NULL); + goto retry; + }} + + error = GOP_ALLOC(vp, off, len, flags, cred); + genfs_node_unlock(vp); + + /* + * clear PG_RDONLY on any pages we are holding + * (since they now have backing store) and unbusy them. + */ + + GOP_SIZE(vp, off + len, &eob, 0); + mutex_enter(&uobj->vmobjlock); + for (i = 0; i < npages; i++) { + if (error) { + pgs[i]->flags |= PG_RELEASED; + } else if (off <= pagestart + (i << PAGE_SHIFT) && + pagestart + ((i + 1) << PAGE_SHIFT) <= eob) { + pgs[i]->flags &= ~PG_RDONLY; + } + } + if (error) { + mutex_enter(&uvm_pageqlock); + uvm_page_unbusy(pgs, npages); + mutex_exit(&uvm_pageqlock); + } else { + uvm_page_unbusy(pgs, npages); + } + mutex_exit(&uobj->vmobjlock); + + out: + kmem_free(pgs, pgssize); + return error; +} diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_inode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_inode.h Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,92 @@ +/* $NetBSD: inode.h,v 1.56 2009/02/22 20:28:07 ad Exp $ */ +/* from NetBSD: inode.h,v 1.56 2009/02/22 20:28:07 ad Exp */ + +/* + * Copyright (c) 1982, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)inode.h 8.9 (Berkeley) 5/14/95 + */ + +#ifndef _UFS_LFS_ULFS_INODE_H_ +#define _UFS_LFS_ULFS_INODE_H_ + +#include + +#include +#include + +/* + * Per-filesystem inode extensions. + */ + +/* struct lfs_inode_ext is defined elsewhere */ +struct lfs_inode_ext; + +#if defined(_KERNEL) + +/* + * The DIP macro is used to access fields in the dinode that are + * not cached in the inode itself. + */ +#define DIP(ip, field) ((ip)->i_ffs1_##field) + +#define DIP_ASSIGN(ip, field, value) \ + do { \ + (ip)->i_ffs1_##field = (value); \ + } while(0) + +#define DIP_ADD(ip, field, value) \ + do { \ + (ip)->i_ffs1_##field += (value); \ + } while(0) + +#define SHORTLINK(ip) ((void *)(ip)->i_ffs1_db) + + +/* + * Structure used to pass around logical block paths generated by + * ulfs_getlbns and used by truncate and bmap code. + */ +struct lfs_indir { + daddr_t in_lbn; /* Logical block number. */ + int in_off; /* Offset in buffer. */ + int in_exists; /* Flag if the block exists. */ +}; + +/* Convert between inode pointers and vnode pointers. */ +#define VTOI(vp) ((struct lfs_inode *)(vp)->v_data) +#define ITOV(ip) ((ip)->i_vnode) + +#endif /* _KERNEL */ + +#endif /* !_UFS_LFS_ULFS_INODE_H_ */ diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_lookup.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_lookup.c Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,1302 @@ +/* $NetBSD: ulfs_lookup.c,v 1.1 2009/11/16 01:00:00 dholland Exp $ */ +/* from NetBSD: ufs_lookup.c,v 1.103 2010/01/08 11:35:12 pooka Exp */ + +/* + * Copyright (c) 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. + * + * @(#)ufs_lookup.c 8.9 (Berkeley) 8/11/94 + */ + +#include +__KERNEL_RCSID(0, "$NetBSD$"); + +#ifdef _KERNEL_OPT +#include "opt_ffs.h" /* XXX */ +#include "opt_lfs.h" +#include "fs_ffs.h" /* XXX */ +#include "fs_lfs.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#ifdef LFS_DIRHASH +#include +#endif +#include +#include +#include + +#ifdef DIAGNOSTIC +int ulfs_dirchk = 1; +#else +int ulfs_dirchk = 0; +#endif + +#define FSFMT(vp) (((vp)->v_mount->mnt_iflag & IMNT_DTYPE) == 0) + +/* + * Convert a component of a pathname into a pointer to a locked inode. + * This is a very central and rather complicated routine. + * If the file system is not maintained in a strict tree hierarchy, + * this can result in a deadlock situation (see comments in code below). + * + * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending + * on whether the name is to be looked up, created, renamed, or deleted. + * When CREATE, RENAME, or DELETE is specified, information usable in + * creating, renaming, or deleting a directory entry may be calculated. + * If flag has LOCKPARENT or'ed into it and the target of the pathname + * exists, lookup returns both the target and its parent directory locked. + * When creating or renaming and LOCKPARENT is specified, the target may + * not be ".". When deleting and LOCKPARENT is specified, the target may + * be "."., but the caller must check to ensure it does an vrele and vput + * instead of two vputs. + * + * Overall outline of ulfs_lookup: + * + * check accessibility of directory + * look for name in cache, if found, then if at end of path + * and deleting or creating, drop it, else return name + * search for name in directory, to found or notfound + * notfound: + * if creating, return locked directory, leaving info on available slots + * else return error + * found: + * if at end of path and deleting, return information to allow delete + * if at end of path and rewriting (RENAME and LOCKPARENT), lock target + * inode and return info to allow rewrite + * if not at end, add name to cache; if at end and neither creating + * nor deleting, add name to cache + */ +int +ulfs_lookup(void *v) +{ + struct vop_lookup_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + } */ *ap = v; + struct vnode *vdp = ap->a_dvp; /* vnode for directory being searched */ + struct lfs_inode *dp = VTOI(vdp); /* inode for directory being searched */ + struct buf *bp; /* a buffer of directory entries */ + struct direct *ep; /* the current directory entry */ + int entryoffsetinblock; /* offset of ep in bp's buffer */ + enum {NONE, COMPACT, FOUND} slotstatus; + lfs_doff_t slotoffset; /* offset of area with free space */ + int slotsize; /* size of area at slotoffset */ + int slotfreespace; /* amount of space free in slot */ + int slotneeded; /* size of the entry we're seeking */ + int numdirpasses; /* strategy for directory search */ + lfs_doff_t endsearch; /* offset to end directory search */ + lfs_doff_t prevoff; /* prev entry dp->i_offset */ + struct vnode *pdp; /* saved dp during symlink work */ + struct vnode *tdp; /* returned by VFS_VGET */ + lfs_doff_t enduseful; /* pointer past last used dir slot */ + u_long bmask; /* block offset mask */ + int namlen, error; + struct vnode **vpp = ap->a_vpp; + struct componentname *cnp = ap->a_cnp; + kauth_cred_t cred = cnp->cn_cred; + int flags; + int nameiop = cnp->cn_nameiop; + struct ulfsmount *ump = dp->i_ump; + const int needswap = ULFS_MPNEEDSWAP(ump); + int dirblksiz = ump->um_dirblksiz; + ino_t foundino; + + flags = cnp->cn_flags; + + bp = NULL; + slotoffset = -1; + *vpp = NULL; + endsearch = 0; /* silence compiler warning */ + /* + * Check accessiblity of directory. + */ + if ((error = VOP_ACCESS(vdp, VEXEC, cred)) != 0) + return (error); + + if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && + (nameiop == DELETE || nameiop == RENAME)) + return (EROFS); + + /* + * We now have a segment name to search for, and a directory to search. + * + * Before tediously performing a linear scan of the directory, + * check the name cache to see if the directory/name pair + * we are looking for is known already. + */ + if ((error = cache_lookup(vdp, vpp, cnp)) >= 0) { + return (error); + } + + fstrans_start(vdp->v_mount, FSTRANS_SHARED); + + /* + * Suppress search for slots unless creating + * file and at end of pathname, in which case + * we watch for a place to put the new file in + * case it doesn't already exist. + */ + slotstatus = FOUND; + slotfreespace = slotsize = slotneeded = 0; + if ((nameiop == CREATE || nameiop == RENAME) && + (flags & ISLASTCN)) { + slotstatus = NONE; + slotneeded = DIRECTSIZ(cnp->cn_namelen); + } + + /* + * If there is cached information on a previous search of + * this directory, pick up where we last left off. + * We cache only lookups as these are the most common + * and have the greatest payoff. Caching CREATE has little + * benefit as it usually must search the entire directory + * to determine that the entry does not exist. Caching the + * location of the last DELETE or RENAME has not reduced + * profiling time and hence has been removed in the interest + * of simplicity. + */ + bmask = vdp->v_mount->mnt_stat.f_iosize - 1; + +#ifdef LFS_DIRHASH + /* + * Use dirhash for fast operations on large directories. The logic + * to determine whether to hash the directory is contained within + * ulfsdirhash_build(); a zero return means that it decided to hash + * this directory and it successfully built up the hash table. + */ + if (ulfsdirhash_build(dp) == 0) { + /* Look for a free slot if needed. */ + enduseful = dp->i_size; + if (slotstatus != FOUND) { + slotoffset = ulfsdirhash_findfree(dp, slotneeded, + &slotsize); + if (slotoffset >= 0) { + slotstatus = COMPACT; + enduseful = ulfsdirhash_enduseful(dp); + if (enduseful < 0) + enduseful = dp->i_size; + } + } + /* Look up the component. */ + numdirpasses = 1; + entryoffsetinblock = 0; /* silence compiler warning */ + switch (ulfsdirhash_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen, + &dp->i_offset, &bp, nameiop == DELETE ? &prevoff : NULL)) { + case 0: + ep = (struct direct *)((char *)bp->b_data + + (dp->i_offset & bmask)); + goto foundentry; + case ENOENT: + dp->i_offset = roundup(dp->i_size, dirblksiz); + goto notfound; + default: + /* Something failed; just do a linear search. */ + break; + } + } +#endif /* LFS_DIRHASH */ + + if (nameiop != LOOKUP || dp->i_diroff == 0 || + dp->i_diroff >= dp->i_size) { + entryoffsetinblock = 0; + dp->i_offset = 0; + numdirpasses = 1; + } else { + dp->i_offset = dp->i_diroff; + if ((entryoffsetinblock = dp->i_offset & bmask) && + (error = ulfs_blkatoff(vdp, (off_t)dp->i_offset, + NULL, &bp, false))) + goto out; + numdirpasses = 2; + nchstats.ncs_2passes++; + } + prevoff = dp->i_offset; + endsearch = roundup(dp->i_size, dirblksiz); + enduseful = 0; + +searchloop: + while (dp->i_offset < endsearch) { + if (curcpu()->ci_schedstate.spc_flags & SPCF_SHOULDYIELD) + preempt(); + /* + * If necessary, get the next directory block. + */ + if ((dp->i_offset & bmask) == 0) { + if (bp != NULL) + brelse(bp, 0); + error = ulfs_blkatoff(vdp, (off_t)dp->i_offset, NULL, + &bp, false); + if (error) + goto out; + entryoffsetinblock = 0; + } + /* + * If still looking for a slot, and at a DIRBLKSIZ + * boundary, have to start looking for free space again. + */ + if (slotstatus == NONE && + (entryoffsetinblock & (dirblksiz - 1)) == 0) { + slotoffset = -1; + slotfreespace = 0; + } + /* + * Get pointer to next entry. + * Full validation checks are slow, so we only check + * enough to insure forward progress through the + * directory. Complete checks can be run by patching + * "ulfs_dirchk" to be true. + */ + KASSERT(bp != NULL); + ep = (struct direct *)((char *)bp->b_data + entryoffsetinblock); + if (ep->d_reclen == 0 || + (ulfs_dirchk && ulfs_dirbadentry(vdp, ep, entryoffsetinblock))) { + int i; + + ulfs_dirbad(dp, dp->i_offset, "mangled entry"); + i = dirblksiz - (entryoffsetinblock & (dirblksiz - 1)); + dp->i_offset += i; + entryoffsetinblock += i; + continue; + } + + /* + * If an appropriate sized slot has not yet been found, + * check to see if one is available. Also accumulate space + * in the current block so that we can determine if + * compaction is viable. + */ + if (slotstatus != FOUND) { + int size = ulfs_rw16(ep->d_reclen, needswap); + + if (ep->d_ino != 0) + size -= DIRSIZ(FSFMT(vdp), ep, needswap); + if (size > 0) { + if (size >= slotneeded) { + slotstatus = FOUND; + slotoffset = dp->i_offset; + slotsize = ulfs_rw16(ep->d_reclen, + needswap); + } else if (slotstatus == NONE) { + slotfreespace += size; + if (slotoffset == -1) + slotoffset = dp->i_offset; + if (slotfreespace >= slotneeded) { + slotstatus = COMPACT; + slotsize = dp->i_offset + + ulfs_rw16(ep->d_reclen, + needswap) - + slotoffset; + } + } + } + } + + /* + * Check for a name match. + */ + if (ep->d_ino) { +#if (BYTE_ORDER == LITTLE_ENDIAN) + if (FSFMT(vdp) && needswap == 0) + namlen = ep->d_type; + else + namlen = ep->d_namlen; +#else + if (FSFMT(vdp) && needswap != 0) + namlen = ep->d_type; + else + namlen = ep->d_namlen; +#endif + if (namlen == cnp->cn_namelen && + !memcmp(cnp->cn_nameptr, ep->d_name, + (unsigned)namlen)) { +#ifdef LFS_DIRHASH +foundentry: +#endif + /* + * Save directory entry's inode number and + * reclen in ndp->ni_ulfs area, and release + * directory buffer. + */ + if (!FSFMT(vdp) && ep->d_type == DT_WHT) { + slotstatus = FOUND; + slotoffset = dp->i_offset; + slotsize = ulfs_rw16(ep->d_reclen, + needswap); + dp->i_reclen = slotsize; + /* + * This is used to set dp->i_endoff, + * which may be used by ulfs_direnter2() + * as a length to truncate the + * directory to. Therefore, it must + * point past the end of the last + * non-empty directory entry. We don't + * know where that is in this case, so + * we effectively disable shrinking by + * using the existing size of the + * directory. + * + * Note that we wouldn't expect to + * shrink the directory while rewriting + * an existing entry anyway. + */ + enduseful = endsearch; + ap->a_cnp->cn_flags |= ISWHITEOUT; + numdirpasses--; + goto notfound; + } + foundino = ulfs_rw32(ep->d_ino, needswap); + dp->i_reclen = ulfs_rw16(ep->d_reclen, needswap); + goto found; + } + } + prevoff = dp->i_offset; + dp->i_offset += ulfs_rw16(ep->d_reclen, needswap); + entryoffsetinblock += ulfs_rw16(ep->d_reclen, needswap); + if (ep->d_ino) + enduseful = dp->i_offset; + } +notfound: + /* + * If we started in the middle of the directory and failed + * to find our target, we must check the beginning as well. + */ + if (numdirpasses == 2) { + numdirpasses--; + dp->i_offset = 0; + endsearch = dp->i_diroff; + goto searchloop; + } + if (bp != NULL) + brelse(bp, 0); + /* + * If creating, and at end of pathname and current + * directory has not been removed, then can consider + * allowing file to be created. + */ + if ((nameiop == CREATE || nameiop == RENAME || + (nameiop == DELETE && + (ap->a_cnp->cn_flags & DOWHITEOUT) && + (ap->a_cnp->cn_flags & ISWHITEOUT))) && + (flags & ISLASTCN) && dp->i_nlink != 0) { + /* + * Access for write is interpreted as allowing + * creation of files in the directory. + */ + error = VOP_ACCESS(vdp, VWRITE, cred); + if (error) + goto out; + /* + * Return an indication of where the new directory + * entry should be put. If we didn't find a slot, + * then set dp->i_count to 0 indicating + * that the new slot belongs at the end of the + * directory. If we found a slot, then the new entry + * can be put in the range from dp->i_offset to + * dp->i_offset + dp->i_count. + */ + if (slotstatus == NONE) { + dp->i_offset = roundup(dp->i_size, dirblksiz); + dp->i_count = 0; + enduseful = dp->i_offset; + } else if (nameiop == DELETE) { + dp->i_offset = slotoffset; + if ((dp->i_offset & (dirblksiz - 1)) == 0) + dp->i_count = 0; + else + dp->i_count = dp->i_offset - prevoff; + } else { + dp->i_offset = slotoffset; + dp->i_count = slotsize; + if (enduseful < slotoffset + slotsize) + enduseful = slotoffset + slotsize; + } + dp->i_endoff = roundup(enduseful, dirblksiz); +#if 0 /* commented out by dbj. none of the on disk fields changed */ + dp->i_flag |= IN_CHANGE | IN_UPDATE; +#endif + /* + * We return with the directory locked, so that + * the parameters we set up above will still be + * valid if we actually decide to do a direnter(). + * We return ni_vp == NULL to indicate that the entry + * does not currently exist; we leave a pointer to + * the (locked) directory inode in ndp->ni_dvp. + * The pathname buffer is saved so that the name + * can be obtained later. + * + * NB - if the directory is unlocked, then this + * information cannot be used. + */ + cnp->cn_flags |= SAVENAME; + error = EJUSTRETURN; + goto out; + } + /* + * Insert name into cache (as non-existent) if appropriate. + */ + if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) + cache_enter(vdp, *vpp, cnp); + error = ENOENT; + goto out; + +found: + if (numdirpasses == 2) + nchstats.ncs_pass2++; + /* + * Check that directory length properly reflects presence + * of this entry. + */ + if (dp->i_offset + DIRSIZ(FSFMT(vdp), ep, needswap) > dp->i_size) { + ulfs_dirbad(dp, dp->i_offset, "i_size too small"); + dp->i_size = dp->i_offset + DIRSIZ(FSFMT(vdp), ep, needswap); + DIP_ASSIGN(dp, size, dp->i_size); + dp->i_flag |= IN_CHANGE | IN_UPDATE; + } + brelse(bp, 0); + + /* + * Found component in pathname. + * If the final component of path name, save information + * in the cache as to where the entry was found. + */ + if ((flags & ISLASTCN) && nameiop == LOOKUP) + dp->i_diroff = dp->i_offset &~ (dirblksiz - 1); + + /* + * If deleting, and at end of pathname, return + * parameters which can be used to remove file. + * Lock the inode, being careful with ".". + */ + if (nameiop == DELETE && (flags & ISLASTCN)) { + /* + * Write access to directory required to delete files. + */ + error = VOP_ACCESS(vdp, VWRITE, cred); + if (error) + goto out; + /* + * Return pointer to current entry in dp->i_offset, + * and distance past previous entry (if there + * is a previous entry in this block) in dp->i_count. + * Save directory inode pointer in ndp->ni_dvp for dirremove(). + */ + if ((dp->i_offset & (dirblksiz - 1)) == 0) + dp->i_count = 0; + else + dp->i_count = dp->i_offset - prevoff; + if (dp->i_number == foundino) { + vref(vdp); + *vpp = vdp; + error = 0; + goto out; + } + if (flags & ISDOTDOT) + VOP_UNLOCK(vdp, 0); /* race to get the inode */ + error = VFS_VGET(vdp->v_mount, foundino, &tdp); + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + if (error) + goto out; + /* + * If directory is "sticky", then user must own + * the directory, or the file in it, else she + * may not delete it (unless she's root). This + * implements append-only directories. + */ + if ((dp->i_mode & ISVTX) && + kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, + NULL) != 0 && + kauth_cred_geteuid(cred) != dp->i_uid && + VTOI(tdp)->i_uid != kauth_cred_geteuid(cred)) { + vput(tdp); + error = EPERM; + goto out; + } + *vpp = tdp; + error = 0; + goto out; + } + + /* + * If rewriting (RENAME), return the inode and the + * information required to rewrite the present directory + * Must get inode of directory entry to verify it's a + * regular file, or empty directory. + */ + if (nameiop == RENAME && (flags & ISLASTCN)) { + error = VOP_ACCESS(vdp, VWRITE, cred); + if (error) + goto out; + /* + * Careful about locking second inode. + * This can only occur if the target is ".". + */ + if (dp->i_number == foundino) { + error = EISDIR; + goto out; + } + if (flags & ISDOTDOT) + VOP_UNLOCK(vdp, 0); /* race to get the inode */ + error = VFS_VGET(vdp->v_mount, foundino, &tdp); + if (flags & ISDOTDOT) + vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); + if (error) + goto out; + *vpp = tdp; + cnp->cn_flags |= SAVENAME; + error = 0; + goto out; + } + + /* + * Step through the translation in the name. We do not `vput' the + * directory because we may need it again if a symbolic link + * is relative to the current directory. Instead we save it + * unlocked as "pdp". We must get the target inode before unlocking + * the directory to insure that the inode will not be removed + * before we get it. We prevent deadlock by always fetching + * inodes from the root, moving down the directory tree. Thus + * when following backward pointers ".." we must unlock the + * parent directory before getting the requested directory. + * There is a potential race condition here if both the current + * and parent directories are removed before the VFS_VGET for the + * inode associated with ".." returns. We hope that this occurs + * infrequently since we cannot avoid this race condition without + * implementing a sophisticated deadlock detection algorithm. + * Note also that this simple deadlock detection scheme will not + * work if the file system has any hard links other than ".." + * that point backwards in the directory structure. + */ + pdp = vdp; + if (flags & ISDOTDOT) { + VOP_UNLOCK(pdp, 0); /* race to get the inode */ + error = VFS_VGET(vdp->v_mount, foundino, &tdp); + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); + if (error) { + goto out; + } + *vpp = tdp; + } else if (dp->i_number == foundino) { + vref(vdp); /* we want ourself, ie "." */ + *vpp = vdp; + } else { + error = VFS_VGET(vdp->v_mount, foundino, &tdp); + if (error) + goto out; + *vpp = tdp; + } + + /* + * Insert name into cache if appropriate. + */ + if (cnp->cn_flags & MAKEENTRY) + cache_enter(vdp, *vpp, cnp); + error = 0; + +out: + fstrans_done(vdp->v_mount); + return error; +} + +void +ulfs_dirbad(struct lfs_inode *ip, lfs_doff_t offset, const char *how) +{ + struct mount *mp; + + mp = ITOV(ip)->v_mount; + printf("%s: bad dir ino %llu at offset %d: %s\n", + mp->mnt_stat.f_mntonname, (unsigned long long)ip->i_number, + offset, how); + if ((mp->mnt_stat.f_flag & MNT_RDONLY) == 0) + panic("bad dir"); +} + +/* + * Do consistency checking on a directory entry: + * record length must be multiple of 4 + * entry must fit in rest of its DIRBLKSIZ block + * record must be large enough to contain entry + * name is not longer than LFS_MAXNAMLEN + * name must be as long as advertised, and null terminated + */ +int +ulfs_dirbadentry(struct vnode *dp, struct direct *ep, int entryoffsetinblock) +{ + int i; + int namlen; + struct ulfsmount *ump = VFSTOULFS(dp->v_mount); + const int needswap = ULFS_MPNEEDSWAP(ump); + int dirblksiz = ump->um_dirblksiz; + +#if (BYTE_ORDER == LITTLE_ENDIAN) + if (FSFMT(dp) && needswap == 0) + namlen = ep->d_type; + else + namlen = ep->d_namlen; +#else + if (FSFMT(dp) && needswap != 0) + namlen = ep->d_type; + else + namlen = ep->d_namlen; +#endif + if ((ulfs_rw16(ep->d_reclen, needswap) & 0x3) != 0 || + ulfs_rw16(ep->d_reclen, needswap) > + dirblksiz - (entryoffsetinblock & (dirblksiz - 1)) || + ulfs_rw16(ep->d_reclen, needswap) < + DIRSIZ(FSFMT(dp), ep, needswap) || + namlen > LFS_MAXNAMLEN) { + /*return (1); */ + printf("First bad, reclen=%#x, DIRSIZ=%lu, namlen=%d, " + "flags=%#x, entryoffsetinblock=%d, dirblksiz = %d\n", + ulfs_rw16(ep->d_reclen, needswap), + (u_long)DIRSIZ(FSFMT(dp), ep, needswap), + namlen, dp->v_mount->mnt_flag, entryoffsetinblock, + dirblksiz); + goto bad; + } + if (ep->d_ino == 0) + return (0); + for (i = 0; i < namlen; i++) + if (ep->d_name[i] == '\0') { + /*return (1); */ + printf("Second bad\n"); + goto bad; + } + if (ep->d_name[i]) + goto bad; + return (0); +bad: + return (1); +} + +/* + * Construct a new directory entry after a call to namei, using the + * parameters that it left in the componentname argument cnp. The + * argument ip is the inode to which the new directory entry will refer. + */ +void +ulfs_makedirentry(struct lfs_inode *ip, struct componentname *cnp, + struct direct *newdirp) +{ +#ifdef DIAGNOSTIC + if ((cnp->cn_flags & SAVENAME) == 0) + panic("makedirentry: missing name"); +#endif + newdirp->d_ino = ip->i_number; + newdirp->d_namlen = cnp->cn_namelen; + memcpy(newdirp->d_name, cnp->cn_nameptr, (size_t)cnp->cn_namelen); + newdirp->d_name[cnp->cn_namelen] = '\0'; + if (FSFMT(ITOV(ip))) + newdirp->d_type = 0; + else + newdirp->d_type = IFTODT(ip->i_mode); +} + +/* + * Write a directory entry after a call to namei, using the parameters + * that it left in nameidata. The argument dirp is the new directory + * entry contents. Dvp is a pointer to the directory to be written, + * which was left locked by namei. Remaining parameters (dp->i_offset, + * dp->i_count) indicate how the space for the new entry is to be obtained. + * Non-null bp indicates that a directory is being created (for the + * soft dependency code). + */ +int +ulfs_direnter(struct vnode *dvp, struct vnode *tvp, struct direct *dirp, + struct componentname *cnp, struct buf *newdirbp) +{ + kauth_cred_t cr; + struct lwp *l; + int newentrysize; + struct lfs_inode *dp; + struct buf *bp; + u_int dsize; + struct direct *ep, *nep; + int error, ret, blkoff, loc, spacefree; + char *dirbuf; + struct timespec ts; + struct ulfsmount *ump = VFSTOULFS(dvp->v_mount); + const int needswap = ULFS_MPNEEDSWAP(ump); + int dirblksiz = ump->um_dirblksiz; + + error = 0; + cr = cnp->cn_cred; + l = curlwp; + + dp = VTOI(dvp); + newentrysize = DIRSIZ(0, dirp, 0); + + if (dp->i_count == 0) { + /* + * If dp->i_count is 0, then namei could find no + * space in the directory. Here, dp->i_offset will + * be on a directory block boundary and we will write the + * new entry into a fresh block. + */ + if (dp->i_offset & (dirblksiz - 1)) + panic("ulfs_direnter: newblk"); + if ((error = ULFS_BALLOC(dvp, (off_t)dp->i_offset, dirblksiz, + cr, B_CLRBUF | B_SYNC, &bp)) != 0) { + return (error); + } + dp->i_size = dp->i_offset + dirblksiz; + DIP_ASSIGN(dp, size, dp->i_size); + dp->i_flag |= IN_CHANGE | IN_UPDATE; + uvm_vnp_setsize(dvp, dp->i_size); + dirp->d_reclen = ulfs_rw16(dirblksiz, needswap); + dirp->d_ino = ulfs_rw32(dirp->d_ino, needswap); + if (FSFMT(dvp)) { +#if (BYTE_ORDER == LITTLE_ENDIAN) + if (needswap == 0) { +#else + if (needswap != 0) { +#endif + u_char tmp = dirp->d_namlen; + dirp->d_namlen = dirp->d_type; + dirp->d_type = tmp; + } + } + blkoff = dp->i_offset & (ump->um_mountp->mnt_stat.f_iosize - 1); + memcpy((char *)bp->b_data + blkoff, dirp, newentrysize); +#ifdef LFS_DIRHASH + if (dp->i_dirhash != NULL) { + ulfsdirhash_newblk(dp, dp->i_offset); + ulfsdirhash_add(dp, dirp, dp->i_offset); + ulfsdirhash_checkblock(dp, (char *)bp->b_data + blkoff, + dp->i_offset); + } +#endif + error = VOP_BWRITE(bp); + vfs_timestamp(&ts); + ret = ULFS_UPDATE(dvp, &ts, &ts, UPDATE_DIROP); + if (error == 0) + return (ret); + return (error); + } + + /* + * If dp->i_count is non-zero, then namei found space for the new + * entry in the range dp->i_offset to dp->i_offset + dp->i_count + * in the directory. To use this space, we may have to compact + * the entries located there, by copying them together towards the + * beginning of the block, leaving the free space in one usable + * chunk at the end. + */ + + /* + * Increase size of directory if entry eats into new space. + * This should never push the size past a new multiple of + * DIRBLKSIZ. + * + * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. + */ + if (dp->i_offset + dp->i_count > dp->i_size) { + dp->i_size = dp->i_offset + dp->i_count; + DIP_ASSIGN(dp, size, dp->i_size); + dp->i_flag |= IN_CHANGE | IN_UPDATE; + } + /* + * Get the block containing the space for the new directory entry. + */ + error = ulfs_blkatoff(dvp, (off_t)dp->i_offset, &dirbuf, &bp, true); + if (error) { + return (error); + } + /* + * Find space for the new entry. In the simple case, the entry at + * offset base will have the space. If it does not, then namei + * arranged that compacting the region dp->i_offset to + * dp->i_offset + dp->i_count would yield the space. + */ + ep = (struct direct *)dirbuf; + dsize = (ep->d_ino != 0) ? DIRSIZ(FSFMT(dvp), ep, needswap) : 0; + spacefree = ulfs_rw16(ep->d_reclen, needswap) - dsize; + for (loc = ulfs_rw16(ep->d_reclen, needswap); loc < dp->i_count; ) { + uint16_t reclen; + + nep = (struct direct *)(dirbuf + loc); + + /* Trim the existing slot (NB: dsize may be zero). */ + ep->d_reclen = ulfs_rw16(dsize, needswap); + ep = (struct direct *)((char *)ep + dsize); + + reclen = ulfs_rw16(nep->d_reclen, needswap); + loc += reclen; + if (nep->d_ino == 0) { + /* + * A mid-block unused entry. Such entries are + * never created by the kernel, but fsck_ffs + * can create them (and it doesn't fix them). + * + * Add up the free space, and initialise the + * relocated entry since we don't memcpy it. + */ + spacefree += reclen; + ep->d_ino = 0; + dsize = 0; + continue; + } + dsize = DIRSIZ(FSFMT(dvp), nep, needswap); + spacefree += reclen - dsize; +#ifdef LFS_DIRHASH + if (dp->i_dirhash != NULL) + ulfsdirhash_move(dp, nep, + dp->i_offset + ((char *)nep - dirbuf), + dp->i_offset + ((char *)ep - dirbuf)); +#endif + memcpy((void *)ep, (void *)nep, dsize); + } + /* + * Here, `ep' points to a directory entry containing `dsize' in-use + * bytes followed by `spacefree' unused bytes. If ep->d_ino == 0, + * then the entry is completely unused (dsize == 0). The value + * of ep->d_reclen is always indeterminate. + * + * Update the pointer fields in the previous entry (if any), + * copy in the new entry, and write out the block. + */ + if (ep->d_ino == 0 || + (ulfs_rw32(ep->d_ino, needswap) == WINO && + memcmp(ep->d_name, dirp->d_name, dirp->d_namlen) == 0)) { + if (spacefree + dsize < newentrysize) + panic("ulfs_direnter: compact1"); + dirp->d_reclen = spacefree + dsize; + } else { + if (spacefree < newentrysize) + panic("ulfs_direnter: compact2"); + dirp->d_reclen = spacefree; + ep->d_reclen = ulfs_rw16(dsize, needswap); + ep = (struct direct *)((char *)ep + dsize); + } + dirp->d_reclen = ulfs_rw16(dirp->d_reclen, needswap); + dirp->d_ino = ulfs_rw32(dirp->d_ino, needswap); + if (FSFMT(dvp)) { +#if (BYTE_ORDER == LITTLE_ENDIAN) + if (needswap == 0) { +#else + if (needswap != 0) { +#endif + u_char tmp = dirp->d_namlen; + dirp->d_namlen = dirp->d_type; + dirp->d_type = tmp; + } + } +#ifdef LFS_DIRHASH + if (dp->i_dirhash != NULL && (ep->d_ino == 0 || + dirp->d_reclen == spacefree)) + ulfsdirhash_add(dp, dirp, dp->i_offset + ((char *)ep - dirbuf)); +#endif + memcpy((void *)ep, (void *)dirp, (u_int)newentrysize); +#ifdef LFS_DIRHASH + if (dp->i_dirhash != NULL) + ulfsdirhash_checkblock(dp, dirbuf - + (dp->i_offset & (dirblksiz - 1)), + dp->i_offset & ~(dirblksiz - 1)); +#endif + error = VOP_BWRITE(bp); + dp->i_flag |= IN_CHANGE | IN_UPDATE; + /* + * If all went well, and the directory can be shortened, proceed + * with the truncation. Note that we have to unlock the inode for + * the entry that we just entered, as the truncation may need to + * lock other inodes which can lead to deadlock if we also hold a + * lock on the newly entered node. + */ + if (error == 0 && dp->i_endoff && dp->i_endoff < dp->i_size) { +#ifdef LFS_DIRHASH + if (dp->i_dirhash != NULL) + ulfsdirhash_dirtrunc(dp, dp->i_endoff); +#endif + (void) ULFS_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, cr); + } + return (error); +} + +/* + * Remove a directory entry after a call to namei, using + * the parameters which it left in nameidata. The entry + * dp->i_offset contains the offset into the directory of the + * entry to be eliminated. The dp->i_count field contains the + * size of the previous record in the directory. If this + * is 0, the first entry is being deleted, so we need only + * zero the inode number to mark the entry as free. If the + * entry is not the first in the directory, we must reclaim + * the space of the now empty record by adding the record size + * to the size of the previous entry. + */ +int +ulfs_dirremove(struct vnode *dvp, struct lfs_inode *ip, int flags, int isrmdir) +{ + struct lfs_inode *dp = VTOI(dvp); + struct direct *ep; + struct buf *bp; + int error; +#ifdef LFS_EI + const int needswap = ULFS_MPNEEDSWAP(dp->i_ump); +#endif + + if (flags & DOWHITEOUT) { + /* + * Whiteout entry: set d_ino to WINO. + */ + error = ulfs_blkatoff(dvp, (off_t)dp->i_offset, (void *)&ep, + &bp, true); + if (error) + return (error); + ep->d_ino = ulfs_rw32(WINO, needswap); + ep->d_type = DT_WHT; + goto out; + } + + if ((error = ulfs_blkatoff(dvp, + (off_t)(dp->i_offset - dp->i_count), (void *)&ep, &bp, true)) != 0) + return (error); + +#ifdef LFS_DIRHASH + /* + * Remove the dirhash entry. This is complicated by the fact + * that `ep' is the previous entry when dp->i_count != 0. + */ + if (dp->i_dirhash != NULL) + ulfsdirhash_remove(dp, (dp->i_count == 0) ? ep : + (struct direct *)((char *)ep + + ulfs_rw16(ep->d_reclen, needswap)), dp->i_offset); +#endif + + if (dp->i_count == 0) { + /* + * First entry in block: set d_ino to zero. + */ + ep->d_ino = 0; + } else { + /* + * Collapse new free space into previous entry. + */ + ep->d_reclen = + ulfs_rw16(ulfs_rw16(ep->d_reclen, needswap) + dp->i_reclen, + needswap); + } + +#ifdef LFS_DIRHASH + if (dp->i_dirhash != NULL) { + int dirblksiz = ip->i_ump->um_dirblksiz; + ulfsdirhash_checkblock(dp, (char *)ep - + ((dp->i_offset - dp->i_count) & (dirblksiz - 1)), + dp->i_offset & ~(dirblksiz - 1)); + } +#endif + +out: + if (ip) { + ip->i_nlink--; + DIP_ASSIGN(ip, nlink, ip->i_nlink); + ip->i_flag |= IN_CHANGE; + } + error = VOP_BWRITE(bp); + dp->i_flag |= IN_CHANGE | IN_UPDATE; +#ifdef LFS_SNAPSHOT + /* + * If the last named reference to a snapshot goes away, + * drop its snapshot reference so that it will be reclaimed + * when last open reference goes away. + */ + if (ip != 0 && (ip->i_flags & SF_SNAPSHOT) != 0 && + ip->i_nlink == 0) + ffs_snapgone(ip); +#endif + return (error); +} + +/* + * Rewrite an existing directory entry to point at the inode + * supplied. The parameters describing the directory entry are + * set up by a call to namei. + */ +int +ulfs_dirrewrite(struct lfs_inode *dp, struct lfs_inode *oip, ino_t newinum, int newtype, + int isrmdir, int iflags) +{ + struct buf *bp; + struct direct *ep; + struct vnode *vdp = ITOV(dp); + int error; + + error = ulfs_blkatoff(vdp, (off_t)dp->i_offset, (void *)&ep, &bp, true); + if (error) + return (error); + ep->d_ino = ulfs_rw32(newinum, ULFS_MPNEEDSWAP(dp->i_ump)); + if (!FSFMT(vdp)) + ep->d_type = newtype; + oip->i_nlink--; + DIP_ASSIGN(oip, nlink, oip->i_nlink); + oip->i_flag |= IN_CHANGE; + error = VOP_BWRITE(bp); + dp->i_flag |= iflags; +#ifdef LFS_SNAPSHOT + /* + * If the last named reference to a snapshot goes away, + * drop its snapshot reference so that it will be reclaimed + * when last open reference goes away. + */ + if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_nlink == 0) + ffs_snapgone(oip); +#endif + return (error); +} + +/* + * Check if a directory is empty or not. + * Inode supplied must be locked. + * + * Using a struct dirtemplate here is not precisely + * what we want, but better than using a struct direct. + * + * NB: does not handle corrupted directories. + */ +int +ulfs_dirempty(struct lfs_inode *ip, ino_t parentino, kauth_cred_t cred) +{ + lfs_doff_t off; + struct dirtemplate dbuf; + struct direct *dp = (struct direct *)&dbuf; + int error, namlen; + size_t count; + const int needswap = ULFS_IPNEEDSWAP(ip); +#define MINDIRSIZ (sizeof (struct dirtemplate) / 2) + + for (off = 0; off < ip->i_size; + off += ulfs_rw16(dp->d_reclen, needswap)) { + error = vn_rdwr(UIO_READ, ITOV(ip), (void *)dp, MINDIRSIZ, off, + UIO_SYSSPACE, IO_NODELOCKED, cred, &count, NULL); + /* + * Since we read MINDIRSIZ, residual must + * be 0 unless we're at end of file. + */ + if (error || count != 0) + return (0); + /* avoid infinite loops */ + if (dp->d_reclen == 0) + return (0); + /* skip empty entries */ + if (dp->d_ino == 0 || ulfs_rw32(dp->d_ino, needswap) == WINO) + continue; + /* accept only "." and ".." */ +#if (BYTE_ORDER == LITTLE_ENDIAN) + if (FSFMT(ITOV(ip)) && needswap == 0) + namlen = dp->d_type; + else + namlen = dp->d_namlen; +#else + if (FSFMT(ITOV(ip)) && needswap != 0) + namlen = dp->d_type; + else + namlen = dp->d_namlen; +#endif + if (namlen > 2) + return (0); + if (dp->d_name[0] != '.') + return (0); + /* + * At this point namlen must be 1 or 2. + * 1 implies ".", 2 implies ".." if second + * char is also "." + */ + if (namlen == 1 && + ulfs_rw32(dp->d_ino, needswap) == ip->i_number) + continue; + if (dp->d_name[1] == '.' && + ulfs_rw32(dp->d_ino, needswap) == parentino) + continue; + return (0); + } + return (1); +} + +/* + * Check if source directory is in the path of the target directory. + * Target is supplied locked, source is unlocked. + * The target is always vput before returning. + */ +int +ulfs_checkpath(struct lfs_inode *source, struct lfs_inode *target, kauth_cred_t cred) +{ + struct vnode *nextvp, *vp; + int error, rootino, namlen; + struct dirtemplate dirbuf; + const int needswap = ULFS_MPNEEDSWAP(target->i_ump); + + vp = ITOV(target); + if (target->i_number == source->i_number) { + error = EEXIST; + goto out; + } + rootino = ROOTINO; + error = 0; + if (target->i_number == rootino) + goto out; + + for (;;) { + if (vp->v_type != VDIR) { + error = ENOTDIR; + break; + } + error = vn_rdwr(UIO_READ, vp, (void *)&dirbuf, + sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, + IO_NODELOCKED, cred, NULL, NULL); + if (error != 0) + break; +#if (BYTE_ORDER == LITTLE_ENDIAN) + if (FSFMT(vp) && needswap == 0) + namlen = dirbuf.dotdot_type; + else + namlen = dirbuf.dotdot_namlen; +#else + if (FSFMT(vp) && needswap != 0) + namlen = dirbuf.dotdot_type; + else + namlen = dirbuf.dotdot_namlen; +#endif + if (namlen != 2 || + dirbuf.dotdot_name[0] != '.' || + dirbuf.dotdot_name[1] != '.') { + error = ENOTDIR; + break; + } + if (ulfs_rw32(dirbuf.dotdot_ino, needswap) == source->i_number) { + error = EINVAL; + break; + } + if (ulfs_rw32(dirbuf.dotdot_ino, needswap) == rootino) + break; + VOP_UNLOCK(vp, 0); + error = VFS_VGET(vp->v_mount, + ulfs_rw32(dirbuf.dotdot_ino, needswap), &nextvp); + vrele(vp); + if (error) { + vp = NULL; + break; + } + vp = nextvp; + } + +out: + if (error == ENOTDIR) + printf("checkpath: .. not a directory\n"); + if (vp != NULL) + vput(vp); + return (error); +} + +#define ULFS_DIRRABLKS 0 +int ulfs_dirrablks = ULFS_DIRRABLKS; + +/* + * ulfs_blkatoff: Return buffer with the contents of block "offset" from + * the beginning of directory "vp". If "res" is non-zero, fill it in with + * a pointer to the remaining space in the directory. If the caller intends + * to modify the buffer returned, "modify" must be true. + */ + +int +ulfs_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp, + bool modify) +{ + struct lfs_inode *ip; + struct buf *bp; + daddr_t lbn; + const int dirrablks = ulfs_dirrablks; + daddr_t *blks; + int *blksizes; + int run, error; + struct mount *mp = vp->v_mount; + const int bshift = mp->mnt_fs_bshift; + const int bsize = 1 << bshift; + off_t eof; + + blks = kmem_alloc((1 + dirrablks) * sizeof(daddr_t), KM_SLEEP); + blksizes = kmem_alloc((1 + dirrablks) * sizeof(int), KM_SLEEP); + ip = VTOI(vp); + KASSERT(vp->v_size == ip->i_size); + GOP_SIZE(vp, vp->v_size, &eof, 0); + lbn = offset >> bshift; + + for (run = 0; run <= dirrablks;) { + const off_t curoff = lbn << bshift; + const int size = MIN(eof - curoff, bsize); + + if (size == 0) { + break; + } + KASSERT(curoff < eof); + blks[run] = lbn; + blksizes[run] = size; + lbn++; + run++; + if (size != bsize) { + break; + } + } + KASSERT(run >= 1); + error = breadn(vp, blks[0], blksizes[0], &blks[1], &blksizes[1], + run - 1, NOCRED, (modify ? B_MODIFY : 0), &bp); + if (error != 0) { + brelse(bp, 0); + *bpp = NULL; + goto out; + } + if (res) { + *res = (char *)bp->b_data + (offset & (bsize - 1)); + } + *bpp = bp; + + out: + kmem_free(blks, (1 + dirrablks) * sizeof(daddr_t)); + kmem_free(blksizes, (1 + dirrablks) * sizeof(int)); + return error; +} diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_mount.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_mount.h Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,153 @@ +/* $NetBSD: ulfs_mount.h,v 1.35 2008/11/13 11:09:45 ad Exp $ */ +/* from NetBSD: ufs_mount.h,v 1.35 2008/11/13 11:09:45 ad 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. + * + * @(#)ufs_mount.h 8.6 (Berkeley) 3/30/95 + */ + +#ifndef _UFS_LFS_ULFS_MOUNT_H_ +#define _UFS_LFS_ULFS_MOUNT_H_ + +#include /* struct export_args30 */ + +/* + * Arguments to mount MFS + */ +struct mfs_args { + char *fspec; /* name to export for statfs */ + struct export_args30 _pad1; /* compat with old userland tools */ + void * base; /* base of file system in memory */ + u_long size; /* size of file system */ +}; + +#ifdef _KERNEL + +#if defined(_KERNEL_OPT) +#include "opt_lfs.h" +#include "opt_ffs.h" /* XXX */ +#endif + +#include + +#include +#include + +struct buf; +struct lfs_inode; +struct nameidata; +struct timeval; +struct uio; +struct vnode; + +/* This structure describes the ULFS specific mount structure data. */ +struct ulfsmount { + struct mount *um_mountp; /* filesystem vfs structure */ + dev_t um_dev; /* device mounted */ + struct vnode *um_devvp; /* block device mounted vnode */ + u_long um_unused; + u_int32_t um_flags; /* ULFS-specific flags - see below */ + union { /* pointer to superblock */ + struct lfs *lfs; /* LFS */ + } ulfsmount_u; +#define um_lfs ulfsmount_u.lfs + + /* Extended attribute information. */ + struct ulfs_extattr_per_mount um_extattr; + + struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */ + kauth_cred_t um_cred[MAXQUOTAS]; /* quota file access cred */ + u_long um_nindir; /* indirect ptrs per block */ + u_long um_lognindir; /* log2 of um_nindir */ + u_long um_bptrtodb; /* indir ptr to disk block */ + u_long um_seqinc; /* inc between seq blocks */ + kmutex_t um_lock; /* lock on global data */ + time_t um_btime[MAXQUOTAS]; /* block quota time limit */ + time_t um_itime[MAXQUOTAS]; /* inode quota time limit */ + char um_qflags[MAXQUOTAS]; /* quota specific flags */ + void *um_oldfscompat; /* save 4.2 rotbl */ + int um_maxsymlinklen; + int um_dirblksiz; + u_int64_t um_maxfilesize; + void *um_snapinfo; /* snapshot private data */ + + const struct ulfs_ops *um_ops; +}; + +struct ulfs_ops { + void (*uo_itimes)(struct lfs_inode *ip, const struct timespec *, + const struct timespec *, const struct timespec *); + int (*uo_update)(struct vnode *, const struct timespec *, + const struct timespec *, int); + int (*uo_truncate)(struct vnode *, off_t, int, kauth_cred_t); + int (*uo_valloc)(struct vnode *, int, kauth_cred_t, struct vnode **); + int (*uo_vfree)(struct vnode *, ino_t, int); + int (*uo_balloc)(struct vnode *, off_t, int, kauth_cred_t, int, + struct buf **); + void (*uo_unmark_vnode)(struct vnode *); +}; + +#define ULFS_OPS(vp) (VFSTOULFS((vp)->v_mount)->um_ops) + +#define ULFS_ITIMES(vp, acc, mod, cre) \ + (*ULFS_OPS(vp)->uo_itimes)(VTOI(vp), (acc), (mod), (cre)) +#define ULFS_UPDATE(vp, acc, mod, flags) \ + (*ULFS_OPS(vp)->uo_update)((vp), (acc), (mod), (flags)) +#define ULFS_TRUNCATE(vp, off, flags, cr) \ + (*ULFS_OPS(vp)->uo_truncate)((vp), (off), (flags), (cr)) +#define ULFS_VALLOC(vp, mode, cr, vpp) \ + (*ULFS_OPS(vp)->uo_valloc)((vp), (mode), (cr), (vpp)) +#define ULFS_VFREE(vp, ino, mode) \ + (*ULFS_OPS(vp)->uo_vfree)((vp), (ino), (mode)) +#define ULFS_BALLOC(vp, off, size, cr, flags, bpp) \ + (*ULFS_OPS(vp)->uo_balloc)((vp), (off), (size), (cr), (flags), (bpp)) +#define ULFS_UNMARK_VNODE(vp) \ + (*ULFS_OPS(vp)->uo_unmark_vnode)((vp)) + +/* ULFS-specific flags */ +#define ULFS_NEEDSWAP 0x01 /* filesystem metadata need byte-swapping */ + +/* + * Flags describing the state of quotas. + */ +#define QTF_OPENING 0x01 /* Q_QUOTAON in progress */ +#define QTF_CLOSING 0x02 /* Q_QUOTAOFF in progress */ + +/* Convert mount ptr to ulfsmount ptr. */ +#define VFSTOULFS(mp) ((struct ulfsmount *)((mp)->mnt_data)) + +/* + * Macros to access file system parameters in the ulfsmount structure. + * Used by ulfs_bmap. + */ +#define MNINDIR(ump) ((ump)->um_nindir) +#define blkptrtodb(ump, b) ((b) << (ump)->um_bptrtodb) +#endif /* _KERNEL */ + +#endif /* !_UFS_LFS_ULFS_MOUNT_H_ */ diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_quota.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_quota.c Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,1038 @@ +/* $NetBSD: ulfs_quota.c,v 1.62 2009/05/07 19:26:09 elad Exp $ */ +/* from NetBSD: ufs_quota.c,v 1.65 2010/01/15 19:46:35 bouyer Exp */ + +/* + * Copyright (c) 1982, 1986, 1990, 1993, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Elz at The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: ulfs_quota.c,v 1.64 2009/08/02 20:50:33 bouyer Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * The following structure records disk usage for a user or group on a + * filesystem. There is one allocated for each quota that exists on any + * filesystem for the current user or group. A cache is kept of recently + * used entries. + * Field markings and the corresponding locks: + * h: dqlock + * d: dq_interlock + * + * Lock order is: dq_interlock -> dqlock + * dq_interlock -> dqvp + */ +struct ulfs_dquot { + LIST_ENTRY(ulfs_dquot) dq_hash; /* h: hash list */ + u_int16_t dq_flags; /* d: flags, see below */ + u_int16_t dq_type; /* d: quota type of this dquot */ + u_int32_t dq_cnt; /* h: count of active references */ + u_int32_t dq_id; /* d: identifier this applies to */ + struct ulfsmount *dq_ump; /* d: filesystem this is taken from */ + kmutex_t dq_interlock; /* d: lock this dquot */ + struct dqblk dq_dqb; /* d: actual usage & quotas */ +}; +/* + * Flag values. + */ +#define DQ_MOD 0x04 /* this quota modified since read */ +#define DQ_FAKE 0x08 /* no limits here, just usage */ +#define DQ_BLKS 0x10 /* has been warned about blk limit */ +#define DQ_INODS 0x20 /* has been warned about inode limit */ +/* + * Shorthand notation. + */ +#define dq_bhardlimit dq_dqb.dqb_bhardlimit +#define dq_bsoftlimit dq_dqb.dqb_bsoftlimit +#define dq_curblocks dq_dqb.dqb_curblocks +#define dq_ihardlimit dq_dqb.dqb_ihardlimit +#define dq_isoftlimit dq_dqb.dqb_isoftlimit +#define dq_curinodes dq_dqb.dqb_curinodes +#define dq_btime dq_dqb.dqb_btime +#define dq_itime dq_dqb.dqb_itime +/* + * If the system has never checked for a quota for this file, then it is + * set to NODQUOT. Once a write attempt is made the inode pointer is set + * to reference a dquot structure. + */ +#define NODQUOT NULL + +static int lfs_chkdqchg(struct lfs_inode *, int64_t, kauth_cred_t, int); +static int lfs_chkiqchg(struct lfs_inode *, int32_t, kauth_cred_t, int); +#ifdef DIAGNOSTIC +static void lfs_dqflush(struct vnode *); +#endif +static int lfs_dqget(struct vnode *, u_long, struct ulfsmount *, int, + struct ulfs_dquot **); +static void lfs_dqref(struct ulfs_dquot *); +static void lfs_dqrele(struct vnode *, struct ulfs_dquot *); +static int lfs_dqsync(struct vnode *, struct ulfs_dquot *); + +static kmutex_t dqlock; +static kcondvar_t dqcv; +/* + * Quota name to error message mapping. + */ +static const char *quotatypes[] = INITQFNAMES; + +/* + * Set up the quotas for an inode. + * + * This routine completely defines the semantics of quotas. + * If other criterion want to be used to establish quotas, the + * MAXQUOTAS value in quotas.h should be increased, and the + * additional dquots set up here. + */ +int +lfs_getinoquota(struct lfs_inode *ip) +{ + struct ulfsmount *ump = ip->i_ump; + struct vnode *vp = ITOV(ip); + int i, error; + u_int32_t ino_ids[MAXQUOTAS]; + + /* + * To avoid deadlocks never update quotas for quota files + * on the same file system + */ + for (i = 0; i < MAXQUOTAS; i++) + if (ITOV(ip) == ump->um_quotas[i]) + return 0; + + ino_ids[USRQUOTA] = ip->i_uid; + ino_ids[GRPQUOTA] = ip->i_gid; + for (i = 0; i < MAXQUOTAS; i++) { + /* + * If the file id changed the quota needs update. + */ + if (ip->i_dquot[i] != NODQUOT && + ip->i_dquot[i]->dq_id != ino_ids[i]) { + lfs_dqrele(ITOV(ip), ip->i_dquot[i]); + ip->i_dquot[i] = NODQUOT; + } + /* + * Set up the quota based on file id. + * EINVAL means that quotas are not enabled. + */ + if (ip->i_dquot[i] == NODQUOT && + (error = lfs_dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) && + error != EINVAL) + return (error); + } + return 0; +} + +/* + * Initialize the quota fields of an inode. + */ +void +ulfsquota_init(struct lfs_inode *ip) +{ + int i; + + for (i = 0; i < MAXQUOTAS; i++) + ip->i_dquot[i] = NODQUOT; +} + +/* + * Release the quota fields from an inode. + */ +void +ulfsquota_free(struct lfs_inode *ip) +{ + int i; + + for (i = 0; i < MAXQUOTAS; i++) { + lfs_dqrele(ITOV(ip), ip->i_dquot[i]); + ip->i_dquot[i] = NODQUOT; + } +} + +/* + * Update disk usage, and take corrective action. + */ +int +lfs_chkdq(struct lfs_inode *ip, int64_t change, kauth_cred_t cred, int flags) +{ + struct ulfs_dquot *dq; + int i; + int ncurblocks, error; + + if ((error = lfs_getinoquota(ip)) != 0) + return error; + if (change == 0) + return (0); + if (change < 0) { + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = ip->i_dquot[i]) == NODQUOT) + continue; + mutex_enter(&dq->dq_interlock); + ncurblocks = dq->dq_curblocks + change; + if (ncurblocks >= 0) + dq->dq_curblocks = ncurblocks; + else + dq->dq_curblocks = 0; + dq->dq_flags &= ~DQ_BLKS; + dq->dq_flags |= DQ_MOD; + mutex_exit(&dq->dq_interlock); + } + return (0); + } + if ((flags & FORCE) == 0 && + kauth_authorize_system(cred, KAUTH_SYSTEM_FS_QUOTA, + KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT, NULL, NULL, NULL) != 0) { + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = ip->i_dquot[i]) == NODQUOT) + continue; + mutex_enter(&dq->dq_interlock); + error = lfs_chkdqchg(ip, change, cred, i); + mutex_exit(&dq->dq_interlock); + if (error != 0) + return (error); + } + } + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = ip->i_dquot[i]) == NODQUOT) + continue; + mutex_enter(&dq->dq_interlock); + dq->dq_curblocks += change; + dq->dq_flags |= DQ_MOD; + mutex_exit(&dq->dq_interlock); + } + return (0); +} + +/* + * Check for a valid change to a users allocation. + * Issue an error message if appropriate. + */ +static int +lfs_chkdqchg(struct lfs_inode *ip, int64_t change, kauth_cred_t cred, int type) +{ + struct ulfs_dquot *dq = ip->i_dquot[type]; + long ncurblocks = dq->dq_curblocks + change; + + KASSERT(mutex_owned(&dq->dq_interlock)); + /* + * If user would exceed their hard limit, disallow space allocation. + */ + if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) { + if ((dq->dq_flags & DQ_BLKS) == 0 && + ip->i_uid == kauth_cred_geteuid(cred)) { + uprintf("\n%s: write failed, %s disk limit reached\n", + ITOV(ip)->v_mount->mnt_stat.f_mntonname, + quotatypes[type]); + dq->dq_flags |= DQ_BLKS; + } + return (EDQUOT); + } + /* + * If user is over their soft limit for too long, disallow space + * allocation. Reset time limit as they cross their soft limit. + */ + if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) { + if (dq->dq_curblocks < dq->dq_bsoftlimit) { + dq->dq_btime = time_second + ip->i_ump->um_btime[type]; + if (ip->i_uid == kauth_cred_geteuid(cred)) + uprintf("\n%s: warning, %s %s\n", + ITOV(ip)->v_mount->mnt_stat.f_mntonname, + quotatypes[type], "disk quota exceeded"); + return (0); + } + if (time_second > dq->dq_btime) { + if ((dq->dq_flags & DQ_BLKS) == 0 && + ip->i_uid == kauth_cred_geteuid(cred)) { + uprintf("\n%s: write failed, %s %s\n", + ITOV(ip)->v_mount->mnt_stat.f_mntonname, + quotatypes[type], + "disk quota exceeded for too long"); + dq->dq_flags |= DQ_BLKS; + } + return (EDQUOT); + } + } + return (0); +} + +/* + * Check the inode limit, applying corrective action. + */ +int +lfs_chkiq(struct lfs_inode *ip, int32_t change, kauth_cred_t cred, int flags) +{ + struct ulfs_dquot *dq; + int i; + int ncurinodes, error; + + if ((error = lfs_getinoquota(ip)) != 0) + return error; + if (change == 0) + return (0); + if (change < 0) { + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = ip->i_dquot[i]) == NODQUOT) + continue; + mutex_enter(&dq->dq_interlock); + ncurinodes = dq->dq_curinodes + change; + if (ncurinodes >= 0) + dq->dq_curinodes = ncurinodes; + else + dq->dq_curinodes = 0; + dq->dq_flags &= ~DQ_INODS; + dq->dq_flags |= DQ_MOD; + mutex_exit(&dq->dq_interlock); + } + return (0); + } + if ((flags & FORCE) == 0 && kauth_authorize_system(cred, + KAUTH_SYSTEM_FS_QUOTA, KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT, NULL, + NULL, NULL) != 0) { + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = ip->i_dquot[i]) == NODQUOT) + continue; + mutex_enter(&dq->dq_interlock); + error = lfs_chkiqchg(ip, change, cred, i); + mutex_exit(&dq->dq_interlock); + if (error != 0) + return (error); + } + } + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = ip->i_dquot[i]) == NODQUOT) + continue; + mutex_enter(&dq->dq_interlock); + dq->dq_curinodes += change; + dq->dq_flags |= DQ_MOD; + mutex_exit(&dq->dq_interlock); + } + return (0); +} + +/* + * Check for a valid change to a users allocation. + * Issue an error message if appropriate. + */ +static int +lfs_chkiqchg(struct lfs_inode *ip, int32_t change, kauth_cred_t cred, int type) +{ + struct ulfs_dquot *dq = ip->i_dquot[type]; + long ncurinodes = dq->dq_curinodes + change; + + KASSERT(mutex_owned(&dq->dq_interlock)); + /* + * If user would exceed their hard limit, disallow inode allocation. + */ + if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) { + if ((dq->dq_flags & DQ_INODS) == 0 && + ip->i_uid == kauth_cred_geteuid(cred)) { + uprintf("\n%s: write failed, %s inode limit reached\n", + ITOV(ip)->v_mount->mnt_stat.f_mntonname, + quotatypes[type]); + dq->dq_flags |= DQ_INODS; + } + return (EDQUOT); + } + /* + * If user is over their soft limit for too long, disallow inode + * allocation. Reset time limit as they cross their soft limit. + */ + if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) { + if (dq->dq_curinodes < dq->dq_isoftlimit) { + dq->dq_itime = time_second + ip->i_ump->um_itime[type]; + if (ip->i_uid == kauth_cred_geteuid(cred)) + uprintf("\n%s: warning, %s %s\n", + ITOV(ip)->v_mount->mnt_stat.f_mntonname, + quotatypes[type], "inode quota exceeded"); + return (0); + } + if (time_second > dq->dq_itime) { + if ((dq->dq_flags & DQ_INODS) == 0 && + ip->i_uid == kauth_cred_geteuid(cred)) { + uprintf("\n%s: write failed, %s %s\n", + ITOV(ip)->v_mount->mnt_stat.f_mntonname, + quotatypes[type], + "inode quota exceeded for too long"); + dq->dq_flags |= DQ_INODS; + } + return (EDQUOT); + } + } + return (0); +} + +/* + * Code to process quotactl commands. + */ + +/* + * Q_QUOTAON - set up a quota file for a particular file system. + */ +int +lfs_quotaon(struct lwp *l, struct mount *mp, int type, void *fname) +{ + struct ulfsmount *ump = VFSTOULFS(mp); + struct vnode *vp, **vpp, *mvp; + struct ulfs_dquot *dq; + int error; + struct nameidata nd; + + vpp = &ump->um_quotas[type]; + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fname); + if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) + return (error); + vp = nd.ni_vp; + VOP_UNLOCK(vp, 0); + if (vp->v_type != VREG) { + (void) vn_close(vp, FREAD|FWRITE, l->l_cred); + return (EACCES); + } + if (*vpp != vp) + lfs_quotaoff(l, mp, type); + mutex_enter(&dqlock); + while ((ump->um_qflags[type] & (QTF_CLOSING | QTF_OPENING)) != 0) + cv_wait(&dqcv, &dqlock); + ump->um_qflags[type] |= QTF_OPENING; + mutex_exit(&dqlock); + mp->mnt_flag |= MNT_QUOTA; + vp->v_vflag |= VV_SYSTEM; /* XXXSMP */ + *vpp = vp; + /* + * Save the credential of the process that turned on quotas. + * Set up the time limits for this quota. + */ + kauth_cred_hold(l->l_cred); + ump->um_cred[type] = l->l_cred; + ump->um_btime[type] = MAX_DQ_TIME; + ump->um_itime[type] = MAX_IQ_TIME; + if (lfs_dqget(NULLVP, 0, ump, type, &dq) == 0) { + if (dq->dq_btime > 0) + ump->um_btime[type] = dq->dq_btime; + if (dq->dq_itime > 0) + ump->um_itime[type] = dq->dq_itime; + lfs_dqrele(NULLVP, dq); + } + /* Allocate a marker vnode. */ + if ((mvp = vnalloc(mp)) == NULL) { + error = ENOMEM; + goto out; + } + /* + * Search vnodes associated with this mount point, + * adding references to quota file being opened. + * NB: only need to add dquot's for inodes being modified. + */ + mutex_enter(&mntvnode_lock); +again: + for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) { + vmark(mvp, vp); + mutex_enter(&vp->v_interlock); + if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) || + vp->v_type == VNON || vp->v_writecount == 0 || + (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) { + mutex_exit(&vp->v_interlock); + continue; + } + mutex_exit(&mntvnode_lock); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) { + mutex_enter(&mntvnode_lock); + (void)vunmark(mvp); + goto again; + } + if ((error = lfs_getinoquota(VTOI(vp))) != 0) { + vput(vp); + mutex_enter(&mntvnode_lock); + (void)vunmark(mvp); + break; + } + vput(vp); + mutex_enter(&mntvnode_lock); + } + mutex_exit(&mntvnode_lock); + vnfree(mvp); + out: + mutex_enter(&dqlock); + ump->um_qflags[type] &= ~QTF_OPENING; + cv_broadcast(&dqcv); + mutex_exit(&dqlock); + if (error) + lfs_quotaoff(l, mp, type); + return (error); +} + +/* + * Q_QUOTAOFF - turn off disk quotas for a filesystem. + */ +int +lfs_quotaoff(struct lwp *l, struct mount *mp, int type) +{ + struct vnode *vp; + struct vnode *qvp, *mvp; + struct ulfsmount *ump = VFSTOULFS(mp); + struct ulfs_dquot *dq; + struct lfs_inode *ip; + kauth_cred_t cred; + int i, error; + + /* Allocate a marker vnode. */ + if ((mvp = vnalloc(mp)) == NULL) + return ENOMEM; + + mutex_enter(&dqlock); + while ((ump->um_qflags[type] & (QTF_CLOSING | QTF_OPENING)) != 0) + cv_wait(&dqcv, &dqlock); + if ((qvp = ump->um_quotas[type]) == NULLVP) { + mutex_exit(&dqlock); + vnfree(mvp); + return (0); + } + ump->um_qflags[type] |= QTF_CLOSING; + mutex_exit(&dqlock); + /* + * Search vnodes associated with this mount point, + * deleting any references to quota file being closed. + */ + mutex_enter(&mntvnode_lock); +again: + for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) { + vmark(mvp, vp); + mutex_enter(&vp->v_interlock); + if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) || + vp->v_type == VNON || + (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) { + mutex_exit(&vp->v_interlock); + continue; + } + mutex_exit(&mntvnode_lock); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) { + mutex_enter(&mntvnode_lock); + (void)vunmark(mvp); + goto again; + } + ip = VTOI(vp); + dq = ip->i_dquot[type]; + ip->i_dquot[type] = NODQUOT; + lfs_dqrele(vp, dq); + vput(vp); + mutex_enter(&mntvnode_lock); + } + mutex_exit(&mntvnode_lock); +#ifdef DIAGNOSTIC + lfs_dqflush(qvp); +#endif + qvp->v_vflag &= ~VV_SYSTEM; + error = vn_close(qvp, FREAD|FWRITE, l->l_cred); + mutex_enter(&dqlock); + ump->um_quotas[type] = NULLVP; + cred = ump->um_cred[type]; + ump->um_cred[type] = NOCRED; + for (i = 0; i < MAXQUOTAS; i++) + if (ump->um_quotas[i] != NULLVP) + break; + ump->um_qflags[type] &= ~QTF_CLOSING; + cv_broadcast(&dqcv); + mutex_exit(&dqlock); + kauth_cred_free(cred); + if (i == MAXQUOTAS) + mp->mnt_flag &= ~MNT_QUOTA; + return (error); +} + +/* + * Q_GETQUOTA - return current values in a dqblk structure. + */ +int +lfs_getquota(struct mount *mp, u_long id, int type, void *addr) +{ + struct ulfs_dquot *dq; + int error; + + if ((error = lfs_dqget(NULLVP, id, VFSTOULFS(mp), type, &dq)) != 0) + return (error); + error = copyout((void *)&dq->dq_dqb, addr, sizeof (struct dqblk)); + lfs_dqrele(NULLVP, dq); + return (error); +} + +/* + * Q_SETQUOTA - assign an entire dqblk structure. + */ +int +lfs_setquota(struct mount *mp, u_long id, int type, void *addr) +{ + struct ulfs_dquot *dq; + struct ulfs_dquot *ndq; + struct ulfsmount *ump = VFSTOULFS(mp); + struct dqblk newlim; + int error; + + error = copyin(addr, (void *)&newlim, sizeof (struct dqblk)); + if (error) + return (error); + if ((error = lfs_dqget(NULLVP, id, ump, type, &ndq)) != 0) + return (error); + dq = ndq; + mutex_enter(&dq->dq_interlock); + /* + * Copy all but the current values. + * Reset time limit if previously had no soft limit or were + * under it, but now have a soft limit and are over it. + */ + newlim.dqb_curblocks = dq->dq_curblocks; + newlim.dqb_curinodes = dq->dq_curinodes; + if (dq->dq_id != 0) { + newlim.dqb_btime = dq->dq_btime; + newlim.dqb_itime = dq->dq_itime; + } + if (newlim.dqb_bsoftlimit && + dq->dq_curblocks >= newlim.dqb_bsoftlimit && + (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit)) + newlim.dqb_btime = time_second + ump->um_btime[type]; + if (newlim.dqb_isoftlimit && + dq->dq_curinodes >= newlim.dqb_isoftlimit && + (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit)) + newlim.dqb_itime = time_second + ump->um_itime[type]; + dq->dq_dqb = newlim; + if (dq->dq_curblocks < dq->dq_bsoftlimit) + dq->dq_flags &= ~DQ_BLKS; + if (dq->dq_curinodes < dq->dq_isoftlimit) + dq->dq_flags &= ~DQ_INODS; + if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 && + dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0) + dq->dq_flags |= DQ_FAKE; + else + dq->dq_flags &= ~DQ_FAKE; + dq->dq_flags |= DQ_MOD; + mutex_exit(&dq->dq_interlock); + lfs_dqrele(NULLVP, dq); + return (0); +} + +/* + * Q_SETUSE - set current inode and block usage. + */ +int +lfs_setuse(struct mount *mp, u_long id, int type, void *addr) +{ + struct ulfs_dquot *dq; + struct ulfsmount *ump = VFSTOULFS(mp); + struct ulfs_dquot *ndq; + struct dqblk usage; + int error; + + error = copyin(addr, (void *)&usage, sizeof (struct dqblk)); + if (error) + return (error); + if ((error = lfs_dqget(NULLVP, id, ump, type, &ndq)) != 0) + return (error); + dq = ndq; + mutex_enter(&dq->dq_interlock); + /* + * Reset time limit if have a soft limit and were + * previously under it, but are now over it. + */ + if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit && + usage.dqb_curblocks >= dq->dq_bsoftlimit) + dq->dq_btime = time_second + ump->um_btime[type]; + if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit && + usage.dqb_curinodes >= dq->dq_isoftlimit) + dq->dq_itime = time_second + ump->um_itime[type]; + dq->dq_curblocks = usage.dqb_curblocks; + dq->dq_curinodes = usage.dqb_curinodes; + if (dq->dq_curblocks < dq->dq_bsoftlimit) + dq->dq_flags &= ~DQ_BLKS; + if (dq->dq_curinodes < dq->dq_isoftlimit) + dq->dq_flags &= ~DQ_INODS; + dq->dq_flags |= DQ_MOD; + mutex_exit(&dq->dq_interlock); + lfs_dqrele(NULLVP, dq); + return (0); +} + +/* + * Q_SYNC - sync quota files to disk. + */ +int +lfs_qsync(struct mount *mp) +{ + struct ulfsmount *ump = VFSTOULFS(mp); + struct vnode *vp, *mvp; + struct ulfs_dquot *dq; + int i, error; + + /* + * Check if the mount point has any quotas. + * If not, simply return. + */ + for (i = 0; i < MAXQUOTAS; i++) + if (ump->um_quotas[i] != NULLVP) + break; + if (i == MAXQUOTAS) + return (0); + + /* Allocate a marker vnode. */ + if ((mvp = vnalloc(mp)) == NULL) + return (ENOMEM); + + /* + * Search vnodes associated with this mount point, + * synchronizing any modified dquot structures. + */ + mutex_enter(&mntvnode_lock); + again: + for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) { + vmark(mvp, vp); + mutex_enter(&vp->v_interlock); + if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) || + vp->v_type == VNON || + (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) { + mutex_exit(&vp->v_interlock); + continue; + } + mutex_exit(&mntvnode_lock); + error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK); + if (error) { + mutex_enter(&mntvnode_lock); + if (error == ENOENT) { + (void)vunmark(mvp); + goto again; + } + continue; + } + for (i = 0; i < MAXQUOTAS; i++) { + dq = VTOI(vp)->i_dquot[i]; + if (dq == NODQUOT) + continue; + mutex_enter(&dq->dq_interlock); + if (dq->dq_flags & DQ_MOD) + lfs_dqsync(vp, dq); + mutex_exit(&dq->dq_interlock); + } + vput(vp); + mutex_enter(&mntvnode_lock); + } + mutex_exit(&mntvnode_lock); + vnfree(mvp); + return (0); +} + +/* + * Code pertaining to management of the in-core dquot data structures. + */ +#define DQHASH(dqvp, id) \ + (((((long)(dqvp)) >> 8) + id) & dqhash) +static LIST_HEAD(dqhashhead, ulfs_dquot) *dqhashtbl; +static u_long dqhash; +static pool_cache_t ulfs_dquot_cache; + +/* + * Initialize the quota system. + */ +void +ulfs_dqinit(void) +{ + + mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); + cv_init(&dqcv, "quota"); + dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash); + ulfs_dquot_cache = pool_cache_init(sizeof(struct ulfs_dquot), 0, 0, 0, "ulfsdq", + NULL, IPL_NONE, NULL, NULL, NULL); +} + +void +ulfs_dqreinit(void) +{ + struct ulfs_dquot *dq; + struct dqhashhead *oldhash, *hash; + struct vnode *dqvp; + u_long oldmask, mask, hashval; + int i; + + hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); + mutex_enter(&dqlock); + oldhash = dqhashtbl; + oldmask = dqhash; + dqhashtbl = hash; + dqhash = mask; + for (i = 0; i <= oldmask; i++) { + while ((dq = LIST_FIRST(&oldhash[i])) != NULL) { + dqvp = dq->dq_ump->um_quotas[dq->dq_type]; + LIST_REMOVE(dq, dq_hash); + hashval = DQHASH(dqvp, dq->dq_id); + LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash); + } + } + mutex_exit(&dqlock); + hashdone(oldhash, HASH_LIST, oldmask); +} + +/* + * Free resources held by quota system. + */ +void +ulfs_dqdone(void) +{ + + pool_cache_destroy(ulfs_dquot_cache); + hashdone(dqhashtbl, HASH_LIST, dqhash); + cv_destroy(&dqcv); + mutex_destroy(&dqlock); +} + +/* + * Obtain a dquot structure for the specified identifier and quota file + * reading the information from the file if necessary. + */ +static int +lfs_dqget(struct vnode *vp, u_long id, struct ulfsmount *ump, int type, + struct ulfs_dquot **dqp) +{ + struct ulfs_dquot *dq, *ndq; + struct dqhashhead *dqh; + struct vnode *dqvp; + struct iovec aiov; + struct uio auio; + int error; + + /* Lock to see an up to date value for QTF_CLOSING. */ + mutex_enter(&dqlock); + dqvp = ump->um_quotas[type]; + if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) { + mutex_exit(&dqlock); + *dqp = NODQUOT; + return (EINVAL); + } + KASSERT(dqvp != vp); + /* + * Check the cache first. + */ + dqh = &dqhashtbl[DQHASH(dqvp, id)]; + LIST_FOREACH(dq, dqh, dq_hash) { + if (dq->dq_id != id || + dq->dq_ump->um_quotas[dq->dq_type] != dqvp) + continue; + KASSERT(dq->dq_cnt > 0); + lfs_dqref(dq); + mutex_exit(&dqlock); + *dqp = dq; + return (0); + } + /* + * Not in cache, allocate a new one. + */ + mutex_exit(&dqlock); + ndq = pool_cache_get(ulfs_dquot_cache, PR_WAITOK); + /* + * Initialize the contents of the dquot structure. + */ + memset((char *)ndq, 0, sizeof *ndq); + ndq->dq_flags = 0; + ndq->dq_id = id; + ndq->dq_ump = ump; + ndq->dq_type = type; + mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE); + mutex_enter(&dqlock); + dqh = &dqhashtbl[DQHASH(dqvp, id)]; + LIST_FOREACH(dq, dqh, dq_hash) { + if (dq->dq_id != id || + dq->dq_ump->um_quotas[dq->dq_type] != dqvp) + continue; + /* + * Another thread beat us allocating this dquot. + */ + KASSERT(dq->dq_cnt > 0); + lfs_dqref(dq); + mutex_exit(&dqlock); + mutex_destroy(&ndq->dq_interlock); + pool_cache_put(ulfs_dquot_cache, ndq); + *dqp = dq; + return 0; + } + dq = ndq; + LIST_INSERT_HEAD(dqh, dq, dq_hash); + lfs_dqref(dq); + mutex_enter(&dq->dq_interlock); + mutex_exit(&dqlock); + vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY); + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = (void *)&dq->dq_dqb; + aiov.iov_len = sizeof (struct dqblk); + auio.uio_resid = sizeof (struct dqblk); + auio.uio_offset = (off_t)(id * sizeof (struct dqblk)); + auio.uio_rw = UIO_READ; + UIO_SETUP_SYSSPACE(&auio); + error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]); + if (auio.uio_resid == sizeof(struct dqblk) && error == 0) + memset((void *)&dq->dq_dqb, 0, sizeof(struct dqblk)); + VOP_UNLOCK(dqvp, 0); + /* + * I/O error in reading quota file, release + * quota structure and reflect problem to caller. + */ + if (error) { + mutex_enter(&dqlock); + LIST_REMOVE(dq, dq_hash); + mutex_exit(&dqlock); + mutex_exit(&dq->dq_interlock); + lfs_dqrele(vp, dq); + *dqp = NODQUOT; + return (error); + } + /* + * Check for no limit to enforce. + * Initialize time values if necessary. + */ + if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 && + dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0) + dq->dq_flags |= DQ_FAKE; + if (dq->dq_id != 0) { + if (dq->dq_btime == 0) + dq->dq_btime = time_second + ump->um_btime[type]; + if (dq->dq_itime == 0) + dq->dq_itime = time_second + ump->um_itime[type]; + } + mutex_exit(&dq->dq_interlock); + *dqp = dq; + return (0); +} + +/* + * Obtain a reference to a dquot. + */ +static void +lfs_dqref(struct ulfs_dquot *dq) +{ + + KASSERT(mutex_owned(&dqlock)); + dq->dq_cnt++; + KASSERT(dq->dq_cnt > 0); +} + +/* + * Release a reference to a dquot. + */ +static void +lfs_dqrele(struct vnode *vp, struct ulfs_dquot *dq) +{ + + if (dq == NODQUOT) + return; + mutex_enter(&dq->dq_interlock); + for (;;) { + mutex_enter(&dqlock); + if (dq->dq_cnt > 1) { + dq->dq_cnt--; + mutex_exit(&dqlock); + mutex_exit(&dq->dq_interlock); + return; + } + if ((dq->dq_flags & DQ_MOD) == 0) + break; + mutex_exit(&dqlock); + (void) lfs_dqsync(vp, dq); + } + KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0); + LIST_REMOVE(dq, dq_hash); + mutex_exit(&dqlock); + mutex_exit(&dq->dq_interlock); + mutex_destroy(&dq->dq_interlock); + pool_cache_put(ulfs_dquot_cache, dq); +} + +/* + * Update the disk quota in the quota file. + */ +static int +lfs_dqsync(struct vnode *vp, struct ulfs_dquot *dq) +{ + struct vnode *dqvp; + struct iovec aiov; + struct uio auio; + int error; + + if (dq == NODQUOT) + panic("lfs_dqsync: dquot"); + KASSERT(mutex_owned(&dq->dq_interlock)); + if ((dq->dq_flags & DQ_MOD) == 0) + return (0); + if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP) + panic("lfs_dqsync: file"); + KASSERT(dqvp != vp); + vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY); + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = (void *)&dq->dq_dqb; + aiov.iov_len = sizeof (struct dqblk); + auio.uio_resid = sizeof (struct dqblk); + auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk)); + auio.uio_rw = UIO_WRITE; + UIO_SETUP_SYSSPACE(&auio); + error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]); + if (auio.uio_resid && error == 0) + error = EIO; + dq->dq_flags &= ~DQ_MOD; + VOP_UNLOCK(dqvp, 0); + return (error); +} + +#ifdef DIAGNOSTIC +/* + * Check the hash chains for stray dquot's. + */ +static void +lfs_dqflush(struct vnode *vp) +{ + struct ulfs_dquot *dq; + int i; + + mutex_enter(&dqlock); + for (i = 0; i <= dqhash; i++) + LIST_FOREACH(dq, &dqhashtbl[i], dq_hash) + KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp); + mutex_exit(&dqlock); +} +#endif diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_quota.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_quota.h Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,60 @@ +/* $NetBSD: quota.h,v 1.25 2007/07/10 09:50:08 hannken Exp $ */ +/* from NetBSD: quota.h,v 1.25 2007/07/10 09:50:08 hannken Exp */ + +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Elz at The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)quota.h 8.3 (Berkeley) 8/19/94 + */ + +#ifndef _UFS_LFS_ULFS_QUOTA_H_ +#define _UFS_LFS_ULFS_QUOTA_H_ + +/* + * Get fs-independent bits, currently in ufs + */ +#include + +/* + * declare the startup bits for the ulfs copy of the implementation + */ +#ifdef _KERNEL + +#include + +__BEGIN_DECLS +void ulfs_dqinit(void); +void ulfs_dqreinit(void); +void ulfs_dqdone(void); +__END_DECLS +#endif /* _KERNEL */ + +#endif /* !_UFS_LFS_ULFS_QUOTA_H_ */ diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_readwrite.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_readwrite.c Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,528 @@ +/* $NetBSD: ulfs_readwrite.c,v 1.94 2009/02/22 20:28:07 ad Exp $ */ +/* from NetBSD: ufs_readwrite.c,v 1.94 2009/02/22 20:28:07 ad Exp */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_readwrite.c 8.11 (Berkeley) 5/8/95 + */ + +#include +__KERNEL_RCSID(1, "$NetBSD: ulfs_readwrite.c,v 1.94 2009/02/22 20:28:07 ad Exp $"); + +#ifdef LFS_READWRITE +#define FS struct lfs +#define I_FS i_lfs +#define READ lfs_read +#define READ_S "lfs_read" +#define WRITE lfs_write +#define WRITE_S "lfs_write" +#define fs_bsize lfs_bsize +#define fs_bmask lfs_bmask +#else +#define FS struct fs +#define I_FS i_fs +#define READ ffs_read +#define READ_S "ffs_read" +#define WRITE ffs_write +#define WRITE_S "ffs_write" +#endif + +/* + * Vnode op for reading. + */ +/* ARGSUSED */ +int +READ(void *v) +{ + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + kauth_cred_t a_cred; + } */ *ap = v; + struct vnode *vp; + struct lfs_inode *ip; + struct uio *uio; + struct ulfsmount *ump; + struct buf *bp; + FS *fs; + vsize_t bytelen; + daddr_t lbn, nextlbn; + off_t bytesinfile; + long size, xfersize, blkoffset; + int error, ioflag; + bool usepc = false; + + vp = ap->a_vp; + ip = VTOI(vp); + ump = ip->i_ump; + uio = ap->a_uio; + ioflag = ap->a_ioflag; + error = 0; + +#ifdef DIAGNOSTIC + if (uio->uio_rw != UIO_READ) + panic("%s: mode", READ_S); + + if (vp->v_type == VLNK) { + if (ip->i_size < ump->um_maxsymlinklen || + (ump->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) + panic("%s: short symlink", READ_S); + } else if (vp->v_type != VREG && vp->v_type != VDIR) + panic("%s: type %d", READ_S, vp->v_type); +#endif + fs = ip->I_FS; + if ((u_int64_t)uio->uio_offset > ump->um_maxfilesize) + return (EFBIG); + if (uio->uio_resid == 0) + return (0); + +#ifndef LFS_READWRITE + if ((ip->i_flags & SF_SNAPSHOT)) + return ffs_snapshot_read(vp, uio, ioflag); +#endif /* !LFS_READWRITE */ + + fstrans_start(vp->v_mount, FSTRANS_SHARED); + + if (uio->uio_offset >= ip->i_size) + goto out; + +#ifdef LFS_READWRITE + usepc = (vp->v_type == VREG && ip->i_number != LFS_IFILE_INUM); +#else /* !LFS_READWRITE */ + usepc = vp->v_type == VREG; +#endif /* !LFS_READWRITE */ + if (usepc) { + const int advice = IO_ADV_DECODE(ap->a_ioflag); + + while (uio->uio_resid > 0) { + if (ioflag & IO_DIRECT) { + genfs_directio(vp, uio, ioflag); + } + bytelen = MIN(ip->i_size - uio->uio_offset, + uio->uio_resid); + if (bytelen == 0) + break; + error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice, + UBC_READ | UBC_PARTIALOK | + (UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0)); + if (error) + break; + } + goto out; + } + + for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) { + bytesinfile = ip->i_size - uio->uio_offset; + if (bytesinfile <= 0) + break; + lbn = lblkno(fs, uio->uio_offset); + nextlbn = lbn + 1; + size = blksize(fs, ip, lbn); + blkoffset = blkoff(fs, uio->uio_offset); + xfersize = MIN(MIN(fs->fs_bsize - blkoffset, uio->uio_resid), + bytesinfile); + + if (lblktosize(fs, nextlbn) >= ip->i_size) + error = bread(vp, lbn, size, NOCRED, 0, &bp); + else { + int nextsize = blksize(fs, ip, nextlbn); + error = breadn(vp, lbn, + size, &nextlbn, &nextsize, 1, NOCRED, 0, &bp); + } + if (error) + break; + + /* + * We should only get non-zero b_resid when an I/O error + * has occurred, which should cause us to break above. + * However, if the short read did not cause an error, + * then we want to ensure that we do not uiomove bad + * or uninitialized data. + */ + size -= bp->b_resid; + if (size < xfersize) { + if (size == 0) + break; + xfersize = size; + } + error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio); + if (error) + break; + brelse(bp, 0); + } + if (bp != NULL) + brelse(bp, 0); + + out: + if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) { + ip->i_flag |= IN_ACCESS; + if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) { + error = ULFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT); + } + } + + fstrans_done(vp->v_mount); + return (error); +} + +/* + * Vnode op for writing. + */ +int +WRITE(void *v) +{ + struct vop_write_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + kauth_cred_t a_cred; + } */ *ap = v; + struct vnode *vp; + struct uio *uio; + struct lfs_inode *ip; + FS *fs; + struct buf *bp; + struct lwp *l; + kauth_cred_t cred; + daddr_t lbn; + off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize; + int blkoffset, error, flags, ioflag, resid, size, xfersize; + int aflag; + int extended=0; + vsize_t bytelen; + bool async; + bool usepc = false; +#ifdef LFS_READWRITE + bool need_unreserve = false; +#endif + struct ulfsmount *ump; + + cred = ap->a_cred; + ioflag = ap->a_ioflag; + uio = ap->a_uio; + vp = ap->a_vp; + ip = VTOI(vp); + ump = ip->i_ump; + + KASSERT(vp->v_size == ip->i_size); +#ifdef DIAGNOSTIC + if (uio->uio_rw != UIO_WRITE) + panic("%s: mode", WRITE_S); +#endif + + switch (vp->v_type) { + case VREG: + if (ioflag & IO_APPEND) + uio->uio_offset = ip->i_size; + if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size) + return (EPERM); + /* FALLTHROUGH */ + case VLNK: + break; + case VDIR: + if ((ioflag & IO_SYNC) == 0) + panic("%s: nonsync dir write", WRITE_S); + break; + default: + panic("%s: type", WRITE_S); + } + + fs = ip->I_FS; + if (uio->uio_offset < 0 || + (u_int64_t)uio->uio_offset + uio->uio_resid > ump->um_maxfilesize) + return (EFBIG); +#ifdef LFS_READWRITE + /* Disallow writes to the Ifile, even if noschg flag is removed */ + /* XXX can this go away when the Ifile is no longer in the namespace? */ + if (vp == fs->lfs_ivnode) + return (EPERM); +#endif + /* + * Maybe this should be above the vnode op call, but so long as + * file servers have no limits, I don't think it matters. + */ + l = curlwp; + if (vp->v_type == VREG && l && + uio->uio_offset + uio->uio_resid > + l->l_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) { + mutex_enter(proc_lock); + psignal(l->l_proc, SIGXFSZ); + mutex_exit(proc_lock); + return (EFBIG); + } + if (uio->uio_resid == 0) + return (0); + + fstrans_start(vp->v_mount, FSTRANS_SHARED); + + flags = ioflag & IO_SYNC ? B_SYNC : 0; + async = vp->v_mount->mnt_flag & MNT_ASYNC; + origoff = uio->uio_offset; + resid = uio->uio_resid; + osize = ip->i_size; + error = 0; + + usepc = vp->v_type == VREG; + +#ifdef LFS_READWRITE + async = true; + lfs_check(vp, LFS_UNUSED_LBN, 0); +#endif /* !LFS_READWRITE */ + if (!usepc) + goto bcache; + + preallocoff = round_page(blkroundup(fs, MAX(osize, uio->uio_offset))); + aflag = ioflag & IO_SYNC ? B_SYNC : 0; + nsize = MAX(osize, uio->uio_offset + uio->uio_resid); + endallocoff = nsize - blkoff(fs, nsize); + + /* + * if we're increasing the file size, deal with expanding + * the fragment if there is one. + */ + + if (nsize > osize && lblkno(fs, osize) < NDADDR && + lblkno(fs, osize) != lblkno(fs, nsize) && + blkroundup(fs, osize) != osize) { + off_t eob; + + eob = blkroundup(fs, osize); + uvm_vnp_setwritesize(vp, eob); + error = ulfs_balloc_range(vp, osize, eob - osize, cred, aflag); + if (error) + goto out; + if (flags & B_SYNC) { + mutex_enter(&vp->v_interlock); + VOP_PUTPAGES(vp, trunc_page(osize & fs->fs_bmask), + round_page(eob), + PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED); + } + } + + while (uio->uio_resid > 0) { + int ubc_flags = UBC_WRITE; + bool overwrite; /* if we're overwrite a whole block */ + off_t newoff; + + if (ioflag & IO_DIRECT) { + genfs_directio(vp, uio, ioflag | IO_JOURNALLOCKED); + } + + oldoff = uio->uio_offset; + blkoffset = blkoff(fs, uio->uio_offset); + bytelen = MIN(fs->fs_bsize - blkoffset, uio->uio_resid); + if (bytelen == 0) { + break; + } + + /* + * if we're filling in a hole, allocate the blocks now and + * initialize the pages first. if we're extending the file, + * we can safely allocate blocks without initializing pages + * since the new blocks will be inaccessible until the write + * is complete. + */ + overwrite = uio->uio_offset >= preallocoff && + uio->uio_offset < endallocoff; + if (!overwrite && (vp->v_vflag & VV_MAPPED) == 0 && + blkoff(fs, uio->uio_offset) == 0 && + (uio->uio_offset & PAGE_MASK) == 0) { + vsize_t len; + + len = trunc_page(bytelen); + len -= blkoff(fs, len); + if (len > 0) { + overwrite = true; + bytelen = len; + } + } + + newoff = oldoff + bytelen; + if (vp->v_size < newoff) { + uvm_vnp_setwritesize(vp, newoff); + } + + if (!overwrite) { + error = ulfs_balloc_range(vp, uio->uio_offset, bytelen, + cred, aflag); + if (error) + break; + } else { + genfs_node_wrlock(vp); + error = GOP_ALLOC(vp, uio->uio_offset, bytelen, + aflag, cred); + genfs_node_unlock(vp); + if (error) + break; + ubc_flags |= UBC_FAULTBUSY; + } + + /* + * copy the data. + */ + + ubc_flags |= UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0; + error = ubc_uiomove(&vp->v_uobj, uio, bytelen, + IO_ADV_DECODE(ioflag), ubc_flags); + + /* + * update UVM's notion of the size now that we've + * copied the data into the vnode's pages. + * + * we should update the size even when uiomove failed. + */ + + if (vp->v_size < newoff) { + uvm_vnp_setsize(vp, newoff); + extended = 1; + } + + if (error) + break; + + /* + * flush what we just wrote if necessary. + * XXXUBC simplistic async flushing. + */ + +#ifndef LFS_READWRITE + if (!async && oldoff >> 16 != uio->uio_offset >> 16) { + mutex_enter(&vp->v_interlock); + error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16, + (uio->uio_offset >> 16) << 16, + PGO_CLEANIT | PGO_JOURNALLOCKED); + if (error) + break; + } +#endif + } + if (error == 0 && ioflag & IO_SYNC) { + mutex_enter(&vp->v_interlock); + error = VOP_PUTPAGES(vp, trunc_page(origoff & fs->fs_bmask), + round_page(blkroundup(fs, uio->uio_offset)), + PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED); + } + goto out; + + bcache: + mutex_enter(&vp->v_interlock); + VOP_PUTPAGES(vp, trunc_page(origoff), round_page(origoff + resid), + PGO_CLEANIT | PGO_FREE | PGO_SYNCIO | PGO_JOURNALLOCKED); + while (uio->uio_resid > 0) { + lbn = lblkno(fs, uio->uio_offset); + blkoffset = blkoff(fs, uio->uio_offset); + xfersize = MIN(fs->fs_bsize - blkoffset, uio->uio_resid); + if (fs->fs_bsize > xfersize) + flags |= B_CLRBUF; + else + flags &= ~B_CLRBUF; + +#ifdef LFS_READWRITE + error = lfs_reserve(fs, vp, NULL, + btofsb(fs, (NIADDR + 1) << fs->lfs_bshift)); + if (error) + break; + need_unreserve = true; +#endif + error = ULFS_BALLOC(vp, uio->uio_offset, xfersize, + ap->a_cred, flags, &bp); + + if (error) + break; + if (uio->uio_offset + xfersize > ip->i_size) { + ip->i_size = uio->uio_offset + xfersize; + DIP_ASSIGN(ip, size, ip->i_size); + uvm_vnp_setsize(vp, ip->i_size); + extended = 1; + } + size = blksize(fs, ip, lbn) - bp->b_resid; + if (xfersize > size) + xfersize = size; + + error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio); + + /* + * if we didn't clear the block and the uiomove failed, + * the buf will now contain part of some other file, + * so we need to invalidate it. + */ + if (error && (flags & B_CLRBUF) == 0) { + brelse(bp, BC_INVAL); + break; + } +#ifdef LFS_READWRITE + (void)VOP_BWRITE(bp); + lfs_reserve(fs, vp, NULL, + -btofsb(fs, (NIADDR + 1) << fs->lfs_bshift)); + need_unreserve = false; +#else + if (ioflag & IO_SYNC) + (void)bwrite(bp); + else if (xfersize + blkoffset == fs->fs_bsize) + bawrite(bp); + else + bdwrite(bp); +#endif + if (error || xfersize == 0) + break; + } +#ifdef LFS_READWRITE + if (need_unreserve) { + lfs_reserve(fs, vp, NULL, + -btofsb(fs, (NIADDR + 1) << fs->lfs_bshift)); + } +#endif + + /* + * If we successfully wrote any data, and we are not the superuser + * we clear the setuid and setgid bits as a precaution against + * tampering. + */ +out: + ip->i_flag |= IN_CHANGE | IN_UPDATE; + if (resid > uio->uio_resid && ap->a_cred && + kauth_authorize_generic(ap->a_cred, KAUTH_GENERIC_ISSUSER, NULL)) { + ip->i_mode &= ~(ISUID | ISGID); + DIP_ASSIGN(ip, mode, ip->i_mode); + } + if (resid > uio->uio_resid) + VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0)); + if (error) { + (void) ULFS_TRUNCATE(vp, osize, ioflag & IO_SYNC, ap->a_cred); + uio->uio_offset -= resid - uio->uio_resid; + uio->uio_resid = resid; + } else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC) + error = ULFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT); + + KASSERT(vp->v_size == ip->i_size); + fstrans_done(vp->v_mount); + + return (error); +} diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_vfsops.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_vfsops.c Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,287 @@ +/* $NetBSD: ulfs_vfsops.c,v 1.40 2009/05/07 19:26:09 elad Exp $ */ +/* from NetBSD: ufs_vfsops.c,v 1.40 2009/05/07 19:26:09 elad Exp */ + +/* + * Copyright (c) 1991, 1993, 1994 + * 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_vfsops.c 8.8 (Berkeley) 5/20/95 + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: ulfs_vfsops.c,v 1.40 2009/05/07 19:26:09 elad Exp $"); + +#if defined(_KERNEL_OPT) +#include "opt_ffs.h" +#include "opt_quota.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#ifdef LFS_DIRHASH +#include +#endif +#include + +/* how many times ulfs_init() was called */ +static int ulfs_initcount = 0; + +pool_cache_t ulfs_direct_cache; + +/* + * Make a filesystem operational. + * Nothing to do at the moment. + */ +/* ARGSUSED */ +int +ulfs_start(struct mount *mp, int flags) +{ + + return (0); +} + +/* + * Return the root of a filesystem. + */ +int +ulfs_root(struct mount *mp, struct vnode **vpp) +{ + struct vnode *nvp; + int error; + + if ((error = VFS_VGET(mp, (ino_t)ROOTINO, &nvp)) != 0) + return (error); + *vpp = nvp; + return (0); +} + +/* + * Do operations associated with quotas + */ +int +ulfs_quotactl(struct mount *mp, int cmds, uid_t uid, void *arg) +{ + struct lwp *l = curlwp; + +#ifndef QUOTA + (void) mp; + (void) cmds; + (void) uid; + (void) arg; + (void) l; + return (EOPNOTSUPP); +#else + int cmd, type, error; + + if (uid == -1) + uid = kauth_cred_getuid(l->l_cred); + cmd = cmds >> SUBCMDSHIFT; + + /* Mark the mount busy, as we're passing it to kauth(9). */ + error = vfs_busy(mp, NULL); + if (error) + return (error); + + switch (cmd) { + case Q_SYNC: + break; + + case Q_GETQUOTA: + /* The user can always query about his own quota. */ + if (uid == kauth_cred_getuid(l->l_cred)) + break; + + error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, + KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(uid), NULL); + + break; + + case Q_QUOTAON: + case Q_QUOTAOFF: + error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, + KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); + + break; + + case Q_SETQUOTA: + case Q_SETUSE: + error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, + KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(uid), NULL); + + break; + + default: + error = EINVAL; + break; + } + + type = cmds & SUBCMDMASK; + if (!error) { + /* Only check if there was no error above. */ + if ((u_int)type >= MAXQUOTAS) + error = EINVAL; + } + + if (error) { + vfs_unbusy(mp, false, NULL); + return (error); + } + + mutex_enter(&mp->mnt_updating); + switch (cmd) { + + case Q_QUOTAON: + error = lfs_quotaon(l, mp, type, arg); + break; + + case Q_QUOTAOFF: + error = lfs_quotaoff(l, mp, type); + break; + + case Q_SETQUOTA: + error = lfs_setquota(mp, uid, type, arg); + break; + + case Q_SETUSE: + error = lfs_setuse(mp, uid, type, arg); + break; + + case Q_GETQUOTA: + error = lfs_getquota(mp, uid, type, arg); + break; + + case Q_SYNC: + error = lfs_qsync(mp); + break; + + default: + error = EINVAL; + } + mutex_exit(&mp->mnt_updating); + vfs_unbusy(mp, false, NULL); + return (error); +#endif +} + +/* + * This is the generic part of fhtovp called after the underlying + * filesystem has validated the file handle. + */ +int +ulfs_fhtovp(struct mount *mp, struct lfid *lfhp, struct vnode **vpp) +{ + struct vnode *nvp; + struct lfs_inode *ip; + int error; + + if ((error = VFS_VGET(mp, lfhp->lfid_ino, &nvp)) != 0) { + *vpp = NULLVP; + return (error); + } + ip = VTOI(nvp); + if (ip->i_mode == 0 || ip->i_gen != lfhp->lfid_gen) { + vput(nvp); + *vpp = NULLVP; + return (ESTALE); + } + *vpp = nvp; + return (0); +} + +/* + * Initialize ULFS filesystems, done only once. + */ +void +ulfs_init(void) +{ + if (ulfs_initcount++ > 0) + return; + + ulfs_direct_cache = pool_cache_init(sizeof(struct direct), 0, 0, 0, + "ulfsdir", NULL, IPL_NONE, NULL, NULL, NULL); + + ulfs_ihashinit(); +#ifdef QUOTA + ulfs_dqinit(); +#endif +#ifdef LFS_DIRHASH + ulfsdirhash_init(); +#endif +#ifdef LFS_EXTATTR + ulfs_extattr_init(); +#endif +} + +void +ulfs_reinit(void) +{ + ulfs_ihashreinit(); +#ifdef QUOTA + ulfs_dqreinit(); +#endif +} + +/* + * Free ULFS filesystem resources, done only once. + */ +void +ulfs_done(void) +{ + if (--ulfs_initcount > 0) + return; + + ulfs_ihashdone(); +#ifdef QUOTA + ulfs_dqdone(); +#endif + pool_cache_destroy(ulfs_direct_cache); +#ifdef LFS_DIRHASH + ulfsdirhash_done(); +#endif +#ifdef LFS_EXTATTR + ulfs_extattr_done(); +#endif +} diff -r f907de68d469 -r fb6a4db31a4e sys/ufs/lfs/ulfs_vnops.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/ufs/lfs/ulfs_vnops.c Sun Feb 07 03:52:22 2010 -0500 @@ -0,0 +1,2172 @@ +/* $NetBSD: ulfs_vnops.c,v 1.179 2009/11/16 01:00:00 dholland Exp $ */ +/* from NetBSD: ufs_vnops.c,v 1.180 2009/10/14 09:40:27 hannken Exp */ + +/*- + * Copyright (c) 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1982, 1986, 1989, 1993, 1995 + * 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_vnops.c 8.28 (Berkeley) 7/31/95 + */ + +#include +__KERNEL_RCSID(0, "$NetBSD$"); + +#if defined(_KERNEL_OPT) +#include "opt_ffs.h" +#include "opt_quota.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef LFS_DIRHASH +#include +#endif +#include + +#include + +static int ulfs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *); +static int ulfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, + struct lwp *); + +/* + * A virgin directory (no blushing please). + */ +static const struct dirtemplate mastertemplate = { + 0, 12, DT_DIR, 1, ".", + 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." +}; + +/* + * Create a regular file + */ +int +ulfs_create(void *v) +{ + struct vop_create_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + } */ *ap = v; + int error; + + fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); + error = + ulfs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode), + ap->a_dvp, ap->a_vpp, ap->a_cnp); + if (error) { + fstrans_done(ap->a_dvp->v_mount); + return (error); + } + fstrans_done(ap->a_dvp->v_mount); + VN_KNOTE(ap->a_dvp, NOTE_WRITE); + return (0); +} + +/* + * Mknod vnode call + */ +/* ARGSUSED */ +int +ulfs_mknod(void *v) +{ + struct vop_mknod_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + } */ *ap = v; + struct vattr *vap; + struct vnode **vpp; + struct lfs_inode *ip; + int error; + struct mount *mp; + ino_t ino; + + vap = ap->a_vap; + vpp = ap->a_vpp; + + fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); + if ((error = + ulfs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode), + ap->a_dvp, vpp, ap->a_cnp)) != 0) + goto out; + VN_KNOTE(ap->a_dvp, NOTE_WRITE); + ip = VTOI(*vpp); + mp = (*vpp)->v_mount; + ino = ip->i_number; + ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; + if (vap->va_rdev != VNOVAL) { + /* + * Want to be able to use this to make badblock + * inodes, so don't truncate the dev number. + */ + ip->i_ffs1_rdev = ulfs_rw32(vap->va_rdev, + ULFS_MPNEEDSWAP(ip->i_ump)); + } + /* + * Remove inode so that it will be reloaded by VFS_VGET and + * checked to see if it is an alias of an existing entry in + * the inode cache. + */ + VOP_UNLOCK(*vpp, 0); + (*vpp)->v_type = VNON; + vgone(*vpp); + error = VFS_VGET(mp, ino, vpp); +out: + fstrans_done(ap->a_dvp->v_mount); + if (error != 0) { + *vpp = NULL; + return (error); + } + return (0); +} + +/* + * Open called. + * + * Nothing to do. + */ +/* ARGSUSED */ +int +ulfs_open(void *v) +{ + struct vop_open_args /* { + struct vnode *a_vp; + int a_mode; + kauth_cred_t a_cred; + } */ *ap = v; + + /* + * Files marked append-only must be opened for appending. + */ + if ((VTOI(ap->a_vp)->i_flags & APPEND) && + (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) + return (EPERM); + return (0); +} + +/* + * Close called. + * + * Update the times on the inode. + */ +/* ARGSUSED */ +int +ulfs_close(void *v) +{ + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + kauth_cred_t a_cred; + } */ *ap = v; + struct vnode *vp; + struct lfs_inode *ip; + + vp = ap->a_vp; + ip = VTOI(vp); + if (vp->v_usecount > 1) + ULFS_ITIMES(vp, NULL, NULL, NULL); + return (0); +} + +static int +ulfs_check_possible(struct vnode *vp, struct lfs_inode *ip, mode_t mode) +{ +#ifdef QUOTA + int error; +#endif /* QUOTA */ + + /* + * Disallow write attempts on read-only file systems; + * unless the file is a socket, fifo, or a block or + * character device resident on the file system. + */ + if (mode & VWRITE) { + switch (vp->v_type) { + case VDIR: + case VLNK: + case VREG: + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); +#ifdef QUOTA + fstrans_start(vp->v_mount, FSTRANS_SHARED); + error = lfs_getinoquota(ip); + fstrans_done(vp->v_mount); + if (error != 0) + return error; +#endif + break; + case VBAD: + case VBLK: + case VCHR: + case VSOCK: + case VFIFO: + case VNON: + default: + break; + } + } + + /* If it is a snapshot, nobody gets access to it. */ + if ((ip->i_flags & SF_SNAPSHOT)) + return (EPERM); + /* If immutable bit set, nobody gets to write it. */ + if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE)) + return (EPERM); + + return 0; +} + +static int +ulfs_check_permitted(struct vnode *vp, struct lfs_inode *ip, mode_t mode, + kauth_cred_t cred) +{ + + return genfs_can_access(vp->v_type, ip->i_mode & ALLPERMS, ip->i_uid, + ip->i_gid, mode, cred); +} + +int +ulfs_access(void *v) +{ + struct vop_access_args /* { + struct vnode *a_vp; + int a_mode; + kauth_cred_t a_cred; + } */ *ap = v; + struct vnode *vp; + struct lfs_inode *ip; + mode_t mode; + int error; + + vp = ap->a_vp; + ip = VTOI(vp); + mode = ap->a_mode; + + error = ulfs_check_possible(vp, ip, mode); + if (error) + return error; + + error = ulfs_check_permitted(vp, ip, mode, ap->a_cred); + + return error; +} + +/* ARGSUSED */ +int +ulfs_getattr(void *v) +{ + struct vop_getattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + kauth_cred_t a_cred; + } */ *ap = v; + struct vnode *vp; + struct lfs_inode *ip; + struct vattr *vap; + + vp = ap->a_vp; + ip = VTOI(vp); + vap = ap->a_vap; + ULFS_ITIMES(vp, NULL, NULL, NULL); + + /* + * Copy from inode table + */ + vap->va_fsid = ip->i_dev; + vap->va_fileid = ip->i_number; + vap->va_mode = ip->i_mode & ALLPERMS; + vap->va_nlink = ip->i_nlink; + vap->va_uid = ip->i_uid; + vap->va_gid = ip->i_gid; + vap->va_size = vp->v_size; + vap->va_rdev = (dev_t)ulfs_rw32(ip->i_ffs1_rdev, + ULFS_MPNEEDSWAP(ip->i_ump)); + vap->va_atime.tv_sec = ip->i_ffs1_atime; + vap->va_atime.tv_nsec = ip->i_ffs1_atimensec; + vap->va_mtime.tv_sec = ip->i_ffs1_mtime; + vap->va_mtime.tv_nsec = ip->i_ffs1_mtimensec; + vap->va_ctime.tv_sec = ip->i_ffs1_ctime; + vap->va_ctime.tv_nsec = ip->i_ffs1_ctimensec; + vap->va_birthtime.tv_sec = 0; + vap->va_birthtime.tv_nsec = 0; + vap->va_bytes = dbtob((u_quad_t)ip->i_ffs1_blocks); + vap->va_gen = ip->i_gen; + vap->va_flags = ip->i_flags; + + /* this doesn't belong here */ + if (vp->v_type == VBLK) + vap->va_blocksize = BLKDEV_IOSIZE; + else if (vp->v_type == VCHR) + vap->va_blocksize = MAXBSIZE; + else + vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; + vap->va_type = vp->v_type; + vap->va_filerev = ip->i_modrev; + return (0); +} + +/* + * Set attribute vnode op. called from several syscalls + */ +int +ulfs_setattr(void *v) +{ + struct vop_setattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + kauth_cred_t a_cred; + } */ *ap = v; + struct vattr *vap; + struct vnode *vp; + struct lfs_inode *ip; + kauth_cred_t cred; + struct lwp *l; + int error; + + vap = ap->a_vap; + vp = ap->a_vp; + ip = VTOI(vp); + cred = ap->a_cred; + l = curlwp; + + /* + * Check for unsettable attributes. + */ + if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || + (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || + (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || + ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { + return (EINVAL); + } + + fstrans_start(vp->v_mount, FSTRANS_SHARED); + + if (vap->va_flags != VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) { + error = EROFS; + goto out; + } + if (kauth_cred_geteuid(cred) != ip->i_uid && + (error = kauth_authorize_generic(cred, + KAUTH_GENERIC_ISSUSER, NULL))) + goto out; + if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, + NULL) == 0) { + if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) && + kauth_authorize_system(l->l_cred, + KAUTH_SYSTEM_CHSYSFLAGS, 0, NULL, NULL, NULL)) { + error = EPERM; + goto out; + } + /* Snapshot flag cannot be set or cleared */ + if ((vap->va_flags & SF_SNAPSHOT) != + (ip->i_flags & SF_SNAPSHOT)) { + error = EPERM; + goto out; + } + error = 0; + ip->i_flags = vap->va_flags; + DIP_ASSIGN(ip, flags, ip->i_flags); + } else { + if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) || + (vap->va_flags & UF_SETTABLE) != vap->va_flags) { + error = EPERM; + goto out; + } + if ((ip->i_flags & SF_SETTABLE) != + (vap->va_flags & SF_SETTABLE)) { + error = EPERM; + goto out; + } + error = 0; + ip->i_flags &= SF_SETTABLE; + ip->i_flags |= (vap->va_flags & UF_SETTABLE); + DIP_ASSIGN(ip, flags, ip->i_flags); + } + ip->i_flag |= IN_CHANGE; + if (vap->va_flags & (IMMUTABLE | APPEND)) { + error = 0; + goto out; + } + } + if (ip->i_flags & (IMMUTABLE | APPEND)) { + error = EPERM; + goto out; + } + /* + * Go through the fields and update iff not VNOVAL. + */ + if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) { + error = EROFS; + goto out; + } + error = ulfs_chown(vp, vap->va_uid, vap->va_gid, cred, l); + if (error) + goto out; + } + if (vap->va_size != VNOVAL) { + /* + * Disallow write attempts on read-only file systems; + * unless the file is a socket, fifo, or a block or + * character device resident on the file system. + */ + switch (vp->v_type) { + case VDIR: + error = EISDIR; + goto out; + case VCHR: + case VBLK: + case VFIFO: + break; + case VREG: + if (vp->v_mount->mnt_flag & MNT_RDONLY) { + error = EROFS; + goto out; + } + if ((ip->i_flags & SF_SNAPSHOT) != 0) { + error = EPERM; + goto out; + } + error = ULFS_TRUNCATE(vp, vap->va_size, 0, cred); + if (error) + goto out; + break; + default: + error = EOPNOTSUPP; + goto out; + } + } + ip = VTOI(vp); + if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || + vap->va_birthtime.tv_sec != VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) { + error = EROFS; + goto out; + } + if ((ip->i_flags & SF_SNAPSHOT) != 0) { + error = EPERM; + goto out; + } + error = genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid, cred); + if (error) + goto out; + if (vap->va_atime.tv_sec != VNOVAL) + if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) + ip->i_flag |= IN_ACCESS; + if (vap->va_mtime.tv_sec != VNOVAL) + ip->i_flag |= IN_CHANGE | IN_UPDATE; +#if 0 /* FUTURE? */ + if (vap->va_birthtime.tv_sec != VNOVAL) { + ip->i_ffs2_birthtime = vap->va_birthtime.tv_sec; + ip->i_ffs2_birthnsec = vap->va_birthtime.tv_nsec; + } +#endif + error = ULFS_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 0); + if (error) + goto out; + } + error = 0; + if (vap->va_mode != (mode_t)VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) { + error = EROFS; + goto out; + } + if ((ip->i_flags & SF_SNAPSHOT) != 0 && + (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP | + S_IXOTH | S_IWOTH))) { + error = EPERM; + goto out; + } + error = ulfs_chmod(vp, (int)vap->va_mode, cred, l); + } + VN_KNOTE(vp, NOTE_ATTRIB); +out: + fstrans_done(vp->v_mount); + return (error); +} + +/* + * Change the mode on a file. + * Inode must be locked before calling. + */ +static int +ulfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l) +{ + struct lfs_inode *ip; + int error; + + ip = VTOI(vp); + + error = genfs_can_chmod(vp, cred, ip->i_uid, ip->i_gid, mode); + if (error) + return (error); + + ip->i_mode &= ~ALLPERMS; + ip->i_mode |= (mode & ALLPERMS); + ip->i_flag |= IN_CHANGE; + DIP_ASSIGN(ip, mode, ip->i_mode); + return (0); +} + +/* + * Perform chown operation on inode ip; + * inode must be locked prior to call. + */ +static int +ulfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred, + struct lwp *l) +{ + struct lfs_inode *ip; + int error = 0; +#ifdef QUOTA + uid_t ouid; + gid_t ogid; + int64_t change; +#endif + ip = VTOI(vp); + error = 0; + + if (uid == (uid_t)VNOVAL) + uid = ip->i_uid; + if (gid == (gid_t)VNOVAL) + gid = ip->i_gid; + + error = genfs_can_chown(vp, cred, ip->i_uid, ip->i_gid, uid, gid); + if (error) + return (error); + +#ifdef QUOTA + ogid = ip->i_gid; + ouid = ip->i_uid; + change = DIP(ip, blocks); + (void) lfs_chkdq(ip, -change, cred, 0); + (void) lfs_chkiq(ip, -1, cred, 0); +#endif + ip->i_gid = gid; + DIP_ASSIGN(ip, gid, gid); + ip->i_uid = uid; + DIP_ASSIGN(ip, uid, uid); +#ifdef QUOTA + if ((error = lfs_chkdq(ip, change, cred, 0)) == 0) { + if ((error = lfs_chkiq(ip, 1, cred, 0)) == 0) + goto good; + else + (void) lfs_chkdq(ip, -change, cred, FORCE); + } + ip->i_gid = ogid; + DIP_ASSIGN(ip, gid, ogid); + ip->i_uid = ouid; + DIP_ASSIGN(ip, uid, ouid); + (void) lfs_chkdq(ip, change, cred, FORCE); + (void) lfs_chkiq(ip, 1, cred, FORCE); + return (error); + good: +#endif /* QUOTA */ + ip->i_flag |= IN_CHANGE; + return (0); +} + +int +ulfs_remove(void *v) +{ + struct vop_remove_args /* { + struct vnode *a_dvp; + struct vnode *a_vp; + struct componentname *a_cnp; + } */ *ap = v; + struct vnode *vp, *dvp; + struct lfs_inode *ip; + int error; + + vp = ap->a_vp; + dvp = ap->a_dvp; + ip = VTOI(vp); + fstrans_start(dvp->v_mount, FSTRANS_SHARED); + if (vp->v_type == VDIR || (ip->i_flags & (IMMUTABLE | APPEND)) || + (VTOI(dvp)->i_flags & APPEND)) + error = EPERM; + else { + error = ulfs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0); + } + VN_KNOTE(vp, NOTE_DELETE); + VN_KNOTE(dvp, NOTE_WRITE); + if (dvp == vp) + vrele(vp); + else + vput(vp); + vput(dvp); + fstrans_done(dvp->v_mount); + return (error); +} + +/* + * link vnode call + */ +int +ulfs_link(void *v) +{ + struct vop_link_args /* { + struct vnode *a_dvp; + struct vnode *a_vp; + struct componentname *a_cnp; + } */ *ap = v; + struct vnode *vp, *dvp; + struct componentname *cnp; + struct lfs_inode *ip; + struct direct *newdir; + int error; + + dvp = ap->a_dvp; + vp = ap->a_vp; + cnp = ap->a_cnp; +#ifdef DIAGNOSTIC + if ((cnp->cn_flags & HASBUF) == 0) + panic("ulfs_link: no name"); +#endif + fstrans_start(dvp->v_mount, FSTRANS_SHARED); + if (vp->v_type == VDIR) { + VOP_ABORTOP(dvp, cnp); + error = EPERM; + goto out2; + } + if (dvp->v_mount != vp->v_mount) { + VOP_ABORTOP(dvp, cnp); + error = EXDEV; + goto out2; + } + if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE))) { + VOP_ABORTOP(dvp, cnp); + goto out2; + } + ip = VTOI(vp); + if ((nlink_t)ip->i_nlink >= LINK_MAX) { + VOP_ABORTOP(dvp, cnp); + error = EMLINK; + goto out1; + } + if (ip->i_flags & (IMMUTABLE | APPEND)) { + VOP_ABORTOP(dvp, cnp); + error = EPERM; + goto out1; + } + ip->i_nlink++; + DIP_ASSIGN(ip, nlink, ip->i_nlink); + ip->i_flag |= IN_CHANGE; + error = ULFS_UPDATE(vp, NULL, NULL, UPDATE_DIROP); + if (!error) { + newdir = pool_cache_get(ulfs_direct_cache, PR_WAITOK); + ulfs_makedirentry(ip, cnp, newdir); + error = ulfs_direnter(dvp, vp, newdir, cnp, NULL); + pool_cache_put(ulfs_direct_cache, newdir); + } + if (error) { + ip->i_nlink--; + DIP_ASSIGN(ip, nlink, ip->i_nlink); + ip->i_flag |= IN_CHANGE; + } + PNBUF_PUT(cnp->cn_pnbuf); + out1: + if (dvp != vp) + VOP_UNLOCK(vp, 0); + out2: + VN_KNOTE(vp, NOTE_LINK); + VN_KNOTE(dvp, NOTE_WRITE); + vput(dvp); + fstrans_done(dvp->v_mount); + return (error); +} + +/* + * whiteout vnode call + */ +int +ulfs_whiteout(void *v) +{ + struct vop_whiteout_args /* { + struct vnode *a_dvp; + struct componentname *a_cnp; + int a_flags; + } */ *ap = v; + struct vnode *dvp = ap->a_dvp; + struct componentname *cnp = ap->a_cnp; + struct direct *newdir; + int error; + struct ulfsmount *ump = VFSTOULFS(dvp->v_mount); + + error = 0; + switch (ap->a_flags) { + case LOOKUP: + /* 4.4 format directories support whiteout operations */ + if (ump->um_maxsymlinklen > 0) + return (0); + return (EOPNOTSUPP); + + case CREATE: + /* create a new directory whiteout */ + fstrans_start(dvp->v_mount, FSTRANS_SHARED); +#ifdef DIAGNOSTIC + if ((cnp->cn_flags & SAVENAME) == 0) + panic("ulfs_whiteout: missing name"); + if (ump->um_maxsymlinklen <= 0) + panic("ulfs_whiteout: old format filesystem"); +#endif + + newdir = pool_cache_get(ulfs_direct_cache, PR_WAITOK); + newdir->d_ino = WINO; + newdir->d_namlen = cnp->cn_namelen; + memcpy(newdir->d_name, cnp->cn_nameptr, + (size_t)cnp->cn_namelen); + newdir->d_name[cnp->cn_namelen] = '\0'; + newdir->d_type = DT_WHT; + error = ulfs_direnter(dvp, NULL, newdir, cnp, NULL); + pool_cache_put(ulfs_direct_cache, newdir); + break; + + case DELETE: + /* remove an existing directory whiteout */ + fstrans_start(dvp->v_mount, FSTRANS_SHARED); +#ifdef DIAGNOSTIC + if (ump->um_maxsymlinklen <= 0) + panic("ulfs_whiteout: old format filesystem"); +#endif + + cnp->cn_flags &= ~DOWHITEOUT; + error = ulfs_dirremove(dvp, NULL, cnp->cn_flags, 0); + break; + default: + panic("ulfs_whiteout: unknown op"); + /* NOTREACHED */ + } + if (cnp->cn_flags & HASBUF) { + PNBUF_PUT(cnp->cn_pnbuf); + cnp->cn_flags &= ~HASBUF; + } + fstrans_done(dvp->v_mount); + return (error); +} + + +/* + * Rename vnode operation + * rename("foo", "bar"); + * is essentially + * unlink("bar"); + * link("foo", "bar"); + * unlink("foo"); + * but ``atomically''. Can't do full commit without saving state in the + * inode on disk which isn't feasible at this time. Best we can do is + * always guarantee the target exists. + * + * Basic algorithm is: + * + * 1) Bump link count on source while we're linking it to the + * target. This also ensure the inode won't be deleted out + * from underneath us while we work (it may be truncated by + * a concurrent `trunc' or `open' for creation). + * 2) Link source to destination. If destination already exists, + * delete it first. + * 3) Unlink source reference to inode if still around. If a + * directory was moved and the parent of the destination + * is different from the source, patch the ".." entry in the + * directory. + */ +int +ulfs_rename(void *v) +{ + struct vop_rename_args /* { + struct vnode *a_fdvp; + struct vnode *a_fvp; + struct componentname *a_fcnp; + struct vnode *a_tdvp; + struct vnode *a_tvp; + struct componentname *a_tcnp; + } */ *ap = v; + struct vnode *tvp, *tdvp, *fvp, *fdvp; + struct componentname *tcnp, *fcnp; + struct lfs_inode *ip, *xp, *dp; + struct mount *mp; + struct direct *newdir; + int doingdirectory, oldparent, newparent, error; + + tvp = ap->a_tvp; + tdvp = ap->a_tdvp; + fvp = ap->a_fvp; + fdvp = ap->a_fdvp; + tcnp = ap->a_tcnp; + fcnp = ap->a_fcnp; + doingdirectory = oldparent = newparent = error = 0; + +#ifdef DIAGNOSTIC + if ((tcnp->cn_flags & HASBUF) == 0 || + (fcnp->cn_flags & HASBUF) == 0) + panic("ulfs_rename: no name"); +#endif + /* + * Check for cross-device rename. + */ + if ((fvp->v_mount != tdvp->v_mount) || + (tvp && (fvp->v_mount != tvp->v_mount))) { + error = EXDEV; + abortit: + VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */ + if (tdvp == tvp) + vrele(tdvp); + else + vput(tdvp); + if (tvp) + vput(tvp); + VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */ + vrele(fdvp); + vrele(fvp); + return (error); + } + + /* + * Check if just deleting a link name. + */ + if (tvp && ((VTOI(tvp)->i_flags & (IMMUTABLE | APPEND)) || + (VTOI(tdvp)->i_flags & APPEND))) { + error = EPERM; + goto abortit; + } + if (fvp == tvp) { + if (fvp->v_type == VDIR) { + error = EINVAL; + goto abortit; + } + + /* Release destination completely. */ + VOP_ABORTOP(tdvp, tcnp); + vput(tdvp); + vput(tvp); + + /* Delete source. */ + vrele(fvp); + fcnp->cn_flags &= ~(MODMASK | SAVESTART); + fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; + fcnp->cn_nameiop = DELETE; + vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY); + if ((error = relookup(fdvp, &fvp, fcnp))) { + vput(fdvp); + return (error); + } + return (VOP_REMOVE(fdvp, fvp, fcnp)); + } + if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) + goto abortit; + dp = VTOI(fdvp); + ip = VTOI(fvp); + if ((nlink_t) ip->i_nlink >= LINK_MAX) { + VOP_UNLOCK(fvp, 0); + error = EMLINK; + goto abortit; + } + if ((ip->i_flags & (IMMUTABLE | APPEND)) || + (dp->i_flags & APPEND)) { + VOP_UNLOCK(fvp, 0); + error = EPERM; + goto abortit; + } + if ((ip->i_mode & IFMT) == IFDIR) { + /* + * Avoid ".", "..", and aliases of "." for obvious reasons. + */ + if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || + dp == ip || + (fcnp->cn_flags & ISDOTDOT) || + (tcnp->cn_flags & ISDOTDOT) || + (ip->i_flag & IN_RENAME)) { + VOP_UNLOCK(fvp, 0); + error = EINVAL; + goto abortit; + } + ip->i_flag |= IN_RENAME; + oldparent = dp->i_number; + doingdirectory = 1; + } + VN_KNOTE(fdvp, NOTE_WRITE); /* XXXLUKEM/XXX: right place? */ + + /* + * When the target exists, both the directory + * and target vnodes are returned locked. + */ + dp = VTOI(tdvp); + xp = NULL; + if (tvp) + xp = VTOI(tvp); + + mp = fdvp->v_mount; + fstrans_start(mp, FSTRANS_SHARED); + + /* + * 1) Bump link count while we're moving stuff + * around. If we crash somewhere before + * completing our work, the link count + * may be wrong, but correctable. + */ + ip->i_nlink++; + DIP_ASSIGN(ip, nlink, ip->i_nlink); + ip->i_flag |= IN_CHANGE; + if ((error = ULFS_UPDATE(fvp, NULL, NULL, UPDATE_DIROP)) != 0) { + VOP_UNLOCK(fvp, 0); + goto bad; + } + + /* + * If ".." must be changed (ie the directory gets a new + * parent) then the source directory must not be in the + * directory hierarchy above the target, as this would + * orphan everything below the source directory. Also + * the user must have write permission in the source so + * as to be able to change "..". We must repeat the call + * to namei, as the parent directory is unlocked by the + * call to checkpath(). + */ + error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred); + VOP_UNLOCK(fvp, 0); + if (oldparent != dp->i_number) + newparent = dp->i_number; + if (doingdirectory && newparent) { + if (error) /* write access check above */ + goto bad; + if (xp != NULL) + vput(tvp); + vref(tdvp); /* compensate for the ref checkpath loses */ + if ((error = ulfs_checkpath(ip, dp, tcnp->cn_cred)) != 0) { + vrele(tdvp); + goto out; + } + tcnp->cn_flags &= ~SAVESTART; + vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY); + error = relookup(tdvp, &tvp, tcnp); + if (error != 0) { + vput(tdvp); + goto out; + } + dp = VTOI(tdvp); + xp = NULL; + if (tvp) + xp = VTOI(tvp); + } + /* + * 2) If target doesn't exist, link the target + * to the source and unlink the source. + * Otherwise, rewrite the target directory + * entry to reference the source inode and + * expunge the original entry's existence. + */ + if (xp == NULL) { + if (dp->i_dev != ip->i_dev) + panic("rename: EXDEV"); + /* + * Account for ".." in new directory. + * When source and destination have the same + * parent we don't fool with the link count. + */ + if (doingdirectory && newparent) { + if ((nlink_t)dp->i_nlink >= LINK_MAX) { + error = EMLINK; + goto bad; + } + dp->i_nlink++; + DIP_ASSIGN(dp, nlink, dp->i_nlink); + dp->i_flag |= IN_CHANGE; + if ((error = ULFS_UPDATE(tdvp, NULL, NULL, + UPDATE_DIROP)) != 0) { + dp->i_nlink--; + DIP_ASSIGN(dp, nlink, dp->i_nlink); + dp->i_flag |= IN_CHANGE; + goto bad; + } + } + newdir = pool_cache_get(ulfs_direct_cache, PR_WAITOK); + ulfs_makedirentry(ip, tcnp, newdir); + error = ulfs_direnter(tdvp, NULL, newdir, tcnp, NULL); + pool_cache_put(ulfs_direct_cache, newdir); + if (error != 0) { + if (doingdirectory && newparent) { + dp->i_nlink--; + DIP_ASSIGN(dp, nlink, dp->i_nlink); + dp->i_flag |= IN_CHANGE; + (void)ULFS_UPDATE(tdvp, NULL, NULL, + UPDATE_WAIT|UPDATE_DIROP); + } + goto bad; + } + VN_KNOTE(tdvp, NOTE_WRITE); + vput(tdvp); + } else { + if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) + panic("rename: EXDEV"); + /* + * Short circuit rename(foo, foo). + */ + if (xp->i_number == ip->i_number) + panic("rename: same file"); + /* + * If the parent directory is "sticky", then the user must + * own the parent directory, or the destination of the rename, + * otherwise the destination may not be changed (except by + * root). This implements append-only directories. + */ + if ((dp->i_mode & S_ISTXT) && + kauth_authorize_generic(tcnp->cn_cred, + KAUTH_GENERIC_ISSUSER, NULL) != 0 && + kauth_cred_geteuid(tcnp->cn_cred) != dp->i_uid && + xp->i_uid != kauth_cred_geteuid(tcnp->cn_cred)) { + error = EPERM; + goto bad; + } + /* + * Target must be empty if a directory and have no links + * to it. Also, ensure source and target are compatible + * (both directories, or both not directories). + */ + if ((xp->i_mode & IFMT) == IFDIR) { + if (xp->i_nlink > 2 || + !ulfs_dirempty(xp, dp->i_number, tcnp->cn_cred)) { + error = ENOTEMPTY; + goto bad; + } + if (!doingdirectory) { + error = ENOTDIR; + goto bad; + } + cache_purge(tdvp); + } else if (doingdirectory) { + error = EISDIR; + goto bad; + } + if ((error = ulfs_dirrewrite(dp, xp, ip->i_number, + IFTODT(ip->i_mode), doingdirectory && newparent ? + newparent : doingdirectory, IN_CHANGE | IN_UPDATE)) != 0) + goto bad; + if (doingdirectory) { + /* + * Truncate inode. The only stuff left in the directory + * is "." and "..". The "." reference is inconsequential + * since we are quashing it. We have removed the "." + * reference and the reference in the parent directory, + * but there may be other hard links. + */ + if (!newparent) { + dp->i_nlink--; + DIP_ASSIGN(dp, nlink, dp->i_nlink); + dp->i_flag |= IN_CHANGE; + } + xp->i_nlink--; + DIP_ASSIGN(xp, nlink, xp->i_nlink); + xp->i_flag |= IN_CHANGE; + if ((error = ULFS_TRUNCATE(tvp, (off_t)0, IO_SYNC, + tcnp->cn_cred))) + goto bad; + } + VN_KNOTE(tdvp, NOTE_WRITE); + vput(tdvp); + VN_KNOTE(tvp, NOTE_DELETE); + vput(tvp); + xp = NULL; + } + + /* + * 3) Unlink the source. + */ + fcnp->cn_flags &= ~(MODMASK | SAVESTART); + fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; + vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY); + if ((error = relookup(fdvp, &fvp, fcnp))) { + vput(fdvp); + vrele(ap->a_fvp); + goto out2; + } + if (fvp != NULL) { + xp = VTOI(fvp); + dp = VTOI(fdvp); + } else { + /* + * From name has disappeared. + */ + if (doingdirectory) + panic("rename: lost dir entry"); + vrele(ap->a_fvp); + error = 0; + goto out2; + } + /* + * Ensure that the directory entry still exists and has not + * changed while the new name has been entered. If the source is + * a file then the entry may have been unlinked or renamed. In + * either case there is no further work to be done. If the source + * is a directory then it cannot have been rmdir'ed; The IRENAME + * flag ensures that it cannot be moved by another rename or removed + * by a rmdir. + */ + if (xp != ip) { + if (doingdirectory) + panic("rename: lost dir entry"); + } else { + /* + * If the source is a directory with a + * new parent, the link count of the old + * parent directory must be decremented + * and ".." set to point to the new parent. + */ + if (doingdirectory && newparent) { + KASSERT(dp != NULL); + xp->i_offset = mastertemplate.dot_reclen; + ulfs_dirrewrite(xp, dp, newparent, DT_DIR, 0, IN_CHANGE); + cache_purge(fdvp); + } + error = ulfs_dirremove(fdvp, xp, fcnp->cn_flags, 0); + xp->i_flag &= ~IN_RENAME; + } + VN_KNOTE(fvp, NOTE_RENAME); + if (dp) + vput(fdvp); + if (xp) + vput(fvp); + vrele(ap->a_fvp); + goto out2; + + /* exit routines from steps 1 & 2 */ + bad: + if (xp) + vput(ITOV(xp)); + vput(ITOV(dp)); + out: + if (doingdirectory) + ip->i_flag &= ~IN_RENAME; + if (vn_lock(fvp, LK_EXCLUSIVE) == 0) { + ip->i_nlink--; + DIP_ASSIGN(ip, nlink, ip->i_nlink); + ip->i_flag |= IN_CHANGE; + ip->i_flag &= ~IN_RENAME; + vput(fvp); + } else + vrele(fvp); + vrele(fdvp); + + /* exit routines from step 3 */ + out2: + fstrans_done(mp); + return (error); +} + +int +ulfs_mkdir(void *v) +{ + struct vop_mkdir_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + } */ *ap = v; + struct vnode *dvp = ap->a_dvp, *tvp; + struct vattr *vap = ap->a_vap; + struct componentname *cnp = ap->a_cnp; + struct lfs_inode *ip, *dp = VTOI(dvp); + struct buf *bp; + struct dirtemplate dirtemplate; + struct direct *newdir; + int error, dmode; + struct ulfsmount *ump = dp->i_ump; + int dirblksiz = ump->um_dirblksiz; + + fstrans_start(dvp->v_mount, FSTRANS_SHARED); + +#ifdef DIAGNOSTIC + if ((cnp->cn_flags & HASBUF) == 0) + panic("ulfs_mkdir: no name"); +#endif + if ((nlink_t)dp->i_nlink >= LINK_MAX) { + error = EMLINK; + goto out; + } + dmode = vap->va_mode & ACCESSPERMS; + dmode |= IFDIR; + /* + * Must simulate part of ulfs_makeinode here to acquire the inode, + * but not have it entered in the parent directory. The entry is + * made later after writing "." and ".." entries. + */ + if ((error = ULFS_VALLOC(dvp, dmode, cnp->cn_cred, ap->a_vpp)) != 0) + goto out; + tvp = *ap->a_vpp; + ip = VTOI(tvp); + ip->i_uid = kauth_cred_geteuid(cnp->cn_cred); + DIP_ASSIGN(ip, uid, ip->i_uid); + ip->i_gid = dp->i_gid; + DIP_ASSIGN(ip, gid, ip->i_gid); +#ifdef QUOTA + if ((error = lfs_chkiq(ip, 1, cnp->cn_cred, 0))) { + PNBUF_PUT(cnp->cn_pnbuf); + ULFS_VFREE(tvp, ip->i_number, dmode); + fstrans_done(dvp->v_mount); + vput(tvp); + vput(dvp); + return (error); + } +#endif + ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; + ip->i_mode = dmode; + DIP_ASSIGN(ip, mode, dmode); + tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ + ip->i_nlink = 2; + DIP_ASSIGN(ip, nlink, 2); + if (cnp->cn_flags & ISWHITEOUT) { + ip->i_flags |= UF_OPAQUE; + DIP_ASSIGN(ip, flags, ip->i_flags); + } + + /* + * Bump link count in parent directory to reflect work done below. + * Should be done before reference is created so cleanup is + * possible if we crash. + */ + dp->i_nlink++; + DIP_ASSIGN(dp, nlink, dp->i_nlink); + dp->i_flag |= IN_CHANGE; + if ((error = ULFS_UPDATE(dvp, NULL, NULL, UPDATE_DIROP)) != 0) + goto bad; + + /* + * Initialize directory with "." and ".." from static template. + */ + dirtemplate = mastertemplate; + dirtemplate.dotdot_reclen = dirblksiz - dirtemplate.dot_reclen; + dirtemplate.dot_ino = ulfs_rw32(ip->i_number, ULFS_MPNEEDSWAP(ump)); + dirtemplate.dotdot_ino = ulfs_rw32(dp->i_number, ULFS_MPNEEDSWAP(ump)); + dirtemplate.dot_reclen = ulfs_rw16(dirtemplate.dot_reclen, + ULFS_MPNEEDSWAP(ump)); + dirtemplate.dotdot_reclen = ulfs_rw16(dirtemplate.dotdot_reclen, + ULFS_MPNEEDSWAP(ump)); + if (ump->um_maxsymlinklen <= 0) { +#if BYTE_ORDER == LITTLE_ENDIAN + if (ULFS_MPNEEDSWAP(ump) == 0) +#else + if (ULFS_MPNEEDSWAP(ump) != 0) +#endif + { + dirtemplate.dot_type = dirtemplate.dot_namlen; + dirtemplate.dotdot_type = dirtemplate.dotdot_namlen; + dirtemplate.dot_namlen = dirtemplate.dotdot_namlen = 0; + } else + dirtemplate.dot_type = dirtemplate.dotdot_type = 0; + } + if ((error = ULFS_BALLOC(tvp, (off_t)0, dirblksiz, cnp->cn_cred, + B_CLRBUF, &bp)) != 0) + goto bad; + ip->i_size = dirblksiz; + DIP_ASSIGN(ip, size, dirblksiz); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + uvm_vnp_setsize(tvp, ip->i_size); + memcpy((void *)bp->b_data, (void *)&dirtemplate, sizeof dirtemplate); + + /* + * Directory set up, now install it's entry in the parent directory. + * We must write out the buffer containing the new directory body + * before entering the new name in the parent. + */ + if ((error = VOP_BWRITE(bp)) != 0) + goto bad; + if ((error = ULFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0) { + goto bad; + } + newdir = pool_cache_get(ulfs_direct_cache, PR_WAITOK); + ulfs_makedirentry(ip, cnp, newdir); + error = ulfs_direnter(dvp, tvp, newdir, cnp, bp); + pool_cache_put(ulfs_direct_cache, newdir); + bad: + if (error == 0) { + VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); + } else { + dp->i_nlink--; + DIP_ASSIGN(dp, nlink, dp->i_nlink); + dp->i_flag |= IN_CHANGE; + /* + * No need to do an explicit ULFS_TRUNCATE here, vrele will + * do this for us because we set the link count to 0. + */ + ip->i_nlink = 0; + DIP_ASSIGN(ip, nlink, 0); + ip->i_flag |= IN_CHANGE; + /* If IN_ADIROP, account for it */ + ULFS_UNMARK_VNODE(tvp); + vput(tvp); + } + out: + PNBUF_PUT(cnp->cn_pnbuf); + fstrans_done(dvp->v_mount); + vput(dvp); + return (error); +} + +int +ulfs_rmdir(void *v) +{ + struct vop_rmdir_args /* { + struct vnode *a_dvp; + struct vnode *a_vp; + struct componentname *a_cnp; + } */ *ap = v; + struct vnode *vp, *dvp; + struct componentname *cnp; + struct lfs_inode *ip, *dp; + int error; + + vp = ap->a_vp; + dvp = ap->a_dvp; + cnp = ap->a_cnp; + ip = VTOI(vp); + dp = VTOI(dvp); + /* + * No rmdir "." or of mounted directories please. + */ + if (dp == ip || vp->v_mountedhere != NULL) { + if (dp == ip) + vrele(vp); + else + vput(vp); + vput(vp); + return (EINVAL); + } + + fstrans_start(dvp->v_mount, FSTRANS_SHARED); + + /* + * Do not remove a directory that is in the process of being renamed. + * Verify that the directory is empty (and valid). (Rmdir ".." won't + * be valid since ".." will contain a reference to the current + * directory and thus be non-empty.) + */ + error = 0; + if (ip->i_flag & IN_RENAME) { + error = EINVAL; + goto out; + } + if (ip->i_nlink != 2 || + !ulfs_dirempty(ip, dp->i_number, cnp->cn_cred)) { + error = ENOTEMPTY; + goto out; + } + if ((dp->i_flags & APPEND) || + (ip->i_flags & (IMMUTABLE | APPEND))) { + error = EPERM; + goto out; + } + /* + * Delete reference to directory before purging + * inode. If we crash in between, the directory + * will be reattached to lost+found, + */ + error = ulfs_dirremove(dvp, ip, cnp->cn_flags, 1); + if (error) { + goto out; + } + VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); + cache_purge(dvp); + /* + * Truncate inode. The only stuff left in the directory is "." and + * "..". The "." reference is inconsequential since we're quashing + * it. + */ + dp->i_nlink--; + DIP_ASSIGN(dp, nlink, dp->i_nlink); + dp->i_flag |= IN_CHANGE; + ip->i_nlink--; + DIP_ASSIGN(ip, nlink, ip->i_nlink); + ip->i_flag |= IN_CHANGE; + error = ULFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred); + cache_purge(vp); + /* + * Unlock the log while we still have reference to unlinked + * directory vp so that it will not get locked for recycling + */ +#ifdef LFS_DIRHASH + if (ip->i_dirhash != NULL) + ulfsdirhash_free(ip); +#endif + out: + VN_KNOTE(vp, NOTE_DELETE); + vput(dvp); + vput(vp); + fstrans_done(dvp->v_mount); + return (error); +} + +/* + * symlink -- make a symbolic link + */ +int +ulfs_symlink(void *v) +{ + struct vop_symlink_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + char *a_target; + } */ *ap = v; + struct vnode *vp, **vpp; + struct lfs_inode *ip; + int len, error; + + vpp = ap->a_vpp; + fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); + error = ulfs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp, + vpp, ap->a_cnp); + if (error) + goto out; + VN_KNOTE(ap->a_dvp, NOTE_WRITE); + vp = *vpp; + len = strlen(ap->a_target); + ip = VTOI(vp); + if (len < ip->i_ump->um_maxsymlinklen) { + memcpy((char *)SHORTLINK(ip), ap->a_target, len); + ip->i_size = len; + DIP_ASSIGN(ip, size, len); + uvm_vnp_setsize(vp, ip->i_size); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } else + error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0, + UIO_SYSSPACE, IO_NODELOCKED | IO_JOURNALLOCKED, + ap->a_cnp->cn_cred, NULL, NULL); + if (error) + vput(vp); +out: + fstrans_done(ap->a_dvp->v_mount); + return (error); +} + +/* + * Vnode op for reading directories. + * + * This routine handles converting from the on-disk directory format + * "struct direct" to the in-memory format "struct dirent" as well as + * byte swapping the entries if necessary. + */ +int +ulfs_readdir(void *v) +{ + struct vop_readdir_args /* { + struct vnode *a_vp; + struct uio *a_uio; + kauth_cred_t a_cred; + int *a_eofflag; + off_t **a_cookies; + int *ncookies; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct direct *cdp, *ecdp; + struct dirent *ndp; + char *cdbuf, *ndbuf, *endp; + struct uio auio, *uio; + struct iovec aiov; + int error; + size_t count, ccount, rcount; + off_t off, *ccp; + off_t startoff; + size_t skipbytes; + struct ulfsmount *ump = VFSTOULFS(vp->v_mount); + int nswap = ULFS_MPNEEDSWAP(ump); +#if BYTE_ORDER == LITTLE_ENDIAN + int needswap = ump->um_maxsymlinklen <= 0 && nswap == 0; +#else + int needswap = ump->um_maxsymlinklen <= 0 && nswap != 0; +#endif + uio = ap->a_uio; + count = uio->uio_resid; + rcount = count - ((uio->uio_offset + count) & (ump->um_dirblksiz - 1)); + + if (rcount < _DIRENT_MINSIZE(cdp) || count < _DIRENT_MINSIZE(ndp)) + return EINVAL; + + startoff = uio->uio_offset & ~(ump->um_dirblksiz - 1); + skipbytes = uio->uio_offset - startoff; + rcount += skipbytes; + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = startoff; + auio.uio_resid = rcount; + UIO_SETUP_SYSSPACE(&auio); + auio.uio_rw = UIO_READ; + cdbuf = malloc(rcount, M_TEMP, M_WAITOK); + aiov.iov_base = cdbuf; + aiov.iov_len = rcount; + error = VOP_READ(vp, &auio, 0, ap->a_cred); + if (error != 0) { + free(cdbuf, M_TEMP); + return error; + } + + rcount -= auio.uio_resid; + + cdp = (struct direct *)(void *)cdbuf; + ecdp = (struct direct *)(void *)&cdbuf[rcount]; + + ndbuf = malloc(count, M_TEMP, M_WAITOK); + ndp = (struct dirent *)(void *)ndbuf; + endp = &ndbuf[count]; + + off = uio->uio_offset; + if (ap->a_cookies) { + ccount = rcount / _DIRENT_RECLEN(cdp, 1); + ccp = *(ap->a_cookies) = malloc(ccount * sizeof(*ccp), + M_TEMP, M_WAITOK); + } else { + /* XXX: GCC */ + ccount = 0; + ccp = NULL; + } + + while (cdp < ecdp) { + cdp->d_reclen = ulfs_rw16(cdp->d_reclen, nswap); + if (skipbytes > 0) { + if (cdp->d_reclen <= skipbytes) { + skipbytes -= cdp->d_reclen; + cdp = _DIRENT_NEXT(cdp); + continue; + } + /* + * invalid cookie. + */ + error = EINVAL; + goto out; + } + if (cdp->d_reclen == 0) { + struct dirent *ondp = ndp; + ndp->d_reclen = _DIRENT_MINSIZE(ndp); + ndp = _DIRENT_NEXT(ndp); + ondp->d_reclen = 0; + cdp = ecdp; + break; + } + if (needswap) { + ndp->d_type = cdp->d_namlen; + ndp->d_namlen = cdp->d_type; + } else { + ndp->d_type = cdp->d_type; + ndp->d_namlen = cdp->d_namlen; + } + ndp->d_reclen = _DIRENT_RECLEN(ndp, ndp->d_namlen); + if ((char *)(void *)ndp + ndp->d_reclen + + _DIRENT_MINSIZE(ndp) > endp) + break; + ndp->d_fileno = ulfs_rw32(cdp->d_ino, nswap); + (void)memcpy(ndp->d_name, cdp->d_name, ndp->d_namlen); + memset(&ndp->d_name[ndp->d_namlen], 0, + ndp->d_reclen - _DIRENT_NAMEOFF(ndp) - ndp->d_namlen); + off += cdp->d_reclen; + if (ap->a_cookies) { + KASSERT(ccp - *(ap->a_cookies) < ccount); + *(ccp++) = off; + } + ndp = _DIRENT_NEXT(ndp); + cdp = _DIRENT_NEXT(cdp); + } + + count = ((char *)(void *)ndp - ndbuf); + error = uiomove(ndbuf, count, uio); +out: + if (ap->a_cookies) { + if (error) { + free(*(ap->a_cookies), M_TEMP); + *(ap->a_cookies) = NULL; + *(ap->a_ncookies) = 0; + } else { + *ap->a_ncookies = ccp - *(ap->a_cookies); + } + } + uio->uio_offset = off; + free(ndbuf, M_TEMP); + free(cdbuf, M_TEMP); + *ap->a_eofflag = VTOI(vp)->i_size <= uio->uio_offset; + return error; +} + +/* + * Return target name of a symbolic link + */ +int +ulfs_readlink(void *v) +{ + struct vop_readlink_args /* { + struct vnode *a_vp; + struct uio *a_uio; + kauth_cred_t a_cred; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct lfs_inode *ip = VTOI(vp); + struct ulfsmount *ump = VFSTOULFS(vp->v_mount); + int isize; + + isize = ip->i_size; + if (isize < ump->um_maxsymlinklen || + (ump->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) { + uiomove((char *)SHORTLINK(ip), isize, ap->a_uio); + return (0); + } + return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); +} + +/* + * Calculate the logical to physical mapping if not done already, + * then call the device strategy routine. + */ +int +ulfs_strategy(void *v) +{ + struct vop_strategy_args /* { + struct vnode *a_vp; + struct buf *a_bp; + } */ *ap = v; + struct buf *bp; + struct vnode *vp; + struct lfs_inode *ip; + int error; + + bp = ap->a_bp; + vp = ap->a_vp; + ip = VTOI(vp); + if (vp->v_type == VBLK || vp->v_type == VCHR) + panic("ulfs_strategy: spec"); + KASSERT(bp->b_bcount != 0); + if (bp->b_blkno == bp->b_lblkno) { + error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, + NULL); + if (error) { + bp->b_error = error; + biodone(bp); + return (error); + } + if (bp->b_blkno == -1) /* no valid data */ + clrbuf(bp); + } + if (bp->b_blkno < 0) { /* block is not on disk */ + biodone(bp); + return (0); + } + vp = ip->i_devvp; + + return VOP_STRATEGY(vp, bp); +} + +/* + * Print out the contents of an inode. + */ +int +ulfs_print(void *v) +{ + struct vop_print_args /* { + struct vnode *a_vp; + } */ *ap = v; + struct vnode *vp; + struct lfs_inode *ip; + + vp = ap->a_vp; + ip = VTOI(vp); + printf("tag VT_ULFS, ino %llu, on dev %llu, %llu", + (unsigned long long)ip->i_number, + (unsigned long long)major(ip->i_dev), + (unsigned long long)minor(ip->i_dev)); + printf(" flags 0x%x, nlink %d\n", + ip->i_flag, ip->i_nlink); + printf("\tmode 0%o, owner %d, group %d, size %qd", + ip->i_mode, ip->i_uid, ip->i_gid, + (long long)ip->i_size); + if (vp->v_type == VFIFO) + fifo_printinfo(vp); + printf("\n"); + return (0); +} + +/* + * Read wrapper for special devices. + */ +int +ulfsspec_read(void *v) +{ + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + kauth_cred_t a_cred; + } */ *ap = v; + + /* + * Set access flag. + */ + if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0) + VTOI(ap->a_vp)->i_flag |= IN_ACCESS; + return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap)); +} + +/* + * Write wrapper for special devices. + */ +int +ulfsspec_write(void *v) +{ + struct vop_write_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + kauth_cred_t a_cred; + } */ *ap = v; + + /* + * Set update and change flags. + */ + if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0) + VTOI(ap->a_vp)->i_flag |= IN_MODIFY; + return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap)); +} + +/* + * Close wrapper for special devices. + * + * Update the times on the inode then do device close. + */ +int +ulfsspec_close(void *v) +{ + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + kauth_cred_t a_cred; + } */ *ap = v; + struct vnode *vp; + struct lfs_inode *ip; + + vp = ap->a_vp; + ip = VTOI(vp); + if (vp->v_usecount > 1) + ULFS_ITIMES(vp, NULL, NULL, NULL); + return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap)); +} + +/* + * Read wrapper for fifo's + */ +int +ulfsfifo_read(void *v) +{ + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + kauth_cred_t a_cred; + } */ *ap = v; + + /* + * Set access flag. + */ + VTOI(ap->a_vp)->i_flag |= IN_ACCESS; + return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap)); +} + +/* + * Write wrapper for fifo's. + */ +int +ulfsfifo_write(void *v) +{ + struct vop_write_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + kauth_cred_t a_cred; + } */ *ap = v; + + /* + * Set update and change flags. + */ + VTOI(ap->a_vp)->i_flag |= IN_MODIFY; + return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap)); +} + +/* + * Close wrapper for fifo's. + * + * Update the times on the inode then do device close. + */ +int +ulfsfifo_close(void *v) +{ + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + kauth_cred_t a_cred; + } */ *ap = v; + struct vnode *vp; + struct lfs_inode *ip; + + vp = ap->a_vp; + ip = VTOI(vp); + if (ap->a_vp->v_usecount > 1) + ULFS_ITIMES(vp, NULL, NULL, NULL); + return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap)); +} + +/* + * Return POSIX pathconf information applicable to ulfs filesystems. + */ +int +ulfs_pathconf(void *v) +{ + struct vop_pathconf_args /* { + struct vnode *a_vp; + int a_name; + register_t *a_retval; + } */ *ap = v; + + switch (ap->a_name) { + case _PC_LINK_MAX: + *ap->a_retval = LINK_MAX; + return (0); + case _PC_NAME_MAX: + *ap->a_retval = NAME_MAX; + return (0); + case _PC_PATH_MAX: + *ap->a_retval = PATH_MAX; + return (0); + case _PC_PIPE_BUF: + *ap->a_retval = PIPE_BUF; + return (0); + case _PC_CHOWN_RESTRICTED: + *ap->a_retval = 1; + return (0); + case _PC_NO_TRUNC: + *ap->a_retval = 1; + return (0); + case _PC_SYNC_IO: + *ap->a_retval = 1; + return (0); + case _PC_FILESIZEBITS: + *ap->a_retval = 42; + return (0); + case _PC_SYMLINK_MAX: + *ap->a_retval = MAXPATHLEN; + return (0); + case _PC_2_SYMLINKS: + *ap->a_retval = 1; + return (0); + default: + return (EINVAL); + } + /* NOTREACHED */ +} + +/* + * Advisory record locking support + */ +int +ulfs_advlock(void *v) +{ + struct vop_advlock_args /* { + struct vnode *a_vp; + void * a_id; + int a_op; + struct flock *a_fl; + int a_flags; + } */ *ap = v; + struct lfs_inode *ip; + + ip = VTOI(ap->a_vp); + return lf_advlock(ap, &ip->i_lockf, ip->i_size); +} + +/* + * Initialize the vnode associated with a new inode, handle aliased + * vnodes. + */ +void +ulfs_vinit(struct mount *mntp, int (**specops)(void *), int (**fifoops)(void *), + struct vnode **vpp) +{ + struct timeval tv; + struct lfs_inode *ip; + struct vnode *vp; + dev_t rdev; + struct ulfsmount *ump; + + vp = *vpp; + ip = VTOI(vp); + switch(vp->v_type = IFTOVT(ip->i_mode)) { + case VCHR: + case VBLK: + vp->v_op = specops; + ump = ip->i_ump; + rdev = (dev_t)ulfs_rw32(ip->i_ffs1_rdev, + ULFS_MPNEEDSWAP(ump)); + spec_node_init(vp, rdev); + break; + case VFIFO: + vp->v_op = fifoops; + break; + case VNON: + case VBAD: + case VSOCK: + case VLNK: + case VDIR: + case VREG: + break; + } + if (ip->i_number == ROOTINO) + vp->v_vflag |= VV_ROOT; + /* + * Initialize modrev times + */ + getmicrouptime(&tv); + ip->i_modrev = (uint64_t)(uint)tv.tv_sec << 32 + | tv.tv_usec * 4294u; + *vpp = vp; +} + +/* + * Allocate a new inode. + */ +int +ulfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp, + struct componentname *cnp) +{ + struct lfs_inode *ip, *pdir; + struct direct *newdir; + struct vnode *tvp; + int error, ismember = 0; + + pdir = VTOI(dvp); +#ifdef DIAGNOSTIC + if ((cnp->cn_flags & HASBUF) == 0) + panic("ulfs_makeinode: no name"); +#endif + if ((mode & IFMT) == 0) + mode |= IFREG; + + if ((error = ULFS_VALLOC(dvp, mode, cnp->cn_cred, vpp)) != 0) { + PNBUF_PUT(cnp->cn_pnbuf); + vput(dvp); + return (error); + } + tvp = *vpp; + ip = VTOI(tvp); + ip->i_gid = pdir->i_gid; + DIP_ASSIGN(ip, gid, ip->i_gid); + ip->i_uid = kauth_cred_geteuid(cnp->cn_cred); + DIP_ASSIGN(ip, uid, ip->i_uid); +#ifdef QUOTA + if ((error = lfs_chkiq(ip, 1, cnp->cn_cred, 0))) { + ULFS_VFREE(tvp, ip->i_number, mode); + vput(tvp); + PNBUF_PUT(cnp->cn_pnbuf); + vput(dvp); + return (error); + } +#endif + ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; + ip->i_mode = mode; + DIP_ASSIGN(ip, mode, mode); + tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ + ip->i_nlink = 1; + DIP_ASSIGN(ip, nlink, 1); + if ((ip->i_mode & ISGID) && (kauth_cred_ismember_gid(cnp->cn_cred, + ip->i_gid, &ismember) != 0 || !ismember) && + kauth_authorize_generic(cnp->cn_cred, KAUTH_GENERIC_ISSUSER, NULL)) { + ip->i_mode &= ~ISGID; + DIP_ASSIGN(ip, mode, ip->i_mode); + } + + if (cnp->cn_flags & ISWHITEOUT) { + ip->i_flags |= UF_OPAQUE; + DIP_ASSIGN(ip, flags, ip->i_flags); + } + + /* + * Make sure inode goes to disk before directory entry. + */ + if ((error = ULFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0) + goto bad; + newdir = pool_cache_get(ulfs_direct_cache, PR_WAITOK); + ulfs_makedirentry(ip, cnp, newdir); + error = ulfs_direnter(dvp, tvp, newdir, cnp, NULL); + pool_cache_put(ulfs_direct_cache, newdir); + if (error) + goto bad; + if ((cnp->cn_flags & SAVESTART) == 0) + PNBUF_PUT(cnp->cn_pnbuf); + vput(dvp); + *vpp = tvp; + return (0); + + bad: + /* + * Write error occurred trying to update the inode + * or the directory so must deallocate the inode. + */ + ip->i_nlink = 0; + DIP_ASSIGN(ip, nlink, 0); + ip->i_flag |= IN_CHANGE; + /* If IN_ADIROP, account for it */ + ULFS_UNMARK_VNODE(tvp); + tvp->v_type = VNON; /* explodes later if VBLK */ + vput(tvp); + PNBUF_PUT(cnp->cn_pnbuf); + vput(dvp); + return (error); +} + +/* + * Allocate len bytes at offset off. + */ +int +ulfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags, + kauth_cred_t cred) +{ + struct lfs_inode *ip = VTOI(vp); + int error, delta, bshift, bsize; + UVMHIST_FUNC("ulfs_gop_alloc"); UVMHIST_CALLED(ubchist); + + error = 0; + bshift = vp->v_mount->mnt_fs_bshift; + bsize = 1 << bshift; + + delta = off & (bsize - 1); + off -= delta; + len += delta; + + while (len > 0) { + bsize = MIN(bsize, len); + + error = ULFS_BALLOC(vp, off, bsize, cred, flags, NULL); + if (error) { + goto out; + } + + /* + * increase file size now, ULFS_BALLOC() requires that + * EOF be up-to-date before each call. + */ + + if (ip->i_size < off + bsize) { + UVMHIST_LOG(ubchist, "vp %p old 0x%x new 0x%x", + vp, ip->i_size, off + bsize, 0); + ip->i_size = off + bsize; + DIP_ASSIGN(ip, size, ip->i_size); + } + + off += bsize; + len -= bsize; + } + +out: + return error; +} + +void +ulfs_gop_markupdate(struct vnode *vp, int flags) +{ + u_int32_t mask = 0; + + if ((flags & GOP_UPDATE_ACCESSED) != 0) { + mask = IN_ACCESS; + } + if ((flags & GOP_UPDATE_MODIFIED) != 0) { + if (vp->v_type == VREG) { + mask |= IN_CHANGE | IN_UPDATE; + } else { + mask |= IN_MODIFY; + } + } + if (mask) { + struct lfs_inode *ip = VTOI(vp); + + ip->i_flag |= mask; + } +} diff -r f907de68d469 -r fb6a4db31a4e usr.sbin/dumplfs/dumplfs.c --- a/usr.sbin/dumplfs/dumplfs.c Sun Feb 07 01:14:00 2010 -0500 +++ b/usr.sbin/dumplfs/dumplfs.c Sun Feb 07 03:52:22 2010 -0500 @@ -49,7 +49,6 @@ #include #include -#include #include #include @@ -64,7 +63,7 @@ static void addseg(char *); static void dump_cleaner_info(struct lfs *, void *); -static void dump_dinode(struct ufs1_dinode *); +static void dump_dinode(struct lfs_dinode *); static void dump_ifile(int, struct lfs *, int, int, daddr_t); static int dump_ipage_ifile(struct lfs *, int, char *, int); static int dump_ipage_segusage(struct lfs *, int, char *, int); @@ -257,7 +256,7 @@ dump_ifile(int fd, struct lfs *lfsp, int do_ientries, int do_segentries, daddr_t addr) { char *ipage; - struct ufs1_dinode *dip, *dpage; + struct lfs_dinode *dip, *dpage; /* XXX ondisk32 */ int32_t *addrp, *dindir, *iaddrp, *indir; int block_limit, i, inum, j, nblocks, psize; @@ -285,7 +284,7 @@ (void)printf("\nIFILE contents\n"); nblocks = dip->di_size >> lfsp->lfs_bshift; - block_limit = MIN(nblocks, NDADDR); + block_limit = MIN(nblocks, LFS_NDIRECTBLKS); /* Get the direct block */ if ((ipage = malloc(psize)) == NULL) @@ -316,7 +315,7 @@ inum = dump_ipage_ifile(lfsp, inum, ipage, lfsp->lfs_ifpb); } - if (nblocks <= NDADDR) + if (nblocks <= LFS_NDIRECTBLKS) goto e0; /* Dump out blocks off of single indirect block */ @@ -442,7 +441,7 @@ } static void -dump_dinode(struct ufs1_dinode *dip) +dump_dinode(struct lfs_dinode *dip) { int i; time_t at, mt, ct; @@ -463,12 +462,12 @@ "ctime ", ctime(&ct)); (void)printf(" inum %d\n", dip->di_inumber); (void)printf(" Direct Addresses\n"); - for (i = 0; i < NDADDR; i++) { + for (i = 0; i < LFS_NDIRECTBLKS; i++) { (void)printf("\t0x%x", dip->di_db[i]); if ((i % 6) == 5) (void)printf("\n"); } - for (i = 0; i < NIADDR; i++) + for (i = 0; i < LFS_NINDIRBLKS; i++) (void)printf("\t0x%x", dip->di_ib[i]); (void)printf("\n"); } @@ -482,7 +481,7 @@ int ck; int numbytes, numblocks; char *datap; - struct ufs1_dinode *inop; + struct lfs_dinode *inop; size_t el_size; u_int32_t datasum; time_t t; diff -r f907de68d469 -r fb6a4db31a4e usr.sbin/puffs/rump_lfs/Makefile --- a/usr.sbin/puffs/rump_lfs/Makefile Sun Feb 07 01:14:00 2010 -0500 +++ b/usr.sbin/puffs/rump_lfs/Makefile Sun Feb 07 03:52:22 2010 -0500 @@ -5,9 +5,6 @@ MOUNTNAME= lfs -LDADD+= -lrumpfs_ffs -DPADD+= ${LIBRUMPFS_FFS} - ISRUMP= # don't deny it RUMP_DISKFS= diff -r f907de68d469 -r fb6a4db31a4e usr.sbin/puffs/rump_lfs/rump_lfs.c --- a/usr.sbin/puffs/rump_lfs/rump_lfs.c Sun Feb 07 01:14:00 2010 -0500 +++ b/usr.sbin/puffs/rump_lfs/rump_lfs.c Sun Feb 07 03:52:22 2010 -0500 @@ -60,7 +60,7 @@ int main(int argc, char *argv[]) { - struct ufs_args args; + struct lfs_args args; char canon_dev[UKFS_DEVICE_MAXPATHLEN], canon_dir[MAXPATHLEN]; char rawdev[MAXPATHLEN]; struct p2k_mount *p2m;