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:
parent
c0d87a13b2
commit
e09c00cada
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=202283
@ -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
973
sys/fs/ext2fs/ext2_alloc.c
Normal 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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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
78
sys/fs/ext2fs/ext2_dinode.h
Executable 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
81
sys/fs/ext2fs/ext2_dir.h
Executable 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_ */
|
||||
|
@ -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_ */
|
@ -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);
|
||||
|
@ -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];
|
||||
}
|
@ -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);
|
||||
}
|
@ -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))
|
||||
|
@ -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);
|
||||
}
|
@ -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;
|
@ -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.
|
||||
*/
|
@ -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
329
sys/fs/ext2fs/ext2fs.h
Executable 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 */
|
@ -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); \
|
||||
}
|
@ -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_ */
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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_ */
|
@ -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 */
|
@ -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 */
|
@ -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);
|
||||
}
|
@ -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
|
@ -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_ */
|
@ -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
|
||||
|
||||
/*
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user