The ext2fs layer, based on the ffs/ufs one. Uses a few functions from
sys/ufs/ufs/
This commit is contained in:
parent
3652b54b5d
commit
9e3c291da4
236
sys/ufs/ext2fs/ext2fs.h
Normal file
236
sys/ufs/ext2fs/ext2fs.h
Normal 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))
|
650
sys/ufs/ext2fs/ext2fs_alloc.c
Normal file
650
sys/ufs/ext2fs/ext2fs_alloc.c
Normal 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);
|
||||
}
|
247
sys/ufs/ext2fs/ext2fs_balloc.c
Normal file
247
sys/ufs/ext2fs/ext2fs_balloc.c
Normal 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);
|
||||
}
|
222
sys/ufs/ext2fs/ext2fs_bmap.c
Normal file
222
sys/ufs/ext2fs/ext2fs_bmap.c
Normal 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 = #
|
||||
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);
|
||||
}
|
132
sys/ufs/ext2fs/ext2fs_dinode.h
Normal file
132
sys/ufs/ext2fs/ext2fs_dinode.h
Normal 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
114
sys/ufs/ext2fs/ext2fs_dir.h
Normal 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_ */
|
154
sys/ufs/ext2fs/ext2fs_extern.h
Normal file
154
sys/ufs/ext2fs/ext2fs_extern.h
Normal 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
|
528
sys/ufs/ext2fs/ext2fs_inode.c
Normal file
528
sys/ufs/ext2fs/ext2fs_inode.c
Normal 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);
|
||||
}
|
1073
sys/ufs/ext2fs/ext2fs_lookup.c
Normal file
1073
sys/ufs/ext2fs/ext2fs_lookup.c
Normal file
File diff suppressed because it is too large
Load Diff
300
sys/ufs/ext2fs/ext2fs_readwrite.c
Normal file
300
sys/ufs/ext2fs/ext2fs_readwrite.c
Normal 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);
|
||||
}
|
120
sys/ufs/ext2fs/ext2fs_subr.c
Normal file
120
sys/ufs/ext2fs/ext2fs_subr.c
Normal 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 */
|
996
sys/ufs/ext2fs/ext2fs_vfsops.c
Normal file
996
sys/ufs/ext2fs/ext2fs_vfsops.c
Normal 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);
|
||||
}
|
1541
sys/ufs/ext2fs/ext2fs_vnops.c
Normal file
1541
sys/ufs/ext2fs/ext2fs_vnops.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user