The ext2fs layer, based on the ffs/ufs one. Uses a few functions from

sys/ufs/ufs/
This commit is contained in:
bouyer 1997-06-11 09:33:37 +00:00
parent 3652b54b5d
commit 9e3c291da4
13 changed files with 6313 additions and 0 deletions

236
sys/ufs/ext2fs/ext2fs.h Normal file
View File

@ -0,0 +1,236 @@
/* $NetBSD: ext2fs.h,v 1.1 1997/06/11 09:33:37 bouyer Exp $ */
/*
* Copyright (c) 1997 Manuel Bouyer.
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)fs.h 8.10 (Berkeley) 10/27/94
* Modified for ext2fs by Manuel Bouyer.
*/
/*
* Each disk drive contains some number of file systems.
* A file system consists of a number of cylinder groups.
* Each cylinder group has inodes and data.
*
* A file system is described by its super-block, which in turn
* describes the cylinder groups. The super-block is critical
* data and is replicated in each cylinder group to protect against
* catastrophic loss. This is done at `newfs' time and the critical
* super-block data does not change, so the copies need not be
* referenced further unless disaster strikes.
*
* The first boot and super blocks are given in absolute disk addresses.
* The byte-offset forms are preferred, as they don't imply a sector size.
*/
#define BBSIZE 1024
#define SBSIZE 1024
#define BBOFF ((off_t)(0))
#define SBOFF ((off_t)(BBOFF + BBSIZE))
#define BBLOCK ((daddr_t)(0))
#define SBLOCK ((daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE))
/*
* Addresses stored in inodes are capable of addressing blocks
* XXX
*/
/*
* MINBSIZE is the smallest allowable block size.
* MINBSIZE must be big enough to hold a cylinder group block,
* thus changes to (struct cg) must keep its size within MINBSIZE.
* Note that super blocks are always of size SBSIZE,
* and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
*/
#define LOG_MINBSIZE 10
#define MINBSIZE (1 << LOG_MINBSIZE)
/*
* The path name on which the file system is mounted is maintained
* in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
* the super block for this name.
*/
#define MAXMNTLEN 512
/*
* MINFREE gives the minimum acceptable percentage of file system
* blocks which may be free. If the freelist drops below this level
* only the superuser may continue to allocate blocks. This may
* be set to 0 if no reserve of free blocks is deemed necessary,
* however throughput drops by fifty percent if the file system
* is run at between 95% and 100% full; thus the minimum default
* value of fs_minfree is 5%. However, to get good clustering
* performance, 10% is a better choice. hence we use 10% as our
* default value. With 10% free space, fragmentation is not a
* problem, so we choose to optimize for time.
*/
#define MINFREE 5
/*
* Super block for an ext2fs file system.
*/
struct ext2fs {
u_int32_t e2fs_icount; /* Inode count */
u_int32_t e2fs_bcount; /* blocks count */
u_int32_t e2fs_rbcount; /* reserved blocks count */
u_int32_t e2fs_fbcount; /* free blocks count */
u_int32_t e2fs_ficount; /* free inodes count */
u_int32_t e2fs_first_dblock; /* first data block */
u_int32_t e2fs_log_bsize; /* block size = 1024*(2^e2fs_log_bsize) */
u_int32_t e2fs_fsize; /* fragment size */
u_int32_t e2fs_bpg; /* blocks per group */
u_int32_t e2fs_fpg; /* frags per group */
u_int32_t e2fs_ipg; /* inodes per group */
u_int32_t e2fs_mtime; /* mount time */
u_int32_t e2fs_wtime; /* write time */
u_int16_t e2fs_mnt_count; /* mount count */
u_int16_t e2fs_max_mnt_count; /* max mount count */
u_int16_t e2fs_magic; /* magic number */
u_int16_t e2fs_state; /* file system state */
u_int16_t e2fs_beh; /* behavior on errors */
u_int16_t reserved;
u_int32_t e2fs_lastfsck; /* time of last fsck */
u_int32_t e2fs_fsckintv; /* max time between fscks */
u_int32_t e2fs_creator; /* creator OS */
u_int32_t e2fs_rev; /* revision level */
u_int16_t e2fs_ruid; /* default uid for reserved blocks */
u_int16_t e2fs_rgid; /* default gid for reserved blocks */
u_int32_t reserved2[235];
};
/* in-memory data for ext2fs */
struct m_ext2fs {
struct ext2fs e2fs;
u_char e2fs_fsmnt[MAXMNTLEN]; /* name mounted on */
int8_t e2fs_ronly; /* mounted read-only flag */
int8_t e2fs_fmod; /* super block modified flag */
int32_t e2fs_bsize; /* block size */
int32_t e2fs_bshift; /* ``lblkno'' calc of logical blkno */
int32_t e2fs_bmask; /* ``blkoff'' calc of blk offsets */
int64_t e2fs_qbmask; /* ~fs_bmask - for use with quad size */
int32_t e2fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
int32_t e2fs_ncg; /* number of cylinder groups */
int32_t e2fs_ngdb; /* number of group descriptor block */
int32_t e2fs_ipb; /* number of inodes per block */
int32_t e2fs_itpg; /* number of inode table per group */
struct ext2_gd *e2fs_gd; /* group descripors */
};
/*
* Filesystem identification
*/
#define E2FS_MAGIC 0xef53 /* the ext2fs magic number */
#define E2FS_REV 0 /* revision level */
/*
* OS identification
*/
#define E2FS_OS_LINUX 0
#define E2FS_OS_HURD 1
#define E2FS_OS_MASIX 2
/*
* Filesystem clean flags
*/
#define E2FS_ISCLEAN 0x01
#define E2FS_ERRORS 0x02
/* ext2 file system block group descriptor */
struct ext2_gd {
u_int32_t ext2bgd_b_bitmap; /* blocks bitmap block */
u_int32_t ext2bgd_i_bitmap; /* inodes bitmap block */
u_int32_t ext2bgd_i_tables; /* inodes table block */
u_int16_t ext2bgd_nbfree; /* number of free blocks */
u_int16_t ext2bgd_nifree; /* number of free inodes */
u_int16_t ext2bgd_ndirs; /* number of directories */
u_int16_t reserved;
u_int32_t reserved2[3];
};
/*
* Turn file system block numbers into disk block addresses.
* This maps file system blocks to device size blocks.
*/
#define fsbtodb(fs, b) ((b) << (fs)->e2fs_fsbtodb)
#define dbtofsb(fs, b) ((b) >> (fs)->e2fs_fsbtodb)
/*
* Macros for handling inode numbers:
* inode number to file system block offset.
* inode number to cylinder group number.
* inode number to file system block address.
*/
#define ino_to_cg(fs, x) (((x) - 1) / (fs)->e2fs.e2fs_ipg)
#define ino_to_fsba(fs, x) \
((fs)->e2fs_gd[ino_to_cg(fs, x)].ext2bgd_i_tables + \
(((x)-1) % (fs)->e2fs.e2fs_ipg)/(fs)->e2fs_ipb)
#define ino_to_fsbo(fs, x) (((x)-1) % (fs)->e2fs_ipb)
/*
* Give cylinder group number for a file system block.
* Give cylinder group block number for a file system block.
*/
#define dtog(fs, d) (((d) - (fs)->e2fs.e2fs_first_dblock) / (fs)->e2fs.e2fs_fpg)
#define dtogd(fs, d) \
(((d) - (fs)->e2fs.e2fs_first_dblock) % (fs)->e2fs.e2fs_fpg)
/*
* The following macros optimize certain frequently calculated
* quantities by using shifts and masks in place of divisions
* modulos and multiplications.
*/
#define blkoff(fs, loc) /* calculates (loc % fs->e2fs_bsize) */ \
((loc) & (fs)->e2fs_qbmask)
#define lblktosize(fs, blk) /* calculates (blk * fs->e2fs_bsize) */ \
((blk) << (fs)->e2fs_bshift)
#define lblkno(fs, loc) /* calculates (loc / fs->e2fs_bsize) */ \
((loc) >> (fs)->e2fs_bshift)
#define blkroundup(fs, size) /* calculates roundup(size, fs->e2fs_bsize) */ \
(((size) + (fs)->e2fs_qbmask) & (fs)->e2fs_bmask)
#define fragroundup(fs, size) /* calculates roundup(size, fs->e2fs_bsize) */ \
(((size) + (fs)->e2fs_qbmask) & (fs)->e2fs_bmask)
/*
* Determine the number of available frags given a
* percentage to hold in reserve.
*/
#define freespace(fs) \
((fs)->e2fs.e2fs_fbcount - (fs)->e2fs.e2fs_rbcount)
/*
* Number of indirects in a file system block.
*/
#define NINDIR(fs) ((fs)->e2fs_bsize / sizeof(u_int32_t))

View File

@ -0,0 +1,650 @@
/* $NetBSD: ext2fs_alloc.c,v 1.1 1997/06/11 09:33:41 bouyer Exp $ */
/*
* Copyright (c) 1997 Manuel Bouyer.
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_alloc.c 8.11 (Berkeley) 10/27/94
* Modified for ext2fs by Manuel Bouyer.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/kernel.h>
#include <sys/syslog.h>
#include <vm/vm.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/ext2fs/ext2fs.h>
#include <ufs/ext2fs/ext2fs_extern.h>
u_long ext2gennumber;
static daddr_t ext2fs_alloccg __P((struct inode *, int, daddr_t, int));
static u_long ext2fs_dirpref __P((struct m_ext2fs *));
static void ext2fs_fserr __P((struct m_ext2fs *, u_int, char *));
static u_long ext2fs_hashalloc __P((struct inode *, int, long, int,
daddr_t (*)(struct inode *, int, daddr_t,
int)));
static daddr_t ext2fs_nodealloccg __P((struct inode *, int, daddr_t, int));
static daddr_t ext2fs_mapsearch __P((struct m_ext2fs *, char *, daddr_t));
/*
* Allocate a block in the file system.
*
* A preference may be optionally specified. If a preference is given
* the following hierarchy is used to allocate a block:
* 1) allocate the requested block.
* 2) allocate a rotationally optimal block in the same cylinder.
* 3) allocate a block in the same cylinder group.
* 4) quadradically rehash into other cylinder groups, until an
* available block is located.
* If no block preference is given the following heirarchy is used
* to allocate a block:
* 1) allocate a block in the cylinder group that contains the
* inode for the file.
* 2) quadradically rehash into other cylinder groups, until an
* available block is located.
*/
int
ext2fs_alloc(ip, lbn, bpref, cred, bnp)
register struct inode *ip;
daddr_t lbn, bpref;
struct ucred *cred;
daddr_t *bnp;
{
register struct m_ext2fs *fs;
daddr_t bno;
int cg;
*bnp = 0;
fs = ip->i_e2fs;
#ifdef DIAGNOSTIC
if (cred == NOCRED)
panic("ext2fs_alloc: missing credential\n");
#endif /* DIAGNOSTIC */
if (fs->e2fs.e2fs_fbcount == 0)
goto nospace;
if (cred->cr_uid != 0 && freespace(fs) <= 0)
goto nospace;
if (bpref >= fs->e2fs.e2fs_bcount)
bpref = 0;
if (bpref == 0)
cg = ino_to_cg(fs, ip->i_number);
else
cg = dtog(fs, bpref);
bno = (daddr_t)ext2fs_hashalloc(ip, cg, bpref, fs->e2fs_bsize,
ext2fs_alloccg);
if (bno > 0) {
ip->i_e2fs_nblock += btodb(fs->e2fs_bsize);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
*bnp = bno;
return (0);
}
nospace:
ext2fs_fserr(fs, cred->cr_uid, "file system full");
uprintf("\n%s: write failed, file system is full\n", fs->e2fs_fsmnt);
return (ENOSPC);
}
/*
* Allocate an inode in the file system.
*
* If allocating a directory, use ext2fs_dirpref to select the inode.
* If allocating in a directory, the following hierarchy is followed:
* 1) allocate the preferred inode.
* 2) allocate an inode in the same cylinder group.
* 3) quadradically rehash into other cylinder groups, until an
* available inode is located.
* If no inode preference is given the following heirarchy is used
* to allocate an inode:
* 1) allocate an inode in cylinder group 0.
* 2) quadradically rehash into other cylinder groups, until an
* available inode is located.
*/
int
ext2fs_valloc(v)
void *v;
{
struct vop_valloc_args /* {
struct vnode *a_pvp;
int a_mode;
struct ucred *a_cred;
struct vnode **a_vpp;
} */ *ap = v;
register struct vnode *pvp = ap->a_pvp;
register struct inode *pip;
register struct m_ext2fs *fs;
register struct inode *ip;
mode_t mode = ap->a_mode;
ino_t ino, ipref;
int cg, error;
*ap->a_vpp = NULL;
pip = VTOI(pvp);
fs = pip->i_e2fs;
if (fs->e2fs.e2fs_ficount == 0)
goto noinodes;
if ((mode & IFMT) == IFDIR)
cg = ext2fs_dirpref(fs);
else
cg = ino_to_cg(fs, pip->i_number);
ipref = cg * fs->e2fs.e2fs_ipg + 1;
ino = (ino_t)ext2fs_hashalloc(pip, cg, (long)ipref, mode, ext2fs_nodealloccg);
if (ino == 0)
goto noinodes;
error = VFS_VGET(pvp->v_mount, ino, ap->a_vpp);
if (error) {
VOP_VFREE(pvp, ino, mode);
return (error);
}
ip = VTOI(*ap->a_vpp);
if (ip->i_e2fs_mode && ip->i_e2fs_nlink != 0) {
printf("mode = 0%o, nlinks %d, inum = %d, fs = %s\n",
ip->i_e2fs_mode, ip->i_e2fs_nlink, ip->i_number, fs->e2fs_fsmnt);
panic("ext2fs_valloc: dup alloc");
}
bzero(&(ip->i_din.e2fs_din), sizeof(struct ext2fs_dinode));
/*
* Set up a new generation number for this inode.
*/
if (++ext2gennumber < (u_long)time.tv_sec)
ext2gennumber = time.tv_sec;
ip->i_e2fs_gen = ext2gennumber;
return (0);
noinodes:
ext2fs_fserr(fs, ap->a_cred->cr_uid, "out of inodes");
uprintf("\n%s: create/symlink failed, no inodes free\n", fs->e2fs_fsmnt);
return (ENOSPC);
}
/*
* Find a cylinder to place a directory.
*
* The policy implemented by this algorithm is to select from
* among those cylinder groups with above the average number of
* free inodes, the one with the smallest number of directories.
*/
static u_long
ext2fs_dirpref(fs)
register struct m_ext2fs *fs;
{
int cg, maxspace, mincg, avgifree;
avgifree = fs->e2fs.e2fs_ficount / fs->e2fs_ncg;
maxspace = 0;
mincg = -1;
for (cg = 0; cg < fs->e2fs_ncg; cg++)
if ( fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree) {
if (mincg == -1 || fs->e2fs_gd[cg].ext2bgd_nbfree > maxspace) {
mincg = cg;
maxspace = fs->e2fs_gd[cg].ext2bgd_nbfree;
}
}
return mincg;
}
/*
* Select the desired position for the next block in a file. The file is
* logically divided into sections. The first section is composed of the
* direct blocks. Each additional section contains fs_maxbpg blocks.
*
* If no blocks have been allocated in the first section, the policy is to
* request a block in the same cylinder group as the inode that describes
* the file. Otherwise, the policy is to try to allocate the blocks
* contigously. The two fields of the ext2 inode extention (see
* ufs/ufs/inode.h) help this.
*/
daddr_t
ext2fs_blkpref(ip, lbn, indx, bap)
struct inode *ip;
daddr_t lbn;
int indx;
daddr_t *bap;
{
register struct m_ext2fs *fs;
register int cg, i;
fs = ip->i_e2fs;
/*
* if we are doing contigous lbn allocation, try to alloc blocks
* contigously on disk
*/
if ( ip->i_e2fs_last_blk && lbn == ip->i_e2fs_last_lblk + 1) {
return ip->i_e2fs_last_blk + 1;
}
/*
* bap, if provided, gives us a list of blocks to which we want to
* stay close
*/
if (bap) {
for (i = indx; i >= 0 ; i--) {
if (bap[i]) {
return bap[i] + 1;
}
}
}
/* fall back to the first block of the cylinder containing the inode */
cg = ino_to_cg(fs, ip->i_number);
return fs->e2fs.e2fs_bpg * cg + fs->e2fs.e2fs_first_dblock + 1;
}
/*
* Implement the cylinder overflow algorithm.
*
* The policy implemented by this algorithm is:
* 1) allocate the block in its requested cylinder group.
* 2) quadradically rehash on the cylinder group number.
* 3) brute force search for a free block.
*/
static u_long
ext2fs_hashalloc(ip, cg, pref, size, allocator)
struct inode *ip;
int cg;
long pref;
int size; /* size for data blocks, mode for inodes */
daddr_t (*allocator) __P((struct inode *, int, daddr_t, int));
{
register struct m_ext2fs *fs;
long result;
int i, icg = cg;
fs = ip->i_e2fs;
/*
* 1: preferred cylinder group
*/
result = (*allocator)(ip, cg, pref, size);
if (result)
return (result);
/*
* 2: quadratic rehash
*/
for (i = 1; i < fs->e2fs_ncg; i *= 2) {
cg += i;
if (cg >= fs->e2fs_ncg)
cg -= fs->e2fs_ncg;
result = (*allocator)(ip, cg, 0, size);
if (result)
return (result);
}
/*
* 3: brute force search
* Note that we start at i == 2, since 0 was checked initially,
* and 1 is always checked in the quadratic rehash.
*/
cg = (icg + 2) % fs->e2fs_ncg;
for (i = 2; i < fs->e2fs_ncg; i++) {
result = (*allocator)(ip, cg, 0, size);
if (result)
return (result);
cg++;
if (cg == fs->e2fs_ncg)
cg = 0;
}
return (NULL);
}
/*
* Determine whether a block can be allocated.
*
* Check to see if a block of the appropriate size is available,
* and if it is, allocate it.
*/
static daddr_t
ext2fs_alloccg(ip, cg, bpref, size)
struct inode *ip;
int cg;
daddr_t bpref;
int size;
{
register struct m_ext2fs *fs;
register char *bbp;
struct buf *bp;
int error, bno, start, end, loc;
fs = ip->i_e2fs;
if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0)
return (NULL);
error = bread(ip->i_devvp, fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
return (NULL);
}
bbp = (char *)bp->b_data;
if (dtog(fs, bpref) != cg)
bpref = 0;
if (bpref != 0) {
bpref = dtogd(fs, bpref);
/*
* if the requested block is available, use it
*/
if (isclr(bbp, bpref)) {
bno = bpref;
goto gotit;
}
}
/*
* no blocks in the requested cylinder, so take next
* available one in this cylinder group.
* first try to get 8 contigous blocks, then fall back to a single
* block.
*/
if (bpref)
start = dtogd(fs, bpref) / NBBY;
else
start = 0;
end = howmany(fs->e2fs.e2fs_fpg, NBBY) - start;
for (loc = start; loc < end; loc++) {
if (bbp[loc] == 0) {
bno = loc * NBBY;
goto gotit;
}
}
for (loc = 0; loc < start; loc++) {
if (bbp[loc] == 0) {
bno = loc * NBBY;
goto gotit;
}
}
bno = ext2fs_mapsearch(fs, bbp, bpref);
if (bno < 0)
return (NULL);
gotit:
#ifdef DIAGNOSTIC
if (isset(bbp, (long)bno)) {
printf("ext2fs_alloccgblk: cg=%d bno=%d fs=%s\n",
cg, bno, fs->e2fs_fsmnt);
panic("ext2fs_valloc: dup alloc");
}
#endif
setbit(bbp, (long)bno);
fs->e2fs.e2fs_fbcount--;
fs->e2fs_gd[cg].ext2bgd_nbfree--;
fs->e2fs_fmod = 1;
bdwrite(bp);
return (cg * fs->e2fs.e2fs_fpg + fs->e2fs.e2fs_first_dblock + bno);
}
/*
* Determine whether an inode can be allocated.
*
* Check to see if an inode is available, and if it is,
* allocate it using the following policy:
* 1) allocate the requested inode.
* 2) allocate the next available inode after the requested
* inode in the specified cylinder group.
*/
static daddr_t
ext2fs_nodealloccg(ip, cg, ipref, mode)
struct inode *ip;
int cg;
daddr_t ipref;
int mode;
{
register struct m_ext2fs *fs;
register char *ibp;
struct buf *bp;
int error, start, len, loc, map, i;
ipref--; /* to avoid a lot of (ipref -1) */
fs = ip->i_e2fs;
if (fs->e2fs_gd[cg].ext2bgd_nifree == 0)
return (NULL);
error = bread(ip->i_devvp, fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
return (NULL);
}
ibp = (char *)bp->b_data;
if (ipref) {
ipref %= fs->e2fs.e2fs_ipg;
if (isclr(ibp, ipref))
goto gotit;
}
start = ipref / NBBY;
len = howmany(fs->e2fs.e2fs_ipg - ipref, NBBY);
loc = skpc(0xff, len, &ibp[start]);
if (loc == 0) {
len = start + 1;
start = 0;
loc = skpc(0xff, len, &ibp[0]);
if (loc == 0) {
printf("cg = %d, ipref = %d, fs = %s\n",
cg, ipref, fs->e2fs_fsmnt);
panic("ext2fs_nodealloccg: map corrupted");
/* NOTREACHED */
}
}
i = start + len - loc;
map = ibp[i];
ipref = i * NBBY;
for (i = 1; i < (1 << NBBY); i <<= 1, ipref++) {
if ((map & i) == 0) {
goto gotit;
}
}
printf("fs = %s\n", fs->e2fs_fsmnt);
panic("ext2fs_nodealloccg: block not in map");
/* NOTREACHED */
gotit:
setbit(ibp, ipref);
fs->e2fs.e2fs_ficount--;
fs->e2fs_gd[cg].ext2bgd_nifree--;
fs->e2fs_fmod = 1;
if ((mode & IFMT) == IFDIR) {
fs->e2fs_gd[cg].ext2bgd_ndirs++;
}
bdwrite(bp);
return (cg * fs->e2fs.e2fs_ipg + ipref +1);
}
/*
* Free a block.
*
* The specified block is placed back in the
* free map.
*/
void
ext2fs_blkfree(ip, bno)
register struct inode *ip;
daddr_t bno;
{
register struct m_ext2fs *fs;
register char *bbp;
struct buf *bp;
int error, cg;
fs = ip->i_e2fs;
cg = dtog(fs, bno);
if ((u_int)bno >= fs->e2fs.e2fs_bcount) {
printf("bad block %d, ino %d\n", bno, ip->i_number);
ext2fs_fserr(fs, ip->i_e2fs_uid, "bad block");
return;
}
error = bread(ip->i_devvp, fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
return;
}
bbp = (char *)bp->b_data;
bno = dtogd(fs, bno);
if (isclr(bbp, bno)) {
printf("dev = 0x%x, block = %d, fs = %s\n",
ip->i_dev, bno, fs->e2fs_fsmnt);
panic("blkfree: freeing free block");
}
clrbit(bbp, bno);
fs->e2fs.e2fs_fbcount++;
fs->e2fs_gd[cg].ext2bgd_nbfree++;
fs->e2fs_fmod = 1;
bdwrite(bp);
}
/*
* Free an inode.
*
* The specified inode is placed back in the free map.
*/
int
ext2fs_vfree(v)
void *v;
{
struct vop_vfree_args /* {
struct vnode *a_pvp;
ino_t a_ino;
int a_mode;
} */ *ap = v;
register struct m_ext2fs *fs;
register char *ibp;
register struct inode *pip;
ino_t ino = ap->a_ino;
struct buf *bp;
int error, cg;
pip = VTOI(ap->a_pvp);
fs = pip->i_e2fs;
if ((u_int)ino >= fs->e2fs.e2fs_icount || (u_int)ino < EXT2_FIRSTINO)
panic("ifree: range: dev = 0x%x, ino = %d, fs = %s\n",
pip->i_dev, ino, fs->e2fs_fsmnt);
cg = ino_to_cg(fs, ino);
error = bread(pip->i_devvp, fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
return (0);
}
ibp = (char *)bp->b_data;
ino = (ino - 1) % fs->e2fs.e2fs_ipg;
if (isclr(ibp, ino)) {
printf("dev = 0x%x, ino = %d, fs = %s\n",
pip->i_dev, ino, fs->e2fs_fsmnt);
if (fs->e2fs_ronly == 0)
panic("ifree: freeing free inode");
}
clrbit(ibp, ino);
fs->e2fs.e2fs_ficount++;
fs->e2fs_gd[cg].ext2bgd_nifree++;
if ((ap->a_mode & IFMT) == IFDIR) {
fs->e2fs_gd[cg].ext2bgd_ndirs--;
}
fs->e2fs_fmod = 1;
bdwrite(bp);
return (0);
}
/*
* Find a block in the specified cylinder group.
*
* It is a panic if a request is made to find a block if none are
* available.
*/
static daddr_t
ext2fs_mapsearch(fs, bbp, bpref)
register struct m_ext2fs *fs;
register char *bbp;
daddr_t bpref;
{
daddr_t bno;
int start, len, loc, i, map;
/*
* find the fragment by searching through the free block
* map for an appropriate bit pattern
*/
if (bpref)
start = dtogd(fs, bpref) / NBBY;
else
start = 0;
len = howmany(fs->e2fs.e2fs_fpg, NBBY) - start;
loc = skpc(0xff, len, &bbp[start]);
if (loc == 0) {
len = start + 1;
start = 0;
loc = skpc(0xff, len, &bbp[start]);
if (loc == 0) {
printf("start = %d, len = %d, fs = %s\n",
start, len, fs->e2fs_fsmnt);
panic("ext2fs_alloccg: map corrupted");
/* NOTREACHED */
}
}
i = start + len - loc;
map = bbp[i];
bno = i * NBBY;
for (i = 1; i < (1 << NBBY); i <<= 1, bno++) {
if ((map & i) == 0)
return (bno);
}
printf("fs = %s\n", fs->e2fs_fsmnt);
panic("ext2fs_mapsearch: block not in map");
/* NOTREACHED */
}
/*
* Fserr prints the name of a file system with an error diagnostic.
*
* The form of the error message is:
* fs: error message
*/
static void
ext2fs_fserr(fs, uid, cp)
struct m_ext2fs *fs;
u_int uid;
char *cp;
{
log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->e2fs_fsmnt, cp);
}

View File

@ -0,0 +1,247 @@
/* $NetBSD: ext2fs_balloc.c,v 1.1 1997/06/11 09:33:44 bouyer Exp $ */
/*
* Copyright (c) 1997 Manuel Bouyer.
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93
* Modified for ext2fs by Manuel Bouyer.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/vnode.h>
#include <vm/vm.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/ext2fs/ext2fs.h>
#include <ufs/ext2fs/ext2fs_extern.h>
/*
* Balloc defines the structure of file system storage
* by allocating the physical blocks on a device given
* the inode and the logical block number in a file.
*/
int
ext2fs_balloc(ip, bn, size, cred, bpp, flags)
register struct inode *ip;
register daddr_t bn;
int size;
struct ucred *cred;
struct buf **bpp;
int flags;
{
register struct m_ext2fs *fs;
register daddr_t nb;
struct buf *bp, *nbp;
struct vnode *vp = ITOV(ip);
struct indir indirs[NIADDR + 2];
daddr_t newb, lbn, *bap, pref;
int num, i, error;
*bpp = NULL;
if (bn < 0)
return (EFBIG);
fs = ip->i_e2fs;
lbn = bn;
/*
* The first NDADDR blocks are direct blocks
*/
if (bn < NDADDR) {
nb = ip->i_e2fs_blocks[bn];
if (nb != 0) {
error = bread(vp, bn, fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
return (error);
}
*bpp = bp;
return (0);
} else {
error = ext2fs_alloc(ip, bn,
ext2fs_blkpref(ip, bn, (int)bn, &ip->i_e2fs_blocks[0]),
cred, &newb);
if (error)
return (error);
ip->i_e2fs_last_lblk = lbn;
ip->i_e2fs_last_blk = newb;
bp = getblk(vp, bn, fs->e2fs_bsize, 0, 0);
bp->b_blkno = fsbtodb(fs, newb);
if (flags & B_CLRBUF)
clrbuf(bp);
}
ip->i_e2fs_blocks[bn] = dbtofsb(fs, bp->b_blkno);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
*bpp = bp;
return (0);
}
/*
* Determine the number of levels of indirection.
*/
pref = 0;
if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0)
return(error);
#ifdef DIAGNOSTIC
if (num < 1)
panic ("ext2fs_balloc: ufs_getlbns returned indirect block\n");
#endif
/*
* Fetch the first indirect block allocating if necessary.
*/
--num;
nb = ip->i_e2fs_blocks[NDADDR + indirs[0].in_off];
if (nb == 0) {
pref = ext2fs_blkpref(ip, lbn, 0, (daddr_t *)0);
error = ext2fs_alloc(ip, lbn, pref,
cred, &newb);
if (error)
return (error);
nb = newb;
ip->i_e2fs_last_blk = newb;
bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0);
bp->b_blkno = fsbtodb(fs, newb);
clrbuf(bp);
/*
* Write synchronously so that indirect blocks
* never point at garbage.
*/
if ((error = bwrite(bp)) != 0) {
ext2fs_blkfree(ip, nb);
return (error);
}
ip->i_e2fs_blocks[NDADDR + indirs[0].in_off] = newb;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
}
/*
* Fetch through the indirect blocks, allocating as necessary.
*/
for (i = 1;;) {
error = bread(vp,
indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
return (error);
}
bap = (daddr_t *)bp->b_data;
nb = bap[indirs[i].in_off];
if (i == num)
break;
i += 1;
if (nb != 0) {
brelse(bp);
continue;
}
pref = ext2fs_blkpref(ip, lbn, 0, (daddr_t *)0);
error = ext2fs_alloc(ip, lbn, pref, cred,
&newb);
if (error) {
brelse(bp);
return (error);
}
nb = newb;
ip->i_e2fs_last_blk = newb;
nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0);
nbp->b_blkno = fsbtodb(fs, nb);
clrbuf(nbp);
/*
* Write synchronously so that indirect blocks
* never point at garbage.
*/
if ((error = bwrite(nbp)) != 0) {
ext2fs_blkfree(ip, nb);
brelse(bp);
return (error);
}
bap[indirs[i - 1].in_off] = nb;
/*
* If required, write synchronously, otherwise use
* delayed write.
*/
if (flags & B_SYNC) {
bwrite(bp);
} else {
bdwrite(bp);
}
}
/*
* Get the data block, allocating if necessary.
*/
if (nb == 0) {
pref = ext2fs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]);
error = ext2fs_alloc(ip, lbn, pref, cred,
&newb);
if (error) {
brelse(bp);
return (error);
}
nb = newb;
ip->i_e2fs_last_lblk = lbn;
ip->i_e2fs_last_blk = newb;
nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0);
nbp->b_blkno = fsbtodb(fs, nb);
if (flags & B_CLRBUF)
clrbuf(nbp);
bap[indirs[i].in_off] = nb;
/*
* If required, write synchronously, otherwise use
* delayed write.
*/
if (flags & B_SYNC) {
bwrite(bp);
} else {
bdwrite(bp);
}
*bpp = nbp;
return (0);
}
brelse(bp);
if (flags & B_CLRBUF) {
error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp);
if (error) {
brelse(nbp);
return (error);
}
} else {
nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0);
nbp->b_blkno = fsbtodb(fs, nb);
}
*bpp = nbp;
return (0);
}

View File

@ -0,0 +1,222 @@
/* $NetBSD: ext2fs_bmap.c,v 1.1 1997/06/11 09:33:46 bouyer Exp $ */
/*
* Copyright (c) 1997 Manuel Bouyer.
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ufs_bmap.c 8.6 (Berkeley) 1/21/94
* Modified for ext2fs by Manuel Bouyer.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/resourcevar.h>
#include <sys/trace.h>
#include <miscfs/specfs/specdev.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/ext2fs/ext2fs_extern.h>
static int ext2fs_bmaparray __P((struct vnode *, daddr_t, daddr_t *,
struct indir *, int *, int *));
/*
* Bmap converts a 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
ext2fs_bmap(v)
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;
/*
* 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);
return (ext2fs_bmaparray(ap->a_vp, ap->a_bn, ap->a_bnp, NULL, NULL,
ap->a_runp));
}
/*
* 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.
*
* ext2fs_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
ext2fs_bmaparray(vp, bn, bnp, ap, nump, runp)
struct vnode *vp;
register daddr_t bn;
daddr_t *bnp;
struct indir *ap;
int *nump;
int *runp;
{
register struct inode *ip;
struct buf *bp;
struct ufsmount *ump;
struct mount *mp;
struct vnode *devvp;
struct indir a[NIADDR], *xap;
daddr_t daddr;
long metalbn;
int error, maxrun = 0, num;
ip = VTOI(vp);
mp = vp->v_mount;
ump = VFSTOUFS(mp);
#ifdef DIAGNOSTIC
if ((ap != NULL && nump == NULL) || (ap == NULL && nump != NULL))
panic("ext2fs_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 = MAXBSIZE / mp->mnt_stat.f_iosize - 1;
}
xap = ap == NULL ? a : ap;
if (!nump)
nump = &num;
if ((error = ufs_getlbns(vp, bn, xap, nump)) != 0)
return (error);
num = *nump;
if (num == 0) {
*bnp = blkptrtodb(ump, ip->i_e2fs_blocks[bn]);
if (*bnp == 0)
*bnp = -1;
else if (runp)
for (++bn; bn < NDADDR && *runp < maxrun &&
is_sequential(ump, ip->i_e2fs_blocks[bn - 1],
ip->i_e2fs_blocks[bn]);
++bn, ++*runp);
return (0);
}
/* Get disk address out of indirect block array */
daddr = ip->i_e2fs_blocks[NDADDR + xap->in_off];
devvp = VFSTOUFS(vp->v_mount)->um_devvp;
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 ((daddr == 0 && !incore(vp, metalbn)) || metalbn == bn)
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);
xap->in_exists = 1;
bp = getblk(vp, metalbn, mp->mnt_stat.f_iosize, 0, 0);
if (bp->b_flags & (B_DONE | B_DELWRI)) {
trace(TR_BREADHIT, pack(vp, size), metalbn);
}
#ifdef DIAGNOSTIC
else if (!daddr)
panic("ext2fs_bmaparry: 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;
VOP_STRATEGY(bp);
curproc->p_stats->p_ru.ru_inblock++; /* XXX */
if ((error = biowait(bp)) != 0) {
brelse(bp);
return (error);
}
}
daddr = ((daddr_t *)bp->b_data)[xap->in_off];
if (num == 1 && daddr && runp)
for (bn = xap->in_off + 1;
bn < MNINDIR(ump) && *runp < maxrun &&
is_sequential(ump, ((daddr_t *)bp->b_data)[bn - 1],
((daddr_t *)bp->b_data)[bn]);
++bn, ++*runp);
}
if (bp)
brelse(bp);
daddr = blkptrtodb(ump, daddr);
*bnp = daddr == 0 ? -1 : daddr;
return (0);
}

View File

@ -0,0 +1,132 @@
/* $NetBSD: ext2fs_dinode.h,v 1.1 1997/06/11 09:33:48 bouyer Exp $ */
/*
* Copyright (c) 1997 Manuel Bouyer.
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)dinode.h 8.6 (Berkeley) 9/13/94
* Modified for ext2fs by Manuel Bouyer.
*/
#include <sys/stat.h>
/*
* The root inode is the root of the file system. Inode 0 can't be used for
* normal purposes and bad blocks are normally linked to inode 1, thus
* the root inode is 2.
* Inode 3 to 10 are reserved in ext2fs.
*/
#define EXT2_ROOTINO ((ino_t)2)
#define EXT2_FIRSTINO ((ino_t)11)
/*
* A dinode contains all the meta-data associated with a UFS file.
* This structure defines the on-disk format of a dinode. Since
* this structure describes an on-disk structure, all its fields
* are defined by types with precise widths.
*/
#define NDADDR 12 /* Direct addresses in inode. */
#define NIADDR 3 /* Indirect addresses in inode. */
#define EXT2_MAXSYMLINKLEN ((NDADDR+NIADDR) * sizeof (u_int32_t))
struct ext2fs_dinode {
u_int16_t e2di_mode; /* 0: IFMT, permissions; see below. */
u_int16_t e2di_uid; /* 2: Owner UID */
u_int32_t e2di_size; /* 4: Size (in bytes) */
u_int32_t e2di_atime; /* 8: Acces time */
u_int32_t e2di_ctime; /* 12: Create time */
u_int32_t e2di_mtime; /* 16: Modification time */
u_int32_t e2di_dtime; /* 20: Deletion time */
u_int16_t e2di_gid; /* 24: Owner GID */
u_int16_t e2di_nlink; /* 26: File link count */
u_int32_t e2di_nblock;/* 28: Blocks count */
u_int32_t e2di_flags; /* 32: Status flags (chflags) */
u_int32_t e2di_linux_reserved1; /* 36 */
u_int32_t e2di_blocks[NDADDR+NIADDR]; /* 40: disk blocks */
u_int32_t e2di_gen; /* 100: generation number (file version) */
u_int32_t e2di_facl; /* 104: file ACL (not implemented) */
u_int32_t e2di_dacl; /* 108: dir ACL (not implemented) */
u_int32_t e2di_faddr; /* 112: fragment address */
u_int8_t e2di_nfrag; /* 116: fragment number */
u_int8_t e2di_fsize; /* 117: fragment size */
u_int16_t e2di_linux_reserved2; /* 118 */
u_int32_t e2di_linux_reserved3[2]; /* 120 */
};
#define E2MAXSYMLINKLEN ((NDADDR + NIADDR) * sizeof(u_int32_t))
/* File permissions. */
#define EXT2_IEXEC 0000100 /* Executable. */
#define EXT2_IWRITE 0000200 /* Writeable. */
#define EXT2_IREAD 0000400 /* Readable. */
#define EXT2_ISVTX 0001000 /* Sticky bit. */
#define EXT2_ISGID 0002000 /* Set-gid. */
#define EXT2_ISUID 0004000 /* Set-uid. */
/* File types. */
#define EXT2_IFMT 0170000 /* Mask of file type. */
#define EXT2_IFIFO 0010000 /* Named pipe (fifo). */
#define EXT2_IFCHR 0020000 /* Character device. */
#define EXT2_IFDIR 0040000 /* Directory file. */
#define EXT2_IFBLK 0060000 /* Block device. */
#define EXT2_IFREG 0100000 /* Regular file. */
#define EXT2_IFLNK 0120000 /* Symbolic link. */
#define EXT2_IFSOCK 0140000 /* UNIX domain socket. */
/* file flags */
#define EXT2_SECRM 0x00000001 /* Secure deletion */
#define EXT2_UNRM 0x00000002 /* Undelete */
#define EXT2_COMPR 0x00000004 /* Compress file */
#define EXT2_SYNC 0x00000008 /* Synchronous updates */
#define EXT2_IMMUTABLE 0x00000010 /* Immutable file */
#define EXT2_APPEND 0x00000020 /* writes to file may only append */
#define EXT2_NODUMP 0x00000040 /* do not dump file */
/*
* The e2di_blocks fields may be overlaid with other information for
* file types that do not have associated disk storage. Block
* and character devices overlay the first data block with their
* dev_t value. Short symbolic links place their path in the
* di_db area.
*/
#define e2di_rdev e2di_blocks[0]
#define e2di_shortlink e2di_blocks

114
sys/ufs/ext2fs/ext2fs_dir.h Normal file
View File

@ -0,0 +1,114 @@
/* $NetBSD: ext2fs_dir.h,v 1.1 1997/06/11 09:33:50 bouyer Exp $ */
/*
* Copyright (c) 1997 Manuel Bouyer.
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)dir.h 8.4 (Berkeley) 8/10/94
* Modified for ext2fs by Manuel Bouyer.
*/
#ifndef _EXT2FS_DIR_H_
#define _EXT2FS_DIR_H_
/*
* Theoretically, directories can be more than 2Gb in length, however, in
* practice this seems unlikely. So, we define the type doff_t as a 32-bit
* quantity to keep down the cost of doing lookup on a 32-bit machine.
*/
#define doff_t int32_t
#define EXT2FS_MAXDIRSIZE (0x7fffffff)
/*
* A directory consists of some number of blocks of e2fs_bsize bytes.
*
* Each block contains some number of directory entry
* structures, which are of variable length. Each directory entry has
* a struct direct at the front of it, containing its inode number,
* the length of the entry, and the length of the name contained in
* the entry. These are followed by the name padded to a 4 byte boundary
* with null bytes. All names are guaranteed null terminated.
* The maximum length of a name in a directory is EXT2FS_MAXNAMLEN.
*
* The macro EXT2FS_DIRSIZ(fmt, dp) gives the amount of space required to
* represent a directory entry. Free space in a directory is represented by
* entries which have dp->e2d_reclen > DIRSIZ(fmt, dp). All d2fs_bsize bytes
* in a directory block are claimed by the directory entries. This
* usually results in the last entry in a directory having a large
* dp->e2d_reclen. When entries are deleted from a directory, the
* space is returned to the previous entry in the same directory
* block by increasing its dp->e2d_reclen. If the first entry of
* a directory block is free, then its dp->e2d_ino is set to 0.
* Entries other than the first in a directory do not normally have
* dp->e2d_ino set to 0.
*/
#define EXT2FS_MAXNAMLEN 255
struct ext2fs_direct {
u_int32_t e2d_ino; /* inode number of entry */
u_int16_t e2d_reclen; /* length of this record */
u_int16_t e2d_namlen; /* length of string in d_name */
char e2d_name[EXT2FS_MAXNAMLEN];/* name with length <= EXT2FS_MAXNAMLEN */
};
/*
* The EXT2FS_DIRSIZ macro gives the minimum record length which will hold
* the directory entryfor a name len "len" (without the terminating null byte).
* This requires the amount of space in struct direct
* without the d_name field, plus enough space for the name without a
* terminating null byte, rounded up to a 4 byte boundary.
*/
#define EXT2FS_DIRSIZ(len) \
(( 8 + len + 3) &~ 3)
/*
* Template for manipulating directories. Should use struct direct's,
* but the name field is EXT2FS_MAXNAMLEN - 1, and this just won't do.
*/
struct ext2fs_dirtemplate {
u_int32_t dot_ino;
int16_t dot_reclen;
u_int16_t dot_namlen;
char dot_name[4]; /* must be multiple of 4 */
u_int32_t dotdot_ino;
int16_t dotdot_reclen;
u_int16_t dotdot_namlen;
char dotdot_name[4]; /* ditto */
};
#endif /* !_EXT2FS_DIR_H_ */

View File

@ -0,0 +1,154 @@
/* $NetBSD: ext2fs_extern.h,v 1.1 1997/06/11 09:33:55 bouyer Exp $ */
/*-
* Copyright (c) 1997 Manuel Bouyer.
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_extern.h 8.3 (Berkeley) 4/16/94
* Modified for ext2fs by Manuel Bouyer.
*/
struct buf;
struct fid;
struct m_ext2fs;
struct inode;
struct mount;
struct nameidata;
struct proc;
struct statfs;
struct timeval;
struct ucred;
struct ufsmount;
struct uio;
struct vnode;
struct mbuf;
struct componentname;
__BEGIN_DECLS
/* ext2fs_alloc.c */
int ext2fs_alloc __P((struct inode *, daddr_t, daddr_t , struct ucred *,
daddr_t *));
int ext2fs_realloccg __P((struct inode *, daddr_t, daddr_t, int, int ,
struct ucred *, struct buf **));
int ext2fs_reallocblks __P((void *));
int ext2fs_valloc __P((void *));
daddr_t ext2fs_blkpref __P((struct inode *, daddr_t, int, daddr_t *));
void ext2fs_blkfree __P((struct inode *, daddr_t));
int ext2fs_vfree __P((void *));
/* ext2fs_balloc.c */
int ext2fs_balloc __P((struct inode *, daddr_t, int, struct ucred *,
struct buf **, int));
/* ext2fs_bmap.c */
int ext2fs_bmap __P((void *));
/* ext2fs_inode.c */
void ext2fs_init __P((void));
int ext2fs_update __P((void *));
int ext2fs_truncate __P((void *));
int ext2fs_inactive __P((void *));
/* ext2fs_lookup.c */
int ext2fs_readdir __P((void *));
int ext2fs_lookup __P((void *));
int ext2fs_direnter __P((struct inode *, struct vnode *,
struct componentname *));
int ext2fs_dirremove __P((struct vnode *, struct componentname *));
int ext2fs_dirrewrite __P((struct inode *, struct inode *,
struct componentname *));
int ext2fs_dirempty __P((struct inode *, ino_t, struct ucred *));
int ext2fs_checkpath __P((struct inode *, struct inode *, struct ucred *));
/* ext2fs_subr.c */
int ext2fs_blkatoff __P((void *));
void ext2fs_fragacct __P((struct m_ext2fs *, int, int32_t[], int));
#ifdef DIAGNOSTIC
void ext2fs_checkoverlap __P((struct buf *, struct inode *));
#endif
/* ext2fs_vfsops.c */
int ext2fs_mountroot __P((void));
int ext2fs_mount __P((struct mount *, const char *, void *, struct nameidata *,
struct proc *));
int ext2fs_reload __P((struct mount *, struct ucred *, struct proc *));
int ext2fs_mountfs __P((struct vnode *, struct mount *, struct proc *));
int ext2fs_unmount __P((struct mount *, int, struct proc *));
int ext2fs_flushfiles __P((struct mount *, int, struct proc *));
int ext2fs_statfs __P((struct mount *, struct statfs *, struct proc *));
int ext2fs_sync __P((struct mount *, int, struct ucred *, struct proc *));
int ext2fs_vget __P((struct mount *, ino_t, struct vnode **));
int ext2fs_fhtovp __P((struct mount *, struct fid *, struct mbuf *,
struct vnode **, int *, struct ucred **));
int ext2fs_vptofh __P((struct vnode *, struct fid *));
int ext2fs_sbupdate __P((struct ufsmount *, int));
int ext2fs_cgupdate __P((struct ufsmount *, int));
/* ext2fs_readwrite.c */
int ext2fs_read __P((void *));
int ext2fs_write __P((void *));
/* ext2fs_vnops.c */
int ext2fs_create __P((void *));
int ext2fs_mknod __P((void *));
int ext2fs_open __P((void *));
int ext2fs_access __P((void *));
int ext2fs_getattr __P((void *));
int ext2fs_setattr __P((void *));
int ext2fs_remove __P((void *));
int ext2fs_link __P((void *));
int ext2fs_rename __P((void *));
int ext2fs_mkdir __P((void *));
int ext2fs_rmdir __P((void *));
int ext2fs_symlink __P((void *));
int ext2fs_readlink __P((void *));
int ext2fs_advlock __P((void *));
int ext2fs_vinit __P(( struct mount *, int (**specops) __P((void *)),
int (**fifoops) __P((void *)), struct vnode **));
int ext2fs_makeinode __P((int, struct vnode *, struct vnode **,
struct componentname *cnp));
int ext2fs_reclaim __P((void *));
#define ext2fs_fsync genfs_fsync
__END_DECLS
#define IS_EXT2_VNODE(vp) (vp->v_tag == VT_EXT2FS)
extern int (**ext2fs_vnodeop_p) __P((void *));
extern int (**ext2fs_specop_p) __P((void *));
#ifdef FIFO
extern int (**ext2fs_fifoop_p) __P((void *));
#define EXT2FS_FIFOOPS ext2fs_fifoop_p
#else
#define EXT2FS_FIFOOPS NULL
#endif

View File

@ -0,0 +1,528 @@
/* $NetBSD: ext2fs_inode.c,v 1.1 1997/06/11 09:33:56 bouyer Exp $ */
/*
* Copyright (c) 1997 Manuel Bouyer.
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_inode.c 8.8 (Berkeley) 10/19/94
* Modified for ext2fs by Manuel Bouyer.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/trace.h>
#include <sys/resourcevar.h>
#include <vm/vm.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/ext2fs/ext2fs.h>
#include <ufs/ext2fs/ext2fs_extern.h>
static int ext2fs_indirtrunc __P((struct inode *, daddr_t, daddr_t,
daddr_t, int, long *));
void
ext2fs_init()
{
static int done = 0;
if (done)
return;
done = 1;
ufs_ihashinit();
return;
}
/*
* Last reference to an inode. If necessary, write or delete it.
*/
int
ext2fs_inactive(v)
void *v;
{
struct vop_inactive_args /* {
struct vnode *a_vp;
} */ *ap = v;
register struct vnode *vp = ap->a_vp;
register struct inode *ip = VTOI(vp);
struct timespec ts;
int error;
extern int prtactive;
if (prtactive && vp->v_usecount != 0)
vprint("ffs_inactive: pushing active", vp);
/* Get rid of inodes related to stale file handles. */
if (ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime != 0) {
if ((vp->v_flag & VXLOCK) == 0)
vgone(vp);
return (0);
}
error = 0;
#ifdef DIAGNOSTIC
if (VOP_ISLOCKED(vp))
panic("ffs_inactive: locked inode");
if (curproc)
ip->i_lockholder = curproc->p_pid;
else
ip->i_lockholder = -1;
#endif
ip->i_flag |= IN_LOCKED;
if (ip->i_e2fs_nlink == 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
error = VOP_TRUNCATE(vp, (off_t)0, 0, NOCRED, NULL);
TIMEVAL_TO_TIMESPEC(&time, &ts);
ip->i_e2fs_dtime = ts.tv_sec;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
VOP_VFREE(vp, ip->i_number, ip->i_e2fs_mode);
}
if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) {
TIMEVAL_TO_TIMESPEC(&time, &ts);
VOP_UPDATE(vp, &ts, &ts, 0);
}
VOP_UNLOCK(vp);
/*
* If we are done with the inode, reclaim it
* so that it can be reused immediately.
*/
if (vp->v_usecount == 0 && ip->i_e2fs_dtime != 0)
vgone(vp);
return (error);
}
/*
* Update the access, modified, and inode change times as specified by the
* IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is
* used to specify that the inode needs to be updated but that the times have
* already been set. The access and modified times are taken from the second
* and third parameters; the inode change time is always taken from the current
* time. If waitfor is set, then wait for the disk write of the inode to
* complete.
*/
int
ext2fs_update(v)
void *v;
{
struct vop_update_args /* {
struct vnode *a_vp;
struct timespec *a_access;
struct timespec *a_modify;
int a_waitfor;
} */ *ap = v;
register struct m_ext2fs *fs;
struct buf *bp;
struct inode *ip;
int error;
struct timespec ts;
if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
return (0);
ip = VTOI(ap->a_vp);
TIMEVAL_TO_TIMESPEC(&time, &ts);
EXT2FS_ITIMES(ip, ap->a_access, ap->a_modify, &ts);
if ((ip->i_flag & IN_MODIFIED) == 0)
return (0);
ip->i_flag &= ~IN_MODIFIED;
fs = ip->i_e2fs;
error = bread(ip->i_devvp,
fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
return (error);
}
bcopy(&ip->i_din.e2fs_din,
((struct ext2fs_dinode *)bp->b_data + ino_to_fsbo(fs, ip->i_number)),
sizeof(struct ext2fs_dinode));
if (ap->a_waitfor)
return (bwrite(bp));
else {
bdwrite(bp);
return (0);
}
}
#define SINGLE 0 /* index of single indirect block */
#define DOUBLE 1 /* index of double indirect block */
#define TRIPLE 2 /* index of triple indirect block */
/*
* Truncate the inode oip to at most length size, freeing the
* disk blocks.
*/
int
ext2fs_truncate(v)
void *v;
{
struct vop_truncate_args /* {
struct vnode *a_vp;
off_t a_length;
int a_flags;
struct ucred *a_cred;
struct proc *a_p;
} */ *ap = v;
register struct vnode *ovp = ap->a_vp;
register daddr_t lastblock;
register struct inode *oip;
daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
off_t length = ap->a_length;
register struct m_ext2fs *fs;
struct buf *bp;
int offset, size, level;
long count, nblocks, vflags, blocksreleased = 0;
struct timespec ts;
register int i;
int aflags, error, allerror;
off_t osize;
if (length < 0)
return (EINVAL);
oip = VTOI(ovp);
TIMEVAL_TO_TIMESPEC(&time, &ts);
if (ovp->v_type == VLNK &&
(oip->i_e2fs_size < ovp->v_mount->mnt_maxsymlinklen ||
(ovp->v_mount->mnt_maxsymlinklen == 0 &&
oip->i_e2fs_nblock == 0))) {
#ifdef DIAGNOSTIC
if (length != 0)
panic("ext2fs_truncate: partial truncate of symlink");
#endif
bzero((char *)&oip->i_din.e2fs_din.e2di_shortlink,
(u_int)oip->i_e2fs_size);
oip->i_e2fs_size = 0;
oip->i_flag |= IN_CHANGE | IN_UPDATE;
return (VOP_UPDATE(ovp, &ts, &ts, 1));
}
if (oip->i_e2fs_size == length) {
oip->i_flag |= IN_CHANGE | IN_UPDATE;
return (VOP_UPDATE(ovp, &ts, &ts, 0));
}
fs = oip->i_e2fs;
osize = oip->i_e2fs_size;
/*
* Lengthen the size of the file. We must ensure that the
* last byte of the file is allocated. Since the smallest
* value of osize is 0, length will be at least 1.
*/
if (osize < length) {
#if 0 /* XXX */
if (length > fs->fs_maxfilesize)
return (EFBIG);
#endif
offset = blkoff(fs, length - 1);
lbn = lblkno(fs, length - 1);
aflags = B_CLRBUF;
if (ap->a_flags & IO_SYNC)
aflags |= B_SYNC;
error = ext2fs_balloc(oip, lbn, offset + 1, ap->a_cred, &bp,
aflags);
if (error)
return (error);
oip->i_e2fs_size = length;
vnode_pager_setsize(ovp, (u_long)length);
(void) vnode_pager_uncache(ovp);
if (aflags & B_SYNC)
bwrite(bp);
else
bawrite(bp);
oip->i_flag |= IN_CHANGE | IN_UPDATE;
return (VOP_UPDATE(ovp, &ts, &ts, 1));
}
/*
* Shorten the size of the file. If the file is not being
* truncated to a block boundry, the contents of the
* partial block following the end of the file must be
* zero'ed in case it ever become accessable again because
* of subsequent file growth.
*/
offset = blkoff(fs, length);
if (offset == 0) {
oip->i_e2fs_size = length;
} else {
lbn = lblkno(fs, length);
aflags = B_CLRBUF;
if (ap->a_flags & IO_SYNC)
aflags |= B_SYNC;
error = ext2fs_balloc(oip, lbn, offset, ap->a_cred, &bp, aflags);
if (error)
return (error);
oip->i_e2fs_size = length;
size = fs->e2fs_bsize;
vnode_pager_setsize(ovp, (u_long)length);
(void) vnode_pager_uncache(ovp);
bzero((char *)bp->b_data + offset, (u_int)(size - offset));
allocbuf(bp, size);
if (aflags & B_SYNC)
bwrite(bp);
else
bawrite(bp);
}
/*
* Calculate index into inode's block list of
* last direct and indirect blocks (if any)
* which we want to keep. Lastblock is -1 when
* the file is truncated to 0.
*/
lastblock = lblkno(fs, length + fs->e2fs_bsize - 1) - 1;
lastiblock[SINGLE] = lastblock - NDADDR;
lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
nblocks = btodb(fs->e2fs_bsize);
/*
* Update file and block pointers on disk before we start freeing
* blocks. If we crash before free'ing blocks below, the blocks
* will be returned to the free list. lastiblock values are also
* normalized to -1 for calls to ext2fs_indirtrunc below.
*/
bcopy((caddr_t)&oip->i_e2fs_blocks[0], (caddr_t)oldblks, sizeof oldblks);
for (level = TRIPLE; level >= SINGLE; level--)
if (lastiblock[level] < 0) {
oip->i_e2fs_blocks[NDADDR + level] = 0;
lastiblock[level] = -1;
}
for (i = NDADDR - 1; i > lastblock; i--)
oip->i_e2fs_blocks[i] = 0;
oip->i_flag |= IN_CHANGE | IN_UPDATE;
if ((error = VOP_UPDATE(ovp, &ts, &ts, 1)) != 0)
allerror = error;
/*
* Having written the new inode to disk, save its new configuration
* and put back the old block pointers long enough to process them.
* Note that we save the new block configuration so we can check it
* when we are done.
*/
bcopy((caddr_t)&oip->i_e2fs_blocks[0], (caddr_t)newblks, sizeof newblks);
bcopy((caddr_t)oldblks, (caddr_t)&oip->i_e2fs_blocks[0], sizeof oldblks);
oip->i_e2fs_size = osize;
vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
allerror = vinvalbuf(ovp, vflags, ap->a_cred, ap->a_p, 0, 0);
/*
* Indirect blocks first.
*/
indir_lbn[SINGLE] = -NDADDR;
indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) -1;
indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
for (level = TRIPLE; level >= SINGLE; level--) {
bn = oip->i_e2fs_blocks[NDADDR + level];
if (bn != 0) {
error = ext2fs_indirtrunc(oip, indir_lbn[level],
fsbtodb(fs, bn), lastiblock[level], level, &count);
if (error)
allerror = error;
blocksreleased += count;
if (lastiblock[level] < 0) {
oip->i_e2fs_blocks[NDADDR + level] = 0;
ext2fs_blkfree(oip, bn);
blocksreleased += nblocks;
}
}
if (lastiblock[level] >= 0)
goto done;
}
/*
* All whole direct blocks or frags.
*/
for (i = NDADDR - 1; i > lastblock; i--) {
bn = oip->i_e2fs_blocks[i];
if (bn == 0)
continue;
oip->i_e2fs_blocks[i] = 0;
ext2fs_blkfree(oip, bn);
blocksreleased += btodb(fs->e2fs_bsize);
}
if (lastblock < 0)
goto done;
done:
#ifdef DIAGNOSTIC
for (level = SINGLE; level <= TRIPLE; level++)
if (newblks[NDADDR + level] != oip->i_e2fs_blocks[NDADDR + level])
panic("itrunc1");
for (i = 0; i < NDADDR; i++)
if (newblks[i] != oip->i_e2fs_blocks[i])
panic("itrunc2");
if (length == 0 &&
(ovp->v_dirtyblkhd.lh_first || ovp->v_cleanblkhd.lh_first))
panic("itrunc3");
#endif /* DIAGNOSTIC */
/*
* Put back the real size.
*/
oip->i_e2fs_size = length;
oip->i_e2fs_nblock -= blocksreleased;
if (oip->i_e2fs_nblock < 0) /* sanity */
oip->i_e2fs_nblock = 0;
oip->i_flag |= IN_CHANGE;
return (allerror);
}
/*
* Release blocks associated with the inode ip and stored in the indirect
* block bn. Blocks are free'd in LIFO order up to (but not including)
* lastbn. If level is greater than SINGLE, the block is an indirect block
* and recursive calls to indirtrunc must be used to cleanse other indirect
* blocks.
*
* NB: triple indirect blocks are untested.
*/
static int
ext2fs_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
register struct inode *ip;
daddr_t lbn, lastbn;
daddr_t dbn;
int level;
long *countp;
{
register int i;
struct buf *bp;
register struct m_ext2fs *fs = ip->i_e2fs;
register daddr_t *bap;
struct vnode *vp;
daddr_t *copy = NULL, nb, nlbn, last;
long blkcount, factor;
int nblocks, blocksreleased = 0;
int error = 0, allerror = 0;
/*
* Calculate index in current block of last
* block to be kept. -1 indicates the entire
* block so we need not calculate the index.
*/
factor = 1;
for (i = SINGLE; i < level; i++)
factor *= NINDIR(fs);
last = lastbn;
if (lastbn > 0)
last /= factor;
nblocks = btodb(fs->e2fs_bsize);
/*
* Get buffer of block pointers, zero those entries corresponding
* to blocks to be free'd, and update on disk copy first. Since
* double(triple) indirect before single(double) indirect, calls
* to bmap on these blocks will fail. However, we already have
* the on disk address, so we have to set the b_blkno field
* explicitly instead of letting bread do everything for us.
*/
vp = ITOV(ip);
bp = getblk(vp, lbn, (int)fs->e2fs_bsize, 0, 0);
if (bp->b_flags & (B_DONE | B_DELWRI)) {
/* Braces must be here in case trace evaluates to nothing. */
trace(TR_BREADHIT, pack(vp, fs->e2fs_bsize), lbn);
} else {
trace(TR_BREADMISS, pack(vp, fs->e2fs_bsize), lbn);
curproc->p_stats->p_ru.ru_inblock++; /* pay for read */
bp->b_flags |= B_READ;
if (bp->b_bcount > bp->b_bufsize)
panic("ext2fs_indirtrunc: bad buffer size");
bp->b_blkno = dbn;
VOP_STRATEGY(bp);
error = biowait(bp);
}
if (error) {
brelse(bp);
*countp = 0;
return (error);
}
bap = (daddr_t *)bp->b_data;
if (lastbn != -1) {
MALLOC(copy, daddr_t *, fs->e2fs_bsize, M_TEMP, M_WAITOK);
bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->e2fs_bsize);
bzero((caddr_t)&bap[last + 1],
(u_int)(NINDIR(fs) - (last + 1)) * sizeof (u_int32_t));
error = bwrite(bp);
if (error)
allerror = error;
bap = copy;
}
/*
* Recursively free totally unused blocks.
*/
for (i = NINDIR(fs) - 1,
nlbn = lbn + 1 - i * factor; i > last;
i--, nlbn += factor) {
nb = bap[i];
if (nb == 0)
continue;
if (level > SINGLE) {
error = ext2fs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
(daddr_t)-1, level - 1,
&blkcount);
if (error)
allerror = error;
blocksreleased += blkcount;
}
ext2fs_blkfree(ip, nb);
blocksreleased += nblocks;
}
/*
* Recursively free last partial block.
*/
if (level > SINGLE && lastbn >= 0) {
last = lastbn % factor;
nb = bap[i];
if (nb != 0) {
error = ext2fs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
last, level - 1, &blkcount);
if (error)
allerror = error;
blocksreleased += blkcount;
}
}
if (copy != NULL) {
FREE(copy, M_TEMP);
} else {
bp->b_flags |= B_INVAL;
brelse(bp);
}
*countp = blocksreleased;
return (allerror);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,300 @@
/* $NetBSD: ext2fs_readwrite.c,v 1.1 1997/06/11 09:34:01 bouyer Exp $ */
/*-
* Copyright (c) 1997 Manuel Bouyer.
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ufs_readwrite.c 8.8 (Berkeley) 8/4/94
* Modified for ext2fs by Manuel Bouyer.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/resourcevar.h>
#include <sys/kernel.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/conf.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/malloc.h>
#include <sys/signalvar.h>
#include <vm/vm.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ext2fs/ext2fs.h>
#include <ufs/ext2fs/ext2fs_extern.h>
#define doclusterread 0 /* XXX underway */
#define doclusterwrite 0
/*
* Vnode op for reading.
*/
/* ARGSUSED */
int
ext2fs_read(v)
void *v;
{
struct vop_read_args /* {
struct vnode *a_vp;
struct uio *a_uio;
int a_ioflag;
struct ucred *a_cred;
} */ *ap = v;
register struct vnode *vp;
register struct inode *ip;
register struct uio *uio;
register struct m_ext2fs *fs;
struct buf *bp;
daddr_t lbn, nextlbn;
off_t bytesinfile;
long size, xfersize, blkoffset;
int error;
u_short mode;
vp = ap->a_vp;
ip = VTOI(vp);
mode = ip->i_e2fs_mode;
uio = ap->a_uio;
#ifdef DIAGNOSTIC
if (uio->uio_rw != UIO_READ)
panic("%s: mode", "ext2fs_read");
if (vp->v_type == VLNK) {
if ((int)ip->i_e2fs_size < vp->v_mount->mnt_maxsymlinklen ||
(vp->v_mount->mnt_maxsymlinklen == 0 &&
ip->i_e2fs_nblock == 0))
panic("%s: short symlink", "ext2fs_read");
} else if (vp->v_type != VREG && vp->v_type != VDIR)
panic("%s: type %d", "ext2fs_read", vp->v_type);
#endif
fs = ip->i_e2fs;
if ((u_int64_t)uio->uio_offset >
((u_int64_t)0x80000000 * fs->e2fs_bsize - 1))
return (EFBIG);
if (uio->uio_resid == 0)
return (0);
for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
if ((bytesinfile = ip->i_e2fs_size - uio->uio_offset) <= 0)
break;
lbn = lblkno(fs, uio->uio_offset);
nextlbn = lbn + 1;
size = fs->e2fs_bsize;
blkoffset = blkoff(fs, uio->uio_offset);
xfersize = fs->e2fs_bsize - blkoffset;
if (uio->uio_resid < xfersize)
xfersize = uio->uio_resid;
if (bytesinfile < xfersize)
xfersize = bytesinfile;
if (lblktosize(fs, nextlbn) >= ip->i_e2fs_size)
error = bread(vp, lbn, size, NOCRED, &bp);
else if (doclusterread)
error = cluster_read(vp,
ip->i_e2fs_size, lbn, size, NOCRED, &bp);
else if (lbn - 1 == vp->v_lastr) {
int nextsize = fs->e2fs_bsize;
error = breadn(vp, lbn,
size, &nextlbn, &nextsize, 1, NOCRED, &bp);
} else
error = bread(vp, lbn, size, NOCRED, &bp);
if (error)
break;
vp->v_lastr = lbn;
/*
* 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, (int)xfersize,
uio);
if (error)
break;
brelse(bp);
}
if (bp != NULL)
brelse(bp);
if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
ip->i_flag |= IN_ACCESS;
return (error);
}
/*
* Vnode op for writing.
*/
int
ext2fs_write(v)
void *v;
{
struct vop_write_args /* {
struct vnode *a_vp;
struct uio *a_uio;
int a_ioflag;
struct ucred *a_cred;
} */ *ap = v;
register struct vnode *vp;
register struct uio *uio;
register struct inode *ip;
register struct m_ext2fs *fs;
struct buf *bp;
struct proc *p;
daddr_t lbn;
off_t osize;
int blkoffset, error, flags, ioflag, resid, size, xfersize;
struct timespec ts;
ioflag = ap->a_ioflag;
uio = ap->a_uio;
vp = ap->a_vp;
ip = VTOI(vp);
#ifdef DIAGNOSTIC
if (uio->uio_rw != UIO_WRITE)
panic("%s: mode", "ext2fs_write");
#endif
switch (vp->v_type) {
case VREG:
if (ioflag & IO_APPEND)
uio->uio_offset = ip->i_e2fs_size;
if ((ip->i_e2fs_flags & EXT2_APPEND) &&
uio->uio_offset != ip->i_e2fs_size)
return (EPERM);
/* FALLTHROUGH */
case VLNK:
break;
case VDIR:
if ((ioflag & IO_SYNC) == 0)
panic("%s: nonsync dir write", "ext2fs_write");
break;
default:
panic("%s: type", "ext2fs_write");
}
fs = ip->i_e2fs;
if (uio->uio_offset < 0 ||
(u_int64_t)uio->uio_offset + uio->uio_resid >
((u_int64_t)0x80000000 * fs->e2fs_bsize - 1))
return (EFBIG);
/*
* Maybe this should be above the vnode op call, but so long as
* file servers have no limits, I don't think it matters.
*/
p = uio->uio_procp;
if (vp->v_type == VREG && p &&
uio->uio_offset + uio->uio_resid >
p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
psignal(p, SIGXFSZ);
return (EFBIG);
}
resid = uio->uio_resid;
osize = ip->i_e2fs_size;
flags = ioflag & IO_SYNC ? B_SYNC : 0;
for (error = 0; uio->uio_resid > 0;) {
lbn = lblkno(fs, uio->uio_offset);
blkoffset = blkoff(fs, uio->uio_offset);
xfersize = fs->e2fs_bsize - blkoffset;
if (uio->uio_resid < xfersize)
xfersize = uio->uio_resid;
if (fs->e2fs_bsize > xfersize)
flags |= B_CLRBUF;
else
flags &= ~B_CLRBUF;
error = ext2fs_balloc(ip,
lbn, blkoffset + xfersize, ap->a_cred, &bp, flags);
if (error)
break;
if (uio->uio_offset + xfersize > ip->i_e2fs_size) {
ip->i_e2fs_size = uio->uio_offset + xfersize;
vnode_pager_setsize(vp, (u_long)ip->i_e2fs_size);
}
(void)vnode_pager_uncache(vp);
size = fs->e2fs_bsize - bp->b_resid;
if (size < xfersize)
xfersize = size;
error =
uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
if (ioflag & IO_SYNC)
(void)bwrite(bp);
else if (xfersize + blkoffset == fs->e2fs_bsize)
if (doclusterwrite)
cluster_write(bp, ip->i_e2fs_size);
else
bawrite(bp);
else
bdwrite(bp);
if (error || xfersize == 0)
break;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
}
/*
* If we successfully wrote any data, and we are not the superuser
* we clear the setuid and setgid bits as a precaution against
* tampering.
*/
if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
ip->i_e2fs_mode &= ~(ISUID | ISGID);
if (error) {
if (ioflag & IO_UNIT) {
(void)VOP_TRUNCATE(vp, osize,
ioflag & IO_SYNC, ap->a_cred, uio->uio_procp);
uio->uio_offset -= resid - uio->uio_resid;
uio->uio_resid = resid;
}
} else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
TIMEVAL_TO_TIMESPEC(&time, &ts);
error = VOP_UPDATE(vp, &ts, &ts, 1);
}
return (error);
}

View File

@ -0,0 +1,120 @@
/* $NetBSD: ext2fs_subr.c,v 1.1 1997/06/11 09:34:03 bouyer Exp $ */
/*
* Copyright (c) 1997 Manuel Bouyer.
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_subr.c 8.2 (Berkeley) 9/21/93
* Modified for ext2fs by Manuel Bouyer.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <ufs/ext2fs/ext2fs.h>
#include <ufs/ext2fs/ext2fs_extern.h>
#ifdef _KERNEL
#include <sys/vnode.h>
#include <sys/buf.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
/*
* Return buffer with the contents of block "offset" from the beginning of
* directory "ip". If "res" is non-zero, fill it in with a pointer to the
* remaining space in the directory.
*/
int
ext2fs_blkatoff(v)
void *v;
{
struct vop_blkatoff_args /* {
struct vnode *a_vp;
off_t a_offset;
char **a_res;
struct buf **a_bpp;
} */ *ap = v;
struct inode *ip;
register struct m_ext2fs *fs;
struct buf *bp;
daddr_t lbn;
int error;
ip = VTOI(ap->a_vp);
fs = ip->i_e2fs;
lbn = lblkno(fs, ap->a_offset);
*ap->a_bpp = NULL;
if ((error = bread(ap->a_vp, lbn, fs->e2fs_bsize, NOCRED, &bp)) != 0) {
brelse(bp);
return (error);
}
if (ap->a_res)
*ap->a_res = (char *)bp->b_data + blkoff(fs, ap->a_offset);
*ap->a_bpp = bp;
return (0);
}
#endif
#if defined(_KERNEL) && defined(DIAGNOSTIC)
void
ext2fs_checkoverlap(bp, ip)
struct buf *bp;
struct inode *ip;
{
register struct buf *ebp, *ep;
register daddr_t start, last;
struct vnode *vp;
ebp = &buf[nbuf];
start = bp->b_blkno;
last = start + btodb(bp->b_bcount) - 1;
for (ep = buf; ep < ebp; ep++) {
if (ep == bp || (ep->b_flags & B_INVAL) ||
ep->b_vp == NULLVP)
continue;
if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0, NULL))
continue;
if (vp != ip->i_devvp)
continue;
/* look for overlap */
if (ep->b_bcount == 0 || ep->b_blkno > last ||
ep->b_blkno + btodb(ep->b_bcount) <= start)
continue;
vprint("Disk overlap", vp);
printf("\tstart %d, end %d overlap start %d, end %ld\n",
start, last, ep->b_blkno,
ep->b_blkno + btodb(ep->b_bcount) - 1);
panic("Disk buffer overlap");
}
}
#endif /* DIAGNOSTIC */

View File

@ -0,0 +1,996 @@
/* $NetBSD: ext2fs_vfsops.c,v 1.1 1997/06/11 09:34:07 bouyer Exp $ */
/*
* Copyright (c) 1997 Manuel Bouyer.
* Copyright (c) 1989, 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_vfsops.c 8.14 (Berkeley) 11/28/94
* Modified for ext2fs by Manuel Bouyer.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <sys/socket.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <sys/mbuf.h>
#include <sys/file.h>
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/malloc.h>
#include <miscfs/specfs/specdev.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/ext2fs/ext2fs.h>
#include <ufs/ext2fs/ext2fs_extern.h>
int ext2fs_sbupdate __P((struct ufsmount *, int));
int ext2fs_check_export __P((struct mount *, struct ufid *, struct mbuf *,
struct vnode **, int *, struct ucred **));
struct vfsops ext2fs_vfsops = {
MOUNT_EXT2FS,
ext2fs_mount,
ufs_start,
ext2fs_unmount,
ufs_root,
ufs_quotactl,
ext2fs_statfs,
ext2fs_sync,
ext2fs_vget,
ext2fs_fhtovp,
ext2fs_vptofh,
ext2fs_init,
ext2fs_mountroot,
};
extern u_long ext2gennumber;
/*
* This is the generic part of fhtovp called after the underlying
* filesystem has validated the file handle.
*
* Verify that a host should have access to a filesystem, and if so
* return a vnode for the presented file handle.
*/
int
ext2fs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)
register struct mount *mp;
struct ufid *ufhp;
struct mbuf *nam;
struct vnode **vpp;
int *exflagsp;
struct ucred **credanonp;
{
register struct inode *ip;
register struct netcred *np;
register struct ufsmount *ump = VFSTOUFS(mp);
struct vnode *nvp;
int error;
/*
* Get the export permission structure for this <mp, client> tuple.
*/
np = vfs_export_lookup(mp, &ump->um_export, nam);
if (np == NULL)
return (EACCES);
if ((error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) != 0) {
*vpp = NULLVP;
return (error);
}
ip = VTOI(nvp);
if (ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime != 0 ||
ip->i_e2fs_gen != ufhp->ufid_gen) {
vput(nvp);
*vpp = NULLVP;
return (ESTALE);
}
*vpp = nvp;
*exflagsp = np->netc_exflags;
*credanonp = &np->netc_anon;
return (0);
}
/*
* Called by main() when ext2fs is going to be mounted as root.
*
* Name is updated by mount(8) after booting.
*/
#define ROOTNAME "root_device"
int
ext2fs_mountroot()
{
extern struct vnode *rootvp;
register struct m_ext2fs *fs;
register struct mount *mp;
struct proc *p = curproc; /* XXX */
struct ufsmount *ump;
size_t size;
int error;
if (root_device->dv_class != DV_DISK)
return (ENODEV);
/*
* Get vnodes for swapdev and rootdev.
*/
if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp))
panic("ext2fs_mountroot: can't setup bdevvp's");
mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK);
bzero((char *)mp, sizeof(struct mount));
mp->mnt_op = &ext2fs_vfsops;
mp->mnt_flag = MNT_RDONLY;
if ((error = ext2fs_mountfs(rootvp, mp, p)) != 0) {
free(mp, M_MOUNT);
return (error);
}
if ((error = vfs_lock(mp)) != 0) {
(void)ext2fs_unmount(mp, 0, p);
free(mp, M_MOUNT);
return (error);
}
CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
mp->mnt_vnodecovered = NULLVP;
ump = VFSTOUFS(mp);
fs = ump->um_e2fs;
bzero(fs->e2fs_fsmnt, sizeof(fs->e2fs_fsmnt));
fs->e2fs_fsmnt[0] = '/';
bcopy(fs->e2fs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN);
(void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
&size);
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
(void)ext2fs_statfs(mp, &mp->mnt_stat, p);
vfs_unlock(mp);
inittodr(fs->e2fs.e2fs_wtime);
return (0);
}
/*
* VFS Operations.
*
* mount system call
*/
int
ext2fs_mount(mp, path, data, ndp, p)
register struct mount *mp;
const char *path;
void * data;
struct nameidata *ndp;
struct proc *p;
{
struct vnode *devvp;
struct ufs_args args;
struct ufsmount *ump = NULL;
register struct m_ext2fs *fs;
size_t size;
int error, flags;
mode_t accessmode;
error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args));
if (error)
return (error);
/*
* If updating, check whether changing from read-only to
* read/write; if there is no device name, that's all we do.
*/
if (mp->mnt_flag & MNT_UPDATE) {
ump = VFSTOUFS(mp);
fs = ump->um_e2fs;
if (fs->e2fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
flags = WRITECLOSE;
if (mp->mnt_flag & MNT_FORCE)
flags |= FORCECLOSE;
if (vfs_busy(mp))
return (EBUSY);
error = ext2fs_flushfiles(mp, flags, p);
if (error == 0 &&
ext2fs_cgupdate(ump, MNT_WAIT) == 0 &&
(fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) {
fs->e2fs.e2fs_state = E2FS_ISCLEAN;
(void) ext2fs_sbupdate(ump, MNT_WAIT);
}
vfs_unbusy(mp);
if (error)
return (error);
fs->e2fs_ronly = 1;
}
if (mp->mnt_flag & MNT_RELOAD) {
error = ext2fs_reload(mp, ndp->ni_cnd.cn_cred, p);
if (error)
return (error);
}
if (fs->e2fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
/*
* If upgrade to read-write by non-root, then verify
* that user has necessary permissions on the device.
*/
if (p->p_ucred->cr_uid != 0) {
devvp = ump->um_devvp;
VOP_LOCK(devvp);
error = VOP_ACCESS(devvp, VREAD | VWRITE,
p->p_ucred, p);
if (error) {
VOP_UNLOCK(devvp);
return (error);
}
VOP_UNLOCK(devvp);
}
fs->e2fs_ronly = 0;
if (fs->e2fs.e2fs_state == E2FS_ISCLEAN)
fs->e2fs.e2fs_state = 0;
else
fs->e2fs.e2fs_state = E2FS_ERRORS;
fs->e2fs_fmod = 1;
}
if (args.fspec == 0) {
/*
* Process export requests.
*/
return (vfs_export(mp, &ump->um_export, &args.export));
}
}
/*
* Not an update, or updating the name: look up the name
* and verify that it refers to a sensible block device.
*/
NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
if ((error = namei(ndp)) != 0)
return (error);
devvp = ndp->ni_vp;
if (devvp->v_type != VBLK) {
vrele(devvp);
return (ENOTBLK);
}
if (major(devvp->v_rdev) >= nblkdev) {
vrele(devvp);
return (ENXIO);
}
/*
* If mount by non-root, then verify that user has necessary
* permissions on the device.
*/
if (p->p_ucred->cr_uid != 0) {
accessmode = VREAD;
if ((mp->mnt_flag & MNT_RDONLY) == 0)
accessmode |= VWRITE;
VOP_LOCK(devvp);
error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p);
if (error) {
vput(devvp);
return (error);
}
VOP_UNLOCK(devvp);
}
if ((mp->mnt_flag & MNT_UPDATE) == 0)
error = ext2fs_mountfs(devvp, mp, p);
else {
if (devvp != ump->um_devvp)
error = EINVAL; /* needs translation */
else
vrele(devvp);
}
if (error) {
vrele(devvp);
return (error);
}
ump = VFSTOUFS(mp);
fs = ump->um_e2fs;
(void) copyinstr(path, fs->e2fs_fsmnt, sizeof(fs->e2fs_fsmnt) - 1, &size);
bzero(fs->e2fs_fsmnt + size, sizeof(fs->e2fs_fsmnt) - size);
bcopy(fs->e2fs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN);
(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
&size);
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
if (fs->e2fs_fmod != 0) { /* XXX */
fs->e2fs_fmod = 0;
if (fs->e2fs.e2fs_state == 0)
fs->e2fs.e2fs_wtime = time.tv_sec;
else
printf("%s: file system not clean; please fsck(8)\n",
mp->mnt_stat.f_mntfromname);
(void) ext2fs_cgupdate(ump, MNT_WAIT);
}
return (0);
}
/*
* Reload all incore data for a filesystem (used after running fsck on
* the root filesystem and finding things to fix). The filesystem must
* be mounted read-only.
*
* Things to do to update the mount:
* 1) invalidate all cached meta-data.
* 2) re-read superblock from disk.
* 3) re-read summary information from disk.
* 4) invalidate all inactive vnodes.
* 5) invalidate all cached file data.
* 6) re-read inode data for all active vnodes.
*/
int
ext2fs_reload(mountp, cred, p)
register struct mount *mountp;
struct ucred *cred;
struct proc *p;
{
register struct vnode *vp, *nvp, *devvp;
struct inode *ip;
struct buf *bp;
struct m_ext2fs *fs;
struct ext2fs *newfs;
struct partinfo dpart;
int i, size, error;
if ((mountp->mnt_flag & MNT_RDONLY) == 0)
return (EINVAL);
/*
* Step 1: invalidate all cached meta-data.
*/
devvp = VFSTOUFS(mountp)->um_devvp;
if (vinvalbuf(devvp, 0, cred, p, 0, 0))
panic("ext2fs_reload: dirty1");
/*
* Step 2: re-read superblock from disk.
*/
if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
size = DEV_BSIZE;
else
size = dpart.disklab->d_secsize;
error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp);
if (error)
return (error);
newfs = (struct ext2fs *)bp->b_data;
if (newfs->e2fs_magic != E2FS_MAGIC || newfs->e2fs_rev != E2FS_REV) {
#ifdef DIAGNOSTIC
printf("Wrong magic number: %x (expected %x for ext2 fs)",
newfs->e2fs_magic, E2FS_MAGIC);
printf("or wrong revision number: %x (expected %x for ext2 fs)",
newfs->e2fs_rev, E2FS_REV);
#endif
brelse(bp);
return (EIO); /* XXX needs translation */
}
if (newfs->e2fs_log_bsize > 2) { /* block size = 1024|2048|4096 */
#ifdef DIAGNOSTIC
printf("wrong block size: %d (expected <=2 for ext2 fs)\n",
newfs->e2fs_log_bsize);
#endif
brelse(bp);
return (EIO); /* XXX needs translation */
}
fs = VFSTOUFS(mountp)->um_e2fs;
/*
* copy in new superblock, and compute in-memory values
*/
bcopy(newfs, &fs->e2fs, SBSIZE);
fs->e2fs_ncg = howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
fs->e2fs.e2fs_bpg);
/* XXX assume hw bsize = 512 */
fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
fs->e2fs_bsize = 1024 << fs->e2fs.e2fs_log_bsize;
fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
fs->e2fs_qbmask = fs->e2fs_bsize - 1;
fs->e2fs_bmask = ~fs->e2fs_qbmask;
fs->e2fs_ngdb = howmany(fs->e2fs_ncg,
fs->e2fs_bsize / sizeof(struct ext2_gd));
fs->e2fs_ipb = fs->e2fs_bsize / sizeof(struct ext2fs_dinode);
fs->e2fs_itpg = fs->e2fs.e2fs_ipg/fs->e2fs_ipb;
/*
* Step 3: re-read summary information from disk.
*/
for (i=0; i < fs->e2fs_ngdb; i++) {
error = bread(devvp , fsbtodb(fs, ((fs->e2fs_bsize>1024)?0:1)+i+1),
fs->e2fs_bsize, NOCRED, &bp);
if (error)
return (error);
bcopy(bp->b_data,
&fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)],
fs->e2fs_bsize);
brelse(bp);
}
loop:
for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
nvp = vp->v_mntvnodes.le_next;
/*
* Step 4: invalidate all inactive vnodes.
*/
if (vp->v_usecount == 0) {
vgone(vp);
continue;
}
/*
* Step 5: invalidate all cached file data.
*/
if (vget(vp, 1))
goto loop;
if (vinvalbuf(vp, 0, cred, p, 0, 0))
panic("ext2fs_reload: dirty2");
/*
* Step 6: re-read inode data for all active vnodes.
*/
ip = VTOI(vp);
error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
vput(vp);
return (error);
}
bcopy((struct ext2fs_dinode *)bp->b_data +
ino_to_fsbo(fs, ip->i_number),
&ip->i_din.e2fs_din, sizeof(struct ext2fs_dinode));
brelse(bp);
vput(vp);
if (vp->v_mount != mountp)
goto loop;
}
return (0);
}
/*
* Common code for mount and mountroot
*/
int
ext2fs_mountfs(devvp, mp, p)
register struct vnode *devvp;
struct mount *mp;
struct proc *p;
{
register struct ufsmount *ump;
struct buf *bp;
register struct ext2fs *fs;
register struct m_ext2fs *m_fs;
dev_t dev;
struct partinfo dpart;
int error, i, size, ronly;
struct ucred *cred;
extern struct vnode *rootvp;
dev = devvp->v_rdev;
cred = p ? p->p_ucred : NOCRED;
/*
* Disallow multiple mounts of the same device.
* Disallow mounting of a device that is currently in use
* (except for root, which might share swap device for miniroot).
* Flush out any old buffers remaining from a previous use.
*/
if ((error = vfs_mountedon(devvp)) != 0)
return (error);
if (vcount(devvp) > 1 && devvp != rootvp)
return (EBUSY);
if ((error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) != 0)
return (error);
ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
if (error)
return (error);
if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
size = DEV_BSIZE;
else
size = dpart.disklab->d_secsize;
bp = NULL;
ump = NULL;
#ifdef DEBUG_EXT2
printf("sb size: %d ino size %d\n", sizeof(struct ext2fs),
sizeof(struct ext2fs_dinode));
#endif
error = bread(devvp, (SBOFF / DEV_BSIZE), SBSIZE, cred, &bp);
if (error)
goto out;
fs = (struct ext2fs *)bp->b_data;
if (fs->e2fs_magic != E2FS_MAGIC || fs->e2fs_rev != E2FS_REV) {
#ifdef DIAGNOSTIC
printf("Wrong magic number: %x (expected %x for ext2 fs)",
fs->e2fs_magic, E2FS_MAGIC);
printf(" or wrong revision number: %x (expected %x for ext2 fs)\n",
fs->e2fs_rev, E2FS_REV);
#endif
error = EINVAL; /* XXX needs translation */
goto out;
}
if (fs->e2fs_log_bsize > 2) { /* block size = 1024|2048|4096 */
#ifdef DIAGNOSTIC
printf("wrong block size: %d (expected <2 for ext2 fs)\n",
fs->e2fs_log_bsize);
#endif
error = EINVAL; /* XXX needs translation */
goto out;
}
ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
bzero((caddr_t)ump, sizeof *ump);
ump->um_e2fs = malloc(sizeof(struct m_ext2fs), M_UFSMNT, M_WAITOK);
bcopy(bp->b_data, ump->um_e2fs, SBSIZE);
brelse(bp);
bp = NULL;
m_fs = ump->um_e2fs;
m_fs->e2fs_ronly = ronly;
if (ronly == 0) {
if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN)
m_fs->e2fs.e2fs_state = 0;
else
m_fs->e2fs.e2fs_state = E2FS_ERRORS;
m_fs->e2fs_fmod = 1;
}
/* compute dynamic sb infos */
m_fs->e2fs_ncg =
howmany(m_fs->e2fs.e2fs_bcount - m_fs->e2fs.e2fs_first_dblock,
m_fs->e2fs.e2fs_bpg);
/* XXX assume hw bsize = 512 */
m_fs->e2fs_fsbtodb = m_fs->e2fs.e2fs_log_bsize + 1;
m_fs->e2fs_bsize = 1024 << m_fs->e2fs.e2fs_log_bsize;
m_fs->e2fs_bshift = LOG_MINBSIZE + m_fs->e2fs.e2fs_log_bsize;
m_fs->e2fs_qbmask = m_fs->e2fs_bsize - 1;
m_fs->e2fs_bmask = ~m_fs->e2fs_qbmask;
m_fs->e2fs_ngdb = howmany(m_fs->e2fs_ncg,
m_fs->e2fs_bsize / sizeof(struct ext2_gd));
m_fs->e2fs_ipb = m_fs->e2fs_bsize / sizeof(struct ext2fs_dinode);
m_fs->e2fs_itpg = m_fs->e2fs.e2fs_ipg/m_fs->e2fs_ipb;
m_fs->e2fs_gd = malloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize,
M_UFSMNT, M_WAITOK);
for (i=0; i < m_fs->e2fs_ngdb; i++) {
error = bread(devvp , fsbtodb(m_fs, ((m_fs->e2fs_bsize>1024)?0:1)+i+1),
m_fs->e2fs_bsize, NOCRED, &bp);
if (error) {
free(m_fs->e2fs_gd, M_UFSMNT);
goto out;
}
bcopy(bp->b_data,
&m_fs->e2fs_gd[i* m_fs->e2fs_bsize / sizeof(struct ext2_gd)],
m_fs->e2fs_bsize);
brelse(bp);
bp = NULL;
}
mp->mnt_data = (qaddr_t)ump;
mp->mnt_stat.f_fsid.val[0] = (long)dev;
mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_EXT2FS);
mp->mnt_maxsymlinklen = EXT2_MAXSYMLINKLEN;
mp->mnt_flag |= MNT_LOCAL;
ump->um_mountp = mp;
ump->um_dev = dev;
ump->um_devvp = devvp;
ump->um_nindir = NINDIR(m_fs);
ump->um_bptrtodb = m_fs->e2fs_fsbtodb;
ump->um_seqinc = 1; /* no frags */
devvp->v_specflags |= SI_MOUNTEDON;
return (0);
out:
if (bp)
brelse(bp);
(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
if (ump) {
free(ump->um_e2fs, M_UFSMNT);
free(ump, M_UFSMNT);
mp->mnt_data = (qaddr_t)0;
}
return (error);
}
/*
* unmount system call
*/
int
ext2fs_unmount(mp, mntflags, p)
struct mount *mp;
int mntflags;
struct proc *p;
{
register struct ufsmount *ump;
register struct m_ext2fs *fs;
int error, flags;
flags = 0;
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
if ((error = ext2fs_flushfiles(mp, flags, p)) != 0)
return (error);
ump = VFSTOUFS(mp);
fs = ump->um_e2fs;
if (fs->e2fs_ronly == 0 &&
ext2fs_cgupdate(ump, MNT_WAIT) == 0 &&
(fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) {
fs->e2fs.e2fs_state = E2FS_ISCLEAN;
(void) ext2fs_sbupdate(ump, MNT_WAIT);
}
ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
error = VOP_CLOSE(ump->um_devvp, fs->e2fs_ronly ? FREAD : FREAD|FWRITE,
NOCRED, p);
vrele(ump->um_devvp);
free(fs->e2fs_gd, M_UFSMNT);
free(fs, M_UFSMNT);
free(ump, M_UFSMNT);
mp->mnt_data = (qaddr_t)0;
mp->mnt_flag &= ~MNT_LOCAL;
return (error);
}
/*
* Flush out all the files in a filesystem.
*/
int
ext2fs_flushfiles(mp, flags, p)
register struct mount *mp;
int flags;
struct proc *p;
{
extern int doforce;
register struct ufsmount *ump;
int error;
if (!doforce)
flags &= ~FORCECLOSE;
ump = VFSTOUFS(mp);
error = vflush(mp, NULLVP, flags);
return (error);
}
/*
* Get file system statistics.
*/
int
ext2fs_statfs(mp, sbp, p)
struct mount *mp;
register struct statfs *sbp;
struct proc *p;
{
register struct ufsmount *ump;
register struct m_ext2fs *fs;
u_int32_t overhead, overhead_per_group;
ump = VFSTOUFS(mp);
fs = ump->um_e2fs;
if (fs->e2fs.e2fs_magic != E2FS_MAGIC)
panic("ext2fs_statfs");
#ifdef COMPAT_09
sbp->f_type = 1;
#else
sbp->f_type = 0;
#endif
/*
* Compute the overhead (FS structures)
*/
overhead_per_group = 1 /* super block */ +
fs->e2fs_ngdb +
1 /* block bitmap */ +
1 /* inode bitmap */ +
fs->e2fs_itpg;
overhead = fs->e2fs.e2fs_first_dblock +
fs->e2fs_ncg * overhead_per_group;
sbp->f_bsize = fs->e2fs_bsize;
sbp->f_iosize = fs->e2fs_bsize;
sbp->f_blocks = fs->e2fs.e2fs_bcount - overhead;
sbp->f_bfree = fs->e2fs.e2fs_fbcount;
sbp->f_bavail = sbp->f_bfree - fs->e2fs.e2fs_rbcount;
sbp->f_files = fs->e2fs.e2fs_icount;
sbp->f_ffree = fs->e2fs.e2fs_ficount;
if (sbp != &mp->mnt_stat) {
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
}
strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN);
return (0);
}
/*
* Go through the disk queues to initiate sandbagged IO;
* go through the inodes to write those that have been modified;
* initiate the writing of the super block if it has been modified.
*
* Note: we are always called with the filesystem marked `MPBUSY'.
*/
int
ext2fs_sync(mp, waitfor, cred, p)
struct mount *mp;
int waitfor;
struct ucred *cred;
struct proc *p;
{
register struct vnode *vp;
register struct inode *ip;
register struct ufsmount *ump = VFSTOUFS(mp);
register struct m_ext2fs *fs;
int error, allerror = 0;
fs = ump->um_e2fs;
/*
* Write back modified superblock.
* Consistency check that the superblock
* is still in the buffer cache.
*/
if (fs->e2fs_fmod != 0) {
if (fs->e2fs_ronly != 0) { /* XXX */
printf("fs = %s\n", fs->e2fs_fsmnt);
panic("update: rofs mod");
}
fs->e2fs_fmod = 0;
fs->e2fs.e2fs_wtime = time.tv_sec;
allerror = ext2fs_cgupdate(ump, waitfor);
}
/*
* Write back each (modified) inode.
*/
loop:
for (vp = mp->mnt_vnodelist.lh_first;
vp != NULL;
vp = vp->v_mntvnodes.le_next) {
/*
* If the vnode that we are about to sync is no longer
* associated with this mount point, start over.
*/
if (vp->v_mount != mp)
goto loop;
if (VOP_ISLOCKED(vp))
continue;
ip = VTOI(vp);
if ((ip->i_flag &
(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
vp->v_dirtyblkhd.lh_first == NULL)
continue;
if (vget(vp, 1))
goto loop;
if ((error = VOP_FSYNC(vp, cred, waitfor, p)) != 0)
allerror = error;
vput(vp);
}
/*
* Force stale file system control information to be flushed.
*/
if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0)
allerror = error;
return (allerror);
}
/*
* Look up a EXT2FS dinode number to find its incore vnode, otherwise read it
* in from disk. If it is in core, wait for the lock bit to clear, then
* return the inode locked. Detection and handling of mount points must be
* done by the calling routine.
*/
int
ext2fs_vget(mp, ino, vpp)
struct mount *mp;
ino_t ino;
struct vnode **vpp;
{
register struct m_ext2fs *fs;
register struct inode *ip;
struct ufsmount *ump;
struct buf *bp;
struct vnode *vp;
dev_t dev;
int error;
ump = VFSTOUFS(mp);
dev = ump->um_dev;
if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
return (0);
/* Allocate a new vnode/inode. */
if ((error = getnewvnode(VT_EXT2FS, mp, ext2fs_vnodeop_p, &vp)) != 0) {
*vpp = NULL;
return (error);
}
MALLOC(ip, struct inode *, sizeof(struct inode), M_EXT2FSNODE, M_WAITOK);
bzero((caddr_t)ip, sizeof(struct inode));
vp->v_data = ip;
ip->i_vnode = vp;
ip->i_e2fs = fs = ump->um_e2fs;
ip->i_dev = dev;
ip->i_number = ino;
ip->i_e2fs_last_lblk = 0;
ip->i_e2fs_last_blk = 0;
/*
* Put it onto its hash chain and lock it so that other requests for
* this inode will block if they arrive while we are sleeping waiting
* for old data structures to be purged or for the contents of the
* disk portion of this inode to be read.
*/
ufs_ihashins(ip);
/* Read in the disk contents for the inode, copy into the inode. */
error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
/*
* The inode does not contain anything useful, so it would
* be misleading to leave it on its hash chain. With mode
* still zero, it will be unlinked and returned to the free
* list by vput().
*/
vput(vp);
brelse(bp);
*vpp = NULL;
return (error);
}
bcopy(((struct ext2fs_dinode*)bp->b_data + ino_to_fsbo(fs, ino)),
&ip->i_din, sizeof(struct ext2fs_dinode));
brelse(bp);
/*
* Initialize the vnode from the inode, check for aliases.
* Note that the underlying vnode may have changed.
*/
error = ufs_vinit(mp, ext2fs_specop_p, EXT2FS_FIFOOPS, &vp);
if (error) {
vput(vp);
*vpp = NULL;
return (error);
}
/*
* Finish inode initialization now that aliasing has been resolved.
*/
ip->i_devvp = ump->um_devvp;
VREF(ip->i_devvp);
/*
* Set up a generation number for this inode if it does not
* already have one. This should only happen on old filesystems.
*/
if (ip->i_e2fs_gen == 0) {
if (++ext2gennumber < (u_long)time.tv_sec)
ext2gennumber = time.tv_sec;
ip->i_e2fs_gen = ext2gennumber;
if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
ip->i_flag |= IN_MODIFIED;
}
*vpp = vp;
return (0);
}
/*
* File handle to vnode
*
* Have to be really careful about stale file handles:
* - check that the inode number is valid
* - call ext2fs_vget() to get the locked inode
* - check for an unallocated inode (i_mode == 0)
* - check that the given client host has export rights and return
* those rights via. exflagsp and credanonp
*/
int
ext2fs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
register struct mount *mp;
struct fid *fhp;
struct mbuf *nam;
struct vnode **vpp;
int *exflagsp;
struct ucred **credanonp;
{
register struct ufid *ufhp;
struct m_ext2fs *fs;
ufhp = (struct ufid *)fhp;
fs = VFSTOUFS(mp)->um_e2fs;
if ((ufhp->ufid_ino < EXT2_FIRSTINO && ufhp->ufid_ino != EXT2_ROOTINO) ||
ufhp->ufid_ino >= fs->e2fs_ncg * fs->e2fs.e2fs_ipg)
return (ESTALE);
return (ext2fs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
}
/*
* Vnode pointer to File handle
*/
/* ARGSUSED */
int
ext2fs_vptofh(vp, fhp)
struct vnode *vp;
struct fid *fhp;
{
register struct inode *ip;
register struct ufid *ufhp;
ip = VTOI(vp);
ufhp = (struct ufid *)fhp;
ufhp->ufid_len = sizeof(struct ufid);
ufhp->ufid_ino = ip->i_number;
ufhp->ufid_gen = ip->i_e2fs_gen;
return (0);
}
/*
* Write a superblock and associated information back to disk.
*/
int
ext2fs_sbupdate(mp, waitfor)
struct ufsmount *mp;
int waitfor;
{
register struct m_ext2fs *fs = mp->um_e2fs;
register struct buf *bp;
int error = 0;
bp = getblk(mp->um_devvp, SBLOCK, SBSIZE, 0, 0);
bcopy((caddr_t)(&fs->e2fs), bp->b_data, SBSIZE);
if (waitfor == MNT_WAIT)
error = bwrite(bp);
else
bawrite(bp);
return (error);
}
int
ext2fs_cgupdate(mp, waitfor)
struct ufsmount *mp;
int waitfor;
{
register struct m_ext2fs *fs = mp->um_e2fs;
register struct buf *bp;
int i, error = 0, allerror = 0;
allerror = ext2fs_sbupdate(mp, waitfor);
for (i = 0; i < fs->e2fs_ngdb; i++) {
bp = getblk(mp->um_devvp, fsbtodb(fs, ((fs->e2fs_bsize>1024)?0:1)+i+1),
fs->e2fs_bsize, 0, 0);
bcopy(&fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)],
bp->b_data, fs->e2fs_bsize);
if (waitfor == MNT_WAIT)
error = bwrite(bp);
else
bawrite(bp);
}
if (!allerror && error)
allerror = error;
return (allerror);
}

File diff suppressed because it is too large Load Diff