Bring in the ext2fs work done by Aditya Sarawgi during and after Google Summer

of Code 2009:

- BSDL block and inode allocation policies for ext2fs. This involves the use
  FFS1 style block and inode allocation for ext2fs. Preallocation was removed
  since it was GPL'd.
- Make ext2fs MPSAFE by introducing locks to per-mount datastructures.
- Fixes for kern/122047 PR.
- Various small bugfixes.
- Move out of gnu/ directory.

Sponsored by:   Google Inc.
Submitted by:	Aditya Sarawgi <sarawgi.aditya AT SPAMFREE gmail DOT com>
This commit is contained in:
Ulf Lilleengen 2010-01-14 14:30:54 +00:00
parent c0d87a13b2
commit e09c00cada
28 changed files with 2157 additions and 3395 deletions

View File

@ -1956,18 +1956,15 @@ geom/virstor/binstream.c optional geom_virstor
geom/virstor/g_virstor.c optional geom_virstor
geom/virstor/g_virstor_md.c optional geom_virstor
geom/zero/g_zero.c optional geom_zero
gnu/fs/ext2fs/ext2_alloc.c optional ext2fs \
warning "kernel contains GPL contaminated ext2fs filesystem"
gnu/fs/ext2fs/ext2_balloc.c optional ext2fs
gnu/fs/ext2fs/ext2_bmap.c optional ext2fs
gnu/fs/ext2fs/ext2_inode.c optional ext2fs
gnu/fs/ext2fs/ext2_inode_cnv.c optional ext2fs
gnu/fs/ext2fs/ext2_linux_balloc.c optional ext2fs
gnu/fs/ext2fs/ext2_linux_ialloc.c optional ext2fs
gnu/fs/ext2fs/ext2_lookup.c optional ext2fs
gnu/fs/ext2fs/ext2_subr.c optional ext2fs
gnu/fs/ext2fs/ext2_vfsops.c optional ext2fs
gnu/fs/ext2fs/ext2_vnops.c optional ext2fs
fs/ext2fs/ext2_alloc.c optional ext2fs
fs/ext2fs/ext2_balloc.c optional ext2fs
fs/ext2fs/ext2_bmap.c optional ext2fs
fs/ext2fs/ext2_inode.c optional ext2fs
fs/ext2fs/ext2_inode_cnv.c optional ext2fs
fs/ext2fs/ext2_lookup.c optional ext2fs
fs/ext2fs/ext2_subr.c optional ext2fs
fs/ext2fs/ext2_vfsops.c optional ext2fs
fs/ext2fs/ext2_vnops.c optional ext2fs
gnu/fs/reiserfs/reiserfs_hashes.c optional reiserfs \
warning "kernel contains GPL contaminated ReiserFS filesystem"
gnu/fs/reiserfs/reiserfs_inode.c optional reiserfs

973
sys/fs/ext2fs/ext2_alloc.c Normal file
View File

@ -0,0 +1,973 @@
/*-
* modified for Lites 1.1
*
* Aug 1995, Godmar Back (gback@cs.utah.edu)
* University of Utah, Department of Computer Science
*/
/*-
* 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.
* 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.8 (Berkeley) 2/21/94
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/vnode.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/syslog.h>
#include <sys/buf.h>
#include <fs/ext2fs/inode.h>
#include <fs/ext2fs/ext2_mount.h>
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/fs.h>
#include <fs/ext2fs/ext2_extern.h>
static daddr_t ext2_alloccg(struct inode *, int, daddr_t, int);
static u_long ext2_dirpref(struct inode *);
static void ext2_fserr(struct m_ext2fs *, uid_t, char *);
static u_long ext2_hashalloc(struct inode *, int, long, int,
daddr_t (*)(struct inode *, int, daddr_t,
int));
static daddr_t ext2_nodealloccg(struct inode *, int, daddr_t, int);
static daddr_t ext2_mapsearch(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 hierarchy is used
* to allocate a block:
* 1) allocate a block in the cylinder group that contains the
* inode for the file.
* 2) quadradically rehash into other cylinder groups, until an
* available block is located.
*
* A preference may be optionally specified. If a preference is given
* the following hierarchy is used to allocate a block:
* 1) allocate the requested block.
* 2) allocate a rotationally optimal block in the same cylinder.
* 3) allocate a block in the same cylinder group.
* 4) quadradically rehash into other cylinder groups, until an
* available block is located.
* If no block preference is given the following hierarchy is used
* to allocate a block:
* 1) allocate a block in the cylinder group that contains the
* inode for the file.
* 2) quadradically rehash into other cylinder groups, until an
* available block is located.
*/
int
ext2_alloc(ip, lbn, bpref, size, cred, bnp)
struct inode *ip;
int32_t lbn, bpref;
int size;
struct ucred *cred;
int32_t *bnp;
{
struct m_ext2fs *fs;
struct ext2mount *ump;
int32_t bno;
int cg;
*bnp = 0;
fs = ip->i_e2fs;
ump = ip->i_ump;
mtx_assert(EXT2_MTX(ump), MA_OWNED);
#ifdef DIAGNOSTIC
if ((u_int)size > fs->e2fs_bsize || blkoff(fs, size) != 0) {
vn_printf(ip->i_devvp, "bsize = %lu, size = %d, fs = %s\n",
(long unsigned int)fs->e2fs_bsize, size, fs->e2fs_fsmnt);
panic("ext2_alloc: bad size");
}
if (cred == NOCRED)
panic("ext2_alloc: missing credential");
#endif /* DIAGNOSTIC */
if (size == fs->e2fs_bsize && fs->e2fs->e2fs_fbcount == 0)
goto nospace;
if (cred->cr_uid != 0 &&
fs->e2fs->e2fs_fbcount < fs->e2fs->e2fs_rbcount)
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)ext2_hashalloc(ip, cg, bpref, fs->e2fs_bsize,
ext2_alloccg);
if (bno > 0) {
ip->i_blocks += btodb(fs->e2fs_bsize);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
*bnp = bno;
return (0);
}
nospace:
EXT2_UNLOCK(ump);
ext2_fserr(fs, cred->cr_uid, "file system full");
uprintf("\n%s: write failed, file system is full\n", fs->e2fs_fsmnt);
return (ENOSPC);
}
/*
* Reallocate a sequence of blocks into a contiguous sequence of blocks.
*
* The vnode and an array of buffer pointers for a range of sequential
* logical blocks to be made contiguous is given. The allocator attempts
* to find a range of sequential blocks starting as close as possible to
* an fs_rotdelay offset from the end of the allocation for the logical
* block immediately preceding the current range. If successful, the
* physical block numbers in the buffer pointers and in the inode are
* changed to reflect the new allocation. If unsuccessful, the allocation
* is left unchanged. The success in doing the reallocation is returned.
* Note that the error return is not reflected back to the user. Rather
* the previous block allocation will be used.
*/
#ifdef FANCY_REALLOC
#include <sys/sysctl.h>
static int doasyncfree = 1;
static int doreallocblks = 1;
#ifdef OPT_DEBUG
SYSCTL_INT(_debug, 14, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, "");
#endif /* OPT_DEBUG */
#endif
int
ext2_reallocblks(ap)
struct vop_reallocblks_args /* {
struct vnode *a_vp;
struct cluster_save *a_buflist;
} */ *ap;
{
#ifndef FANCY_REALLOC
/* printf("ext2_reallocblks not implemented\n"); */
return ENOSPC;
#else
struct m_ext2fs *fs;
struct inode *ip;
struct vnode *vp;
struct buf *sbp, *ebp;
int32_t *bap, *sbap, *ebap = 0;
struct ext2mount *ump;
struct cluster_save *buflist;
struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp;
int32_t start_lbn, end_lbn, soff, newblk, blkno =0;
int i, len, start_lvl, end_lvl, pref, ssize;
vp = ap->a_vp;
ip = VTOI(vp);
fs = ip->i_e2fs;
ump = ip->i_ump;
#ifdef UNKLAR
if (fs->fs_contigsumsize <= 0)
return (ENOSPC);
#endif
buflist = ap->a_buflist;
len = buflist->bs_nchildren;
start_lbn = buflist->bs_children[0]->b_lblkno;
end_lbn = start_lbn + len - 1;
#ifdef DIAGNOSTIC
for (i = 1; i < len; i++)
if (buflist->bs_children[i]->b_lblkno != start_lbn + i)
panic("ext2_reallocblks: non-cluster");
#endif
/*
* If the latest allocation is in a new cylinder group, assume that
* the filesystem has decided to move and do not force it back to
* the previous cylinder group.
*/
if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) !=
dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno)))
return (ENOSPC);
if (ext2_getlbns(vp, start_lbn, start_ap, &start_lvl) ||
ext2_getlbns(vp, end_lbn, end_ap, &end_lvl))
return (ENOSPC);
/*
* Get the starting offset and block map for the first block.
*/
if (start_lvl == 0) {
sbap = &ip->i_db[0];
soff = start_lbn;
} else {
idp = &start_ap[start_lvl - 1];
if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &sbp)) {
brelse(sbp);
return (ENOSPC);
}
sbap = (int32_t *)sbp->b_data;
soff = idp->in_off;
}
/*
* Find the preferred location for the cluster.
*/
EXT2_LOCK(ump);
pref = ext2_blkpref(ip, start_lbn, soff, sbap, blkno);
/*
* If the block range spans two block maps, get the second map.
*/
if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) {
ssize = len;
} else {
#ifdef DIAGNOSTIC
if (start_ap[start_lvl-1].in_lbn == idp->in_lbn)
panic("ext2_reallocblk: start == end");
#endif
ssize = len - (idp->in_off + 1);
if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &ebp)){
EXT2_UNLOCK(ump);
goto fail;
}
ebap = (int32_t *)ebp->b_data;
}
/*
* Search the block map looking for an allocation of the desired size.
*/
if ((newblk = (int32_t)ext2_hashalloc(ip, dtog(fs, pref), pref,
len, ext2_clusteralloc)) == 0){
EXT2_UNLOCK(ump);
goto fail;
}
/*
* We have found a new contiguous block.
*
* First we have to replace the old block pointers with the new
* block pointers in the inode and indirect blocks associated
* with the file.
*/
blkno = newblk;
for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->e2fs_fpb) {
if (i == ssize)
bap = ebap;
soff = -i;
#ifdef DIAGNOSTIC
if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap))
panic("ext2_reallocblks: alloc mismatch");
#endif
*bap++ = blkno;
}
/*
* Next we must write out the modified inode and indirect blocks.
* For strict correctness, the writes should be synchronous since
* the old block values may have been written to disk. In practise
* they are almost never written, but if we are concerned about
* strict correctness, the `doasyncfree' flag should be set to zero.
*
* The test on `doasyncfree' should be changed to test a flag
* that shows whether the associated buffers and inodes have
* been written. The flag should be set when the cluster is
* started and cleared whenever the buffer or inode is flushed.
* We can then check below to see if it is set, and do the
* synchronous write only when it has been cleared.
*/
if (sbap != &ip->i_db[0]) {
if (doasyncfree)
bdwrite(sbp);
else
bwrite(sbp);
} else {
ip->i_flag |= IN_CHANGE | IN_UPDATE;
if (!doasyncfree)
ext2_update(vp, 1);
}
if (ssize < len) {
if (doasyncfree)
bdwrite(ebp);
else
bwrite(ebp);
}
/*
* Last, free the old blocks and assign the new blocks to the buffers.
*/
for (blkno = newblk, i = 0; i < len; i++, blkno += fs->e2fs_fpb) {
ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno),
fs->e2fs_bsize);
buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno);
}
return (0);
fail:
if (ssize < len)
brelse(ebp);
if (sbap != &ip->i_db[0])
brelse(sbp);
return (ENOSPC);
#endif /* FANCY_REALLOC */
}
/*
* Allocate an inode in the file system.
*
*/
int
ext2_valloc(pvp, mode, cred, vpp)
struct vnode *pvp;
int mode;
struct ucred *cred;
struct vnode **vpp;
{
struct inode *pip;
struct m_ext2fs *fs;
struct inode *ip;
struct ext2mount *ump;
ino_t ino, ipref;
int i, error, cg;
*vpp = NULL;
pip = VTOI(pvp);
fs = pip->i_e2fs;
ump = pip->i_ump;
EXT2_LOCK(ump);
if (fs->e2fs->e2fs_ficount == 0)
goto noinodes;
/*
* If it is a directory then obtain a cylinder group based on
* ext2_dirpref else obtain it using ino_to_cg. The preferred inode is
* always the next inode.
*/
if((mode & IFMT) == IFDIR) {
cg = ext2_dirpref(pip);
if (fs->e2fs_contigdirs[cg] < 255)
fs->e2fs_contigdirs[cg]++;
} else {
cg = ino_to_cg(fs, pip->i_number);
if (fs->e2fs_contigdirs[cg] > 0)
fs->e2fs_contigdirs[cg]--;
}
ipref = cg * fs->e2fs->e2fs_ipg + 1;
ino = (ino_t)ext2_hashalloc(pip, cg, (long)ipref, mode, ext2_nodealloccg);
if (ino == 0)
goto noinodes;
error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp);
if (error) {
ext2_vfree(pvp, ino, mode);
return (error);
}
ip = VTOI(*vpp);
/*
the question is whether using VGET was such good idea at all -
Linux doesn't read the old inode in when it's allocating a
new one. I will set at least i_size & i_blocks the zero.
*/
ip->i_mode = 0;
ip->i_size = 0;
ip->i_blocks = 0;
ip->i_flags = 0;
/* now we want to make sure that the block pointers are zeroed out */
for (i = 0; i < NDADDR; i++)
ip->i_db[i] = 0;
for (i = 0; i < NIADDR; i++)
ip->i_ib[i] = 0;
/*
* Set up a new generation number for this inode.
* XXX check if this makes sense in ext2
*/
if (ip->i_gen == 0 || ++ip->i_gen == 0)
ip->i_gen = random() / 2 + 1;
/*
printf("ext2_valloc: allocated inode %d\n", ino);
*/
return (0);
noinodes:
EXT2_UNLOCK(ump);
ext2_fserr(fs, 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 allocate a
* directory inode in the same cylinder group as its parent
* directory, but also to reserve space for its files inodes
* and data. Restrict the number of directories which may be
* allocated one after another in the same cylinder group
* without intervening allocation of files.
*
* If we allocate a first level directory then force allocation
* in another cylinder group.
*
*/
static u_long
ext2_dirpref(struct inode *pip)
{
struct m_ext2fs *fs;
int cg, prefcg, dirsize, cgsize;
int avgifree, avgbfree, avgndir, curdirsize;
int minifree, minbfree, maxndir;
int mincg, minndir;
int maxcontigdirs;
mtx_assert(EXT2_MTX(pip->i_ump), MA_OWNED);
fs = pip->i_e2fs;
avgifree = fs->e2fs->e2fs_ficount / fs->e2fs_gcount;
avgbfree = fs->e2fs->e2fs_fbcount / fs->e2fs_gcount;
avgndir = fs->e2fs_total_dir / fs->e2fs_gcount;
/*
* Force allocation in another cg if creating a first level dir.
*/
ASSERT_VOP_LOCKED(ITOV(pip), "ext2fs_dirpref");
if (ITOV(pip)->v_vflag & VV_ROOT) {
prefcg = arc4random() % fs->e2fs_gcount;
mincg = prefcg;
minndir = fs->e2fs_ipg;
for (cg = prefcg; cg < fs->e2fs_gcount; cg++)
if (fs->e2fs_gd[cg].ext2bgd_ndirs < minndir &&
fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree &&
fs->e2fs_gd[cg].ext2bgd_nbfree >= avgbfree) {
mincg = cg;
minndir = fs->e2fs_gd[cg].ext2bgd_ndirs;
}
for (cg = 0; cg < prefcg; cg++)
if (fs->e2fs_gd[cg].ext2bgd_ndirs < minndir &&
fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree &&
fs->e2fs_gd[cg].ext2bgd_nbfree >= avgbfree) {
mincg = cg;
minndir = fs->e2fs_gd[cg].ext2bgd_ndirs;
}
return (mincg);
}
/*
* Count various limits which used for
* optimal allocation of a directory inode.
*/
maxndir = min(avgndir + fs->e2fs_ipg / 16, fs->e2fs_ipg);
minifree = avgifree - avgifree / 4;
if (minifree < 1)
minifree = 1;
minbfree = avgbfree - avgbfree / 4;
if (minbfree < 1)
minbfree = 1;
cgsize = fs->e2fs_fsize * fs->e2fs_fpg;
dirsize = AVGDIRSIZE;
curdirsize = avgndir ? (cgsize - avgbfree * fs->e2fs_bsize) / avgndir : 0;
if (dirsize < curdirsize)
dirsize = curdirsize;
if (dirsize <= 0)
maxcontigdirs = 0; /* dirsize overflowed */
else
maxcontigdirs = min((avgbfree * fs->e2fs_bsize) / dirsize, 255);
maxcontigdirs = min(maxcontigdirs, fs->e2fs_ipg / AFPDIR);
if (maxcontigdirs == 0)
maxcontigdirs = 1;
/*
* Limit number of dirs in one cg and reserve space for
* regular files, but only if we have no deficit in
* inodes or space.
*/
prefcg = ino_to_cg(fs, pip->i_number);
for (cg = prefcg; cg < fs->e2fs_gcount; cg++)
if (fs->e2fs_gd[cg].ext2bgd_ndirs < maxndir &&
fs->e2fs_gd[cg].ext2bgd_nifree >= minifree &&
fs->e2fs_gd[cg].ext2bgd_nbfree >= minbfree) {
if (fs->e2fs_contigdirs[cg] < maxcontigdirs)
return (cg);
}
for (cg = 0; cg < prefcg; cg++)
if (fs->e2fs_gd[cg].ext2bgd_ndirs < maxndir &&
fs->e2fs_gd[cg].ext2bgd_nifree >= minifree &&
fs->e2fs_gd[cg].ext2bgd_nbfree >= minbfree) {
if (fs->e2fs_contigdirs[cg] < maxcontigdirs)
return (cg);
}
/*
* This is a backstop when we have deficit in space.
*/
for (cg = prefcg; cg < fs->e2fs_gcount; cg++)
if (fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree)
return (cg);
for (cg = 0; cg < prefcg; cg++)
if (fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree)
break;
return (cg);
}
/*
* Select the desired position for the next block in a file.
*
* we try to mimic what Remy does in inode_getblk/block_getblk
*
* we note: blocknr == 0 means that we're about to allocate either
* a direct block or a pointer block at the first level of indirection
* (In other words, stuff that will go in i_db[] or i_ib[])
*
* blocknr != 0 means that we're allocating a block that is none
* of the above. Then, blocknr tells us the number of the block
* that will hold the pointer
*/
int32_t
ext2_blkpref(ip, lbn, indx, bap, blocknr)
struct inode *ip;
int32_t lbn;
int indx;
int32_t *bap;
int32_t blocknr;
{
int tmp;
mtx_assert(EXT2_MTX(ip->i_ump), MA_OWNED);
/* if the next block is actually what we thought it is,
then set the goal to what we thought it should be
*/
if(ip->i_next_alloc_block == lbn && ip->i_next_alloc_goal != 0)
return ip->i_next_alloc_goal;
/* now check whether we were provided with an array that basically
tells us previous blocks to which we want to stay closeby
*/
if(bap)
for (tmp = indx - 1; tmp >= 0; tmp--)
if (bap[tmp])
return bap[tmp];
/* else let's fall back to the blocknr, or, if there is none,
follow the rule that a block should be allocated near its inode
*/
return blocknr ? blocknr :
(int32_t)(ip->i_block_group *
EXT2_BLOCKS_PER_GROUP(ip->i_e2fs)) +
ip->i_e2fs->e2fs->e2fs_first_dblock;
}
/*
* 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
ext2_hashalloc(struct inode *ip, int cg, long pref, int size,
daddr_t (*allocator)(struct inode *, int, daddr_t, int))
{
struct m_ext2fs *fs;
ino_t result;
int i, icg = cg;
mtx_assert(EXT2_MTX(ip->i_ump), MA_OWNED);
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_gcount; i *= 2) {
cg += i;
if (cg >= fs->e2fs_gcount)
cg -= fs->e2fs_gcount;
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_gcount;
for (i = 2; i < fs->e2fs_gcount; i++) {
result = (*allocator)(ip, cg, 0, size);
if (result)
return (result);
cg++;
if (cg == fs->e2fs_gcount)
cg = 0;
}
return (0);
}
/*
* Determine whether a block can be allocated.
*
* Check to see if a block of the appropriate size is available,
* and if it is, allocate it.
*/
static daddr_t
ext2_alloccg(struct inode *ip, int cg, daddr_t bpref, int size)
{
struct m_ext2fs *fs;
struct buf *bp;
struct ext2mount *ump;
int error, bno, start, end, loc;
char *bbp;
/* XXX ondisk32 */
fs = ip->i_e2fs;
ump = ip->i_ump;
if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0)
return (0);
EXT2_UNLOCK(ump);
error = bread(ip->i_devvp, fsbtodb(fs,
fs->e2fs_gd[cg].ext2bgd_b_bitmap),
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
EXT2_LOCK(ump);
return (0);
}
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 = ext2_mapsearch(fs, bbp, bpref);
if (bno < 0){
brelse(bp);
EXT2_LOCK(ump);
return (0);
}
gotit:
#ifdef DIAGNOSTIC
if (isset(bbp, (daddr_t)bno)) {
printf("ext2fs_alloccgblk: cg=%d bno=%d fs=%s\n",
cg, bno, fs->e2fs_fsmnt);
panic("ext2fs_alloccg: dup alloc");
}
#endif
setbit(bbp, (daddr_t)bno);
EXT2_LOCK(ump);
fs->e2fs->e2fs_fbcount--;
fs->e2fs_gd[cg].ext2bgd_nbfree--;
fs->e2fs_fmod = 1;
EXT2_UNLOCK(ump);
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 tode in the specified cylinder group.
*/
static daddr_t
ext2_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode)
{
struct m_ext2fs *fs;
struct buf *bp;
struct ext2mount *ump;
int error, start, len, loc, map, i;
char *ibp;
ipref--; /* to avoid a lot of (ipref -1) */
if (ipref == -1)
ipref = 0;
fs = ip->i_e2fs;
ump = ip->i_ump;
if (fs->e2fs_gd[cg].ext2bgd_nifree == 0)
return (0);
EXT2_UNLOCK(ump);
error = bread(ip->i_devvp, fsbtodb(fs,
fs->e2fs_gd[cg].ext2bgd_i_bitmap),
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
EXT2_LOCK(ump);
return (0);
}
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 = %lld, fs = %s\n",
cg, (long long)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);
EXT2_LOCK(ump);
fs->e2fs_gd[cg].ext2bgd_nifree--;
fs->e2fs->e2fs_ficount--;
fs->e2fs_fmod = 1;
if ((mode & IFMT) == IFDIR) {
fs->e2fs_gd[cg].ext2bgd_ndirs++;
fs->e2fs_total_dir++;
}
EXT2_UNLOCK(ump);
bdwrite(bp);
return (cg * fs->e2fs->e2fs_ipg + ipref +1);
}
/*
* Free a block or fragment.
*
*/
void
ext2_blkfree(ip, bno, size)
struct inode *ip;
int32_t bno;
long size;
{
struct m_ext2fs *fs;
struct buf *bp;
struct ext2mount *ump;
int cg, error;
char *bbp;
fs = ip->i_e2fs;
ump = ip->i_ump;
cg = dtog(fs, bno);
if ((u_int)bno >= fs->e2fs->e2fs_bcount) {
printf("bad block %lld, ino %llu\n", (long long)bno,
(unsigned long long)ip->i_number);
ext2_fserr(fs, ip->i_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("block = %lld, fs = %s\n",
(long long)bno, fs->e2fs_fsmnt);
panic("blkfree: freeing free block");
}
clrbit(bbp, bno);
EXT2_LOCK(ump);
fs->e2fs->e2fs_fbcount++;
fs->e2fs_gd[cg].ext2bgd_nbfree++;
fs->e2fs_fmod = 1;
EXT2_UNLOCK(ump);
bdwrite(bp);
}
/*
* Free an inode.
*
*/
int
ext2_vfree(pvp, ino, mode)
struct vnode *pvp;
ino_t ino;
int mode;
{
struct m_ext2fs *fs;
struct inode *pip;
struct buf *bp;
struct ext2mount *ump;
int error, cg;
char * ibp;
/* mode_t save_i_mode; */
pip = VTOI(pvp);
fs = pip->i_e2fs;
ump = pip->i_ump;
if ((u_int)ino > fs->e2fs_ipg * fs->e2fs_gcount)
panic("ext2_vfree: range: devvp = %p, ino = %d, fs = %s",
pip->i_devvp, 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("ino = %llu, fs = %s\n",
(unsigned long long)ino, fs->e2fs_fsmnt);
if (fs->e2fs_ronly == 0)
panic("ifree: freeing free inode");
}
clrbit(ibp, ino);
EXT2_LOCK(ump);
fs->e2fs->e2fs_ficount++;
fs->e2fs_gd[cg].ext2bgd_nifree++;
if ((mode & IFMT) == IFDIR) {
fs->e2fs_gd[cg].ext2bgd_ndirs--;
fs->e2fs_total_dir--;
}
fs->e2fs_fmod = 1;
EXT2_UNLOCK(ump);
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
ext2_mapsearch(struct m_ext2fs *fs, 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
ext2_fserr(fs, uid, cp)
struct m_ext2fs *fs;
uid_t uid;
char *cp;
{
log(LOG_ERR, "uid %u on %s: %s\n", uid, fs->e2fs_fsmnt, cp);
}
int
cg_has_sb(int i)
{
int a3, a5, a7;
if (i == 0 || i == 1)
return 1;
for (a3 = 3, a5 = 5, a7 = 7;
a3 <= i || a5 <= i || a7 <= i;
a3 *= 3, a5 *= 5, a7 *= 7)
if (i == a3 || i == a5 || i == a7)
return 1;
return 0;
}

View File

@ -44,42 +44,39 @@
#include <sys/ucred.h>
#include <sys/vnode.h>
#include <gnu/fs/ext2fs/inode.h>
#include <gnu/fs/ext2fs/ext2_fs.h>
#include <gnu/fs/ext2fs/ext2_fs_sb.h>
#include <gnu/fs/ext2fs/fs.h>
#include <gnu/fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/inode.h>
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/fs.h>
#include <fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/ext2_mount.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
ext2_balloc(ip, bn, size, cred, bpp, flags)
ext2_balloc(ip, lbn, size, cred, bpp, flags)
struct inode *ip;
int32_t bn;
int32_t lbn;
int size;
struct ucred *cred;
struct buf **bpp;
int flags;
{
struct ext2_sb_info *fs;
struct m_ext2fs *fs;
struct ext2mount *ump;
int32_t nb;
struct buf *bp, *nbp;
struct vnode *vp = ITOV(ip);
struct indir indirs[NIADDR + 2];
int32_t newb, lbn, *bap, pref;
int32_t newb, *bap, pref;
int osize, nsize, num, i, error;
/*
ext2_debug("ext2_balloc called (%d, %d, %d)\n",
ip->i_number, (int)bn, (int)size);
*/
*bpp = NULL;
if (bn < 0)
if (lbn < 0)
return (EFBIG);
fs = ip->i_e2fs;
lbn = bn;
ump = ip->i_ump;
/*
* check if this is a sequential block allocation.
@ -94,12 +91,12 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
/*
* The first NDADDR blocks are direct blocks
*/
if (bn < NDADDR) {
nb = ip->i_db[bn];
if (lbn < NDADDR) {
nb = ip->i_db[lbn];
/* no new block is to be allocated, and no need to expand
the file */
if (nb != 0 && ip->i_size >= (bn + 1) * fs->s_blocksize) {
error = bread(vp, bn, fs->s_blocksize, NOCRED, &bp);
if (nb != 0 && ip->i_size >= (lbn + 1) * fs->e2fs_bsize) {
error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
return (error);
@ -115,7 +112,7 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
osize = fragroundup(fs, blkoff(fs, ip->i_size));
nsize = fragroundup(fs, size);
if (nsize <= osize) {
error = bread(vp, bn, osize, NOCRED, &bp);
error = bread(vp, lbn, osize, NOCRED, &bp);
if (error) {
brelse(bp);
return (error);
@ -134,21 +131,22 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
*/
}
} else {
if (ip->i_size < (bn + 1) * fs->s_blocksize)
if (ip->i_size < (lbn + 1) * fs->e2fs_bsize)
nsize = fragroundup(fs, size);
else
nsize = fs->s_blocksize;
error = ext2_alloc(ip, bn,
ext2_blkpref(ip, bn, (int)bn, &ip->i_db[0], 0),
nsize = fs->e2fs_bsize;
EXT2_LOCK(ump);
error = ext2_alloc(ip, lbn,
ext2_blkpref(ip, lbn, (int)lbn, &ip->i_db[0], 0),
nsize, cred, &newb);
if (error)
return (error);
bp = getblk(vp, bn, nsize, 0, 0, 0);
bp = getblk(vp, lbn, nsize, 0, 0, 0);
bp->b_blkno = fsbtodb(fs, newb);
if (flags & B_CLRBUF)
vfs_bio_clrbuf(bp);
}
ip->i_db[bn] = dbtofsb(fs, bp->b_blkno);
ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
*bpp = bp;
return (0);
@ -157,7 +155,7 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
* Determine the number of levels of indirection.
*/
pref = 0;
if ((error = ext2_getlbns(vp, bn, indirs, &num)) != 0)
if ((error = ext2_getlbns(vp, lbn, indirs, &num)) != 0)
return(error);
#ifdef DIAGNOSTIC
if (num < 1)
@ -169,28 +167,14 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
--num;
nb = ip->i_ib[indirs[0].in_off];
if (nb == 0) {
#if 0
pref = ext2_blkpref(ip, lbn, 0, (int32_t *)0, 0);
#else
/* see the comment by ext2_blkpref. What we do here is
to pretend that it'd be good for a block holding indirect
pointers to be allocated near its predecessor in terms
of indirection, or the last direct block.
We shamelessly exploit the fact that i_ib immediately
follows i_db.
Godmar thinks it make sense to allocate i_ib[0] immediately
after i_db[11], but it's not utterly clear whether this also
applies to i_ib[1] and i_ib[0]
*/
EXT2_LOCK(ump);
pref = ext2_blkpref(ip, lbn, indirs[0].in_off +
EXT2_NDIR_BLOCKS, &ip->i_db[0], 0);
#endif
if ((error = ext2_alloc(ip, lbn, pref, (int)fs->s_blocksize,
cred, &newb)) != 0)
if ((error = ext2_alloc(ip, lbn, pref,
(int)fs->e2fs_bsize, cred, &newb)))
return (error);
nb = newb;
bp = getblk(vp, indirs[1].in_lbn, fs->s_blocksize, 0, 0, 0);
bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0, 0);
bp->b_blkno = fsbtodb(fs, newb);
vfs_bio_clrbuf(bp);
/*
@ -198,7 +182,7 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
* never point at garbage.
*/
if ((error = bwrite(bp)) != 0) {
ext2_blkfree(ip, nb, fs->s_blocksize);
ext2_blkfree(ip, nb, fs->e2fs_bsize);
return (error);
}
ip->i_ib[indirs[0].in_off] = newb;
@ -209,7 +193,7 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
*/
for (i = 1;;) {
error = bread(vp,
indirs[i].in_lbn, (int)fs->s_blocksize, NOCRED, &bp);
indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
return (error);
@ -220,29 +204,20 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
break;
i += 1;
if (nb != 0) {
brelse(bp);
bqrelse(bp);
continue;
}
if (pref == 0)
#if 1
/* see the comment above and by ext2_blkpref
* I think this implements Linux policy, but
* does it really make sense to allocate to
* block containing pointers together ?
* Also, will it ever succeed ?
*/
EXT2_LOCK(ump);
if (pref == 0)
pref = ext2_blkpref(ip, lbn, indirs[i].in_off, bap,
bp->b_lblkno);
#else
pref = ext2_blkpref(ip, lbn, 0, (int32_t *)0, 0);
#endif
if ((error =
ext2_alloc(ip, lbn, pref, (int)fs->s_blocksize, cred, &newb)) != 0) {
error = ext2_alloc(ip, lbn, pref, (int)fs->e2fs_bsize, cred, &newb);
if (error) {
brelse(bp);
return (error);
}
nb = newb;
nbp = getblk(vp, indirs[i].in_lbn, fs->s_blocksize, 0, 0, 0);
nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0, 0);
nbp->b_blkno = fsbtodb(fs, nb);
vfs_bio_clrbuf(nbp);
/*
@ -250,7 +225,8 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
* never point at garbage.
*/
if ((error = bwrite(nbp)) != 0) {
ext2_blkfree(ip, nb, fs->s_blocksize);
ext2_blkfree(ip, nb, fs->e2fs_bsize);
EXT2_UNLOCK(ump);
brelse(bp);
return (error);
}
@ -262,6 +238,8 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
if (flags & B_SYNC) {
bwrite(bp);
} else {
if (bp->b_bufsize == fs->e2fs_bsize)
bp->b_flags |= B_CLUSTEROK;
bdwrite(bp);
}
}
@ -269,15 +247,16 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
* Get the data block, allocating if necessary.
*/
if (nb == 0) {
EXT2_LOCK(ump);
pref = ext2_blkpref(ip, lbn, indirs[i].in_off, &bap[0],
bp->b_lblkno);
if ((error = ext2_alloc(ip,
lbn, pref, (int)fs->s_blocksize, cred, &newb)) != 0) {
lbn, pref, (int)fs->e2fs_bsize, cred, &newb)) != 0) {
brelse(bp);
return (error);
}
nb = newb;
nbp = getblk(vp, lbn, fs->s_blocksize, 0, 0, 0);
nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0);
nbp->b_blkno = fsbtodb(fs, nb);
if (flags & B_CLRBUF)
vfs_bio_clrbuf(nbp);
@ -289,6 +268,8 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
if (flags & B_SYNC) {
bwrite(bp);
} else {
if (bp->b_bufsize == fs->e2fs_bsize)
bp->b_flags |= B_CLUSTEROK;
bdwrite(bp);
}
*bpp = nbp;
@ -296,15 +277,16 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
}
brelse(bp);
if (flags & B_CLRBUF) {
error = bread(vp, lbn, (int)fs->s_blocksize, NOCRED, &nbp);
error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp);
if (error) {
brelse(nbp);
return (error);
}
} else {
nbp = getblk(vp, lbn, fs->s_blocksize, 0, 0, 0);
nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0);
nbp->b_blkno = fsbtodb(fs, nb);
}
*bpp = nbp;
return (0);
}

View File

@ -45,14 +45,13 @@
#include <sys/resourcevar.h>
#include <sys/stat.h>
#include <gnu/fs/ext2fs/inode.h>
#include <gnu/fs/ext2fs/ext2_fs.h>
#include <gnu/fs/ext2fs/ext2_fs_sb.h>
#include <gnu/fs/ext2fs/ext2_mount.h>
#include <gnu/fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/inode.h>
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/ext2_mount.h>
#include <fs/ext2fs/ext2_extern.h>
/*
* Bmap converts a the logical block number of a file to its physical block
* Bmap converts the logical block number of a file to its physical block
* number on the disk. The conversion is done by using the logical block
* number to index into the array of block pointers described by the dinode.
*/
@ -93,7 +92,7 @@ ext2_bmap(ap)
* which they point. Triple indirect blocks are addressed by one less than
* the address of the first double indirect block to which they point.
*
* ufs_bmaparray does the bmap conversion, and if requested returns the
* ext2_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).

78
sys/fs/ext2fs/ext2_dinode.h Executable file
View File

@ -0,0 +1,78 @@
/*-
* Copyright (c) 2009 Aditya Sarawgi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _FS_EXT2FS_EXT2_DINODE_H_
#define _FS_EXT2FS_EXT2_DINODE_H_
#define e2di_size_high e2di_dacl
/*
* Inode flags
* The current implementation uses only EXT2_IMMUTABLE and EXT2_APPEND 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 */
#define EXT2_NOATIME 0x00000080 /* do not update atime */
/*
* Structure of an inode on the disk
*/
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: Access 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[EXT2_N_BLOCKS]; /* 40: disk blocks */
u_int32_t e2di_gen; /* 100: generation number */
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_int16_t e2di_uid_high; /* 120: Owner UID top 16 bits */
u_int16_t e2di_gid_high; /* 122: Owner GID top 16 bits */
u_int32_t e2di_linux_reserved3; /* 124 */
};
#endif /* _FS_EXT2FS_EXT2_DINODE_H_ */

81
sys/fs/ext2fs/ext2_dir.h Executable file
View File

@ -0,0 +1,81 @@
/*-
* Copyright (c) 2009 Aditya Sarawgi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _FS_EXT2FS_EXT2_DIR_H_
#define _FS_EXT2FS_EXT2_DIR_H_
/*
* Structure of a directory entry
*/
#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 new version of the directory entry. Since EXT2 structures are
* stored in intel byte order, and the name_len field could never be
* bigger than 255 chars, it's safe to reclaim the extra byte for the
* file_type field.
*/
struct ext2fs_direct_2 {
u_int32_t e2d_ino; /* inode number of entry */
u_int16_t e2d_reclen; /* length of this record */
u_int8_t e2d_namlen; /* length of string in d_name */
u_int8_t e2d_type; /* file type */
char e2d_name[EXT2FS_MAXNAMLEN];/* name with length<=EXT2FS_MAXNAMLEN */
};
/*
* Ext2 directory file types. Only the low 3 bits are used. The
* other bits are reserved for now.
*/
#define EXT2_FT_UNKNOWN 0
#define EXT2_FT_REG_FILE 1
#define EXT2_FT_DIR 2
#define EXT2_FT_CHRDEV 3
#define EXT2_FT_BLKDEV 4
#define EXT2_FT_FIFO 5
#define EXT2_FT_SOCK 6
#define EXT2_FT_SYMLINK 7
#define EXT2_FT_MAX 8
/*
* EXT2_DIR_PAD defines the directory entries boundaries
*
* NOTE: It must be a multiple of 4
*/
#define EXT2_DIR_PAD 4
#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
~EXT2_DIR_ROUND)
#endif /* !_FS_EXT2FS_EXT2_DIR_H_ */

View File

@ -36,10 +36,10 @@
* $FreeBSD$
*/
#ifndef _SYS_GNU_EXT2FS_EXT2_EXTERN_H_
#define _SYS_GNU_EXT2FS_EXT2_EXTERN_H_
#ifndef _FS_EXT2FS_EXT2_EXTERN_H_
#define _FS_EXT2FS_EXT2_EXTERN_H_
struct ext2_inode;
struct ext2fs_dinode;
struct indir;
struct inode;
struct mount;
@ -56,13 +56,13 @@ int32_t ext2_blkpref(struct inode *, int32_t, int, int32_t *, int32_t);
int ext2_bmap(struct vop_bmap_args *);
int ext2_bmaparray(struct vnode *, int32_t, int32_t *, int *, int *);
void ext2_dirbad(struct inode *ip, doff_t offset, char *how);
void ext2_ei2i(struct ext2_inode *, struct inode *);
void ext2_ei2i(struct ext2fs_dinode *, struct inode *);
int ext2_getlbns(struct vnode *, int32_t, struct indir *, int *);
void ext2_i2ei(struct inode *, struct ext2_inode *);
void ext2_i2ei(struct inode *, struct ext2fs_dinode *);
void ext2_itimes(struct vnode *vp);
int ext2_reallocblks(struct vop_reallocblks_args *);
int ext2_reclaim(struct vop_reclaim_args *);
void ext2_setblock(struct ext2_sb_info *, u_char *, int32_t);
void ext2_setblock(struct m_ext2fs *, u_char *, int32_t);
int ext2_truncate(struct vnode *, off_t, int, struct ucred *, struct thread *);
int ext2_update(struct vnode *, int);
int ext2_valloc(struct vnode *, int, struct ucred *, struct vnode **);
@ -78,19 +78,8 @@ int ext2_dirrewrite(struct inode *,
struct inode *, struct componentname *);
int ext2_dirempty(struct inode *, ino_t, struct ucred *);
int ext2_checkpath(struct inode *, struct inode *, struct ucred *);
struct ext2_group_desc * get_group_desc(struct mount * ,
unsigned int , struct buf ** );
int ext2_group_sparse(int group);
void ext2_discard_prealloc(struct inode *);
int cg_has_sb(int i);
int ext2_inactive(struct vop_inactive_args *);
int ext2_new_block(struct mount * mp, unsigned long goal,
u_int32_t *prealloc_count, u_int32_t *prealloc_block);
ino_t ext2_new_inode(const struct inode * dir, int mode);
unsigned long ext2_count_free(struct buf *map, unsigned int numchars);
void ext2_free_blocks(struct mount *mp, unsigned long block,
unsigned long count);
void ext2_free_inode(struct inode * inode);
void mark_buffer_dirty(struct buf *bh);
/* Flags to low-level allocation routines. */
#define B_CLRBUF 0x01 /* Request allocated buffer be cleared. */
@ -101,4 +90,4 @@ void mark_buffer_dirty(struct buf *bh);
extern struct vop_vector ext2_vnodeops;
extern struct vop_vector ext2_fifoops;
#endif /* !_SYS_GNU_EXT2FS_EXT2_EXTERN_H_ */
#endif /* !_FS_EXT2FS_EXT2_EXTERN_H_ */

View File

@ -47,12 +47,11 @@
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <gnu/fs/ext2fs/inode.h>
#include <gnu/fs/ext2fs/ext2_mount.h>
#include <gnu/fs/ext2fs/ext2_fs.h>
#include <gnu/fs/ext2fs/ext2_fs_sb.h>
#include <gnu/fs/ext2fs/fs.h>
#include <gnu/fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/inode.h>
#include <fs/ext2fs/ext2_mount.h>
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/fs.h>
#include <fs/ext2fs/ext2_extern.h>
static int ext2_indirtrunc(struct inode *, int32_t, int32_t, int32_t, int,
long *);
@ -71,26 +70,27 @@ ext2_update(vp, waitfor)
struct vnode *vp;
int waitfor;
{
struct ext2_sb_info *fs;
struct m_ext2fs *fs;
struct buf *bp;
struct inode *ip;
int error;
ASSERT_VOP_ELOCKED(vp, "ext2_update");
ext2_itimes(vp);
ip = VTOI(vp);
if ((ip->i_flag & IN_MODIFIED) == 0)
return (0);
ip->i_flag &= ~(IN_LAZYMOD | IN_MODIFIED);
if (vp->v_mount->mnt_flag & MNT_RDONLY)
if ((ip->i_flag & IN_MODIFIED) == 0 && waitfor == 0)
return (0);
ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED);
fs = ip->i_e2fs;
if(fs->e2fs_ronly)
return (0);
if ((error = bread(ip->i_devvp,
fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
(int)fs->s_blocksize, NOCRED, &bp)) != 0) {
(int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
brelse(bp);
return (error);
}
ext2_i2ei(ip, (struct ext2_inode *)((char *)bp->b_data +
ext2_i2ei(ip, (struct ext2fs_dinode *)((char *)bp->b_data +
EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)));
if (waitfor && (vp->v_mount->mnt_kern_flag & MNTK_ASYNC) == 0)
return (bwrite(bp));
@ -120,22 +120,22 @@ ext2_truncate(vp, length, flags, cred, td)
struct inode *oip;
int32_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
int32_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
struct ext2_sb_info *fs;
struct bufobj *bo;
struct m_ext2fs *fs;
struct buf *bp;
int offset, size, level;
long count, nblocks, blocksreleased = 0;
int aflags, error, i, allerror;
off_t osize;
/*
printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
*/ /*
* negative file sizes will totally break the code below and
* are not meaningful anyways.
*/
if (length < 0)
return EFBIG;
oip = VTOI(ovp);
bo = &ovp->v_bufobj;
ASSERT_VOP_LOCKED(vp, "ext2_truncate");
if (length < 0)
return (EINVAL);
if (ovp->v_type == VLNK &&
oip->i_size < ovp->v_mount->mnt_maxsymlinklen) {
#ifdef DIAGNOSTIC
@ -153,27 +153,32 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
}
fs = oip->i_e2fs;
osize = oip->i_size;
ext2_discard_prealloc(oip);
/*
* Lengthen the size of the file. We must ensure that the
* last byte of the file is allocated. Since the smallest
* value of oszie is 0, length will be at least 1.
* value of osize is 0, length will be at least 1.
*/
if (osize < length) {
if (length > oip->i_e2fs->fs_maxfilesize)
if (length > oip->i_e2fs->e2fs_maxfilesize)
return (EFBIG);
vnode_pager_setsize(ovp, length);
offset = blkoff(fs, length - 1);
lbn = lblkno(fs, length - 1);
aflags = B_CLRBUF;
if (flags & IO_SYNC)
aflags |= B_SYNC;
vnode_pager_setsize(ovp, length);
if ((error = ext2_balloc(oip, lbn, offset + 1, cred, &bp,
aflags)) != 0)
error = ext2_balloc(oip, lbn, offset + 1, cred, &bp, aflags);
if (error) {
vnode_pager_setsize(vp, osize);
return (error);
}
oip->i_size = length;
if (aflags & IO_SYNC)
if (bp->b_bufsize == fs->e2fs_bsize)
bp->b_flags |= B_CLUSTEROK;
if (aflags & B_SYNC)
bwrite(bp);
else if (ovp->v_mount->mnt_flag & MNT_ASYNC)
bdwrite(bp);
else
bawrite(bp);
oip->i_flag |= IN_CHANGE | IN_UPDATE;
@ -195,15 +200,19 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
aflags = B_CLRBUF;
if (flags & IO_SYNC)
aflags |= B_SYNC;
if ((error = ext2_balloc(oip, lbn, offset, cred, &bp,
aflags)) != 0)
error = ext2_balloc(oip, lbn, offset, cred, &bp, aflags);
if (error)
return (error);
oip->i_size = length;
size = blksize(fs, oip, lbn);
bzero((char *)bp->b_data + offset, (u_int)(size - offset));
allocbuf(bp, size);
if (aflags & IO_SYNC)
if (bp->b_bufsize == fs->e2fs_bsize)
bp->b_flags |= B_CLUSTEROK;
if (aflags & B_SYNC)
bwrite(bp);
else if (ovp->v_mount->mnt_flag & MNT_ASYNC)
bdwrite(bp);
else
bawrite(bp);
}
@ -213,11 +222,11 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
* which we want to keep. Lastblock is -1 when
* the file is truncated to 0.
*/
lastblock = lblkno(fs, length + fs->s_blocksize - 1) - 1;
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->s_blocksize);
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
@ -244,10 +253,11 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
bcopy((caddr_t)&oip->i_db[0], (caddr_t)newblks, sizeof newblks);
bcopy((caddr_t)oldblks, (caddr_t)&oip->i_db[0], sizeof oldblks);
oip->i_size = osize;
error = vtruncbuf(ovp, cred, td, length, (int)fs->s_blocksize);
error = vtruncbuf(ovp, cred, td, length, (int)fs->e2fs_bsize);
if (error && (allerror == 0))
allerror = error;
vnode_pager_setsize(ovp, length);
/*
* Indirect blocks first.
*/
@ -264,7 +274,7 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
blocksreleased += count;
if (lastiblock[level] < 0) {
oip->i_ib[level] = 0;
ext2_blkfree(oip, bn, fs->s_frag_size);
ext2_blkfree(oip, bn, fs->e2fs_fsize);
blocksreleased += nblocks;
}
}
@ -325,11 +335,11 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
for (i = 0; i < NDADDR; i++)
if (newblks[i] != oip->i_db[i])
panic("itrunc2");
VI_LOCK(ovp);
if (length == 0 && (ovp->v_bufobj.bo_dirty.bv_cnt != 0 ||
ovp->v_bufobj.bo_clean.bv_cnt != 0))
BO_LOCK(bo);
if (length == 0 && (bo->bo_dirty.bv_cnt != 0 ||
bo->bo_clean.bv_cnt != 0))
panic("itrunc3");
VI_UNLOCK(ovp);
BO_UNLOCK(bo);
#endif /* DIAGNOSTIC */
/*
* Put back the real size.
@ -362,7 +372,7 @@ ext2_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
long *countp;
{
struct buf *bp;
struct ext2_sb_info *fs = ip->i_e2fs;
struct m_ext2fs *fs = ip->i_e2fs;
struct vnode *vp;
int32_t *bap, *copy, nb, nlbn, last;
long blkcount, factor;
@ -380,7 +390,7 @@ ext2_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
last = lastbn;
if (lastbn > 0)
last /= factor;
nblocks = btodb(fs->s_blocksize);
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
@ -390,7 +400,7 @@ ext2_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
* explicitly instead of letting bread do everything for us.
*/
vp = ITOV(ip);
bp = getblk(vp, lbn, (int)fs->s_blocksize, 0, 0, 0);
bp = getblk(vp, lbn, (int)fs->e2fs_bsize, 0, 0, 0);
if (bp->b_flags & (B_DONE | B_DELWRI)) {
} else {
bp->b_iocmd = BIO_READ;
@ -409,8 +419,8 @@ ext2_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
}
bap = (int32_t *)bp->b_data;
copy = malloc(fs->s_blocksize, M_TEMP, M_WAITOK);
bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->s_blocksize);
copy = malloc(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 (int32_t));
if (last == -1)
@ -434,7 +444,7 @@ ext2_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
allerror = error;
blocksreleased += blkcount;
}
ext2_blkfree(ip, nb, fs->s_blocksize);
ext2_blkfree(ip, nb, fs->e2fs_bsize);
blocksreleased += nblocks;
}
@ -471,7 +481,6 @@ ext2_inactive(ap)
struct thread *td = ap->a_td;
int mode, error = 0;
ext2_discard_prealloc(ip);
if (prtactive && vrefcnt(vp) != 0)
vprint("ext2_inactive: pushing active", vp);

View File

@ -31,9 +31,10 @@
#include <sys/stat.h>
#include <sys/vnode.h>
#include <gnu/fs/ext2fs/inode.h>
#include <gnu/fs/ext2fs/ext2_fs.h>
#include <gnu/fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/inode.h>
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/ext2_dinode.h>
void
ext2_print_inode( in )
@ -64,37 +65,37 @@ ext2_print_inode( in )
*/
void
ext2_ei2i(ei, ip)
struct ext2_inode *ei;
struct ext2fs_dinode *ei;
struct inode *ip;
{
int i;
ip->i_nlink = ei->i_links_count;
ip->i_nlink = ei->e2di_nlink;
/* Godmar thinks - if the link count is zero, then the inode is
unused - according to ext2 standards. Ufs marks this fact
by setting i_mode to zero - why ?
I can see that this might lead to problems in an undelete.
*/
ip->i_mode = ei->i_links_count ? ei->i_mode : 0;
ip->i_size = ei->i_size;
ip->i_mode = ei->e2di_nlink ? ei->e2di_mode : 0;
ip->i_size = ei->e2di_size;
if (S_ISREG(ip->i_mode))
ip->i_size |= ((u_int64_t)ei->i_size_high) << 32;
ip->i_atime = ei->i_atime;
ip->i_mtime = ei->i_mtime;
ip->i_ctime = ei->i_ctime;
ip->i_size |= ((u_int64_t)ei->e2di_size_high) << 32;
ip->i_atime = ei->e2di_atime;
ip->i_mtime = ei->e2di_mtime;
ip->i_ctime = ei->e2di_ctime;
ip->i_flags = 0;
ip->i_flags |= (ei->i_flags & EXT2_APPEND_FL) ? SF_APPEND : 0;
ip->i_flags |= (ei->i_flags & EXT2_IMMUTABLE_FL) ? SF_IMMUTABLE : 0;
ip->i_flags |= (ei->i_flags & EXT2_NODUMP_FL) ? UF_NODUMP : 0;
ip->i_blocks = ei->i_blocks;
ip->i_gen = ei->i_generation;
ip->i_uid = ei->i_uid;
ip->i_gid = ei->i_gid;
ip->i_flags |= (ei->e2di_flags & EXT2_APPEND) ? SF_APPEND : 0;
ip->i_flags |= (ei->e2di_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
ip->i_flags |= (ei->e2di_flags & EXT2_NODUMP) ? UF_NODUMP : 0;
ip->i_blocks = ei->e2di_nblock;
ip->i_gen = ei->e2di_gen;
ip->i_uid = ei->e2di_uid;
ip->i_gid = ei->e2di_gid;
/* XXX use memcpy */
for(i = 0; i < NDADDR; i++)
ip->i_db[i] = ei->i_block[i];
ip->i_db[i] = ei->e2di_blocks[i];
for(i = 0; i < NIADDR; i++)
ip->i_ib[i] = ei->i_block[EXT2_NDIR_BLOCKS + i];
ip->i_ib[i] = ei->e2di_blocks[EXT2_NDIR_BLOCKS + i];
}
/*
@ -103,35 +104,35 @@ ext2_ei2i(ei, ip)
void
ext2_i2ei(ip, ei)
struct inode *ip;
struct ext2_inode *ei;
struct ext2fs_dinode *ei;
{
int i;
ei->i_mode = ip->i_mode;
ei->i_links_count = ip->i_nlink;
ei->e2di_mode = ip->i_mode;
ei->e2di_nlink = ip->i_nlink;
/*
Godmar thinks: if dtime is nonzero, ext2 says this inode
has been deleted, this would correspond to a zero link count
*/
ei->i_dtime = ei->i_links_count ? 0 : ip->i_mtime;
ei->i_size = ip->i_size;
ei->e2di_dtime = ei->e2di_nlink ? 0 : ip->i_mtime;
ei->e2di_size = ip->i_size;
if (S_ISREG(ip->i_mode))
ei->i_size_high = ip->i_size >> 32;
ei->i_atime = ip->i_atime;
ei->i_mtime = ip->i_mtime;
ei->i_ctime = ip->i_ctime;
ei->i_flags = ip->i_flags;
ei->i_flags = 0;
ei->i_flags |= (ip->i_flags & SF_APPEND) ? EXT2_APPEND_FL: 0;
ei->i_flags |= (ip->i_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE_FL: 0;
ei->i_flags |= (ip->i_flags & UF_NODUMP) ? EXT2_NODUMP_FL : 0;
ei->i_blocks = ip->i_blocks;
ei->i_generation = ip->i_gen;
ei->i_uid = ip->i_uid;
ei->i_gid = ip->i_gid;
ei->e2di_size_high = ip->i_size >> 32;
ei->e2di_atime = ip->i_atime;
ei->e2di_mtime = ip->i_mtime;
ei->e2di_ctime = ip->i_ctime;
ei->e2di_flags = ip->i_flags;
ei->e2di_flags = 0;
ei->e2di_flags |= (ip->i_flags & SF_APPEND) ? EXT2_APPEND: 0;
ei->e2di_flags |= (ip->i_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
ei->e2di_flags |= (ip->i_flags & UF_NODUMP) ? EXT2_NODUMP: 0;
ei->e2di_nblock = ip->i_blocks;
ei->e2di_gen = ip->i_gen;
ei->e2di_uid = ip->i_uid;
ei->e2di_gid = ip->i_gid;
/* XXX use memcpy */
for(i = 0; i < NDADDR; i++)
ei->i_block[i] = ip->i_db[i];
ei->e2di_blocks[i] = ip->i_db[i];
for(i = 0; i < NIADDR; i++)
ei->i_block[EXT2_NDIR_BLOCKS + i] = ip->i_ib[i];
ei->e2di_blocks[EXT2_NDIR_BLOCKS + i] = ip->i_ib[i];
}

View File

@ -55,11 +55,11 @@
#include <ufs/ufs/dir.h>
#include <gnu/fs/ext2fs/inode.h>
#include <gnu/fs/ext2fs/ext2_mount.h>
#include <gnu/fs/ext2fs/ext2_extern.h>
#include <gnu/fs/ext2fs/ext2_fs.h>
#include <gnu/fs/ext2fs/ext2_fs_sb.h>
#include <fs/ext2fs/inode.h>
#include <fs/ext2fs/ext2_mount.h>
#include <fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/ext2_dir.h>
#ifdef DIAGNOSTIC
static int dirchk = 1;
@ -112,7 +112,7 @@ static u_char dt_to_ext2_ft[] = {
((dt) > sizeof(dt_to_ext2_ft) / sizeof(dt_to_ext2_ft[0]) ? \
EXT2_FT_UNKNOWN : dt_to_ext2_ft[(dt)])
static int ext2_dirbadentry(struct vnode *dp, struct ext2_dir_entry_2 *de,
static int ext2_dirbadentry(struct vnode *dp, struct ext2fs_direct_2 *de,
int entryoffsetinblock);
/*
@ -144,13 +144,13 @@ ext2_readdir(ap)
struct uio *uio = ap->a_uio;
int count, error;
struct ext2_dir_entry_2 *edp, *dp;
struct ext2fs_direct_2 *edp, *dp;
int ncookies;
struct dirent dstdp;
struct uio auio;
struct iovec aiov;
caddr_t dirbuf;
int DIRBLKSIZ = VTOI(ap->a_vp)->i_e2fs->s_blocksize;
int DIRBLKSIZ = VTOI(ap->a_vp)->i_e2fs->e2fs_bsize;
int readcnt;
off_t startoffset = uio->uio_offset;
@ -166,12 +166,6 @@ ext2_readdir(ap)
count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
if (count <= 0)
count += DIRBLKSIZ;
#ifdef EXT2FS_DEBUG
printf("ext2_readdir: uio_offset = %lld, uio_resid = %d, count = %d\n",
uio->uio_offset, uio->uio_resid, count);
#endif
auio = *uio;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
@ -183,10 +177,10 @@ ext2_readdir(ap)
error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
if (error == 0) {
readcnt = count - auio.uio_resid;
edp = (struct ext2_dir_entry_2 *)&dirbuf[readcnt];
edp = (struct ext2fs_direct_2 *)&dirbuf[readcnt];
ncookies = 0;
bzero(&dstdp, offsetof(struct dirent, d_name));
for (dp = (struct ext2_dir_entry_2 *)dirbuf;
for (dp = (struct ext2fs_direct_2 *)dirbuf;
!error && uio->uio_resid > 0 && dp < edp; ) {
/*-
* "New" ext2fs directory entries differ in 3 ways
@ -204,20 +198,20 @@ ext2_readdir(ap)
* because ext2fs uses a machine-independent disk
* layout.
*/
dstdp.d_fileno = dp->inode;
dstdp.d_type = FTTODT(dp->file_type);
dstdp.d_namlen = dp->name_len;
dstdp.d_fileno = dp->e2d_ino;
dstdp.d_type = FTTODT(dp->e2d_type);
dstdp.d_namlen = dp->e2d_namlen;
dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp);
bcopy(dp->name, dstdp.d_name, dstdp.d_namlen);
bcopy(dp->e2d_name, dstdp.d_name, dstdp.d_namlen);
bzero(dstdp.d_name + dstdp.d_namlen,
dstdp.d_reclen - offsetof(struct dirent, d_name) -
dstdp.d_namlen);
if (dp->rec_len > 0) {
if (dp->e2d_reclen > 0) {
if(dstdp.d_reclen <= uio->uio_resid) {
/* advance dp */
dp = (struct ext2_dir_entry_2 *)
((char *)dp + dp->rec_len);
dp = (struct ext2fs_direct_2 *)
((char *)dp + dp->e2d_reclen);
error =
uiomove(&dstdp, dstdp.d_reclen, uio);
if (!error)
@ -241,11 +235,11 @@ ext2_readdir(ap)
cookies = malloc(ncookies * sizeof(u_long), M_TEMP,
M_WAITOK);
off = startoffset;
for (dp = (struct ext2_dir_entry_2 *)dirbuf,
for (dp = (struct ext2fs_direct_2 *)dirbuf,
cookiep = cookies, ecookies = cookies + ncookies;
cookiep < ecookies;
dp = (struct ext2_dir_entry_2 *)((caddr_t) dp + dp->rec_len)) {
off += dp->rec_len;
dp = (struct ext2fs_direct_2 *)((caddr_t) dp + dp->e2d_reclen)) {
off += dp->e2d_reclen;
*cookiep++ = (u_long) off;
}
*ap->a_ncookies = ncookies;
@ -299,11 +293,13 @@ ext2_lookup(ap)
struct vnode *vdp; /* vnode for directory being searched */
struct inode *dp; /* inode for directory being searched */
struct buf *bp; /* a buffer of directory entries */
struct ext2_dir_entry_2 *ep; /* the current directory entry */
struct ext2fs_direct_2 *ep; /* the current directory entry */
int entryoffsetinblock; /* offset of ep in bp's buffer */
enum {NONE, COMPACT, FOUND} slotstatus;
doff_t slotoffset; /* offset of area with free space */
int slotsize; /* size of area at slotoffset */
doff_t i_diroff; /* cached i_diroff value */
doff_t i_offset; /* cached i_offset value */
int slotfreespace; /* amount of space free in slot */
int slotneeded; /* size of the entry we're seeking */
int numdirpasses; /* strategy for directory search */
@ -319,9 +315,10 @@ ext2_lookup(ap)
struct ucred *cred = cnp->cn_cred;
int flags = cnp->cn_flags;
int nameiop = cnp->cn_nameiop;
ino_t saved_ino;
ino_t ino;
int ltype;
int DIRBLKSIZ = VTOI(ap->a_dvp)->i_e2fs->s_blocksize;
int DIRBLKSIZ = VTOI(ap->a_dvp)->i_e2fs->e2fs_bsize;
bp = NULL;
slotoffset = -1;
@ -338,6 +335,8 @@ ext2_lookup(ap)
* we watch for a place to put the new file in
* case it doesn't already exist.
*/
ino = 0;
i_diroff = dp->i_diroff;
slotstatus = FOUND;
slotfreespace = slotsize = slotneeded = 0;
if ((nameiop == CREATE || nameiop == RENAME) &&
@ -361,34 +360,34 @@ ext2_lookup(ap)
* of simplicity.
*/
bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
if (nameiop != LOOKUP || dp->i_diroff == 0 ||
dp->i_diroff > dp->i_size) {
if (nameiop != LOOKUP || i_diroff == 0 ||
i_diroff > dp->i_size) {
entryoffsetinblock = 0;
dp->i_offset = 0;
i_offset = 0;
numdirpasses = 1;
} else {
dp->i_offset = dp->i_diroff;
if ((entryoffsetinblock = dp->i_offset & bmask) &&
(error = ext2_blkatoff(vdp, (off_t)dp->i_offset, NULL,
i_offset = i_diroff;
if ((entryoffsetinblock = i_offset & bmask) &&
(error = ext2_blkatoff(vdp, (off_t)i_offset, NULL,
&bp)))
return (error);
numdirpasses = 2;
nchstats.ncs_2passes++;
}
prevoff = dp->i_offset;
endsearch = roundup(dp->i_size, DIRBLKSIZ);
prevoff = i_offset;
endsearch = roundup2(dp->i_size, DIRBLKSIZ);
enduseful = 0;
searchloop:
while (dp->i_offset < endsearch) {
while (i_offset < endsearch) {
/*
* If necessary, get the next directory block.
*/
if ((dp->i_offset & bmask) == 0) {
if ((i_offset & bmask) == 0) {
if (bp != NULL)
brelse(bp);
if ((error =
ext2_blkatoff(vdp, (off_t)dp->i_offset, NULL,
ext2_blkatoff(vdp, (off_t)i_offset, NULL,
&bp)) != 0)
return (error);
entryoffsetinblock = 0;
@ -409,14 +408,14 @@ ext2_lookup(ap)
* directory. Complete checks can be run by setting
* "vfs.e2fs.dirchk" to be true.
*/
ep = (struct ext2_dir_entry_2 *)
ep = (struct ext2fs_direct_2 *)
((char *)bp->b_data + entryoffsetinblock);
if (ep->rec_len == 0 ||
if (ep->e2d_reclen == 0 ||
(dirchk && ext2_dirbadentry(vdp, ep, entryoffsetinblock))) {
int i;
ext2_dirbad(dp, dp->i_offset, "mangled entry");
ext2_dirbad(dp, i_offset, "mangled entry");
i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
dp->i_offset += i;
i_offset += i;
entryoffsetinblock += i;
continue;
}
@ -428,23 +427,23 @@ ext2_lookup(ap)
* compaction is viable.
*/
if (slotstatus != FOUND) {
int size = ep->rec_len;
int size = ep->e2d_reclen;
if (ep->inode != 0)
size -= EXT2_DIR_REC_LEN(ep->name_len);
if (ep->e2d_ino != 0)
size -= EXT2_DIR_REC_LEN(ep->e2d_namlen);
if (size > 0) {
if (size >= slotneeded) {
slotstatus = FOUND;
slotoffset = dp->i_offset;
slotsize = ep->rec_len;
slotoffset = i_offset;
slotsize = ep->e2d_reclen;
} else if (slotstatus == NONE) {
slotfreespace += size;
if (slotoffset == -1)
slotoffset = dp->i_offset;
slotoffset = i_offset;
if (slotfreespace >= slotneeded) {
slotstatus = COMPACT;
slotsize = dp->i_offset +
ep->rec_len - slotoffset;
slotsize = i_offset +
ep->e2d_reclen - slotoffset;
}
}
}
@ -453,26 +452,25 @@ ext2_lookup(ap)
/*
* Check for a name match.
*/
if (ep->inode) {
namlen = ep->name_len;
if (ep->e2d_ino) {
namlen = ep->e2d_namlen;
if (namlen == cnp->cn_namelen &&
!bcmp(cnp->cn_nameptr, ep->name,
!bcmp(cnp->cn_nameptr, ep->e2d_name,
(unsigned)namlen)) {
/*
* Save directory entry's inode number and
* reclen in ndp->ni_ufs area, and release
* directory buffer.
*/
dp->i_ino = ep->inode;
dp->i_reclen = ep->rec_len;
ino = ep->e2d_ino;
goto found;
}
}
prevoff = dp->i_offset;
dp->i_offset += ep->rec_len;
entryoffsetinblock += ep->rec_len;
if (ep->inode)
enduseful = dp->i_offset;
prevoff = i_offset;
i_offset += ep->e2d_reclen;
entryoffsetinblock += ep->e2d_reclen;
if (ep->e2d_ino)
enduseful = i_offset;
}
/* notfound: */
/*
@ -481,10 +479,11 @@ ext2_lookup(ap)
*/
if (numdirpasses == 2) {
numdirpasses--;
dp->i_offset = 0;
endsearch = dp->i_diroff;
i_offset = 0;
endsearch = i_diroff;
goto searchloop;
}
dp->i_offset = i_offset;
if (bp != NULL)
brelse(bp);
/*
@ -510,7 +509,7 @@ ext2_lookup(ap)
* dp->i_offset + dp->i_count.
*/
if (slotstatus == NONE) {
dp->i_offset = roundup(dp->i_size, DIRBLKSIZ);
dp->i_offset = roundup2(dp->i_size, DIRBLKSIZ);
dp->i_count = 0;
enduseful = dp->i_offset;
} else {
@ -519,7 +518,7 @@ ext2_lookup(ap)
if (enduseful < slotoffset + slotsize)
enduseful = slotoffset + slotsize;
}
dp->i_endoff = roundup(enduseful, DIRBLKSIZ);
dp->i_endoff = roundup2(enduseful, DIRBLKSIZ);
dp->i_flag |= IN_CHANGE | IN_UPDATE;
/*
* We return with the directory locked, so that
@ -551,10 +550,10 @@ ext2_lookup(ap)
* Check that directory length properly reflects presence
* of this entry.
*/
if (entryoffsetinblock + EXT2_DIR_REC_LEN(ep->name_len)
if (entryoffsetinblock + EXT2_DIR_REC_LEN(ep->e2d_namlen)
> dp->i_size) {
ext2_dirbad(dp, dp->i_offset, "i_size too small");
dp->i_size = entryoffsetinblock+EXT2_DIR_REC_LEN(ep->name_len);
ext2_dirbad(dp, i_offset, "i_size too small");
dp->i_size = entryoffsetinblock+EXT2_DIR_REC_LEN(ep->e2d_namlen);
dp->i_flag |= IN_CHANGE | IN_UPDATE;
}
brelse(bp);
@ -565,8 +564,8 @@ ext2_lookup(ap)
* in the cache as to where the entry was found.
*/
if ((flags & ISLASTCN) && nameiop == LOOKUP)
dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1);
dp->i_diroff = i_offset &~ (DIRBLKSIZ - 1);
dp->i_offset = i_offset;
/*
* If deleting, and at end of pathname, return
* parameters which can be used to remove file.
@ -587,12 +586,12 @@ ext2_lookup(ap)
dp->i_count = 0;
else
dp->i_count = dp->i_offset - prevoff;
if (dp->i_number == dp->i_ino) {
if (dp->i_number == ino) {
VREF(vdp);
*vpp = vdp;
return (0);
}
if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, LK_EXCLUSIVE,
if ((error = VFS_VGET(vdp->v_mount, ino, LK_EXCLUSIVE,
&tdp)) != 0)
return (error);
/*
@ -625,9 +624,9 @@ ext2_lookup(ap)
* Careful about locking second inode.
* This can only occur if the target is ".".
*/
if (dp->i_number == dp->i_ino)
if (dp->i_number == ino)
return (EISDIR);
if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, LK_EXCLUSIVE,
if ((error = VFS_VGET(vdp->v_mount, ino, LK_EXCLUSIVE,
&tdp)) != 0)
return (error);
*vpp = tdp;
@ -656,18 +655,29 @@ ext2_lookup(ap)
*/
pdp = vdp;
if (flags & ISDOTDOT) {
saved_ino = dp->i_ino;
ltype = VOP_ISLOCKED(pdp);
VOP_UNLOCK(pdp, 0); /* race to get the inode */
error = VFS_VGET(vdp->v_mount, saved_ino, LK_EXCLUSIVE, &tdp);
vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY);
error = VFS_VGET(vdp->v_mount, ino, cnp->cn_lkflags, &tdp);
vn_lock(pdp, ltype | LK_RETRY);
if (error != 0)
return (error);
*vpp = tdp;
} else if (dp->i_number == dp->i_ino) {
} else if (dp->i_number == ino) {
VREF(vdp); /* we want ourself, ie "." */
/*
* When we lookup "." we still can be asked to lock it
* differently.
*/
ltype = cnp->cn_lkflags & LK_TYPE_MASK;
if (ltype != VOP_ISLOCKED(vdp)) {
if (ltype == LK_EXCLUSIVE)
vn_lock(vdp, LK_UPGRADE | LK_RETRY);
else /* if (ltype == LK_SHARED) */
vn_lock(vdp, LK_DOWNGRADE | LK_RETRY);
}
*vpp = vdp;
} else {
if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, LK_EXCLUSIVE,
if ((error = VFS_VGET(vdp->v_mount, ino, cnp->cn_lkflags,
&tdp)) != 0)
return (error);
*vpp = tdp;
@ -690,10 +700,13 @@ ext2_dirbad(ip, offset, how)
struct mount *mp;
mp = ITOV(ip)->v_mount;
(void)printf("%s: bad dir ino %lu at offset %ld: %s\n",
mp->mnt_stat.f_mntonname, (u_long)ip->i_number, (long)offset, how);
if ((mp->mnt_flag & MNT_RDONLY) == 0)
panic("ext2_dirbad: bad dir");
panic("ext2_dirbad: %s: bad dir ino %lu at offset %ld: %s\n",
mp->mnt_stat.f_mntonname, (u_long)ip->i_number,(long)offset, how);
else
(void)printf("%s: bad dir ino %lu at offset %ld: %s\n",
mp->mnt_stat.f_mntonname, (u_long)ip->i_number, (long)offset, how);
}
/*
@ -710,20 +723,20 @@ ext2_dirbad(ip, offset, how)
static int
ext2_dirbadentry(dp, de, entryoffsetinblock)
struct vnode *dp;
struct ext2_dir_entry_2 *de;
struct ext2fs_direct_2 *de;
int entryoffsetinblock;
{
int DIRBLKSIZ = VTOI(dp)->i_e2fs->s_blocksize;
int DIRBLKSIZ = VTOI(dp)->i_e2fs->e2fs_bsize;
char * error_msg = NULL;
if (de->rec_len < EXT2_DIR_REC_LEN(1))
if (de->e2d_reclen < EXT2_DIR_REC_LEN(1))
error_msg = "rec_len is smaller than minimal";
else if (de->rec_len % 4 != 0)
else if (de->e2d_reclen % 4 != 0)
error_msg = "rec_len % 4 != 0";
else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len))
else if (de->e2d_reclen < EXT2_DIR_REC_LEN(de->e2d_namlen))
error_msg = "reclen is too small for name_len";
else if (entryoffsetinblock + de->rec_len > DIRBLKSIZ)
else if (entryoffsetinblock + de->e2d_reclen > DIRBLKSIZ)
error_msg = "directory entry across blocks";
/* else LATER
if (de->inode > dir->i_sb->u.ext2_sb.s_es->s_inodes_count)
@ -733,8 +746,8 @@ ext2_dirbadentry(dp, de, entryoffsetinblock)
if (error_msg != NULL) {
printf("bad directory entry: %s\n", error_msg);
printf("offset=%d, inode=%lu, rec_len=%u, name_len=%u\n",
entryoffsetinblock, (unsigned long)de->inode,
de->rec_len, de->name_len);
entryoffsetinblock, (unsigned long)de->e2d_ino,
de->e2d_reclen, de->e2d_namlen);
}
return error_msg == NULL ? 0 : 1;
}
@ -753,16 +766,16 @@ ext2_direnter(ip, dvp, cnp)
struct vnode *dvp;
struct componentname *cnp;
{
struct ext2_dir_entry_2 *ep, *nep;
struct ext2fs_direct_2 *ep, *nep;
struct inode *dp;
struct buf *bp;
struct ext2_dir_entry_2 newdir;
struct ext2fs_direct_2 newdir;
struct iovec aiov;
struct uio auio;
u_int dsize;
int error, loc, newentrysize, spacefree;
char *dirbuf;
int DIRBLKSIZ = ip->i_e2fs->s_blocksize;
int DIRBLKSIZ = ip->i_e2fs->e2fs_bsize;
#ifdef DIAGNOSTIC
@ -770,15 +783,15 @@ ext2_direnter(ip, dvp, cnp)
panic("direnter: missing name");
#endif
dp = VTOI(dvp);
newdir.inode = ip->i_number;
newdir.name_len = cnp->cn_namelen;
newdir.e2d_ino = ip->i_number;
newdir.e2d_namlen = cnp->cn_namelen;
if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs,
EXT2_FEATURE_INCOMPAT_FILETYPE))
newdir.file_type = DTTOFT(IFTODT(ip->i_mode));
EXT2F_INCOMPAT_FTYPE))
newdir.e2d_type = DTTOFT(IFTODT(ip->i_mode));
else
newdir.file_type = EXT2_FT_UNKNOWN;
bcopy(cnp->cn_nameptr, newdir.name, (unsigned)cnp->cn_namelen + 1);
newentrysize = EXT2_DIR_REC_LEN(newdir.name_len);
newdir.e2d_type = EXT2_FT_UNKNOWN;
bcopy(cnp->cn_nameptr, newdir.e2d_name, (unsigned)cnp->cn_namelen + 1);
newentrysize = EXT2_DIR_REC_LEN(newdir.e2d_namlen);
if (dp->i_count == 0) {
/*
* If dp->i_count is 0, then namei could find no
@ -789,7 +802,7 @@ ext2_direnter(ip, dvp, cnp)
if (dp->i_offset & (DIRBLKSIZ - 1))
panic("ext2_direnter: newblk");
auio.uio_offset = dp->i_offset;
newdir.rec_len = DIRBLKSIZ;
newdir.e2d_reclen = DIRBLKSIZ;
auio.uio_resid = newentrysize;
aiov.iov_len = newentrysize;
aiov.iov_base = (caddr_t)&newdir;
@ -804,7 +817,7 @@ ext2_direnter(ip, dvp, cnp)
/* XXX should grow with balloc() */
panic("ext2_direnter: frag size");
else if (!error) {
dp->i_size = roundup(dp->i_size, DIRBLKSIZ);
dp->i_size = roundup2(dp->i_size, DIRBLKSIZ);
dp->i_flag |= IN_CHANGE;
}
return (error);
@ -841,38 +854,38 @@ ext2_direnter(ip, dvp, cnp)
* dp->i_offset + dp->i_count would yield the
* space.
*/
ep = (struct ext2_dir_entry_2 *)dirbuf;
dsize = EXT2_DIR_REC_LEN(ep->name_len);
spacefree = ep->rec_len - dsize;
for (loc = ep->rec_len; loc < dp->i_count; ) {
nep = (struct ext2_dir_entry_2 *)(dirbuf + loc);
if (ep->inode) {
ep = (struct ext2fs_direct_2 *)dirbuf;
dsize = EXT2_DIR_REC_LEN(ep->e2d_namlen);
spacefree = ep->e2d_reclen - dsize;
for (loc = ep->e2d_reclen; loc < dp->i_count; ) {
nep = (struct ext2fs_direct_2 *)(dirbuf + loc);
if (ep->e2d_ino) {
/* trim the existing slot */
ep->rec_len = dsize;
ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
ep->e2d_reclen = dsize;
ep = (struct ext2fs_direct_2 *)((char *)ep + dsize);
} else {
/* overwrite; nothing there; header is ours */
spacefree += dsize;
}
dsize = EXT2_DIR_REC_LEN(nep->name_len);
spacefree += nep->rec_len - dsize;
loc += nep->rec_len;
dsize = EXT2_DIR_REC_LEN(nep->e2d_namlen);
spacefree += nep->e2d_reclen - dsize;
loc += nep->e2d_reclen;
bcopy((caddr_t)nep, (caddr_t)ep, dsize);
}
/*
* Update the pointer fields in the previous entry (if any),
* copy in the new entry, and write out the block.
*/
if (ep->inode == 0) {
if (ep->e2d_ino == 0) {
if (spacefree + dsize < newentrysize)
panic("ext2_direnter: compact1");
newdir.rec_len = spacefree + dsize;
newdir.e2d_reclen = spacefree + dsize;
} else {
if (spacefree < newentrysize)
panic("ext2_direnter: compact2");
newdir.rec_len = spacefree;
ep->rec_len = dsize;
ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
newdir.e2d_reclen = spacefree;
ep->e2d_reclen = dsize;
ep = (struct ext2fs_direct_2 *)((char *)ep + dsize);
}
bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize);
error = bwrite(bp);
@ -901,7 +914,7 @@ ext2_dirremove(dvp, cnp)
struct componentname *cnp;
{
struct inode *dp;
struct ext2_dir_entry_2 *ep;
struct ext2fs_direct_2 *ep, *rep;
struct buf *bp;
int error;
@ -914,7 +927,7 @@ ext2_dirremove(dvp, cnp)
ext2_blkatoff(dvp, (off_t)dp->i_offset, (char **)&ep,
&bp)) != 0)
return (error);
ep->inode = 0;
ep->e2d_ino = 0;
error = bwrite(bp);
dp->i_flag |= IN_CHANGE | IN_UPDATE;
return (error);
@ -925,7 +938,13 @@ ext2_dirremove(dvp, cnp)
if ((error = ext2_blkatoff(dvp, (off_t)(dp->i_offset - dp->i_count),
(char **)&ep, &bp)) != 0)
return (error);
ep->rec_len += dp->i_reclen;
/* Set 'rep' to the entry being removed. */
if (dp->i_count == 0)
rep = ep;
else
rep = (struct ext2fs_direct_2 *)((char *)ep + ep->e2d_reclen);
ep->e2d_reclen += rep->e2d_reclen;
error = bwrite(bp);
dp->i_flag |= IN_CHANGE | IN_UPDATE;
return (error);
@ -942,19 +961,19 @@ ext2_dirrewrite(dp, ip, cnp)
struct componentname *cnp;
{
struct buf *bp;
struct ext2_dir_entry_2 *ep;
struct ext2fs_direct_2 *ep;
struct vnode *vdp = ITOV(dp);
int error;
if ((error = ext2_blkatoff(vdp, (off_t)dp->i_offset, (char **)&ep,
&bp)) != 0)
return (error);
ep->inode = ip->i_number;
ep->e2d_ino = ip->i_number;
if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs,
EXT2_FEATURE_INCOMPAT_FILETYPE))
ep->file_type = DTTOFT(IFTODT(ip->i_mode));
EXT2F_INCOMPAT_FTYPE))
ep->e2d_type = DTTOFT(IFTODT(ip->i_mode));
else
ep->file_type = EXT2_FT_UNKNOWN;
ep->e2d_type = EXT2_FT_UNKNOWN;
error = bwrite(bp);
dp->i_flag |= IN_CHANGE | IN_UPDATE;
return (error);
@ -977,11 +996,11 @@ ext2_dirempty(ip, parentino, cred)
{
off_t off;
struct dirtemplate dbuf;
struct ext2_dir_entry_2 *dp = (struct ext2_dir_entry_2 *)&dbuf;
struct ext2fs_direct_2 *dp = (struct ext2fs_direct_2 *)&dbuf;
int error, count, namlen;
#define MINDIRSIZ (sizeof (struct dirtemplate) / 2)
for (off = 0; off < ip->i_size; off += dp->rec_len) {
for (off = 0; off < ip->i_size; off += dp->e2d_reclen) {
error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ,
off, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, cred,
NOCRED, &count, (struct thread *)0);
@ -992,16 +1011,16 @@ ext2_dirempty(ip, parentino, cred)
if (error || count != 0)
return (0);
/* avoid infinite loops */
if (dp->rec_len == 0)
if (dp->e2d_reclen == 0)
return (0);
/* skip empty entries */
if (dp->inode == 0)
if (dp->e2d_ino == 0)
continue;
/* accept only "." and ".." */
namlen = dp->name_len;
namlen = dp->e2d_namlen;
if (namlen > 2)
return (0);
if (dp->name[0] != '.')
if (dp->e2d_name[0] != '.')
return (0);
/*
* At this point namlen must be 1 or 2.
@ -1010,7 +1029,7 @@ ext2_dirempty(ip, parentino, cred)
*/
if (namlen == 1)
continue;
if (dp->name[1] == '.' && dp->inode == parentino)
if (dp->e2d_name[1] == '.' && dp->e2d_ino == parentino)
continue;
return (0);
}

View File

@ -30,8 +30,8 @@
* $FreeBSD$
*/
#ifndef _SYS_GNU_EXT2FS_EXT2_MOUNT_H_
#define _SYS_GNU_EXT2FS_EXT2_MOUNT_H_
#ifndef _FS_EXT2FS_EXT2_MOUNT_H_
#define _FS_EXT2FS_EXT2_MOUNT_H_
#ifdef _KERNEL
@ -47,17 +47,23 @@ struct ext2mount {
struct cdev *um_dev; /* device mounted */
struct vnode *um_devvp; /* block device mounted vnode */
struct ext2_sb_info *um_e2fs; /* EXT2FS */
#define em_e2fsb um_e2fs->s_es
struct m_ext2fs *um_e2fs; /* EXT2FS */
#define em_e2fsb um_e2fs->e2fs
u_long um_nindir; /* indirect ptrs per block */
u_long um_bptrtodb; /* indir ptr to disk block */
u_long um_seqinc; /* inc between seq blocks */
struct mtx um_lock; /* Protects ext2mount & fs */
struct g_consumer *um_cp;
struct bufobj *um_bo;
};
#define EXT2_LOCK(aa) mtx_lock(&(aa)->um_lock)
#define EXT2_UNLOCK(aa) mtx_unlock(&(aa)->um_lock)
#define EXT2_MTX(aa) (&(aa)->um_lock)
/* Convert mount ptr to ext2fsmount ptr. */
#define VFSTOEXT2(mp) ((struct ext2mount *)((mp)->mnt_data))

View File

@ -36,8 +36,9 @@
* $FreeBSD$
*/
/* XXX TODO: remove these obfuscations (as in ffs_vnops.c). */
#define BLKSIZE(a, b, c) blksize(a, b, c)
#define FS struct ext2_sb_info
#define FS struct m_ext2fs
#define I_FS i_e2fs
#define READ ext2_read
#define READ_S "ext2_read"
@ -47,7 +48,6 @@
/*
* Vnode op for reading.
*/
/* ARGSUSED */
static int
READ(ap)
struct vop_read_args /* {
@ -65,8 +65,8 @@ READ(ap)
daddr_t lbn, nextlbn;
off_t bytesinfile;
long size, xfersize, blkoffset;
int error, orig_resid;
int seqcount = ap->a_ioflag >> IO_SEQSHIFT;
int error, orig_resid, seqcount;
seqcount = ap->a_ioflag >> IO_SEQSHIFT;
u_short mode;
vp = ap->a_vp;
@ -84,11 +84,14 @@ READ(ap)
} else if (vp->v_type != VREG && vp->v_type != VDIR)
panic("%s: type %d", READ_S, vp->v_type);
#endif
fs = ip->I_FS;
if ((uoff_t)uio->uio_offset > fs->fs_maxfilesize)
return (EFBIG);
orig_resid = uio->uio_resid;
KASSERT(orig_resid >= 0, ("ext2_read: uio->uio_resid < 0"));
if (orig_resid == 0)
return (0);
KASSERT(uio->uio_offset >= 0, ("ext2_read: uio->uio_offset < 0"));
fs = ip->I_FS;
if (uio->uio_offset < ip->i_size && uio->uio_offset >= fs->e2fs_maxfilesize)
return (EOVERFLOW);
for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
break;
@ -97,7 +100,7 @@ READ(ap)
size = BLKSIZE(fs, ip, lbn);
blkoffset = blkoff(fs, uio->uio_offset);
xfersize = fs->s_frag_size - blkoffset;
xfersize = fs->e2fs_fsize - blkoffset;
if (uio->uio_resid < xfersize)
xfersize = uio->uio_resid;
if (bytesinfile < xfersize)
@ -106,9 +109,8 @@ READ(ap)
if (lblktosize(fs, nextlbn) >= ip->i_size)
error = bread(vp, lbn, size, NOCRED, &bp);
else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0)
error = cluster_read(vp,
ip->i_size, lbn, size, NOCRED,
uio->uio_resid, (ap->a_ioflag >> IO_SEQSHIFT), &bp);
error = cluster_read(vp, ip->i_size, lbn, size,
NOCRED, blkoffset + uio->uio_resid, seqcount, &bp);
else if (seqcount > 1) {
int nextsize = BLKSIZE(fs, ip, nextlbn);
error = breadn(vp, lbn,
@ -134,8 +136,8 @@ READ(ap)
break;
xfersize = size;
}
error =
uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
error = uiomove((char *)bp->b_data + blkoffset,
(int)xfersize, uio);
if (error)
break;
@ -143,7 +145,7 @@ READ(ap)
}
if (bp != NULL)
bqrelse(bp);
if (orig_resid > 0 && (error == 0 || uio->uio_resid != orig_resid) &&
if ((error == 0 || uio->uio_resid != orig_resid) &&
(vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
ip->i_flag |= IN_ACCESS;
return (error);
@ -169,11 +171,10 @@ WRITE(ap)
struct thread *td;
daddr_t lbn;
off_t osize;
int seqcount;
int blkoffset, error, flags, ioflag, resid, size, xfersize;
int blkoffset, error, flags, ioflag, resid, size, seqcount, xfersize;
ioflag = ap->a_ioflag;
seqcount = ap->a_ioflag >> IO_SEQSHIFT;
seqcount = ioflag >> IO_SEQSHIFT;
uio = ap->a_uio;
vp = ap->a_vp;
ip = VTOI(vp);
@ -193,16 +194,20 @@ WRITE(ap)
case VLNK:
break;
case VDIR:
/* XXX differs from ffs -- this is called from ext2_mkdir(). */
if ((ioflag & IO_SYNC) == 0)
panic("%s: nonsync dir write", WRITE_S);
panic("ext2_write: nonsync dir write");
break;
default:
panic("%s: type", WRITE_S);
panic("ext2_write: type %p %d (%jd,%jd)", (void *)vp,
vp->v_type, (intmax_t)uio->uio_offset,
(intmax_t)uio->uio_resid);
}
KASSERT(uio->uio_resid >= 0, ("ext2_write: uio->uio_resid < 0"));
KASSERT(uio->uio_offset >= 0, ("ext2_write: uio->uio_offset < 0"));
fs = ip->I_FS;
if (uio->uio_offset < 0 ||
(uoff_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize)
if ((uoff_t)uio->uio_offset + uio->uio_resid > fs->e2fs_maxfilesize)
return (EFBIG);
/*
* Maybe this should be above the vnode op call, but so long as
@ -227,36 +232,25 @@ WRITE(ap)
for (error = 0; uio->uio_resid > 0;) {
lbn = lblkno(fs, uio->uio_offset);
blkoffset = blkoff(fs, uio->uio_offset);
xfersize = fs->s_frag_size - blkoffset;
xfersize = fs->e2fs_fsize - blkoffset;
if (uio->uio_resid < xfersize)
xfersize = uio->uio_resid;
if (uio->uio_offset + xfersize > ip->i_size)
vnode_pager_setsize(vp, uio->uio_offset + xfersize);
/*
* Avoid a data-consistency race between write() and mmap()
* by ensuring that newly allocated blocks are zerod. The
* by ensuring that newly allocated blocks are zeroed. The
* race can occur even in the case where the write covers
* the entire block.
*/
flags |= B_CLRBUF;
#if 0
if (fs->s_frag_size > xfersize)
flags |= B_CLRBUF;
else
flags &= ~B_CLRBUF;
#endif
error = ext2_balloc(ip,
lbn, blkoffset + xfersize, ap->a_cred, &bp, flags);
if (error)
error = ext2_balloc(ip, lbn, blkoffset + xfersize,
ap->a_cred, &bp, flags);
if (error != 0)
break;
if (uio->uio_offset + xfersize > ip->i_size) {
if (uio->uio_offset + xfersize > ip->i_size)
ip->i_size = uio->uio_offset + xfersize;
}
size = BLKSIZE(fs, ip, lbn) - bp->b_resid;
if (size < xfersize)
xfersize = size;
@ -264,12 +258,12 @@ WRITE(ap)
error =
uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
if ((ioflag & IO_VMIO) &&
(LIST_FIRST(&bp->b_dep) == NULL)) /* in ext2fs? */
LIST_FIRST(&bp->b_dep) == NULL) /* in ext2fs? */
bp->b_flags |= B_RELBUF;
if (ioflag & IO_SYNC) {
(void)bwrite(bp);
} else if (xfersize + blkoffset == fs->s_frag_size) {
} else if (xfersize + blkoffset == fs->e2fs_fsize) {
if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0) {
bp->b_flags |= B_CLUSTEROK;
cluster_write(vp, bp, ip->i_size, seqcount);
@ -282,23 +276,34 @@ WRITE(ap)
}
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.
* XXX too late, the tamperer may have opened the file while we
* were writing the data (or before).
* XXX too early, if (error && ioflag & IO_UNIT) then we will
* unwrite the data.
*/
if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
ip->i_mode &= ~(ISUID | ISGID);
if (error) {
/*
* XXX should truncate to the last successfully written
* data if the uiomove() failed.
*/
if (ioflag & IO_UNIT) {
(void)ext2_truncate(vp, osize,
ioflag & IO_SYNC, ap->a_cred, uio->uio_td);
uio->uio_offset -= resid - uio->uio_resid;
uio->uio_resid = resid;
}
} else if (resid > uio->uio_resid && (ioflag & IO_SYNC))
error = ext2_update(vp, 1);
}
if (uio->uio_resid != resid) {
ip->i_flag |= IN_CHANGE | IN_UPDATE;
if (ioflag & IO_SYNC)
error = ext2_update(vp, 1);
}
return (error);
}

View File

@ -46,10 +46,10 @@
#include <sys/ucred.h>
#include <sys/vnode.h>
#include <gnu/fs/ext2fs/inode.h>
#include <gnu/fs/ext2fs/ext2_extern.h>
#include <gnu/fs/ext2fs/ext2_fs_sb.h>
#include <gnu/fs/ext2fs/fs.h>
#include <fs/ext2fs/inode.h>
#include <fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/fs.h>
#ifdef KDB
void ext2_checkoverlap(struct buf *, struct inode *);
@ -68,7 +68,7 @@ ext2_blkatoff(vp, offset, res, bpp)
struct buf **bpp;
{
struct inode *ip;
struct ext2_sb_info *fs;
struct m_ext2fs *fs;
struct buf *bp;
int32_t lbn;
int bsize, error;

View File

@ -36,24 +36,6 @@
* $FreeBSD$
*/
/*-
* COPYRIGHT.INFO says this has some GPL'd code from ext2_super.c in it
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/namei.h>
@ -73,19 +55,18 @@
#include <geom/geom.h>
#include <geom/geom_vfs.h>
#include <gnu/fs/ext2fs/ext2_mount.h>
#include <gnu/fs/ext2fs/inode.h>
#include <fs/ext2fs/ext2_mount.h>
#include <fs/ext2fs/inode.h>
#include <gnu/fs/ext2fs/fs.h>
#include <gnu/fs/ext2fs/ext2_extern.h>
#include <gnu/fs/ext2fs/ext2_fs_sb.h>
#include <gnu/fs/ext2fs/ext2_fs.h>
#include <fs/ext2fs/fs.h>
#include <fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/ext2fs.h>
static int ext2_flushfiles(struct mount *mp, int flags, struct thread *td);
static int ext2_mountfs(struct vnode *, struct mount *);
static int ext2_reload(struct mount *mp, struct thread *td);
static int ext2_sbupdate(struct ext2mount *, int);
static int ext2_cgupdate(struct ext2mount *, int);
static vfs_unmount_t ext2_unmount;
static vfs_root_t ext2_root;
static vfs_statfs_t ext2_statfs;
@ -109,10 +90,10 @@ static struct vfsops ext2fs_vfsops = {
VFS_SET(ext2fs_vfsops, ext2fs, 0);
static int ext2_check_sb_compat(struct ext2_super_block *es, struct cdev *dev,
static int ext2_check_sb_compat(struct ext2fs *es, struct cdev *dev,
int ronly);
static int compute_sb_data(struct vnode * devvp,
struct ext2_super_block * es, struct ext2_sb_info * fs);
struct ext2fs * es, struct m_ext2fs * fs);
static const char *ext2_opts[] = { "from", "export", "acls", "noexec",
"noatime", "union", "suiddir", "multilabel", "nosymfollow",
@ -130,7 +111,7 @@ ext2_mount(struct mount *mp)
struct vnode *devvp;
struct thread *td;
struct ext2mount *ump = 0;
struct ext2_sb_info *fs;
struct m_ext2fs *fs;
struct nameidata nd, *ndp = &nd;
accmode_t accmode;
char *path, *fspec;
@ -158,9 +139,9 @@ ext2_mount(struct mount *mp)
*/
if (mp->mnt_flag & MNT_UPDATE) {
ump = VFSTOEXT2(mp);
fs = ump->um_e2fs;
fs = ump->um_e2fs;
error = 0;
if (fs->s_rd_only == 0 &&
if (fs->e2fs_ronly == 0 &&
vfs_flagopt(opts, "ro", NULL, 0)) {
error = VFS_SYNC(mp, MNT_WAIT);
if (error)
@ -168,15 +149,12 @@ ext2_mount(struct mount *mp)
flags = WRITECLOSE;
if (mp->mnt_flag & MNT_FORCE)
flags |= FORCECLOSE;
if (vfs_busy(mp, MBF_NOWAIT))
return (EBUSY);
error = ext2_flushfiles(mp, flags, td);
vfs_unbusy(mp);
if (!error && fs->s_wasvalid) {
fs->s_es->s_state |= EXT2_VALID_FS;
if ( error == 0 && fs->e2fs_wasvalid && ext2_cgupdate(ump, MNT_WAIT) == 0) {
fs->e2fs->e2fs_state |= E2FS_ISCLEAN;
ext2_sbupdate(ump, MNT_WAIT);
}
fs->s_rd_only = 1;
fs->e2fs_ronly = 1;
vfs_flagopt(opts, "ro", &mp->mnt_flag, MNT_RDONLY);
DROP_GIANT();
g_topology_lock();
@ -189,8 +167,8 @@ ext2_mount(struct mount *mp)
if (error)
return (error);
devvp = ump->um_devvp;
if (fs->s_rd_only && !vfs_flagopt(opts, "ro", NULL, 0)) {
if (ext2_check_sb_compat(fs->s_es, devvp->v_rdev, 0))
if (fs->e2fs_ronly && !vfs_flagopt(opts, "ro", NULL, 0)) {
if (ext2_check_sb_compat(fs->e2fs, devvp->v_rdev, 0))
return (EPERM);
/*
@ -215,21 +193,21 @@ ext2_mount(struct mount *mp)
if (error)
return (error);
if ((fs->s_es->s_state & EXT2_VALID_FS) == 0 ||
(fs->s_es->s_state & EXT2_ERROR_FS)) {
if ((fs->e2fs->e2fs_state & E2FS_ISCLEAN) == 0 ||
(fs->e2fs->e2fs_state & E2FS_ERRORS)) {
if (mp->mnt_flag & MNT_FORCE) {
printf(
"WARNING: %s was not properly dismounted\n", fs->fs_fsmnt);
"WARNING: %s was not properly dismounted\n", fs->e2fs_fsmnt);
} else {
printf(
"WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n",
fs->fs_fsmnt);
fs->e2fs_fsmnt);
return (EPERM);
}
}
fs->s_es->s_state &= ~EXT2_VALID_FS;
ext2_sbupdate(ump, MNT_WAIT);
fs->s_rd_only = 0;
fs->e2fs->e2fs_state &= ~E2FS_ISCLEAN;
(void)ext2_cgupdate(ump, MNT_WAIT);
fs->e2fs_ronly = 0;
MNT_ILOCK(mp);
mp->mnt_flag &= ~MNT_RDONLY;
MNT_IUNLOCK(mp);
@ -294,78 +272,30 @@ ext2_mount(struct mount *mp)
* Note that this strncpy() is ok because of a check at the start
* of ext2_mount().
*/
strncpy(fs->fs_fsmnt, path, MAXMNTLEN);
fs->fs_fsmnt[MAXMNTLEN - 1] = '\0';
strncpy(fs->e2fs_fsmnt, path, MAXMNTLEN);
fs->e2fs_fsmnt[MAXMNTLEN - 1] = '\0';
vfs_mountedfrom(mp, fspec);
return (0);
}
/*
* Checks that the data in the descriptor blocks make sense
* this is taken from ext2/super.c.
*/
static int
ext2_check_descriptors(struct ext2_sb_info *sb)
{
struct ext2_group_desc *gdp = NULL;
unsigned long block = sb->s_es->s_first_data_block;
int desc_block = 0;
int i;
for (i = 0; i < sb->s_groups_count; i++) {
/* examine next descriptor block */
if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0)
gdp = (struct ext2_group_desc *)
sb->s_group_desc[desc_block++]->b_data;
if (gdp->bg_block_bitmap < block ||
gdp->bg_block_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb)) {
printf ("ext2_check_descriptors: "
"Block bitmap for group %d"
" not in group (block %lu)!\n",
i, (unsigned long) gdp->bg_block_bitmap);
return (0);
}
if (gdp->bg_inode_bitmap < block ||
gdp->bg_inode_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb)) {
printf ("ext2_check_descriptors: "
"Inode bitmap for group %d"
" not in group (block %lu)!\n",
i, (unsigned long) gdp->bg_inode_bitmap);
return (0);
}
if (gdp->bg_inode_table < block ||
gdp->bg_inode_table + sb->s_itb_per_group >=
block + EXT2_BLOCKS_PER_GROUP(sb)) {
printf ("ext2_check_descriptors: "
"Inode table for group %d"
" not in group (block %lu)!\n",
i, (unsigned long) gdp->bg_inode_table);
return (0);
}
block += EXT2_BLOCKS_PER_GROUP(sb);
gdp++;
}
return (1);
}
static int
ext2_check_sb_compat(struct ext2_super_block *es, struct cdev *dev, int ronly)
ext2_check_sb_compat(struct ext2fs *es, struct cdev *dev, int ronly)
{
if (es->s_magic != EXT2_SUPER_MAGIC) {
if (es->e2fs_magic != E2FS_MAGIC) {
printf("ext2fs: %s: wrong magic number %#x (expected %#x)\n",
devtoname(dev), es->s_magic, EXT2_SUPER_MAGIC);
devtoname(dev), es->e2fs_magic, E2FS_MAGIC);
return (1);
}
if (es->s_rev_level > EXT2_GOOD_OLD_REV) {
if (es->s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPP) {
if (es->e2fs_rev > E2FS_REV0) {
if (es->e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP) {
printf(
"WARNING: mount of %s denied due to unsupported optional features\n",
devtoname(dev));
return (1);
}
if (!ronly &&
(es->s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPP)) {
(es->e2fs_features_rocompat & ~EXT2F_ROCOMPAT_SUPP)) {
printf("WARNING: R/W mount of %s denied due to "
"unsupported optional features\n", devtoname(dev));
return (1);
@ -379,52 +309,55 @@ ext2_check_sb_compat(struct ext2_super_block *es, struct cdev *dev, int ronly)
* data in the ext2_super_block structure read in.
*/
static int
compute_sb_data(struct vnode *devvp, struct ext2_super_block *es,
struct ext2_sb_info *fs)
compute_sb_data(struct vnode *devvp, struct ext2fs *es,
struct m_ext2fs *fs)
{
int db_count, error;
int i, j;
int i;
int logic_sb_block = 1; /* XXX for now */
struct buf *bp;
fs->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size;
fs->s_bshift = EXT2_MIN_BLOCK_LOG_SIZE + es->s_log_block_size;
fs->s_fsbtodb = es->s_log_block_size + 1;
fs->s_qbmask = fs->s_blocksize - 1;
fs->s_blocksize_bits = es->s_log_block_size + 10;
fs->s_frag_size = EXT2_MIN_FRAG_SIZE << es->s_log_frag_size;
if (fs->s_frag_size)
fs->s_frags_per_block = fs->s_blocksize / fs->s_frag_size;
fs->s_blocks_per_group = es->s_blocks_per_group;
fs->s_frags_per_group = es->s_frags_per_group;
fs->s_inodes_per_group = es->s_inodes_per_group;
if (es->s_rev_level == EXT2_GOOD_OLD_REV) {
fs->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
fs->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
fs->e2fs_bsize = EXT2_MIN_BLOCK_SIZE << es->e2fs_log_bsize;
fs->e2fs_bshift = EXT2_MIN_BLOCK_LOG_SIZE + es->e2fs_log_bsize;
fs->e2fs_fsbtodb = es->e2fs_log_bsize + 1;
fs->e2fs_qbmask = fs->e2fs_bsize - 1;
fs->e2fs_blocksize_bits = es->e2fs_log_bsize + 10;
fs->e2fs_fsize = EXT2_MIN_FRAG_SIZE << es->e2fs_log_fsize;
if (fs->e2fs_fsize)
fs->e2fs_fpb = fs->e2fs_bsize / fs->e2fs_fsize;
fs->e2fs_bpg = es->e2fs_bpg;
fs->e2fs_fpg = es->e2fs_fpg;
fs->e2fs_ipg = es->e2fs_ipg;
if (es->e2fs_rev == E2FS_REV0) {
fs->e2fs_first_inode = E2FS_REV0_FIRST_INO;
fs->e2fs_isize = E2FS_REV0_INODE_SIZE ;
} else {
fs->s_first_ino = es->s_first_ino;
fs->s_inode_size = es->s_inode_size;
fs->e2fs_first_inode = es->e2fs_first_ino;
fs->e2fs_isize = es->e2fs_inode_size;
/*
* Simple sanity check for superblock inode size value.
*/
if (fs->s_inode_size < EXT2_GOOD_OLD_INODE_SIZE ||
fs->s_inode_size > fs->s_blocksize ||
(fs->s_inode_size & (fs->s_inode_size - 1)) != 0) {
if (fs->e2fs_isize < E2FS_REV0_INODE_SIZE ||
fs->e2fs_isize > fs->e2fs_bsize ||
(fs->e2fs_isize & (fs->e2fs_isize - 1)) != 0) {
printf("EXT2-fs: invalid inode size %d\n",
fs->s_inode_size);
fs->e2fs_isize);
return (EIO);
}
}
fs->s_inodes_per_block = fs->s_blocksize / EXT2_INODE_SIZE(fs);
fs->s_itb_per_group = fs->s_inodes_per_group /fs->s_inodes_per_block;
fs->s_desc_per_block = fs->s_blocksize / sizeof (struct ext2_group_desc);
fs->e2fs_ipb = fs->e2fs_bsize / EXT2_INODE_SIZE(fs);
fs->e2fs_itpg = fs->e2fs_ipg /fs->e2fs_ipb;
fs->e2fs_descpb = fs->e2fs_bsize / sizeof (struct ext2_gd);
/* s_resuid / s_resgid ? */
fs->s_groups_count = (es->s_blocks_count - es->s_first_data_block +
fs->e2fs_gcount = (es->e2fs_bcount - es->e2fs_first_dblock +
EXT2_BLOCKS_PER_GROUP(fs) - 1) / EXT2_BLOCKS_PER_GROUP(fs);
db_count = (fs->s_groups_count + EXT2_DESC_PER_BLOCK(fs) - 1) /
db_count = (fs->e2fs_gcount + EXT2_DESC_PER_BLOCK(fs) - 1) /
EXT2_DESC_PER_BLOCK(fs);
fs->s_gdb_count = db_count;
fs->s_group_desc = malloc(db_count * sizeof (struct buf *),
fs->e2fs_gdbcount = db_count;
fs->e2fs_gd = malloc(db_count * fs->e2fs_bsize,
M_EXT2MNT, M_WAITOK);
fs->e2fs_contigdirs = malloc(fs->e2fs_gcount * sizeof(*fs->e2fs_contigdirs),
M_EXT2MNT, M_WAITOK);
/*
@ -432,43 +365,34 @@ compute_sb_data(struct vnode *devvp, struct ext2_super_block *es,
* Godmar thinks: if the blocksize is greater than 1024, then
* the superblock is logically part of block zero.
*/
if(fs->s_blocksize > SBSIZE)
if(fs->e2fs_bsize > SBSIZE)
logic_sb_block = 0;
for (i = 0; i < db_count; i++) {
error = bread(devvp , fsbtodb(fs, logic_sb_block + i + 1),
fs->s_blocksize, NOCRED, &fs->s_group_desc[i]);
if(error) {
for (j = 0; j < i; j++)
brelse(fs->s_group_desc[j]);
free(fs->s_group_desc, M_EXT2MNT);
printf("EXT2-fs: unable to read group descriptors"
" (%d)\n", error);
return (EIO);
error = bread(devvp ,
fsbtodb(fs, logic_sb_block + i + 1 ),
fs->e2fs_bsize, NOCRED, &bp);
if (error) {
free(fs->e2fs_gd, M_EXT2MNT);
brelse(bp);
return (error);
}
LCK_BUF(fs->s_group_desc[i])
e2fs_cgload((struct ext2_gd *)bp->b_data,
&fs->e2fs_gd[
i * fs->e2fs_bsize / sizeof(struct ext2_gd)],
fs->e2fs_bsize);
brelse(bp);
bp = NULL;
}
if(!ext2_check_descriptors(fs)) {
for (j = 0; j < db_count; j++)
ULCK_BUF(fs->s_group_desc[j])
free(fs->s_group_desc, M_EXT2MNT);
printf("EXT2-fs: (ext2_check_descriptors failure) "
"unable to read group descriptors\n");
return (EIO);
fs->e2fs_total_dir = 0;
for (i=0; i < fs->e2fs_gcount; i++){
fs->e2fs_total_dir += fs->e2fs_gd[i].ext2bgd_ndirs;
fs->e2fs_contigdirs[i] = 0;
}
for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) {
fs->s_inode_bitmap_number[i] = 0;
fs->s_inode_bitmap[i] = NULL;
fs->s_block_bitmap_number[i] = 0;
fs->s_block_bitmap[i] = NULL;
}
fs->s_loaded_inode_bitmaps = 0;
fs->s_loaded_block_bitmaps = 0;
if (es->s_rev_level == EXT2_GOOD_OLD_REV ||
(es->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_LARGE_FILE) == 0)
fs->fs_maxfilesize = 0x7fffffff;
if (es->e2fs_rev == E2FS_REV0 ||
(es->e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE) == 0)
fs->e2fs_maxfilesize = 0x7fffffff;
else
fs->fs_maxfilesize = 0x7fffffffffffffff;
fs->e2fs_maxfilesize = 0x7fffffffffffffff;
return (0);
}
@ -484,6 +408,7 @@ compute_sb_data(struct vnode *devvp, struct ext2_super_block *es,
* 4) invalidate all inactive vnodes.
* 5) invalidate all cached file data.
* 6) re-read inode data for all active vnodes.
* XXX we are missing some steps, in particular # 3, this has to be reviewed.
*/
static int
ext2_reload(struct mount *mp, struct thread *td)
@ -491,8 +416,8 @@ ext2_reload(struct mount *mp, struct thread *td)
struct vnode *vp, *mvp, *devvp;
struct inode *ip;
struct buf *bp;
struct ext2_super_block *es;
struct ext2_sb_info *fs;
struct ext2fs *es;
struct m_ext2fs *fs;
int error;
if ((mp->mnt_flag & MNT_RDONLY) == 0)
@ -512,13 +437,13 @@ ext2_reload(struct mount *mp, struct thread *td)
*/
if ((error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) != 0)
return (error);
es = (struct ext2_super_block *)bp->b_data;
es = (struct ext2fs *)bp->b_data;
if (ext2_check_sb_compat(es, devvp->v_rdev, 0) != 0) {
brelse(bp);
return (EIO); /* XXX needs translation */
}
fs = VFSTOEXT2(mp)->um_e2fs;
bcopy(bp->b_data, fs->s_es, sizeof(struct ext2_super_block));
bcopy(bp->b_data, fs->e2fs, sizeof(struct ext2fs));
if((error = compute_sb_data(devvp, es, fs)) != 0) {
brelse(bp);
@ -554,14 +479,14 @@ ext2_reload(struct mount *mp, struct thread *td)
*/
ip = VTOI(vp);
error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
(int)fs->s_blocksize, NOCRED, &bp);
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
VOP_UNLOCK(vp, 0);
vrele(vp);
MNT_VNODE_FOREACH_ABORT(mp, mvp);
return (error);
}
ext2_ei2i((struct ext2_inode *) ((char *)bp->b_data +
ext2_ei2i((struct ext2fs_dinode *) ((char *)bp->b_data +
EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)), ip);
brelse(bp);
VOP_UNLOCK(vp, 0);
@ -580,8 +505,8 @@ ext2_mountfs(struct vnode *devvp, struct mount *mp)
{
struct ext2mount *ump;
struct buf *bp;
struct ext2_sb_info *fs;
struct ext2_super_block *es;
struct m_ext2fs *fs;
struct ext2fs *es;
struct cdev *dev = devvp->v_rdev;
struct g_consumer *cp;
struct bufobj *bo;
@ -622,13 +547,13 @@ ext2_mountfs(struct vnode *devvp, struct mount *mp)
ump = NULL;
if ((error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) != 0)
goto out;
es = (struct ext2_super_block *)bp->b_data;
es = (struct ext2fs *)bp->b_data;
if (ext2_check_sb_compat(es, dev, ronly) != 0) {
error = EINVAL; /* XXX needs translation */
goto out;
}
if ((es->s_state & EXT2_VALID_FS) == 0 ||
(es->s_state & EXT2_ERROR_FS)) {
if ((es->e2fs_state & E2FS_ISCLEAN) == 0 ||
(es->e2fs_state & E2FS_ERRORS)) {
if (ronly || (mp->mnt_flag & MNT_FORCE)) {
printf(
"WARNING: Filesystem was not properly dismounted\n");
@ -647,31 +572,28 @@ ext2_mountfs(struct vnode *devvp, struct mount *mp)
* we dynamically allocate both an ext2_sb_info and an ext2_super_block
* while Linux keeps the super block in a locked buffer.
*/
ump->um_e2fs = malloc(sizeof(struct ext2_sb_info),
ump->um_e2fs = malloc(sizeof(struct m_ext2fs),
M_EXT2MNT, M_WAITOK);
ump->um_e2fs->s_es = malloc(sizeof(struct ext2_super_block),
ump->um_e2fs->e2fs = malloc(sizeof(struct ext2fs),
M_EXT2MNT, M_WAITOK);
bcopy(es, ump->um_e2fs->s_es, (u_int)sizeof(struct ext2_super_block));
if ((error = compute_sb_data(devvp, ump->um_e2fs->s_es, ump->um_e2fs)))
mtx_init(EXT2_MTX(ump), "EXT2FS", "EXT2FS Lock", MTX_DEF);
bcopy(es, ump->um_e2fs->e2fs, (u_int)sizeof(struct ext2fs));
if ((error = compute_sb_data(devvp, ump->um_e2fs->e2fs, ump->um_e2fs)))
goto out;
/*
* We don't free the group descriptors allocated by compute_sb_data()
* until ext2_unmount(). This is OK since the mount will succeed.
*/
brelse(bp);
bp = NULL;
fs = ump->um_e2fs;
fs->s_rd_only = ronly; /* ronly is set according to mnt_flags */
fs->e2fs_ronly = ronly; /* ronly is set according to mnt_flags */
/*
* If the fs is not mounted read-only, make sure the super block is
* always written back on a sync().
*/
fs->s_wasvalid = fs->s_es->s_state & EXT2_VALID_FS ? 1 : 0;
fs->e2fs_wasvalid = fs->e2fs->e2fs_state & E2FS_ISCLEAN ? 1 : 0;
if (ronly == 0) {
fs->s_dirt = 1; /* mark it modified */
fs->s_es->s_state &= ~EXT2_VALID_FS; /* set fs invalid */
fs->e2fs_fmod = 1; /* mark it modified */
fs->e2fs->e2fs_state &= ~E2FS_ISCLEAN; /* set fs invalid */
}
mp->mnt_data = ump;
mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
@ -691,10 +613,17 @@ ext2_mountfs(struct vnode *devvp, struct mount *mp)
* ufs_bmap w/o changse!
*/
ump->um_nindir = EXT2_ADDR_PER_BLOCK(fs);
ump->um_bptrtodb = fs->s_es->s_log_block_size + 1;
ump->um_bptrtodb = fs->e2fs->e2fs_log_bsize + 1;
ump->um_seqinc = EXT2_FRAGS_PER_BLOCK(fs);
if (ronly == 0)
ext2_sbupdate(ump, MNT_WAIT);
/*
* Initialize filesystem stat information in mount struct.
*/
MNT_ILOCK(mp);
mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED |
MNTK_EXTENDED_SHARED;
MNT_IUNLOCK(mp);
return (0);
out:
if (bp)
@ -707,7 +636,10 @@ ext2_mountfs(struct vnode *devvp, struct mount *mp)
PICKUP_GIANT();
}
if (ump) {
free(ump->um_e2fs->s_es, M_EXT2MNT);
mtx_destroy(EXT2_MTX(ump));
free(ump->um_e2fs->e2fs_gd, M_EXT2MNT);
free(ump->um_e2fs->e2fs_contigdirs, M_EXT2MNT);
free(ump->um_e2fs->e2fs, M_EXT2MNT);
free(ump->um_e2fs, M_EXT2MNT);
free(ump, M_EXT2MNT);
mp->mnt_data = NULL;
@ -722,8 +654,8 @@ static int
ext2_unmount(struct mount *mp, int mntflags)
{
struct ext2mount *ump;
struct ext2_sb_info *fs;
int error, flags, ronly, i;
struct m_ext2fs *fs;
int error, flags, ronly;
flags = 0;
if (mntflags & MNT_FORCE) {
@ -735,33 +667,22 @@ ext2_unmount(struct mount *mp, int mntflags)
return (error);
ump = VFSTOEXT2(mp);
fs = ump->um_e2fs;
ronly = fs->s_rd_only;
if (ronly == 0) {
if (fs->s_wasvalid)
fs->s_es->s_state |= EXT2_VALID_FS;
ext2_sbupdate(ump, MNT_WAIT);
ronly = fs->e2fs_ronly;
if (ronly == 0 && ext2_cgupdate(ump, MNT_WAIT) == 0) {
if (fs->e2fs_wasvalid)
fs->e2fs->e2fs_state |= E2FS_ISCLEAN;
ext2_sbupdate(ump, MNT_WAIT);
}
/* release buffers containing group descriptors */
for(i = 0; i < fs->s_gdb_count; i++)
ULCK_BUF(fs->s_group_desc[i])
free(fs->s_group_desc, M_EXT2MNT);
/* release cached inode/block bitmaps */
for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
if (fs->s_inode_bitmap[i])
ULCK_BUF(fs->s_inode_bitmap[i])
for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
if (fs->s_block_bitmap[i])
ULCK_BUF(fs->s_block_bitmap[i])
DROP_GIANT();
g_topology_lock();
g_vfs_close(ump->um_cp);
g_topology_unlock();
PICKUP_GIANT();
vrele(ump->um_devvp);
free(fs->s_es, M_EXT2MNT);
free(fs->e2fs_gd, M_EXT2MNT);
free(fs->e2fs_contigdirs, M_EXT2MNT);
free(fs->e2fs, M_EXT2MNT);
free(fs, M_EXT2MNT);
free(ump, M_EXT2MNT);
mp->mnt_data = NULL;
@ -782,50 +703,53 @@ ext2_flushfiles(struct mount *mp, int flags, struct thread *td)
error = vflush(mp, 0, flags, td);
return (error);
}
/*
* Get file system statistics.
* taken from ext2/super.c ext2_statfs.
*/
static int
int
ext2_statfs(struct mount *mp, struct statfs *sbp)
{
struct ext2mount *ump;
struct ext2_sb_info *fs;
struct ext2_super_block *es;
unsigned long overhead;
int i, nsb;
struct m_ext2fs *fs;
uint32_t overhead, overhead_per_group, ngdb;
int i, ngroups;
ump = VFSTOEXT2(mp);
fs = ump->um_e2fs;
es = fs->s_es;
if (es->s_magic != EXT2_SUPER_MAGIC)
panic("ext2_statfs - magic number spoiled");
if (fs->e2fs->e2fs_magic != E2FS_MAGIC)
panic("ext2fs_statvfs");
/*
* Compute the overhead (FS structures)
*/
if (es->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) {
nsb = 0;
for (i = 0 ; i < fs->s_groups_count; i++)
if (ext2_group_sparse(i))
nsb++;
} else
nsb = fs->s_groups_count;
overhead = es->s_first_data_block +
/* Superblocks and block group descriptors: */
nsb * (1 + fs->s_gdb_count) +
/* Inode bitmap, block bitmap, and inode table: */
fs->s_groups_count * (1 + 1 + fs->s_itb_per_group);
overhead_per_group =
1 /* block bitmap */ +
1 /* inode bitmap */ +
fs->e2fs_itpg;
overhead = fs->e2fs->e2fs_first_dblock +
fs->e2fs_gcount * overhead_per_group;
if (fs->e2fs->e2fs_rev > E2FS_REV0 &&
fs->e2fs->e2fs_features_rocompat & EXT2F_ROCOMPAT_SPARSESUPER) {
for (i = 0, ngroups = 0; i < fs->e2fs_gcount; i++) {
if (cg_has_sb(i))
ngroups++;
}
} else {
ngroups = fs->e2fs_gcount;
}
ngdb = fs->e2fs_gdbcount;
if (fs->e2fs->e2fs_rev > E2FS_REV0 &&
fs->e2fs->e2fs_features_compat & EXT2F_COMPAT_RESIZE)
ngdb += fs->e2fs->e2fs_reserved_ngdb;
overhead += ngroups * (1 /* superblock */ + ngdb);
sbp->f_bsize = EXT2_FRAG_SIZE(fs);
sbp->f_iosize = EXT2_BLOCK_SIZE(fs);
sbp->f_blocks = es->s_blocks_count - overhead;
sbp->f_bfree = es->s_free_blocks_count;
sbp->f_bavail = sbp->f_bfree - es->s_r_blocks_count;
sbp->f_files = es->s_inodes_count;
sbp->f_ffree = es->s_free_inodes_count;
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;
return (0);
}
@ -843,13 +767,13 @@ ext2_sync(struct mount *mp, int waitfor)
struct thread *td;
struct inode *ip;
struct ext2mount *ump = VFSTOEXT2(mp);
struct ext2_sb_info *fs;
struct m_ext2fs *fs;
int error, allerror = 0;
td = curthread;
fs = ump->um_e2fs;
if (fs->s_dirt != 0 && fs->s_rd_only != 0) { /* XXX */
printf("fs = %s\n", fs->fs_fsmnt);
if (fs->e2fs_fmod != 0 && fs->e2fs_ronly != 0) { /* XXX */
printf("fs = %s\n", fs->e2fs_fsmnt);
panic("ext2_sync: rofs mod");
}
@ -904,10 +828,10 @@ ext2_sync(struct mount *mp, int waitfor)
/*
* Write back modified superblock.
*/
if (fs->s_dirt != 0) {
fs->s_dirt = 0;
fs->s_es->s_wtime = time_second;
if ((error = ext2_sbupdate(ump, waitfor)) != 0)
if (fs->e2fs_fmod != 0) {
fs->e2fs_fmod = 0;
fs->e2fs->e2fs_wtime = time_second;
if ((error = ext2_cgupdate(ump, waitfor)) != 0)
allerror = error;
}
return (allerror);
@ -922,7 +846,7 @@ ext2_sync(struct mount *mp, int waitfor)
static int
ext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
{
struct ext2_sb_info *fs;
struct m_ext2fs *fs;
struct inode *ip;
struct ext2mount *ump;
struct buf *bp;
@ -958,6 +882,7 @@ ext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
vp->v_data = ip;
ip->i_vnode = vp;
ip->i_e2fs = fs = ump->um_e2fs;
ip->i_ump = ump;
ip->i_number = ino;
lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
@ -973,20 +898,20 @@ ext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
/* Read in the disk contents for the inode, copy into the inode. */
if ((error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
(int)fs->s_blocksize, NOCRED, &bp)) != 0) {
(int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
/*
* 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);
vput(vp);
*vpp = NULL;
return (error);
}
/* convert ext2 inode to dinode */
ext2_ei2i((struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE(fs) *
ext2_ei2i((struct ext2fs_dinode *) ((char *)bp->b_data + EXT2_INODE_SIZE(fs) *
ino_to_fsbo(fs, ino)), ip);
ip->i_block_group = ino_to_cg(fs, ino);
ip->i_next_alloc_block = 0;
@ -1000,14 +925,14 @@ ext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
* although for regular files and directories only
*/
if(S_ISDIR(ip->i_mode) || S_ISREG(ip->i_mode)) {
used_blocks = (ip->i_size+fs->s_blocksize-1) / fs->s_blocksize;
used_blocks = (ip->i_size+fs->e2fs_bsize-1) / fs->e2fs_bsize;
for(i = used_blocks; i < EXT2_NDIR_BLOCKS; i++)
ip->i_db[i] = 0;
}
/*
ext2_print_inode(ip);
*/
brelse(bp);
bqrelse(bp);
/*
* Initialize the vnode from the inode, check for aliases.
@ -1053,13 +978,13 @@ ext2_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
struct inode *ip;
struct ufid *ufhp;
struct vnode *nvp;
struct ext2_sb_info *fs;
struct m_ext2fs *fs;
int error;
ufhp = (struct ufid *)fhp;
fs = VFSTOEXT2(mp)->um_e2fs;
if (ufhp->ufid_ino < ROOTINO ||
ufhp->ufid_ino > fs->s_groups_count * fs->s_es->s_inodes_per_group)
ufhp->ufid_ino > fs->e2fs_gcount * fs->e2fs->e2fs_ipg)
return (ESTALE);
error = VFS_VGET(mp, ufhp->ufid_ino, LK_EXCLUSIVE, &nvp);
@ -1085,13 +1010,13 @@ ext2_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
static int
ext2_sbupdate(struct ext2mount *mp, int waitfor)
{
struct ext2_sb_info *fs = mp->um_e2fs;
struct ext2_super_block *es = fs->s_es;
struct m_ext2fs *fs = mp->um_e2fs;
struct ext2fs *es = fs->e2fs;
struct buf *bp;
int error = 0;
bp = getblk(mp->um_devvp, SBLOCK, SBSIZE, 0, 0, 0);
bcopy((caddr_t)es, bp->b_data, (u_int)sizeof(struct ext2_super_block));
bcopy((caddr_t)es, bp->b_data, (u_int)sizeof(struct ext2fs));
if (waitfor == MNT_WAIT)
error = bwrite(bp);
else
@ -1104,7 +1029,31 @@ ext2_sbupdate(struct ext2mount *mp, int waitfor)
*/
return (error);
}
int
ext2_cgupdate(struct ext2mount *mp, int waitfor)
{
struct m_ext2fs *fs = mp->um_e2fs;
struct buf *bp;
int i, error = 0, allerror = 0;
allerror = ext2_sbupdate(mp, waitfor);
for (i = 0; i < fs->e2fs_gdbcount; i++) {
bp = getblk(mp->um_devvp, fsbtodb(fs,
fs->e2fs->e2fs_first_dblock +
1 /* superblock */ + i), fs->e2fs_bsize, 0, 0, 0);
e2fs_cgsave(&fs->e2fs_gd[
i * fs->e2fs_bsize / sizeof(struct ext2_gd)],
(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);
}
/*
* Return the root of a filesystem.
*/

View File

@ -74,14 +74,15 @@
#include <sys/signalvar.h>
#include <ufs/ufs/dir.h>
#include <gnu/fs/ext2fs/inode.h>
#include <gnu/fs/ext2fs/ext2_mount.h>
#include <gnu/fs/ext2fs/ext2_fs_sb.h>
#include <gnu/fs/ext2fs/fs.h>
#include <gnu/fs/ext2fs/ext2_extern.h>
#include <gnu/fs/ext2fs/ext2_fs.h>
#include <fs/ext2fs/inode.h>
#include <fs/ext2fs/ext2_mount.h>
#include <fs/ext2fs/fs.h>
#include <fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/ext2_dir.h>
static int ext2_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *);
static void ext2_itimes_locked(struct vnode *);
static vop_access_t ext2_access;
static int ext2_chmod(struct vnode *, int, struct ucred *, struct thread *);
@ -160,7 +161,7 @@ struct vop_vector ext2_fifoops = {
.vop_vptofh = ext2_vptofh,
};
#include <gnu/fs/ext2fs/ext2_readwrite.c>
#include <fs/ext2fs/ext2_readwrite.c>
/*
* A virgin directory (no blushing please).
@ -177,13 +178,14 @@ static struct dirtemplate omastertemplate = {
0, DIRBLKSIZ - 12, 2, EXT2_FT_UNKNOWN, ".."
};
void
ext2_itimes(vp)
struct vnode *vp;
static void
ext2_itimes_locked(struct vnode *vp)
{
struct inode *ip;
struct timespec ts;
ASSERT_VI_LOCKED(vp, __func__);
ip = VTOI(vp);
if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0)
return;
@ -210,6 +212,15 @@ ext2_itimes(vp)
ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);
}
void
ext2_itimes(struct vnode *vp)
{
VI_LOCK(vp);
ext2_itimes_locked(vp);
VI_UNLOCK(vp);
}
/*
* Create a regular file
*/
@ -275,7 +286,7 @@ ext2_close(ap)
VI_LOCK(vp);
if (vp->v_usecount > 1)
ext2_itimes(vp);
ext2_itimes_locked(vp);
VI_UNLOCK(vp);
return (0);
}
@ -316,7 +327,7 @@ ext2_access(ap)
}
/* If immutable bit set, nobody gets to write it. */
if ((accmode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT)))
if ((accmode & VWRITE) && (ip->i_flags & (SF_IMMUTABLE | SF_SNAPSHOT)))
return (EPERM);
error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid,
@ -391,12 +402,11 @@ ext2_setattr(ap)
return (EINVAL);
}
if (vap->va_flags != VNOVAL) {
/* Disallow flags not supported by ext2fs. */
if (vap->va_flags & ~(SF_APPEND | SF_IMMUTABLE | UF_NODUMP))
return (EOPNOTSUPP);
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
/* Disallow flags not supported by ext2fs. */
if(vap->va_flags & ~(SF_APPEND | SF_IMMUTABLE | UF_NODUMP))
return(EOPNOTSUPP);
/*
* Callers may only modify the file flags on objects they
* have VADMIN rights for.
@ -420,11 +430,9 @@ ext2_setattr(ap)
ip->i_flags = vap->va_flags;
} else {
if (ip->i_flags
& (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) ||
(vap->va_flags & UF_SETTABLE) != vap->va_flags)
& (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND))
return (EPERM);
ip->i_flags &= SF_SETTABLE;
ip->i_flags |= (vap->va_flags & UF_SETTABLE);
}
ip->i_flag |= IN_CHANGE;
if (vap->va_flags & (IMMUTABLE | APPEND))
@ -610,7 +618,6 @@ ext2_fsync(ap)
/*
* Flush all dirty buffers associated with a vnode.
*/
ext2_discard_prealloc(VTOI(ap->a_vp));
vop_stdfsync(ap);
@ -743,7 +750,27 @@ ext2_link(ap)
/*
* Rename system call.
* See comments in sys/ufs/ufs/ufs_vnops.c
* rename("foo", "bar");
* is essentially
* unlink("bar");
* link("foo", "bar");
* unlink("foo");
* but ``atomically''. Can't do full commit without saving state in the
* inode on disk which isn't feasible at this time. Best we can do is
* always guarantee the target exists.
*
* Basic algorithm is:
*
* 1) Bump link count on source while we're linking it to the
* target. This also ensure the inode won't be deleted out
* from underneath us while we work (it may be truncated by
* a concurrent `trunc' or `open' for creation).
* 2) Link source to destination. If destination already exists,
* delete it first.
* 3) Unlink source reference to inode if still around. If a
* directory was moved and the parent of the destination
* is different from the source, patch the ".." entry in the
* directory.
*/
static int
ext2_rename(ap)
@ -1189,7 +1216,7 @@ ext2_mkdir(ap)
/* Initialize directory with "." and ".." from static template. */
if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs,
EXT2_FEATURE_INCOMPAT_FILETYPE))
EXT2F_INCOMPAT_FTYPE))
dtp = &mastertemplate;
else
dtp = &omastertemplate;
@ -1200,7 +1227,7 @@ ext2_mkdir(ap)
* so let's just redefine it - for this function only
*/
#undef DIRBLKSIZ
#define DIRBLKSIZ VTOI(dvp)->i_e2fs->s_blocksize
#define DIRBLKSIZ VTOI(dvp)->i_e2fs->e2fs_bsize
dirtemplate.dotdot_reclen = DIRBLKSIZ - 12;
error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
@ -1454,7 +1481,7 @@ ext2fifo_close(ap)
VI_LOCK(vp);
if (vp->v_usecount > 1)
ext2_itimes(vp);
ext2_itimes_locked(vp);
VI_UNLOCK(vp);
return (fifo_specops.vop_close(ap));
}

329
sys/fs/ext2fs/ext2fs.h Executable file
View File

@ -0,0 +1,329 @@
/*-
* modified for EXT2FS support in Lites 1.1
*
* Aug 1995, Godmar Back (gback@cs.utah.edu)
* University of Utah, Department of Computer Science
*
* $FreeBSD$
*/
/*-
* Copyright (c) 2009 Aditya Sarawgi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
*/
#ifndef _FS_EXT2FS_EXT2_FS_H
#define _FS_EXT2FS_EXT2_FS_H
#include <sys/types.h>
/*
* Special inode numbers
*/
#define EXT2_BAD_INO 1 /* Bad blocks inode */
#define EXT2_ROOT_INO 2 /* Root inode */
#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
/* First non-reserved inode for old ext2 filesystems */
#define E2FS_REV0_FIRST_INO 11
/*
* The second extended file system magic number
*/
#define E2FS_MAGIC 0xEF53
#if defined(_KERNEL)
/*
* FreeBSD passes the pointer to the in-core struct with relevant
* fields to EXT2_SB macro when accessing superblock fields.
*/
#define EXT2_SB(sb) (sb)
#else
/* Assume that user mode programs are passing in an ext2fs superblock, not
* a kernel struct super_block. This will allow us to call the feature-test
* macros from user land. */
#define EXT2_SB(sb) (sb)
#endif
/*
* Maximal count of links to a file
*/
#define EXT2_LINK_MAX 32000
/*
* Constants relative to the data blocks
*/
#define EXT2_NDIR_BLOCKS 12
#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
#define EXT2_MAXSYMLINKLEN (EXT2_N_BLOCKS * sizeof (uint32_t))
/*
* 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
/*
* 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_log_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 e2fs_minrev; /* minor revision level */
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 */
/* EXT2_DYNAMIC_REV superblocks */
u_int32_t e2fs_first_ino; /* first non-reserved inode */
u_int16_t e2fs_inode_size; /* size of inode structure */
u_int16_t e2fs_block_group_nr; /* block grp number of this sblk*/
u_int32_t e2fs_features_compat; /* compatible feature set */
u_int32_t e2fs_features_incompat; /* incompatible feature set */
u_int32_t e2fs_features_rocompat; /* RO-compatible feature set */
u_int8_t e2fs_uuid[16]; /* 128-bit uuid for volume */
char e2fs_vname[16]; /* volume name */
char e2fs_fsmnt[64]; /* name mounted on */
u_int32_t e2fs_algo; /* For comcate for dir */
u_int16_t e2fs_reserved_ngdb; /* # of reserved gd blocks for resize */
u_int32_t reserved2[204];
};
/* Assume that user mode programs are passing in an ext2fs superblock, not
* a kernel struct super_block. This will allow us to call the feature-test
* macros from user land. */
#define EXT2_SB(sb) (sb)
/*
* In-Memory Superblock
*/
struct m_ext2fs {
struct ext2fs * e2fs;
char e2fs_fsmnt[MAXMNTLEN];/* name mounted on */
char e2fs_ronly; /* mounted read-only flag */
char e2fs_fmod; /* super block modified flag */
uint32_t e2fs_bsize; /* Block size */
uint32_t e2fs_bshift; /* calc of logical block no */
int32_t e2fs_bmask; /* calc of block offset */
int32_t e2fs_bpg; /* Number of blocks per group */
int64_t e2fs_qbmask; /* = s_blocksize -1 */
uint32_t e2fs_fsbtodb; /* Shift to get disk block */
uint32_t e2fs_ipg; /* Number of inodes per group */
uint32_t e2fs_ipb; /* Number of inodes per block */
uint32_t e2fs_itpg; /* Number of inode table per group */
uint32_t e2fs_fsize; /* Size of fragments per block */
uint32_t e2fs_fpb; /* Number of fragments per block */
uint32_t e2fs_fpg; /* Number of fragments per group */
uint32_t e2fs_dbpg; /* Number of descriptor blocks per group */
uint32_t e2fs_descpb; /* Number of group descriptors per block */
uint32_t e2fs_gdbcount; /* Number of group descriptors */
uint32_t e2fs_gcount; /* Number of groups */
uint32_t e2fs_first_inode;/* First inode on fs */
int32_t e2fs_isize; /* Size of inode */
uint32_t e2fs_mount_opt;
uint32_t e2fs_blocksize_bits;
uint32_t e2fs_total_dir; /* Total number of directories */
uint8_t *e2fs_contigdirs;
char e2fs_wasvalid; /* valid at mount time */
off_t e2fs_maxfilesize;
struct ext2_gd *e2fs_gd; /* Group Descriptors */
};
/*
* The second extended file system version
*/
#define E2FS_DATE "95/08/09"
#define E2FS_VERSION "0.5b"
/*
* Revision levels
*/
#define E2FS_REV0 0 /* The good old (original) format */
#define E2FS_REV1 1 /* V2 format w/ dynamic inode sizes */
#define E2FS_CURRENT_REV E2FS_REV0
#define E2FS_MAX_SUPP_REV E2FS_REV1
#define E2FS_REV0_INODE_SIZE 128
/*
* compatible/incompatible features
*/
#define EXT2F_COMPAT_PREALLOC 0x0001
#define EXT2F_COMPAT_RESIZE 0x0010
#define EXT2F_ROCOMPAT_SPARSESUPER 0x0001
#define EXT2F_ROCOMPAT_LARGEFILE 0x0002
#define EXT2F_ROCOMPAT_BTREE_DIR 0x0004
#define EXT2F_INCOMPAT_COMP 0x0001
#define EXT2F_INCOMPAT_FTYPE 0x0002
/*
* Features supported in this implementation
*
* We support the following REV1 features:
* - EXT2F_ROCOMPAT_SPARSESUPER
* - EXT2F_ROCOMPAT_LARGEFILE
* - EXT2F_INCOMPAT_FTYPE
*/
#define EXT2F_COMPAT_SUPP 0x0000
#define EXT2F_ROCOMPAT_SUPP (EXT2F_ROCOMPAT_SPARSESUPER \
| EXT2F_ROCOMPAT_LARGEFILE)
#define EXT2F_INCOMPAT_SUPP EXT2F_INCOMPAT_FTYPE
/*
* Feature set definitions
*/
#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
( EXT2_SB(sb)->e2fs->e2fs_features_compat & htole32(mask) )
#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
( EXT2_SB(sb)->e2fs->e2fs_features_rocompat & htole32(mask) )
#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
( EXT2_SB(sb)->e2fs->e2fs_features_incompat & htole32(mask) )
/*
* Definitions of behavior on errors
*/
#define E2FS_BEH_CONTINUE 1 /* continue operation */
#define E2FS_BEH_READONLY 2 /* remount fs read only */
#define E2FS_BEH_PANIC 3 /* cause panic */
#define E2FS_BEH_DEFAULT E2FS_BEH_CONTINUE
/*
* OS identification
*/
#define E2FS_OS_LINUX 0
#define E2FS_OS_HURD 1
#define E2FS_OS_MASIX 2
#define E2FS_OS_FREEBSD 3
#define E2FS_OS_LITES 4
/*
* File clean flags
*/
#define E2FS_ISCLEAN 0x0001 /* Unmounted cleanly */
#define E2FS_ERRORS 0x0002 /* Errors detected */
/* 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];
};
/* EXT2FS metadatas are stored in little-endian byte order. These macros
* helps reading these metadatas
*/
#define e2fs_cgload(old, new, size) memcpy((new), (old), (size));
#define e2fs_cgsave(old, new, size) memcpy((new), (old), (size));
/*
* Macro-instructions used to manage several block sizes
*/
#define EXT2_MIN_BLOCK_SIZE 1024
#define EXT2_MAX_BLOCK_SIZE 4096
#define EXT2_MIN_BLOCK_LOG_SIZE 10
#if defined(_KERNEL)
# define EXT2_BLOCK_SIZE(s) ((s)->e2fs_bsize)
#else
# define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->e2fs_log_bsize)
#endif
#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (uint32_t))
#if defined(_KERNEL)
# define EXT2_BLOCK_SIZE_BITS(s) ((s)->e2fs_blocksize_bits)
#else
# define EXT2_BLOCK_SIZE_BITS(s) ((s)->e2fs_log_bsize + 10)
#endif
#if defined(_KERNEL)
#define EXT2_ADDR_PER_BLOCK_BITS(s) (EXT2_SB(s)->s_addr_per_block_bits)
#define EXT2_INODE_SIZE(s) (EXT2_SB(s)->e2fs_isize)
#define EXT2_FIRST_INO(s) (EXT2_SB(s)->e2fs_first_inode)
#else
#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == E2FS_REV0) ? \
E2FS_REV0 : (s)->s_inode_size)
#define EXT2_FIRST_INO(s) (((s)->s_rev_level == E2FS_REV0) ? \
E2FS_REV0 : (s)->e2fs_first_ino)
#endif
/*
* Macro-instructions used to manage fragments
*/
#define EXT2_MIN_FRAG_SIZE 1024
#define EXT2_MAX_FRAG_SIZE 4096
#define EXT2_MIN_FRAG_LOG_SIZE 10
#if defined(_KERNEL)
# define EXT2_FRAG_SIZE(s) (EXT2_SB(s)->e2fs_fsize)
# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_SB(s)->e2fs_fpb)
#else
# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->e2fs_log_fsize)
# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
#endif
/*
* Macro-instructions used to manage group descriptors
*/
#if defined(_KERNEL)
# define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->e2fs_bpg)
# define EXT2_DESC_PER_BLOCK(s) (EXT2_SB(s)->e2fs_descpb)
# define EXT2_DESC_PER_BLOCK_BITS(s) (EXT2_SB(s)->s_desc_per_block_bits)
#else
# define EXT2_BLOCKS_PER_GROUP(s) ((s)->e2fs_bpg)
# define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_gd))
#endif
#endif /* _LINUX_EXT2_FS_H */

View File

@ -57,45 +57,55 @@
/*
* 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.
* the super block for this name.
*/
#define MAXMNTLEN 512
#define MAXMNTLEN 512
/*
* Grigoriy Orlov <gluk@ptci.ru> has done some extensive work to fine
* tune the layout preferences for directories within a filesystem.
* His algorithm can be tuned by adjusting the following parameters
* which tell the system the average file size and the average number
* of files per directory. These defaults are well selected for typical
* filesystems, but may need to be tuned for odd cases like filesystems
* being used for squid caches or news spools.
* AVFPDIR is the expected number of files per directory. AVGDIRSIZE is
* obtained by multiplying AVFPDIR and AVFILESIZ which is assumed to be
* 16384.
*/
#define AFPDIR 64
#define AVGDIRSIZE 1048576
/*
* Macros for access to superblock array structures
*/
/*
* Convert cylinder group to base address of its global summary info.
*/
#define fs_cs(fs, cgindx) (((struct ext2_group_desc *) \
(fs->s_group_desc[cgindx / EXT2_DESC_PER_BLOCK(fs)]->b_data)) \
[cgindx % EXT2_DESC_PER_BLOCK(fs)])
/*
* Turn file system block numbers into disk block addresses.
* This maps file system blocks to device size blocks.
*/
#define fsbtodb(fs, b) ((b) << ((fs)->s_fsbtodb))
#define dbtofsb(fs, b) ((b) >> ((fs)->s_fsbtodb))
#define fsbtodb(fs, b) ((b) << ((fs)->e2fs_fsbtodb))
#define dbtofsb(fs, b) ((b) >> ((fs)->e2fs_fsbtodb))
/* get group containing inode */
#define ino_to_cg(fs, x) (((x) - 1) / EXT2_INODES_PER_GROUP(fs))
#define ino_to_cg(fs, x) (((x) - 1) / (fs->e2fs_ipg))
/* get block containing inode from its number x */
#define ino_to_fsba(fs, x) fs_cs(fs, ino_to_cg(fs, x)).bg_inode_table + \
(((x)-1) % EXT2_INODES_PER_GROUP(fs))/EXT2_INODES_PER_BLOCK(fs)
#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)
/* get offset for inode in block */
#define ino_to_fsbo(fs, x) ((x-1) % EXT2_INODES_PER_BLOCK(fs))
#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->s_es->s_first_data_block) / \
#define dtog(fs, d) (((d) - fs->e2fs->e2fs_first_dblock) / \
EXT2_BLOCKS_PER_GROUP(fs))
#define dtogd(fs, d) (((d) - fs->s_es->s_first_data_block) % \
#define dtogd(fs, d) (((d) - fs->e2fs->e2fs_first_dblock) % \
EXT2_BLOCKS_PER_GROUP(fs))
/*
@ -104,32 +114,32 @@
* modulos and multiplications.
*/
#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
((loc) & (fs)->s_qbmask)
((loc) & (fs)->e2fs_qbmask)
#define lblktosize(fs, blk) /* calculates (blk * fs->fs_bsize) */ \
((blk) << (fs->s_bshift))
((blk) << (fs->e2fs_bshift))
#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
((loc) >> (fs->s_bshift))
((loc) >> (fs->e2fs_bshift))
/* no fragments -> logical block number equal # of frags */
#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \
((loc) >> (fs->s_bshift))
((loc) >> (fs->e2fs_bshift))
#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
roundup(size, fs->s_frag_size)
roundup(size, fs->e2fs_fsize)
/* was (((size) + (fs)->fs_qfmask) & (fs)->fs_fmask) */
/*
* Determining the size of a file block in the file system.
* easy w/o fragments
*/
#define blksize(fs, ip, lbn) ((fs)->s_frag_size)
#define blksize(fs, ip, lbn) ((fs)->e2fs_fsize)
/*
* INOPB is the number of inodes in a secondary storage block.
*/
#define INOPB(fs) EXT2_INODES_PER_BLOCK(fs)
#define INOPB(fs) (fs->e2fs_ipb)
/*
* NINDIR is the number of indirects in a file system block.
@ -139,32 +149,4 @@
extern int inside[], around[];
extern u_char *fragtbl[];
/* a few remarks about superblock locking/unlocking
* Linux provides special routines for doing so
* I haven't figured out yet what BSD does
* I think I'll try a VOP_LOCK/VOP_UNLOCK on the device vnode
*/
#define DEVVP(inode) (VFSTOEXT2(ITOV(inode)->v_mount)->um_devvp)
#define lock_super(devvp) vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY)
#define unlock_super(devvp) VOP_UNLOCK(devvp, 0)
/*
* Historically, ext2fs kept it's metadata buffers on the LOCKED queue. Now,
* we change the lock owner to kern so that we may use it from contexts other
* than the one that originally locked it. When we are finished with the
* buffer, we release it, writing it first if it was dirty.
*/
#define LCK_BUF(bp) { \
(bp)->b_flags |= B_PERSISTENT; \
BUF_KERNPROC(bp); \
}
#define ULCK_BUF(bp) { \
long flags; \
flags = (bp)->b_flags; \
(bp)->b_flags &= ~(B_DIRTY | B_PERSISTENT); \
if (flags & B_DIRTY) \
bwrite(bp); \
else \
brelse(bp); \
}

View File

@ -35,8 +35,8 @@
* $FreeBSD$
*/
#ifndef _SYS_GNU_EXT2FS_INODE_H_
#define _SYS_GNU_EXT2FS_INODE_H_
#ifndef _FS_EXT2FS_INODE_H_
#define _FS_EXT2FS_INODE_H_
#include <sys/lock.h>
#include <sys/queue.h>
@ -63,10 +63,11 @@
struct inode {
struct vnode *i_vnode;/* Vnode associated with this inode. */
struct vnode *i_devvp;/* Vnode for block I/O. */
struct ext2mount *i_ump;
u_int32_t i_flag; /* flags, see below */
ino_t i_number; /* The identity of the inode. */
struct ext2_sb_info *i_e2fs; /* EXT2FS */
struct m_ext2fs *i_e2fs; /* EXT2FS */
u_quad_t i_modrev; /* Revision level for NFS lease. */
/*
* Side effects; used during directory lookup.
@ -75,8 +76,6 @@ struct inode {
doff_t i_endoff; /* End of useful stuff in directory. */
doff_t i_diroff; /* Offset in dir, where we found last entry. */
doff_t i_offset; /* Offset of free space in directory. */
ino_t i_ino; /* Inode number of found directory. */
u_int32_t i_reclen; /* Size of found directory entry. */
u_int32_t i_block_group;
u_int32_t i_next_alloc_block;
@ -142,7 +141,8 @@ struct inode {
#define IN_HASHED 0x0020 /* Inode is on hash list */
#define IN_LAZYMOD 0x0040 /* Modified, but don't write yet. */
#define IN_SPACECOUNTED 0x0080 /* Blocks to be freed in free count. */
#define IN_LAZYACCESS 0x0100 /* Process IN_ACCESS after the
suspension finished */
#ifdef _KERNEL
/*
* Structure used to pass around logical block paths generated by
@ -167,4 +167,4 @@ struct ufid {
};
#endif /* _KERNEL */
#endif /* !_SYS_GNU_EXT2FS_INODE_H_ */
#endif /* !_FS_EXT2FS_INODE_H_ */

View File

@ -1,35 +0,0 @@
$FreeBSD$
Most of the files in this directory are written by Godmar Back or modified
by him using the CSRG sources. Those files are covered by the Berkeley-style
copyright. However the following files are covered by GPL. Since the policy
of the FreeBSD project is to keep the files with the more restrictive
copyright in the gnu tree and it is a good idea to keep the filesystem code
all together, the EXT2FS in its entirety resides under the gnu tree. Note
that only the files below are under the GPL. In the eventuality that these
files are redesigned or rewritten, this tree can be moved back into the less
restrictive FreeBSD tree.
ext2_bitmap.c (in the cvs attic)
ext2_fs.h
ext2_fs_i.h
ext2_fs_sb.h
ext2_linux_balloc.c
ext2_linux_ialloc.c
ext2_super.c (in the cvs attic)
ext2_vfsops.c (has some GPL'ed code from ext2_super.c)
i386-bitops.h
PS.
THANKS GODMAR!!!
Note that this port has been modified by John Dyson and others on
the FreeBSD team, and it is best to send the bug reports to the FreeBSD
team. If there are any non-FreeBSD specific bugs, fixes will be sent to
Godmar to help him fix the original code base. It is also our intention
to send Godmar any FreeBSD specific porting changes so that he can keep
control of his code....
John
dyson@freebsd.org

View File

@ -1,535 +0,0 @@
/*-
* modified for Lites 1.1
*
* Aug 1995, Godmar Back (gback@cs.utah.edu)
* University of Utah, Department of Computer Science
*/
/*-
* 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.
* 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.8 (Berkeley) 2/21/94
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/vnode.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/syslog.h>
#include <gnu/fs/ext2fs/inode.h>
#include <gnu/fs/ext2fs/ext2_mount.h>
#include <gnu/fs/ext2fs/ext2_fs.h>
#include <gnu/fs/ext2fs/ext2_fs_sb.h>
#include <gnu/fs/ext2fs/fs.h>
#include <gnu/fs/ext2fs/ext2_extern.h>
static void ext2_fserr(struct ext2_sb_info *, u_int, char *);
/*
* Linux calls this functions at the following locations:
* (1) the inode is freed
* (2) a preallocation miss occurs
* (3) truncate is called
* (4) release_file is called and f_mode & 2
*
* I call it in ext2_inactive, ext2_truncate, ext2_vfree and in (2)
* the call in vfree might be redundant
*/
void
ext2_discard_prealloc(ip)
struct inode * ip;
{
#ifdef EXT2_PREALLOCATE
if (ip->i_prealloc_count) {
int i = ip->i_prealloc_count;
ip->i_prealloc_count = 0;
ext2_free_blocks (ITOV(ip)->v_mount,
ip->i_prealloc_block,
i);
}
#endif
}
/*
* Allocate a block in the file system.
*
* this takes the framework from ffs_alloc. To implement the
* actual allocation, it calls ext2_new_block, the ported version
* of the same Linux routine.
*
* we note that this is always called in connection with ext2_blkpref
*
* preallocation is done as Linux does it
*/
int
ext2_alloc(ip, lbn, bpref, size, cred, bnp)
struct inode *ip;
int32_t lbn, bpref;
int size;
struct ucred *cred;
int32_t *bnp;
{
struct ext2_sb_info *fs;
int32_t bno;
*bnp = 0;
fs = ip->i_e2fs;
#ifdef DIAGNOSTIC
if ((u_int)size > fs->s_blocksize || blkoff(fs, size) != 0) {
vn_printf(ip->i_devvp, "bsize = %lu, size = %d, fs = %s\n",
fs->s_blocksize, size, fs->fs_fsmnt);
panic("ext2_alloc: bad size");
}
if (cred == NOCRED)
panic("ext2_alloc: missing credential");
#endif /* DIAGNOSTIC */
if (size == fs->s_blocksize && fs->s_es->s_free_blocks_count == 0)
goto nospace;
if (cred->cr_uid != 0 &&
fs->s_es->s_free_blocks_count < fs->s_es->s_r_blocks_count)
goto nospace;
if (bpref >= fs->s_es->s_blocks_count)
bpref = 0;
/* call the Linux code */
#ifdef EXT2_PREALLOCATE
/* To have a preallocation hit, we must
* - have at least one block preallocated
* - and our preferred block must have that block number or one below
*/
if (ip->i_prealloc_count &&
(bpref == ip->i_prealloc_block ||
bpref + 1 == ip->i_prealloc_block))
{
bno = ip->i_prealloc_block++;
ip->i_prealloc_count--;
/* ext2_debug ("preallocation hit (%lu/%lu).\n",
++alloc_hits, ++alloc_attempts); */
/* Linux gets, clears, and releases the buffer at this
point - we don't have to that; we leave it to the caller
*/
} else {
ext2_discard_prealloc (ip);
/* ext2_debug ("preallocation miss (%lu/%lu).\n",
alloc_hits, ++alloc_attempts); */
if (S_ISREG(ip->i_mode))
bno = ext2_new_block
(ITOV(ip)->v_mount, bpref,
&ip->i_prealloc_count,
&ip->i_prealloc_block);
else
bno = (int32_t)ext2_new_block(ITOV(ip)->v_mount,
bpref, 0, 0);
}
#else
bno = (int32_t)ext2_new_block(ITOV(ip)->v_mount, bpref, 0, 0);
#endif
if (bno > 0) {
/* set next_alloc fields as done in block_getblk */
ip->i_next_alloc_block = lbn;
ip->i_next_alloc_goal = bno;
ip->i_blocks += btodb(size);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
*bnp = bno;
return (0);
}
nospace:
ext2_fserr(fs, cred->cr_uid, "file system full");
uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
return (ENOSPC);
}
/*
* Reallocate a sequence of blocks into a contiguous sequence of blocks.
*
* The vnode and an array of buffer pointers for a range of sequential
* logical blocks to be made contiguous is given. The allocator attempts
* to find a range of sequential blocks starting as close as possible to
* an fs_rotdelay offset from the end of the allocation for the logical
* block immediately preceding the current range. If successful, the
* physical block numbers in the buffer pointers and in the inode are
* changed to reflect the new allocation. If unsuccessful, the allocation
* is left unchanged. The success in doing the reallocation is returned.
* Note that the error return is not reflected back to the user. Rather
* the previous block allocation will be used.
*/
#ifdef FANCY_REALLOC
#include <sys/sysctl.h>
static int doasyncfree = 1;
#ifdef OPT_DEBUG
SYSCTL_INT(_debug, 14, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, "");
#endif /* OPT_DEBUG */
#endif
int
ext2_reallocblks(ap)
struct vop_reallocblks_args /* {
struct vnode *a_vp;
struct cluster_save *a_buflist;
} */ *ap;
{
#ifndef FANCY_REALLOC
/* printf("ext2_reallocblks not implemented\n"); */
return ENOSPC;
#else
struct ext2_sb_info *fs;
struct inode *ip;
struct vnode *vp;
struct buf *sbp, *ebp;
int32_t *bap, *sbap, *ebap;
struct cluster_save *buflist;
int32_t start_lbn, end_lbn, soff, eoff, newblk, blkno;
struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp;
int i, len, start_lvl, end_lvl, pref, ssize;
vp = ap->a_vp;
ip = VTOI(vp);
fs = ip->i_e2fs;
#ifdef UNKLAR
if (fs->fs_contigsumsize <= 0)
return (ENOSPC);
#endif
buflist = ap->a_buflist;
len = buflist->bs_nchildren;
start_lbn = buflist->bs_children[0]->b_lblkno;
end_lbn = start_lbn + len - 1;
#ifdef DIAGNOSTIC
for (i = 1; i < len; i++)
if (buflist->bs_children[i]->b_lblkno != start_lbn + i)
panic("ext2_reallocblks: non-cluster");
#endif
/*
* If the latest allocation is in a new cylinder group, assume that
* the filesystem has decided to move and do not force it back to
* the previous cylinder group.
*/
if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) !=
dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno)))
return (ENOSPC);
if (ufs_getlbns(vp, start_lbn, start_ap, &start_lvl) ||
ufs_getlbns(vp, end_lbn, end_ap, &end_lvl))
return (ENOSPC);
/*
* Get the starting offset and block map for the first block.
*/
if (start_lvl == 0) {
sbap = &ip->i_db[0];
soff = start_lbn;
} else {
idp = &start_ap[start_lvl - 1];
if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &sbp)) {
brelse(sbp);
return (ENOSPC);
}
sbap = (int32_t *)sbp->b_data;
soff = idp->in_off;
}
/*
* Find the preferred location for the cluster.
*/
pref = ext2_blkpref(ip, start_lbn, soff, sbap);
/*
* If the block range spans two block maps, get the second map.
*/
if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) {
ssize = len;
} else {
#ifdef DIAGNOSTIC
if (start_ap[start_lvl-1].in_lbn == idp->in_lbn)
panic("ext2_reallocblk: start == end");
#endif
ssize = len - (idp->in_off + 1);
if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &ebp))
goto fail;
ebap = (int32_t *)ebp->b_data;
}
/*
* Search the block map looking for an allocation of the desired size.
*/
if ((newblk = (int32_t)ext2_hashalloc(ip, dtog(fs, pref), (long)pref,
len, (u_long (*)())ext2_clusteralloc)) == 0)
goto fail;
/*
* We have found a new contiguous block.
*
* First we have to replace the old block pointers with the new
* block pointers in the inode and indirect blocks associated
* with the file.
*/
blkno = newblk;
for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->s_frags_per_block) {
if (i == ssize)
bap = ebap;
#ifdef DIAGNOSTIC
if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap))
panic("ext2_reallocblks: alloc mismatch");
#endif
*bap++ = blkno;
}
/*
* Next we must write out the modified inode and indirect blocks.
* For strict correctness, the writes should be synchronous since
* the old block values may have been written to disk. In practise
* they are almost never written, but if we are concerned about
* strict correctness, the `doasyncfree' flag should be set to zero.
*
* The test on `doasyncfree' should be changed to test a flag
* that shows whether the associated buffers and inodes have
* been written. The flag should be set when the cluster is
* started and cleared whenever the buffer or inode is flushed.
* We can then check below to see if it is set, and do the
* synchronous write only when it has been cleared.
*/
if (sbap != &ip->i_db[0]) {
if (doasyncfree)
bdwrite(sbp);
else
bwrite(sbp);
} else {
ip->i_flag |= IN_CHANGE | IN_UPDATE;
if (!doasyncfree)
ext2_update(vp, 1);
}
if (ssize < len)
if (doasyncfree)
bdwrite(ebp);
else
bwrite(ebp);
/*
* Last, free the old blocks and assign the new blocks to the buffers.
*/
for (blkno = newblk, i = 0; i < len; i++, blkno += fs->s_frags_per_block) {
ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno),
fs->s_blocksize);
buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno);
}
return (0);
fail:
if (ssize < len)
brelse(ebp);
if (sbap != &ip->i_db[0])
brelse(sbp);
return (ENOSPC);
#endif /* FANCY_REALLOC */
}
/*
* Allocate an inode in the file system.
*
* we leave the actual allocation strategy to the (modified)
* ext2_new_inode(), to make sure we get the policies right
*/
int
ext2_valloc(pvp, mode, cred, vpp)
struct vnode *pvp;
int mode;
struct ucred *cred;
struct vnode **vpp;
{
struct inode *pip;
struct ext2_sb_info *fs;
struct inode *ip;
ino_t ino;
int i, error;
*vpp = NULL;
pip = VTOI(pvp);
fs = pip->i_e2fs;
if (fs->s_es->s_free_inodes_count == 0)
goto noinodes;
/* call the Linux routine - it returns the inode number only */
ino = ext2_new_inode(pip, mode);
if (ino == 0)
goto noinodes;
error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp);
if (error) {
ext2_vfree(pvp, ino, mode);
return (error);
}
ip = VTOI(*vpp);
/*
the question is whether using VGET was such good idea at all -
Linux doesn't read the old inode in when it's allocating a
new one. I will set at least i_size & i_blocks the zero.
*/
ip->i_mode = 0;
ip->i_size = 0;
ip->i_blocks = 0;
ip->i_flags = 0;
/* now we want to make sure that the block pointers are zeroed out */
for (i = 0; i < NDADDR; i++)
ip->i_db[i] = 0;
for (i = 0; i < NIADDR; i++)
ip->i_ib[i] = 0;
/*
* Set up a new generation number for this inode.
* XXX check if this makes sense in ext2
*/
if (ip->i_gen == 0 || ++ip->i_gen == 0)
ip->i_gen = random() / 2 + 1;
/*
printf("ext2_valloc: allocated inode %d\n", ino);
*/
return (0);
noinodes:
ext2_fserr(fs, cred->cr_uid, "out of inodes");
uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
return (ENOSPC);
}
/*
* Select the desired position for the next block in a file.
*
* we try to mimic what Remy does in inode_getblk/block_getblk
*
* we note: blocknr == 0 means that we're about to allocate either
* a direct block or a pointer block at the first level of indirection
* (In other words, stuff that will go in i_db[] or i_ib[])
*
* blocknr != 0 means that we're allocating a block that is none
* of the above. Then, blocknr tells us the number of the block
* that will hold the pointer
*/
int32_t
ext2_blkpref(ip, lbn, indx, bap, blocknr)
struct inode *ip;
int32_t lbn;
int indx;
int32_t *bap;
int32_t blocknr;
{
int tmp;
/* if the next block is actually what we thought it is,
then set the goal to what we thought it should be
*/
if(ip->i_next_alloc_block == lbn)
return ip->i_next_alloc_goal;
/* now check whether we were provided with an array that basically
tells us previous blocks to which we want to stay closeby
*/
if(bap)
for (tmp = indx - 1; tmp >= 0; tmp--)
if (bap[tmp])
return bap[tmp];
/* else let's fall back to the blocknr, or, if there is none,
follow the rule that a block should be allocated near its inode
*/
return blocknr ? blocknr :
(int32_t)(ip->i_block_group *
EXT2_BLOCKS_PER_GROUP(ip->i_e2fs)) +
ip->i_e2fs->s_es->s_first_data_block;
}
/*
* Free a block or fragment.
*
* pass on to the Linux code
*/
void
ext2_blkfree(ip, bno, size)
struct inode *ip;
int32_t bno;
long size;
{
struct ext2_sb_info *fs;
fs = ip->i_e2fs;
/*
* call Linux code with mount *, block number, count
*/
ext2_free_blocks(ITOV(ip)->v_mount, bno, size / fs->s_frag_size);
}
/*
* Free an inode.
*
* the maintenance of the actual bitmaps is again up to the linux code
*/
int
ext2_vfree(pvp, ino, mode)
struct vnode *pvp;
ino_t ino;
int mode;
{
struct ext2_sb_info *fs;
struct inode *pip;
mode_t save_i_mode;
pip = VTOI(pvp);
fs = pip->i_e2fs;
if ((u_int)ino > fs->s_inodes_per_group * fs->s_groups_count)
panic("ext2_vfree: range: devvp = %p, ino = %d, fs = %s",
pip->i_devvp, ino, fs->fs_fsmnt);
/* ext2_debug("ext2_vfree (%d, %d) called\n", pip->i_number, mode);
*/
ext2_discard_prealloc(pip);
/* we need to make sure that ext2_free_inode can adjust the
used_dir_counts in the group summary information - I'd
really like to know what the rationale behind this
'set i_mode to zero to denote an unused inode' is
*/
save_i_mode = pip->i_mode;
pip->i_mode = mode;
ext2_free_inode(pip);
pip->i_mode = save_i_mode;
return (0);
}
/*
* Fserr prints the name of a file system with an error diagnostic.
*
* The form of the error message is:
* fs: error message
*/
static void
ext2_fserr(fs, uid, cp)
struct ext2_sb_info *fs;
u_int uid;
char *cp;
{
log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->fs_fsmnt, cp);
}

View File

@ -1,114 +0,0 @@
/*-
* Copyright (c) 2003 Marcel Moolenaar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _SYS_GNU_EXT2FS_EXT2_BITOPS_H_
#define _SYS_GNU_EXT2FS_EXT2_BITOPS_H_
#define find_first_zero_bit(data, sz) find_next_zero_bit(data, sz, 0)
static __inline int
clear_bit(int no, void *data)
{
uint32_t *p;
uint32_t mask, new, old;
p = (uint32_t*)data + (no >> 5);
mask = (1U << (no & 31));
do {
old = *p;
new = old & ~mask;
} while (!atomic_cmpset_32(p, old, new));
return (old & mask);
}
static __inline int
set_bit(int no, void *data)
{
uint32_t *p;
uint32_t mask, new, old;
p = (uint32_t*)data + (no >> 5);
mask = (1U << (no & 31));
do {
old = *p;
new = old | mask;
} while (!atomic_cmpset_32(p, old, new));
return (old & mask);
}
static __inline int
test_bit(int no, void *data)
{
uint32_t *p;
uint32_t mask;
p = (uint32_t*)data + (no >> 5);
mask = (1U << (no & 31));
return (*p & mask);
}
static __inline size_t
find_next_zero_bit(void *data, size_t sz, size_t ofs)
{
uint32_t *p;
uint32_t mask;
int bit;
p = (uint32_t*)data + (ofs >> 5);
if (ofs & 31) {
mask = ~0U << (ofs & 31);
bit = *p | ~mask;
if (bit != ~0U)
return (ffs(~bit) + (ofs & ~31U) - 1);
p++;
ofs = (ofs + 31U) & ~31U;
}
while(ofs < sz && *p == ~0U) {
p++;
ofs += 32;
}
if (ofs == sz)
return (ofs);
bit = *p;
return (ffs(~bit) + ofs - 1);
}
static __inline void *
memscan(void *data, int c, size_t sz)
{
uint8_t *p;
p = data;
while (sz && *p != c) {
p++;
sz--;
}
return (p);
}
#endif /* _SYS_GNU_EXT2FS_EXT2_BITOPS_H_ */

View File

@ -1,556 +0,0 @@
/*-
* modified for EXT2FS support in Lites 1.1
*
* Aug 1995, Godmar Back (gback@cs.utah.edu)
* University of Utah, Department of Computer Science
*
* $FreeBSD$
*/
/*-
* linux/include/linux/ext2_fs.h
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*
* from
*
* linux/include/linux/minix_fs.h
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef _LINUX_EXT2_FS_H
#define _LINUX_EXT2_FS_H
#include <sys/types.h>
#define __u32 u_int32_t
#define u32 u_int32_t
#define __u16 u_int16_t
#define __u8 u_int8_t
#define __s32 int32_t
#define __s16 int16_t
#define __s8 int8_t
#define umode_t mode_t
#define loff_t off_t
#define cpu_to_le32(x) htole32(x)
/*
* The second extended filesystem constants/structures
*/
/*
* Define EXT2FS_DEBUG to produce debug messages
*/
#undef EXT2FS_DEBUG
/*
* Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
*/
#define EXT2_PREALLOCATE
#define EXT2_DEFAULT_PREALLOC_BLOCKS 8
/*
* The second extended file system version
*/
#define EXT2FS_DATE "95/08/09"
#define EXT2FS_VERSION "0.5b"
/*
* Debug code
*/
#ifdef EXT2FS_DEBUG
# define ext2_debug(f, a...) { \
printf ("EXT2-fs DEBUG (%s, %d): %s:", \
__FILE__, __LINE__, __func__); \
printf (f, ## a); \
}
#else
# define ext2_debug(f, a...) /**/
#endif
/*
* Special inode numbers
*/
#define EXT2_BAD_INO 1 /* Bad blocks inode */
#define EXT2_ROOT_INO 2 /* Root inode */
#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
/* First non-reserved inode for old ext2 filesystems */
#define EXT2_GOOD_OLD_FIRST_INO 11
/*
* The second extended file system magic number
*/
#define EXT2_SUPER_MAGIC 0xEF53
#ifdef __KERNEL__
#include <linux/ext2_fs_sb.h>
static inline struct ext2_sb_info *EXT2_SB(struct super_block *sb)
{
return sb->s_fs_info;
}
#elif defined(_KERNEL)
/*
* FreeBSD passes the pointer to the in-core struct with relevant
* fields to EXT2_SB macro when accessing superblock fields.
*/
#define EXT2_SB(sb) (sb)
#else
/* Assume that user mode programs are passing in an ext2fs superblock, not
* a kernel struct super_block. This will allow us to call the feature-test
* macros from user land. */
#define EXT2_SB(sb) (sb)
#endif
/*
* Maximal count of links to a file
*/
#define EXT2_LINK_MAX 32000
/*
* Macro-instructions used to manage several block sizes
*/
#define EXT2_MIN_BLOCK_SIZE 1024
#define EXT2_MAX_BLOCK_SIZE 4096
#define EXT2_MIN_BLOCK_LOG_SIZE 10
#if defined(__KERNEL__) || defined(_KERNEL)
# define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize)
#else
# define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
#endif
#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
#if defined(__KERNEL__) || defined(_KERNEL)
# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
#else
# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
#endif
#if defined(__KERNEL__) || defined(_KERNEL)
#define EXT2_ADDR_PER_BLOCK_BITS(s) (EXT2_SB(s)->s_addr_per_block_bits)
#define EXT2_INODE_SIZE(s) (EXT2_SB(s)->s_inode_size)
#define EXT2_FIRST_INO(s) (EXT2_SB(s)->s_first_ino)
#define EXT2_INODES_PER_BLOCK(s) ((s)->s_inodes_per_block)
#else
#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
EXT2_GOOD_OLD_INODE_SIZE : \
(s)->s_inode_size)
#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
EXT2_GOOD_OLD_FIRST_INO : \
(s)->s_first_ino)
#endif
/*
* Macro-instructions used to manage fragments
*/
#define EXT2_MIN_FRAG_SIZE 1024
#define EXT2_MAX_FRAG_SIZE 4096
#define EXT2_MIN_FRAG_LOG_SIZE 10
#if defined(__KERNEL__) || defined(_KERNEL)
# define EXT2_FRAG_SIZE(s) (EXT2_SB(s)->s_frag_size)
# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_SB(s)->s_frags_per_block)
#else
# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
#endif
/*
* ACL structures
*/
struct ext2_acl_header /* Header of Access Control Lists */
{
__u32 aclh_size;
__u32 aclh_file_count;
__u32 aclh_acle_count;
__u32 aclh_first_acle;
};
struct ext2_acl_entry /* Access Control List Entry */
{
__u32 acle_size;
__u16 acle_perms; /* Access permissions */
__u16 acle_type; /* Type of entry */
__u16 acle_tag; /* User or group identity */
__u16 acle_pad1;
__u32 acle_next; /* Pointer on next entry for the */
/* same inode or on next free entry */
};
/*
* Structure of a blocks group descriptor
*/
struct ext2_group_desc
{
__u32 bg_block_bitmap; /* Blocks bitmap block */
__u32 bg_inode_bitmap; /* Inodes bitmap block */
__u32 bg_inode_table; /* Inodes table block */
__u16 bg_free_blocks_count; /* Free blocks count */
__u16 bg_free_inodes_count; /* Free inodes count */
__u16 bg_used_dirs_count; /* Directories count */
__u16 bg_pad;
__u32 bg_reserved[3];
};
/*
* Macro-instructions used to manage group descriptors
*/
#if defined(__KERNEL__) || defined(_KERNEL)
# define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->s_blocks_per_group)
# define EXT2_DESC_PER_BLOCK(s) (EXT2_SB(s)->s_desc_per_block)
# define EXT2_INODES_PER_GROUP(s) (EXT2_SB(s)->s_inodes_per_group)
# define EXT2_DESC_PER_BLOCK_BITS(s) (EXT2_SB(s)->s_desc_per_block_bits)
#else
# define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
# define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
# define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
#endif
/*
* Constants relative to the data blocks
*/
#define EXT2_NDIR_BLOCKS 12
#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
#define EXT2_MAXSYMLINKLEN (EXT2_N_BLOCKS * sizeof (__u32))
/*
* Inode flags
*/
#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
#define EXT2_UNRM_FL 0x00000002 /* Undelete */
#define EXT2_COMPR_FL 0x00000004 /* Compress file */
#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
/* Reserved for compression usage... */
#define EXT2_DIRTY_FL 0x00000100
#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
#define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */
#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
/* End compression flags --- maybe not all used */
#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
#define EXT2_FL_USER_VISIBLE 0x00001FFF /* User visible flags */
#define EXT2_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */
/*
* ioctl commands
*/
#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
/*
* Structure of an inode on the disk
*/
struct ext2_inode {
__u16 i_mode; /* File mode */
__u16 i_uid; /* Owner Uid */
__u32 i_size; /* Size in bytes */
__u32 i_atime; /* Access time */
__u32 i_ctime; /* Creation time */
__u32 i_mtime; /* Modification time */
__u32 i_dtime; /* Deletion Time */
__u16 i_gid; /* Group Id */
__u16 i_links_count; /* Links count */
__u32 i_blocks; /* Blocks count */
__u32 i_flags; /* File flags */
union {
struct {
__u32 l_i_reserved1;
} linux1;
struct {
__u32 h_i_translator;
} hurd1;
struct {
__u32 m_i_reserved1;
} masix1;
} osd1; /* OS dependent 1 */
__u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
__u32 i_generation; /* File version (for NFS) */
__u32 i_file_acl; /* File ACL */
__u32 i_dir_acl; /* Directory ACL */
__u32 i_faddr; /* Fragment address */
union {
struct {
__u8 l_i_frag; /* Fragment number */
__u8 l_i_fsize; /* Fragment size */
__u16 i_pad1;
__u32 l_i_reserved2[2];
} linux2;
struct {
__u8 h_i_frag; /* Fragment number */
__u8 h_i_fsize; /* Fragment size */
__u16 h_i_mode_high;
__u16 h_i_uid_high;
__u16 h_i_gid_high;
__u32 h_i_author;
} hurd2;
struct {
__u8 m_i_frag; /* Fragment number */
__u8 m_i_fsize; /* Fragment size */
__u16 m_pad1;
__u32 m_i_reserved2[2];
} masix2;
} osd2; /* OS dependent 2 */
};
#define i_size_high i_dir_acl
#if defined(__KERNEL__) || defined(__linux__)
#define i_reserved1 osd1.linux1.l_i_reserved1
#define i_frag osd2.linux2.l_i_frag
#define i_fsize osd2.linux2.l_i_fsize
#define i_reserved2 osd2.linux2.l_i_reserved2
#endif
#ifdef __hurd__
#define i_translator osd1.hurd1.h_i_translator
#define i_frag osd2.hurd2.h_i_frag;
#define i_fsize osd2.hurd2.h_i_fsize;
#define i_uid_high osd2.hurd2.h_i_uid_high
#define i_gid_high osd2.hurd2.h_i_gid_high
#define i_author osd2.hurd2.h_i_author
#endif
#ifdef __masix__
#define i_reserved1 osd1.masix1.m_i_reserved1
#define i_frag osd2.masix2.m_i_frag
#define i_fsize osd2.masix2.m_i_fsize
#define i_reserved2 osd2.masix2.m_i_reserved2
#endif
/*
* File system states
*/
#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
#define EXT2_ERROR_FS 0x0002 /* Errors detected */
/*
* Mount flags
*/
#define EXT2_MOUNT_CHECK_NORMAL 0x0001 /* Do some more checks */
#define EXT2_MOUNT_CHECK_STRICT 0x0002 /* Do again more checks */
#define EXT2_MOUNT_CHECK (EXT2_MOUNT_CHECK_NORMAL | \
EXT2_MOUNT_CHECK_STRICT)
#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
#define test_opt(sb, opt) (EXT2_SB(sb)->s_mount_opt & \
EXT2_MOUNT_##opt)
/*
* Maximal mount counts between two filesystem checks
*/
#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
/*
* Behaviour when detecting errors
*/
#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
#define EXT2_ERRORS_PANIC 3 /* Panic */
#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
/*
* Structure of the super block
*/
struct ext2_super_block {
__u32 s_inodes_count; /* Inodes count */
__u32 s_blocks_count; /* Blocks count */
__u32 s_r_blocks_count; /* Reserved blocks count */
__u32 s_free_blocks_count; /* Free blocks count */
__u32 s_free_inodes_count; /* Free inodes count */
__u32 s_first_data_block; /* First Data Block */
__u32 s_log_block_size; /* Block size */
__s32 s_log_frag_size; /* Fragment size */
__u32 s_blocks_per_group; /* # Blocks per group */
__u32 s_frags_per_group; /* # Fragments per group */
__u32 s_inodes_per_group; /* # Inodes per group */
__u32 s_mtime; /* Mount time */
__u32 s_wtime; /* Write time */
__u16 s_mnt_count; /* Mount count */
__s16 s_max_mnt_count; /* Maximal mount count */
__u16 s_magic; /* Magic signature */
__u16 s_state; /* File system state */
__u16 s_errors; /* Behaviour when detecting errors */
__u16 s_minor_rev_level; /* minor revision level */
__u32 s_lastcheck; /* time of last check */
__u32 s_checkinterval; /* max. time between checks */
__u32 s_creator_os; /* OS */
__u32 s_rev_level; /* Revision level */
__u16 s_def_resuid; /* Default uid for reserved blocks */
__u16 s_def_resgid; /* Default gid for reserved blocks */
/*
* These fields are for EXT2_DYNAMIC_REV superblocks only.
*
* Note: the difference between the compatible feature set and
* the incompatible feature set is that if there is a bit set
* in the incompatible feature set that the kernel doesn't
* know about, it should refuse to mount the filesystem.
*
* e2fsck's requirements are more strict; if it doesn't know
* about a feature in either the compatible or incompatible
* feature set, it must abort and not try to meddle with
* things it doesn't understand...
*/
__u32 s_first_ino; /* First non-reserved inode */
__u16 s_inode_size; /* size of inode structure */
__u16 s_block_group_nr; /* block group # of this superblock */
__u32 s_feature_compat; /* compatible feature set */
__u32 s_feature_incompat; /* incompatible feature set */
__u32 s_feature_ro_compat; /* readonly-compatible feature set */
__u8 s_uuid[16]; /* 128-bit uuid for volume */
char s_volume_name[16]; /* volume name */
char s_last_mounted[64]; /* directory where last mounted */
__u32 s_algorithm_usage_bitmap; /* For compression */
/*
* Performance hints. Directory preallocation should only
* happen if the EXT2_COMPAT_PREALLOC flag is on.
*/
__u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
__u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
__u16 s_padding1;
__u32 s_reserved[204]; /* Padding to the end of the block */
};
/*
* Codes for operating systems
*/
#define EXT2_OS_LINUX 0
#define EXT2_OS_HURD 1
#define EXT2_OS_MASIX 2
#define EXT2_OS_FREEBSD 3
#define EXT2_OS_LITES 4
/*
* Revision levels
*/
#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
#define EXT2_GOOD_OLD_INODE_SIZE 128
/*
* Feature set definitions
*/
#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
#define EXT2_FEATURE_COMPAT_SUPP 0
#define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE
#ifdef notyet
#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
#else
#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
#endif
/*
* Default values for user and/or group using reserved blocks
*/
#define EXT2_DEF_RESUID 0
#define EXT2_DEF_RESGID 0
/*
* Structure of a directory entry
*/
#define EXT2_NAME_LEN 255
struct ext2_dir_entry {
__u32 inode; /* Inode number */
__u16 rec_len; /* Directory entry length */
__u16 name_len; /* Name length */
char name[EXT2_NAME_LEN]; /* File name */
};
/*
* The new version of the directory entry. Since EXT2 structures are
* stored in intel byte order, and the name_len field could never be
* bigger than 255 chars, it's safe to reclaim the extra byte for the
* file_type field.
*/
struct ext2_dir_entry_2 {
__u32 inode; /* Inode number */
__u16 rec_len; /* Directory entry length */
__u8 name_len; /* Name length */
__u8 file_type;
char name[EXT2_NAME_LEN]; /* File name */
};
/*
* Ext2 directory file types. Only the low 3 bits are used. The
* other bits are reserved for now.
*/
#define EXT2_FT_UNKNOWN 0
#define EXT2_FT_REG_FILE 1
#define EXT2_FT_DIR 2
#define EXT2_FT_CHRDEV 3
#define EXT2_FT_BLKDEV 4
#define EXT2_FT_FIFO 5
#define EXT2_FT_SOCK 6
#define EXT2_FT_SYMLINK 7
#define EXT2_FT_MAX 8
/*
* EXT2_DIR_PAD defines the directory entries boundaries
*
* NOTE: It must be a multiple of 4
*/
#define EXT2_DIR_PAD 4
#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
~EXT2_DIR_ROUND)
#endif /* _LINUX_EXT2_FS_H */

View File

@ -1,100 +0,0 @@
/*-
* modified for EXT2FS support in Lites 1.1
*
* Aug 1995, Godmar Back (gback@cs.utah.edu)
* University of Utah, Department of Computer Science
*
* $FreeBSD$
*/
/*-
* linux/include/linux/ext2_fs_sb.h
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*
* from
*
* linux/include/linux/minix_fs_sb.h
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef _LINUX_EXT2_FS_SB
#define _LINUX_EXT2_FS_SB
/*
* The following is not needed anymore since the descriptors buffer
* heads are now dynamically allocated
*/
/* #define EXT2_MAX_GROUP_DESC 8 */
#define EXT2_MAX_GROUP_LOADED 8
#define buffer_head buf
#define MAXMNTLEN 512
/*
* second extended-fs super-block data in memory
*/
struct ext2_sb_info {
unsigned long s_frag_size; /* Size of a fragment in bytes */
unsigned long s_frags_per_block;/* Number of fragments per block */
unsigned long s_inodes_per_block;/* Number of inodes per block */
unsigned long s_frags_per_group;/* Number of fragments in a group */
unsigned long s_blocks_per_group;/* Number of blocks in a group */
unsigned long s_inodes_per_group;/* Number of inodes in a group */
unsigned long s_itb_per_group; /* Number of inode table blocks per group */
unsigned long s_gdb_count; /* Number of group descriptor blocks */
unsigned long s_desc_per_block; /* Number of group descriptors per block */
unsigned long s_groups_count; /* Number of groups in the fs */
struct buffer_head * s_sbh; /* Buffer containing the super block */
struct ext2_super_block * s_es; /* Pointer to the super block in the buffer */
struct buffer_head ** s_group_desc;
unsigned short s_loaded_inode_bitmaps;
unsigned short s_loaded_block_bitmaps;
unsigned long s_inode_bitmap_number[EXT2_MAX_GROUP_LOADED];
struct buffer_head * s_inode_bitmap[EXT2_MAX_GROUP_LOADED];
unsigned long s_block_bitmap_number[EXT2_MAX_GROUP_LOADED];
struct buffer_head * s_block_bitmap[EXT2_MAX_GROUP_LOADED];
unsigned long s_mount_opt;
#ifdef notyet
uid_t s_resuid;
gid_t s_resgid;
#endif
unsigned short s_inode_size;
unsigned int s_first_ino;
unsigned short s_mount_state;
/*
stuff that FFS keeps in its super block or that linux
has in its non-ext2 specific super block and which is
generally considered useful
*/
unsigned long s_blocksize;
unsigned long s_blocksize_bits;
unsigned int s_bshift; /* = log2(s_blocksize) */
quad_t s_qbmask; /* = s_blocksize - 1 */
unsigned int s_fsbtodb; /* shift to get disk block */
char s_rd_only; /* read-only */
char s_dirt; /* fs modified flag */
char s_wasvalid; /* valid at mount time */
off_t fs_maxfilesize;
char fs_fsmnt[MAXMNTLEN]; /* name mounted on */
};
#endif /* _LINUX_EXT2_FS_SB */

View File

@ -1,624 +0,0 @@
/*-
* modified for Lites 1.1
*
* Aug 1995, Godmar Back (gback@cs.utah.edu)
* University of Utah, Department of Computer Science
*
* $FreeBSD$
*/
/*-
* linux/fs/ext2/balloc.c
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*
* Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License..
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
* The free blocks are managed by bitmaps. A file system contains several
* blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
* block for inodes, N blocks for the inode table and data blocks.
*
* The file system contains group descriptors which are located after the
* super block. Each descriptor contains the number of the bitmap block and
* the free blocks count in the block. The descriptors are loaded in memory
* when a file system is mounted (see ext2_read_super).
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <gnu/fs/ext2fs/inode.h>
#include <gnu/fs/ext2fs/ext2_mount.h>
#include <gnu/fs/ext2fs/ext2_extern.h>
#include <gnu/fs/ext2fs/ext2_fs.h>
#include <gnu/fs/ext2fs/ext2_fs_sb.h>
#include <gnu/fs/ext2fs/fs.h>
#ifdef __i386__
#include <gnu/fs/ext2fs/i386-bitops.h>
#else
#include <gnu/fs/ext2fs/ext2_bitops.h>
#endif
#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
/* got rid of get_group_desc since it can already be found in
* ext2_linux_ialloc.c
*/
static void read_block_bitmap (struct mount * mp,
unsigned int block_group,
unsigned long bitmap_nr)
{
struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
struct ext2_group_desc * gdp;
struct buffer_head * bh;
int error;
gdp = get_group_desc (mp, block_group, NULL);
if ((error = bread (VFSTOEXT2(mp)->um_devvp,
fsbtodb(sb, gdp->bg_block_bitmap),sb->s_blocksize, NOCRED, &bh)) != 0)
panic ( "read_block_bitmap: "
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %lu",
block_group, (unsigned long) gdp->bg_block_bitmap);
sb->s_block_bitmap_number[bitmap_nr] = block_group;
sb->s_block_bitmap[bitmap_nr] = bh;
LCK_BUF(bh)
}
/*
* load_block_bitmap loads the block bitmap for a blocks group
*
* It maintains a cache for the last bitmaps loaded. This cache is managed
* with a LRU algorithm.
*
* Notes:
* 1/ There is one cache per mounted file system.
* 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
* this function reads the bitmap without maintaining a LRU cache.
*/
static int load__block_bitmap (struct mount * mp,
unsigned int block_group)
{
int i, j;
struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
unsigned long block_bitmap_number;
struct buffer_head * block_bitmap;
if (block_group >= sb->s_groups_count)
panic ( "load_block_bitmap: "
"block_group >= groups_count - "
"block_group = %d, groups_count = %lu",
block_group, sb->s_groups_count);
if (sb->s_groups_count <= EXT2_MAX_GROUP_LOADED) {
if (sb->s_block_bitmap[block_group]) {
if (sb->s_block_bitmap_number[block_group] !=
block_group)
panic ( "load_block_bitmap: "
"block_group != block_bitmap_number");
else
return block_group;
} else {
read_block_bitmap (mp, block_group, block_group);
return block_group;
}
}
for (i = 0; i < sb->s_loaded_block_bitmaps &&
sb->s_block_bitmap_number[i] != block_group; i++)
;
if (i < sb->s_loaded_block_bitmaps &&
sb->s_block_bitmap_number[i] == block_group) {
block_bitmap_number = sb->s_block_bitmap_number[i];
block_bitmap = sb->s_block_bitmap[i];
for (j = i; j > 0; j--) {
sb->s_block_bitmap_number[j] =
sb->s_block_bitmap_number[j - 1];
sb->s_block_bitmap[j] =
sb->s_block_bitmap[j - 1];
}
sb->s_block_bitmap_number[0] = block_bitmap_number;
sb->s_block_bitmap[0] = block_bitmap;
} else {
if (sb->s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
sb->s_loaded_block_bitmaps++;
else
ULCK_BUF(sb->s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1])
for (j = sb->s_loaded_block_bitmaps - 1; j > 0; j--) {
sb->s_block_bitmap_number[j] =
sb->s_block_bitmap_number[j - 1];
sb->s_block_bitmap[j] =
sb->s_block_bitmap[j - 1];
}
read_block_bitmap (mp, block_group, 0);
}
return 0;
}
static __inline int load_block_bitmap (struct mount * mp,
unsigned int block_group)
{
struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
if (sb->s_loaded_block_bitmaps > 0 &&
sb->s_block_bitmap_number[0] == block_group)
return 0;
if (sb->s_groups_count <= EXT2_MAX_GROUP_LOADED &&
sb->s_block_bitmap_number[block_group] == block_group &&
sb->s_block_bitmap[block_group])
return block_group;
return load__block_bitmap (mp, block_group);
}
void ext2_free_blocks (struct mount * mp, unsigned long block,
unsigned long count)
{
struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
struct buffer_head * bh;
struct buffer_head * bh2;
unsigned long block_group;
unsigned long bit;
unsigned long i;
int bitmap_nr;
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
if (!sb) {
printf ("ext2_free_blocks: nonexistent device");
return;
}
es = sb->s_es;
lock_super (VFSTOEXT2(mp)->um_devvp);
if (block < es->s_first_data_block ||
(block + count) > es->s_blocks_count) {
printf ( "ext2_free_blocks: "
"Freeing blocks not in datazone - "
"block = %lu, count = %lu", block, count);
unlock_super (VFSTOEXT2(mp)->um_devvp);
return;
}
ext2_debug ("freeing blocks %lu to %lu\n", block, block+count-1);
block_group = (block - es->s_first_data_block) /
EXT2_BLOCKS_PER_GROUP(sb);
bit = (block - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb);
if (bit + count > EXT2_BLOCKS_PER_GROUP(sb))
panic ( "ext2_free_blocks: "
"Freeing blocks across group boundary - "
"Block = %lu, count = %lu",
block, count);
bitmap_nr = load_block_bitmap (mp, block_group);
bh = sb->s_block_bitmap[bitmap_nr];
gdp = get_group_desc (mp, block_group, &bh2);
if (/* test_opt (sb, CHECK_STRICT) && assume always strict ! */
(in_range (gdp->bg_block_bitmap, block, count) ||
in_range (gdp->bg_inode_bitmap, block, count) ||
in_range (block, gdp->bg_inode_table,
sb->s_itb_per_group) ||
in_range (block + count - 1, gdp->bg_inode_table,
sb->s_itb_per_group)))
panic ( "ext2_free_blocks: "
"Freeing blocks in system zones - "
"Block = %lu, count = %lu",
block, count);
for (i = 0; i < count; i++) {
if (!clear_bit (bit + i, bh->b_data))
printf ("ext2_free_blocks: "
"bit already cleared for block %lu",
block);
else {
gdp->bg_free_blocks_count++;
es->s_free_blocks_count++;
}
}
mark_buffer_dirty(bh2);
mark_buffer_dirty(bh);
/****
if (sb->s_flags & MS_SYNCHRONOUS) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
****/
sb->s_dirt = 1;
unlock_super (VFSTOEXT2(mp)->um_devvp);
return;
}
/*
* ext2_new_block uses a goal block to assist allocation. If the goal is
* free, or there is a free block within 32 blocks of the goal, that block
* is allocated. Otherwise a forward search is made for a free block; within
* each block group the search first looks for an entire free byte in the block
* bitmap, and then for any free bit if that fails.
*/
int ext2_new_block (struct mount * mp, unsigned long goal,
u_int32_t * prealloc_count,
u_int32_t * prealloc_block)
{
struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
struct buffer_head * bh;
struct buffer_head * bh2;
char * p, * r;
int i, j, k, tmp;
int bitmap_nr;
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
#ifdef EXT2FS_DEBUG
static int goal_hits = 0, goal_attempts = 0;
#endif
if (!sb) {
printf ("ext2_new_block: nonexistent device");
return 0;
}
es = sb->s_es;
lock_super (VFSTOEXT2(mp)->um_devvp);
ext2_debug ("goal=%lu.\n", goal);
repeat:
/*
* First, test whether the goal block is free.
*/
if (goal < es->s_first_data_block || goal >= es->s_blocks_count)
goal = es->s_first_data_block;
i = (goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb);
gdp = get_group_desc (mp, i, &bh2);
if (gdp->bg_free_blocks_count > 0) {
j = ((goal - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb));
#ifdef EXT2FS_DEBUG
if (j)
goal_attempts++;
#endif
bitmap_nr = load_block_bitmap (mp, i);
bh = sb->s_block_bitmap[bitmap_nr];
ext2_debug ("goal is at %d:%d.\n", i, j);
if (!test_bit(j, bh->b_data)) {
#ifdef EXT2FS_DEBUG
goal_hits++;
ext2_debug ("goal bit allocated.\n");
#endif
goto got_block;
}
if (j) {
/*
* The goal was occupied; search forward for a free
* block within the next XX blocks.
*
* end_goal is more or less random, but it has to be
* less than EXT2_BLOCKS_PER_GROUP. Aligning up to the
* next 64-bit boundary is simple..
*/
int end_goal = (j + 63) & ~63;
j = find_next_zero_bit(bh->b_data, end_goal, j);
if (j < end_goal)
goto got_block;
}
ext2_debug ("Bit not found near goal\n");
/*
* There has been no free block found in the near vicinity
* of the goal: do a search forward through the block groups,
* searching in each group first for an entire free byte in
* the bitmap and then for any free bit.
*
* Search first in the remainder of the current group; then,
* cyclicly search through the rest of the groups.
*/
p = ((char *) bh->b_data) + (j >> 3);
r = memscan(p, 0, (EXT2_BLOCKS_PER_GROUP(sb) - j + 7) >> 3);
k = (r - ((char *) bh->b_data)) << 3;
if (k < EXT2_BLOCKS_PER_GROUP(sb)) {
j = k;
goto search_back;
}
k = find_next_zero_bit ((unsigned long *) bh->b_data,
EXT2_BLOCKS_PER_GROUP(sb),
j);
if (k < EXT2_BLOCKS_PER_GROUP(sb)) {
j = k;
goto got_block;
}
}
ext2_debug ("Bit not found in block group %d.\n", i);
/*
* Now search the rest of the groups. We assume that
* i and gdp correctly point to the last group visited.
*/
for (k = 0; k < sb->s_groups_count; k++) {
i++;
if (i >= sb->s_groups_count)
i = 0;
gdp = get_group_desc (mp, i, &bh2);
if (gdp->bg_free_blocks_count > 0)
break;
}
if (k >= sb->s_groups_count) {
unlock_super (VFSTOEXT2(mp)->um_devvp);
return 0;
}
bitmap_nr = load_block_bitmap (mp, i);
bh = sb->s_block_bitmap[bitmap_nr];
r = memscan(bh->b_data, 0, EXT2_BLOCKS_PER_GROUP(sb) >> 3);
j = (r - bh->b_data) << 3;
if (j < EXT2_BLOCKS_PER_GROUP(sb))
goto search_back;
else
j = find_first_zero_bit ((unsigned long *) bh->b_data,
EXT2_BLOCKS_PER_GROUP(sb));
if (j >= EXT2_BLOCKS_PER_GROUP(sb)) {
printf ( "ext2_new_block: "
"Free blocks count corrupted for block group %d", i);
unlock_super (VFSTOEXT2(mp)->um_devvp);
return 0;
}
search_back:
/*
* We have succeeded in finding a free byte in the block
* bitmap. Now search backwards up to 7 bits to find the
* start of this group of free blocks.
*/
for (k = 0; k < 7 && j > 0 && !test_bit (j - 1, bh->b_data); k++, j--);
got_block:
ext2_debug ("using block group %d(%d)\n", i, gdp->bg_free_blocks_count);
tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block;
if (/* test_opt (sb, CHECK_STRICT) && we are always strict. */
(tmp == gdp->bg_block_bitmap ||
tmp == gdp->bg_inode_bitmap ||
in_range (tmp, gdp->bg_inode_table, sb->s_itb_per_group)))
panic ( "ext2_new_block: "
"Allocating block in system zone - "
"%dth block = %u in group %u", j, tmp, i);
if (set_bit (j, bh->b_data)) {
printf ( "ext2_new_block: "
"bit already set for block %d", j);
goto repeat;
}
ext2_debug ("found bit %d\n", j);
/*
* Do block preallocation now if required.
*/
#ifdef EXT2_PREALLOCATE
if (prealloc_block) {
*prealloc_count = 0;
*prealloc_block = tmp + 1;
for (k = 1;
k < 8 && (j + k) < EXT2_BLOCKS_PER_GROUP(sb); k++) {
if (set_bit (j + k, bh->b_data))
break;
(*prealloc_count)++;
}
gdp->bg_free_blocks_count -= *prealloc_count;
es->s_free_blocks_count -= *prealloc_count;
ext2_debug ("Preallocated a further %lu bits.\n",
*prealloc_count);
}
#endif
j = tmp;
mark_buffer_dirty(bh);
/****
if (sb->s_flags & MS_SYNCHRONOUS) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
****/
if (j >= es->s_blocks_count) {
printf ( "ext2_new_block: "
"block >= blocks count - "
"block_group = %d, block=%d", i, j);
unlock_super (VFSTOEXT2(mp)->um_devvp);
return 0;
}
ext2_debug ("allocating block %d. "
"Goal hits %d of %d.\n", j, goal_hits, goal_attempts);
gdp->bg_free_blocks_count--;
mark_buffer_dirty(bh2);
es->s_free_blocks_count--;
sb->s_dirt = 1;
unlock_super (VFSTOEXT2(mp)->um_devvp);
return j;
}
#ifdef unused
static unsigned long ext2_count_free_blocks (struct mount * mp)
{
struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
#ifdef EXT2FS_DEBUG
struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x;
int bitmap_nr;
struct ext2_group_desc * gdp;
int i;
lock_super (VFSTOEXT2(mp)->um_devvp);
es = sb->s_es;
desc_count = 0;
bitmap_count = 0;
gdp = NULL;
for (i = 0; i < sb->s_groups_count; i++) {
gdp = get_group_desc (mp, i, NULL);
desc_count += gdp->bg_free_blocks_count;
bitmap_nr = load_block_bitmap (mp, i);
x = ext2_count_free (sb->s_block_bitmap[bitmap_nr],
sb->s_blocksize);
ext2_debug ("group %d: stored = %d, counted = %lu\n",
i, gdp->bg_free_blocks_count, x);
bitmap_count += x;
}
ext2_debug( "stored = %lu, computed = %lu, %lu\n",
es->s_free_blocks_count, desc_count, bitmap_count);
unlock_super (VFSTOEXT2(mp)->um_devvp);
return bitmap_count;
#else
return sb->s_es->s_free_blocks_count;
#endif
}
#endif /* unused */
static __inline int block_in_use (unsigned long block,
struct ext2_sb_info * sb,
unsigned char * map)
{
return test_bit ((block - sb->s_es->s_first_data_block) %
EXT2_BLOCKS_PER_GROUP(sb), map);
}
static int test_root(int a, int b)
{
if (a == 0)
return 1;
while (1) {
if (a == 1)
return 1;
if (a % b)
return 0;
a = a / b;
}
}
int ext2_group_sparse(int group)
{
return (test_root(group, 3) || test_root(group, 5) ||
test_root(group, 7));
}
#ifdef unused
static void ext2_check_blocks_bitmap (struct mount * mp)
{
struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
struct buffer_head * bh;
struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x;
unsigned long desc_blocks;
int bitmap_nr;
struct ext2_group_desc * gdp;
int i, j;
lock_super (VFSTOEXT2(mp)->um_devvp);
es = sb->s_es;
desc_count = 0;
bitmap_count = 0;
gdp = NULL;
desc_blocks = (sb->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
EXT2_DESC_PER_BLOCK(sb);
for (i = 0; i < sb->s_groups_count; i++) {
gdp = get_group_desc (mp, i, NULL);
desc_count += gdp->bg_free_blocks_count;
bitmap_nr = load_block_bitmap (mp, i);
bh = sb->s_block_bitmap[bitmap_nr];
if (!(es->s_feature_ro_compat &
EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
ext2_group_sparse(i)) {
if (!test_bit (0, bh->b_data))
printf ("ext2_check_blocks_bitmap: "
"Superblock in group %d "
"is marked free", i);
for (j = 0; j < desc_blocks; j++)
if (!test_bit (j + 1, bh->b_data))
printf ("ext2_check_blocks_bitmap: "
"Descriptor block #%d in group "
"%d is marked free", j, i);
}
if (!block_in_use (gdp->bg_block_bitmap, sb, bh->b_data))
printf ("ext2_check_blocks_bitmap: "
"Block bitmap for group %d is marked free",
i);
if (!block_in_use (gdp->bg_inode_bitmap, sb, bh->b_data))
printf ("ext2_check_blocks_bitmap: "
"Inode bitmap for group %d is marked free",
i);
for (j = 0; j < sb->s_itb_per_group; j++)
if (!block_in_use (gdp->bg_inode_table + j, sb, bh->b_data))
printf ("ext2_check_blocks_bitmap: "
"Block #%d of the inode table in "
"group %d is marked free", j, i);
x = ext2_count_free (bh, sb->s_blocksize);
if (gdp->bg_free_blocks_count != x)
printf ("ext2_check_blocks_bitmap: "
"Wrong free blocks count for group %d, "
"stored = %d, counted = %lu", i,
gdp->bg_free_blocks_count, x);
bitmap_count += x;
}
if (es->s_free_blocks_count != bitmap_count)
printf ("ext2_check_blocks_bitmap: "
"Wrong free blocks count in super block, "
"stored = %lu, counted = %lu",
(unsigned long) es->s_free_blocks_count, bitmap_count);
unlock_super (VFSTOEXT2(mp)->um_devvp);
}
#endif /* unused */
/*
* this function is taken from
* linux/fs/ext2/bitmap.c
*/
static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars)
{
unsigned int i;
unsigned long sum = 0;
if (!map)
return (0);
for (i = 0; i < numchars; i++)
sum += nibblemap[map->b_data[i] & 0xf] +
nibblemap[(map->b_data[i] >> 4) & 0xf];
return (sum);
}

View File

@ -1,526 +0,0 @@
/*-
* modified for Lites 1.1
*
* Aug 1995, Godmar Back (gback@cs.utah.edu)
* University of Utah, Department of Computer Science
*
* $FreeBSD$
*/
/*-
* linux/fs/ext2/ialloc.c
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*
* BSD ufs-inspired inode and directory allocation by
* Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
* The free inodes are managed by bitmaps. A file system contains several
* blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
* block for inodes, N blocks for the inode table and data blocks.
*
* The file system contains group descriptors which are located after the
* super block. Each descriptor contains the number of the bitmap block and
* the free blocks count in the block. The descriptors are loaded in memory
* when a file system is mounted (see ext2_read_super).
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <gnu/fs/ext2fs/inode.h>
#include <gnu/fs/ext2fs/ext2_mount.h>
#include <gnu/fs/ext2fs/ext2_extern.h>
#include <gnu/fs/ext2fs/ext2_fs.h>
#include <gnu/fs/ext2fs/ext2_fs_sb.h>
#include <gnu/fs/ext2fs/fs.h>
#include <sys/stat.h>
#ifdef __i386__
#include <gnu/fs/ext2fs/i386-bitops.h>
#else
#include <gnu/fs/ext2fs/ext2_bitops.h>
#endif
/* this is supposed to mark a buffer dirty on ready for delayed writing
*/
void mark_buffer_dirty(struct buf *bh)
{
int s;
s = splbio();
bh->b_flags |= B_DIRTY;
splx(s);
}
struct ext2_group_desc * get_group_desc (struct mount * mp,
unsigned int block_group,
struct buffer_head ** bh)
{
struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
unsigned long group_desc;
unsigned long desc;
struct ext2_group_desc * gdp;
if (block_group >= sb->s_groups_count)
panic ("get_group_desc: "
"block_group >= groups_count - "
"block_group = %d, groups_count = %lu",
block_group, sb->s_groups_count);
group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
desc = block_group % EXT2_DESC_PER_BLOCK(sb);
if (!sb->s_group_desc[group_desc])
panic ( "get_group_desc:"
"Group descriptor not loaded - "
"block_group = %d, group_desc = %lu, desc = %lu",
block_group, group_desc, desc);
gdp = (struct ext2_group_desc *)
sb->s_group_desc[group_desc]->b_data;
if (bh)
*bh = sb->s_group_desc[group_desc];
return gdp + desc;
}
static void read_inode_bitmap (struct mount * mp,
unsigned long block_group,
unsigned int bitmap_nr)
{
struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
struct ext2_group_desc * gdp;
struct buffer_head * bh;
int error;
gdp = get_group_desc (mp, block_group, NULL);
if ((error = bread (VFSTOEXT2(mp)->um_devvp,
fsbtodb(sb, gdp->bg_inode_bitmap),
sb->s_blocksize,
NOCRED, &bh)) != 0)
panic ( "read_inode_bitmap:"
"Cannot read inode bitmap - "
"block_group = %lu, inode_bitmap = %lu",
block_group, (unsigned long) gdp->bg_inode_bitmap);
sb->s_inode_bitmap_number[bitmap_nr] = block_group;
sb->s_inode_bitmap[bitmap_nr] = bh;
LCK_BUF(bh)
}
/*
* load_inode_bitmap loads the inode bitmap for a blocks group
*
* It maintains a cache for the last bitmaps loaded. This cache is managed
* with a LRU algorithm.
*
* Notes:
* 1/ There is one cache per mounted file system.
* 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
* this function reads the bitmap without maintaining a LRU cache.
*/
static int load_inode_bitmap (struct mount * mp,
unsigned int block_group)
{
struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
int i, j;
unsigned long inode_bitmap_number;
struct buffer_head * inode_bitmap;
if (block_group >= sb->s_groups_count)
panic ("load_inode_bitmap:"
"block_group >= groups_count - "
"block_group = %d, groups_count = %lu",
block_group, sb->s_groups_count);
if (sb->s_loaded_inode_bitmaps > 0 &&
sb->s_inode_bitmap_number[0] == block_group)
return 0;
if (sb->s_groups_count <= EXT2_MAX_GROUP_LOADED) {
if (sb->s_inode_bitmap[block_group]) {
if (sb->s_inode_bitmap_number[block_group] !=
block_group)
panic ( "load_inode_bitmap:"
"block_group != inode_bitmap_number");
else
return block_group;
} else {
read_inode_bitmap (mp, block_group, block_group);
return block_group;
}
}
for (i = 0; i < sb->s_loaded_inode_bitmaps &&
sb->s_inode_bitmap_number[i] != block_group;
i++)
;
if (i < sb->s_loaded_inode_bitmaps &&
sb->s_inode_bitmap_number[i] == block_group) {
inode_bitmap_number = sb->s_inode_bitmap_number[i];
inode_bitmap = sb->s_inode_bitmap[i];
for (j = i; j > 0; j--) {
sb->s_inode_bitmap_number[j] =
sb->s_inode_bitmap_number[j - 1];
sb->s_inode_bitmap[j] =
sb->s_inode_bitmap[j - 1];
}
sb->s_inode_bitmap_number[0] = inode_bitmap_number;
sb->s_inode_bitmap[0] = inode_bitmap;
} else {
if (sb->s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED)
sb->s_loaded_inode_bitmaps++;
else
ULCK_BUF(sb->s_inode_bitmap[EXT2_MAX_GROUP_LOADED - 1])
for (j = sb->s_loaded_inode_bitmaps - 1; j > 0; j--) {
sb->s_inode_bitmap_number[j] =
sb->s_inode_bitmap_number[j - 1];
sb->s_inode_bitmap[j] =
sb->s_inode_bitmap[j - 1];
}
read_inode_bitmap (mp, block_group, 0);
}
return 0;
}
void ext2_free_inode (struct inode * inode)
{
struct ext2_sb_info * sb;
struct buffer_head * bh;
struct buffer_head * bh2;
unsigned long block_group;
unsigned long bit;
int bitmap_nr;
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
if (!inode)
return;
if (inode->i_nlink) {
printf ("ext2_free_inode: inode has nlink=%d\n",
inode->i_nlink);
return;
}
ext2_debug ("freeing inode %lu\n", inode->i_number);
sb = inode->i_e2fs;
lock_super (DEVVP(inode));
if (inode->i_number < EXT2_FIRST_INO(sb) ||
inode->i_number > sb->s_es->s_inodes_count) {
printf ("free_inode reserved inode or nonexistent inode");
unlock_super (DEVVP(inode));
return;
}
es = sb->s_es;
block_group = (inode->i_number - 1) / EXT2_INODES_PER_GROUP(sb);
bit = (inode->i_number - 1) % EXT2_INODES_PER_GROUP(sb);
bitmap_nr = load_inode_bitmap (ITOV(inode)->v_mount, block_group);
bh = sb->s_inode_bitmap[bitmap_nr];
if (!clear_bit (bit, bh->b_data))
printf ( "ext2_free_inode:"
"bit already cleared for inode %lu",
(unsigned long)inode->i_number);
else {
gdp = get_group_desc (ITOV(inode)->v_mount, block_group, &bh2);
gdp->bg_free_inodes_count++;
if (S_ISDIR(inode->i_mode))
gdp->bg_used_dirs_count--;
mark_buffer_dirty(bh2);
es->s_free_inodes_count++;
}
mark_buffer_dirty(bh);
/*** XXX
if (sb->s_flags & MS_SYNCHRONOUS) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
***/
sb->s_dirt = 1;
unlock_super (DEVVP(inode));
}
#ifdef linux
/*
* This function increments the inode version number
*
* This may be used one day by the NFS server
*/
static void inc_inode_version (struct inode * inode,
struct ext2_group_desc *gdp,
int mode)
{
unsigned long inode_block;
struct buffer_head * bh;
struct ext2_inode * raw_inode;
inode_block = gdp->bg_inode_table + (((inode->i_number - 1) %
EXT2_INODES_PER_GROUP(inode->i_sb)) /
EXT2_INODES_PER_BLOCK(inode->i_sb));
bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize);
if (!bh) {
printf ("inc_inode_version Cannot load inode table block - "
"inode=%lu, inode_block=%lu\n",
inode->i_number, inode_block);
inode->u.ext2_i.i_version = 1;
return;
}
raw_inode = ((struct ext2_inode *) bh->b_data) +
(((inode->i_number - 1) %
EXT2_INODES_PER_GROUP(inode->i_sb)) %
EXT2_INODES_PER_BLOCK(inode->i_sb));
raw_inode->i_version++;
inode->u.ext2_i.i_version = raw_inode->i_version;
bdwrite (bh);
}
#endif /* linux */
/*
* There are two policies for allocating an inode. If the new inode is
* a directory, then a forward search is made for a block group with both
* free space and a low directory-to-inode ratio; if that fails, then of
* the groups with above-average free space, that group with the fewest
* directories already is chosen.
*
* For other inodes, search forward from the parent directory\'s block
* group to find a free inode.
*/
/*
* this functino has been reduced to the actual 'find the inode number' part
*/
ino_t ext2_new_inode (const struct inode * dir, int mode)
{
struct ext2_sb_info * sb;
struct buffer_head * bh;
struct buffer_head * bh2;
int i, j, avefreei;
int bitmap_nr;
struct ext2_group_desc * gdp;
struct ext2_group_desc * tmp;
struct ext2_super_block * es;
if (!dir)
return 0;
sb = dir->i_e2fs;
lock_super (DEVVP(dir));
es = sb->s_es;
repeat:
gdp = NULL; i=0;
if (S_ISDIR(mode)) {
avefreei = es->s_free_inodes_count /
sb->s_groups_count;
/* I am not yet convinced that this next bit is necessary.
i = dir->u.ext2_i.i_block_group;
for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
tmp = get_group_desc (sb, i, &bh2);
if ((tmp->bg_used_dirs_count << 8) <
tmp->bg_free_inodes_count) {
gdp = tmp;
break;
}
else
i = ++i % sb->u.ext2_sb.s_groups_count;
}
*/
if (!gdp) {
for (j = 0; j < sb->s_groups_count; j++) {
tmp = get_group_desc(ITOV(dir)->v_mount,j,&bh2);
if (tmp->bg_free_inodes_count &&
tmp->bg_free_inodes_count >= avefreei) {
if (!gdp ||
(tmp->bg_free_blocks_count >
gdp->bg_free_blocks_count)) {
i = j;
gdp = tmp;
}
}
}
}
}
else
{
/*
* Try to place the inode in its parent directory
*/
i = dir->i_block_group;
tmp = get_group_desc (ITOV(dir)->v_mount, i, &bh2);
if (tmp->bg_free_inodes_count)
gdp = tmp;
else
{
/*
* Use a quadratic hash to find a group with a
* free inode
*/
for (j = 1; j < sb->s_groups_count; j <<= 1) {
i += j;
if (i >= sb->s_groups_count)
i -= sb->s_groups_count;
tmp = get_group_desc(ITOV(dir)->v_mount,i,&bh2);
if (tmp->bg_free_inodes_count) {
gdp = tmp;
break;
}
}
}
if (!gdp) {
/*
* That failed: try linear search for a free inode
*/
i = dir->i_block_group + 1;
for (j = 2; j < sb->s_groups_count; j++) {
if (++i >= sb->s_groups_count)
i = 0;
tmp = get_group_desc(ITOV(dir)->v_mount,i,&bh2);
if (tmp->bg_free_inodes_count) {
gdp = tmp;
break;
}
}
}
}
if (!gdp) {
unlock_super (DEVVP(dir));
return 0;
}
bitmap_nr = load_inode_bitmap (ITOV(dir)->v_mount, i);
bh = sb->s_inode_bitmap[bitmap_nr];
if ((j = find_first_zero_bit ((unsigned long *) bh->b_data,
EXT2_INODES_PER_GROUP(sb))) <
EXT2_INODES_PER_GROUP(sb)) {
if (set_bit (j, bh->b_data)) {
printf ( "ext2_new_inode:"
"bit already set for inode %d", j);
goto repeat;
}
/* Linux now does the following:
mark_buffer_dirty(bh);
if (sb->s_flags & MS_SYNCHRONOUS) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
*/
mark_buffer_dirty(bh);
} else {
if (gdp->bg_free_inodes_count != 0) {
printf ( "ext2_new_inode:"
"Free inodes count corrupted in group %d",
i);
unlock_super (DEVVP(dir));
return 0;
}
goto repeat;
}
j += i * EXT2_INODES_PER_GROUP(sb) + 1;
if (j < EXT2_FIRST_INO(sb) || j > es->s_inodes_count) {
printf ( "ext2_new_inode:"
"reserved inode or inode > inodes count - "
"block_group = %d,inode=%d", i, j);
unlock_super (DEVVP(dir));
return 0;
}
gdp->bg_free_inodes_count--;
if (S_ISDIR(mode))
gdp->bg_used_dirs_count++;
mark_buffer_dirty(bh2);
es->s_free_inodes_count--;
/* mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); */
sb->s_dirt = 1;
unlock_super (DEVVP(dir));
return j;
}
#ifdef unused
static unsigned long ext2_count_free_inodes (struct mount * mp)
{
#ifdef EXT2FS_DEBUG
struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x;
int bitmap_nr;
struct ext2_group_desc * gdp;
int i;
lock_super (VFSTOEXT2(mp)->um_devvp);
es = sb->s_es;
desc_count = 0;
bitmap_count = 0;
gdp = NULL;
for (i = 0; i < sb->s_groups_count; i++) {
gdp = get_group_desc (mp, i, NULL);
desc_count += gdp->bg_free_inodes_count;
bitmap_nr = load_inode_bitmap (mp, i);
x = ext2_count_free (sb->s_inode_bitmap[bitmap_nr],
EXT2_INODES_PER_GROUP(sb) / 8);
ext2_debug ("group %d: stored = %d, counted = %lu\n",
i, gdp->bg_free_inodes_count, x);
bitmap_count += x;
}
ext2_debug("stored = %lu, computed = %lu, %lu\n",
es->s_free_inodes_count, desc_count, bitmap_count);
unlock_super (VFSTOEXT2(mp)->um_devvp);
return desc_count;
#else
return VFSTOEXT2(mp)->um_e2fsb->s_free_inodes_count;
#endif
}
#endif /* unused */
#ifdef LATER
void ext2_check_inodes_bitmap (struct mount * mp)
{
struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x;
int bitmap_nr;
struct ext2_group_desc * gdp;
int i;
lock_super (sb);
es = sb->u.ext2_sb.s_es;
desc_count = 0;
bitmap_count = 0;
gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
gdp = get_group_desc (sb, i, NULL);
desc_count += gdp->bg_free_inodes_count;
bitmap_nr = load_inode_bitmap (sb, i);
x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
EXT2_INODES_PER_GROUP(sb) / 8);
if (gdp->bg_free_inodes_count != x)
printf ( "ext2_check_inodes_bitmap:"
"Wrong free inodes count in group %d, "
"stored = %d, counted = %lu", i,
gdp->bg_free_inodes_count, x);
bitmap_count += x;
}
if (es->s_free_inodes_count != bitmap_count)
printf ( "ext2_check_inodes_bitmap:"
"Wrong free inodes count in super block, "
"stored = %lu, counted = %lu",
(unsigned long) es->s_free_inodes_count, bitmap_count);
unlock_super (sb);
}
#endif

View File

@ -1,175 +0,0 @@
/* $FreeBSD$ */
/*
* this is mixture of i386/bitops.h and asm/string.h
* taken from the Linux source tree
*
* XXX replace with Mach routines or reprogram in C
*/
/*-
* Copyright 1992, Linus Torvalds.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef _SYS_GNU_EXT2FS_I386_BITOPS_H_
#define _SYS_GNU_EXT2FS_I386_BITOPS_H_
/*
* These have to be done with inline assembly: that way the bit-setting
* is guaranteed to be atomic. All bit operations return 0 if the bit
* was cleared before the operation and != 0 if it was not.
*
* bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
*/
/*
* Some hacks to defeat gcc over-optimizations..
*/
struct __dummy { unsigned long a[100]; };
#define ADDR (*(struct __dummy *) addr)
static __inline__ int set_bit(int nr, void * addr)
{
int oldbit;
__asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit),"=m" (ADDR)
:"ir" (nr));
return oldbit;
}
static __inline__ int clear_bit(int nr, void * addr)
{
int oldbit;
__asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit),"=m" (ADDR)
:"ir" (nr));
return oldbit;
}
static __inline__ int change_bit(int nr, void * addr)
{
int oldbit;
__asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit),"=m" (ADDR)
:"ir" (nr));
return oldbit;
}
/*
* This routine doesn't need to be atomic, but it's faster to code it
* this way.
*/
static __inline__ int test_bit(int nr, void * addr)
{
int oldbit;
__asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit)
:"m" (ADDR),"ir" (nr));
return oldbit;
}
/*
* Find-bit routines..
*/
static __inline__ int find_first_zero_bit(void * addr, unsigned size)
{
int res;
int _count = (size + 31) >> 5;
if (!size)
return 0;
__asm__(" \n\
cld \n\
movl $-1,%%eax \n\
xorl %%edx,%%edx \n\
repe; scasl \n\
je 1f \n\
xorl -4(%%edi),%%eax \n\
subl $4,%%edi \n\
bsfl %%eax,%%edx \n\
1: subl %%ebx,%%edi \n\
shll $3,%%edi \n\
addl %%edi,%%edx"
: "=c" (_count), "=D" (addr), "=d" (res)
: "0" (_count), "1" (addr), "b" (addr)
: "ax");
return res;
}
static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
{
unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
int set = 0, bit = offset & 31, res;
if (bit) {
/*
* Look for zero in first byte
*/
__asm__(" \n\
bsfl %1,%0 \n\
jne 1f \n\
movl $32, %0 \n\
1: "
: "=r" (set)
: "r" (~(*p >> bit)));
if (set < (32 - bit))
return set + offset;
set = 32 - bit;
p++;
}
/*
* No zero yet, search remaining full bytes for a zero
*/
res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
return (offset + set + res);
}
/*
* ffz = Find First Zero in word. Undefined if no zero exists,
* so code should check against ~0UL first..
*/
static __inline__ unsigned long ffz(unsigned long word)
{
__asm__("bsfl %1,%0"
:"=r" (word)
:"r" (~word));
return word;
}
/*
* memscan() taken from linux asm/string.h
*/
/*
* find the first occurrence of byte 'c', or 1 past the area if none
*/
static __inline__ char * memscan(void * addr, unsigned char c, int size)
{
if (!size)
return addr;
__asm__(" \n\
cld \n\
repnz; scasb \n\
jnz 1f \n\
dec %%edi \n\
1: "
: "=D" (addr), "=c" (size)
: "0" (addr), "1" (size), "a" (c));
return addr;
}
#endif /* !_SYS_GNU_EXT2FS_I386_BITOPS_H_ */

View File

@ -728,15 +728,16 @@ struct stat_data_v1 {
* We want common flags to have the same values as in ext2,
* so chattr(1) will work without problems
*/
#include <gnu/fs/ext2fs/ext2_fs.h>
#define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL
#define REISERFS_APPEND_FL EXT2_APPEND_FL
#define REISERFS_SYNC_FL EXT2_SYNC_FL
#define REISERFS_NOATIME_FL EXT2_NOATIME_FL
#define REISERFS_NODUMP_FL EXT2_NODUMP_FL
#define REISERFS_SECRM_FL EXT2_SECRM_FL
#define REISERFS_UNRM_FL EXT2_UNRM_FL
#define REISERFS_COMPR_FL EXT2_COMPR_FL
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/ext2_dinode.h>
#define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE
#define REISERFS_APPEND_FL EXT2_APPEND
#define REISERFS_SYNC_FL EXT2_SYNC
#define REISERFS_NOATIME_FL EXT2_NOATIME
#define REISERFS_NODUMP_FL EXT2_NODUMP
#define REISERFS_SECRM_FL EXT2_SECRM
#define REISERFS_UNRM_FL EXT2_UNRM
#define REISERFS_COMPR_FL EXT2_COMPR
#define REISERFS_NOTAIL_FL EXT2_NOTAIL_FL
/*

View File

@ -1,10 +1,10 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../gnu/fs/ext2fs
.PATH: ${.CURDIR}/../../fs/ext2fs
KMOD= ext2fs
SRCS= opt_ddb.h opt_quota.h opt_suiddir.h vnode_if.h \
ext2_alloc.c ext2_balloc.c ext2_bmap.c ext2_inode.c \
ext2_inode_cnv.c ext2_linux_balloc.c ext2_linux_ialloc.c \
ext2_lookup.c ext2_subr.c ext2_vfsops.c ext2_vnops.c
ext2_inode_cnv.c ext2_lookup.c ext2_subr.c ext2_vfsops.c \
ext2_vnops.c
.include <bsd.kmod.mk>