mirror of
https://github.com/opnsense/src.git
synced 2026-06-10 09:11:07 -04:00
Move ext2fs from src/gnu to src/gnu/fs.
Discussed on arch@. Reviewed by: kan Approved by: re (blanket), kan Discussed with: dumbbell
This commit is contained in:
parent
e28e75cfd6
commit
88a2c1983d
22 changed files with 0 additions and 9058 deletions
|
|
@ -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/ext2fs/inode.h>
|
||||
#include <gnu/ext2fs/ext2_mount.h>
|
||||
#include <gnu/ext2fs/ext2_fs.h>
|
||||
#include <gnu/ext2fs/ext2_fs_sb.h>
|
||||
#include <gnu/ext2fs/fs.h>
|
||||
#include <gnu/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;
|
||||
#if 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;
|
||||
#if 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 {
|
||||
#if 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;
|
||||
#if 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,310 +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_balloc.c 8.4 (Berkeley) 9/23/93
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bio.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <gnu/ext2fs/inode.h>
|
||||
#include <gnu/ext2fs/ext2_fs.h>
|
||||
#include <gnu/ext2fs/ext2_fs_sb.h>
|
||||
#include <gnu/ext2fs/fs.h>
|
||||
#include <gnu/ext2fs/ext2_extern.h>
|
||||
|
||||
/*
|
||||
* Balloc defines the structure of file system storage
|
||||
* by allocating the physical blocks on a device given
|
||||
* the inode and the logical block number in a file.
|
||||
*/
|
||||
int
|
||||
ext2_balloc(ip, bn, size, cred, bpp, flags)
|
||||
struct inode *ip;
|
||||
int32_t bn;
|
||||
int size;
|
||||
struct ucred *cred;
|
||||
struct buf **bpp;
|
||||
int flags;
|
||||
{
|
||||
struct ext2_sb_info *fs;
|
||||
int32_t nb;
|
||||
struct buf *bp, *nbp;
|
||||
struct vnode *vp = ITOV(ip);
|
||||
struct indir indirs[NIADDR + 2];
|
||||
int32_t newb, lbn, *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)
|
||||
return (EFBIG);
|
||||
fs = ip->i_e2fs;
|
||||
lbn = bn;
|
||||
|
||||
/*
|
||||
* check if this is a sequential block allocation.
|
||||
* If so, increment next_alloc fields to allow ext2_blkpref
|
||||
* to make a good guess
|
||||
*/
|
||||
if (lbn == ip->i_next_alloc_block + 1) {
|
||||
ip->i_next_alloc_block++;
|
||||
ip->i_next_alloc_goal++;
|
||||
}
|
||||
|
||||
/*
|
||||
* The first NDADDR blocks are direct blocks
|
||||
*/
|
||||
if (bn < NDADDR) {
|
||||
nb = ip->i_db[bn];
|
||||
/* 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 (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
bp->b_blkno = fsbtodb(fs, nb);
|
||||
*bpp = bp;
|
||||
return (0);
|
||||
}
|
||||
if (nb != 0) {
|
||||
/*
|
||||
* Consider need to reallocate a fragment.
|
||||
*/
|
||||
osize = fragroundup(fs, blkoff(fs, ip->i_size));
|
||||
nsize = fragroundup(fs, size);
|
||||
if (nsize <= osize) {
|
||||
error = bread(vp, bn, osize, NOCRED, &bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
bp->b_blkno = fsbtodb(fs, nb);
|
||||
} else {
|
||||
/* Godmar thinks: this shouldn't happen w/o fragments */
|
||||
printf("nsize %d(%d) > osize %d(%d) nb %d\n",
|
||||
(int)nsize, (int)size, (int)osize,
|
||||
(int)ip->i_size, (int)nb);
|
||||
panic(
|
||||
"ext2_balloc: Something is terribly wrong");
|
||||
/*
|
||||
* please note there haven't been any changes from here on -
|
||||
* FFS seems to work.
|
||||
*/
|
||||
}
|
||||
} else {
|
||||
if (ip->i_size < (bn + 1) * fs->s_blocksize)
|
||||
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, cred, &newb);
|
||||
if (error)
|
||||
return (error);
|
||||
bp = getblk(vp, bn, 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_flag |= IN_CHANGE | IN_UPDATE;
|
||||
*bpp = bp;
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* Determine the number of levels of indirection.
|
||||
*/
|
||||
pref = 0;
|
||||
if ((error = ext2_getlbns(vp, bn, indirs, &num)) != 0)
|
||||
return(error);
|
||||
#if DIAGNOSTIC
|
||||
if (num < 1)
|
||||
panic ("ext2_balloc: ext2_getlbns returned indirect block");
|
||||
#endif
|
||||
/*
|
||||
* Fetch the first indirect block allocating if necessary.
|
||||
*/
|
||||
--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]
|
||||
*/
|
||||
|
||||
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)
|
||||
return (error);
|
||||
nb = newb;
|
||||
bp = getblk(vp, indirs[1].in_lbn, fs->s_blocksize, 0, 0, 0);
|
||||
bp->b_blkno = fsbtodb(fs, newb);
|
||||
vfs_bio_clrbuf(bp);
|
||||
/*
|
||||
* Write synchronously so that indirect blocks
|
||||
* never point at garbage.
|
||||
*/
|
||||
if ((error = bwrite(bp)) != 0) {
|
||||
ext2_blkfree(ip, nb, fs->s_blocksize);
|
||||
return (error);
|
||||
}
|
||||
ip->i_ib[indirs[0].in_off] = newb;
|
||||
ip->i_flag |= IN_CHANGE | IN_UPDATE;
|
||||
}
|
||||
/*
|
||||
* Fetch through the indirect blocks, allocating as necessary.
|
||||
*/
|
||||
for (i = 1;;) {
|
||||
error = bread(vp,
|
||||
indirs[i].in_lbn, (int)fs->s_blocksize, NOCRED, &bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
bap = (int32_t *)bp->b_data;
|
||||
nb = bap[indirs[i].in_off];
|
||||
if (i == num)
|
||||
break;
|
||||
i += 1;
|
||||
if (nb != 0) {
|
||||
brelse(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 ?
|
||||
*/
|
||||
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) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
nb = newb;
|
||||
nbp = getblk(vp, indirs[i].in_lbn, fs->s_blocksize, 0, 0, 0);
|
||||
nbp->b_blkno = fsbtodb(fs, nb);
|
||||
vfs_bio_clrbuf(nbp);
|
||||
/*
|
||||
* Write synchronously so that indirect blocks
|
||||
* never point at garbage.
|
||||
*/
|
||||
if ((error = bwrite(nbp)) != 0) {
|
||||
ext2_blkfree(ip, nb, fs->s_blocksize);
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
bap[indirs[i - 1].in_off] = nb;
|
||||
/*
|
||||
* If required, write synchronously, otherwise use
|
||||
* delayed write.
|
||||
*/
|
||||
if (flags & B_SYNC) {
|
||||
bwrite(bp);
|
||||
} else {
|
||||
bdwrite(bp);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Get the data block, allocating if necessary.
|
||||
*/
|
||||
if (nb == 0) {
|
||||
pref = 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) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
nb = newb;
|
||||
nbp = getblk(vp, lbn, fs->s_blocksize, 0, 0, 0);
|
||||
nbp->b_blkno = fsbtodb(fs, nb);
|
||||
if (flags & B_CLRBUF)
|
||||
vfs_bio_clrbuf(nbp);
|
||||
bap[indirs[i].in_off] = nb;
|
||||
/*
|
||||
* If required, write synchronously, otherwise use
|
||||
* delayed write.
|
||||
*/
|
||||
if (flags & B_SYNC) {
|
||||
bwrite(bp);
|
||||
} else {
|
||||
bdwrite(bp);
|
||||
}
|
||||
*bpp = nbp;
|
||||
return (0);
|
||||
}
|
||||
brelse(bp);
|
||||
if (flags & B_CLRBUF) {
|
||||
error = bread(vp, lbn, (int)fs->s_blocksize, NOCRED, &nbp);
|
||||
if (error) {
|
||||
brelse(nbp);
|
||||
return (error);
|
||||
}
|
||||
} else {
|
||||
nbp = getblk(vp, lbn, fs->s_blocksize, 0, 0, 0);
|
||||
nbp->b_blkno = fsbtodb(fs, nb);
|
||||
}
|
||||
*bpp = nbp;
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -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 - 1);
|
||||
p++;
|
||||
ofs = (ofs + 31U) & ~31U;
|
||||
}
|
||||
while(*p == ~0U && ofs < sz) {
|
||||
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,335 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 1989, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)ufs_bmap.c 8.7 (Berkeley) 3/21/95
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bio.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/resourcevar.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <gnu/ext2fs/inode.h>
|
||||
#include <gnu/ext2fs/ext2_fs.h>
|
||||
#include <gnu/ext2fs/ext2_fs_sb.h>
|
||||
#include <gnu/ext2fs/ext2_mount.h>
|
||||
#include <gnu/ext2fs/ext2_extern.h>
|
||||
|
||||
/*
|
||||
* Bmap converts a the logical block number of a file to its physical block
|
||||
* number on the disk. The conversion is done by using the logical block
|
||||
* number to index into the array of block pointers described by the dinode.
|
||||
*/
|
||||
int
|
||||
ext2_bmap(ap)
|
||||
struct vop_bmap_args /* {
|
||||
struct vnode *a_vp;
|
||||
daddr_t a_bn;
|
||||
struct bufobj **a_bop;
|
||||
daddr_t *a_bnp;
|
||||
int *a_runp;
|
||||
int *a_runb;
|
||||
} */ *ap;
|
||||
{
|
||||
int32_t blkno;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Check for underlying vnode requests and ensure that logical
|
||||
* to physical mapping is requested.
|
||||
*/
|
||||
if (ap->a_bop != NULL)
|
||||
*ap->a_bop = &VTOI(ap->a_vp)->i_devvp->v_bufobj;
|
||||
if (ap->a_bnp == NULL)
|
||||
return (0);
|
||||
|
||||
error = ext2_bmaparray(ap->a_vp, ap->a_bn, &blkno,
|
||||
ap->a_runp, ap->a_runb);
|
||||
*ap->a_bnp = blkno;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Indirect blocks are now on the vnode for the file. They are given negative
|
||||
* logical block numbers. Indirect blocks are addressed by the negative
|
||||
* address of the first data block to which they point. Double indirect blocks
|
||||
* are addressed by one less than the address of the first indirect block to
|
||||
* which they point. Triple indirect blocks are addressed by one less than
|
||||
* the address of the first double indirect block to which they point.
|
||||
*
|
||||
* ufs_bmaparray does the bmap conversion, and if requested returns the
|
||||
* array of logical blocks which must be traversed to get to a block.
|
||||
* Each entry contains the offset into that block that gets you to the
|
||||
* next block and the disk address of the block (if it is assigned).
|
||||
*/
|
||||
|
||||
int
|
||||
ext2_bmaparray(vp, bn, bnp, runp, runb)
|
||||
struct vnode *vp;
|
||||
int32_t bn;
|
||||
int32_t *bnp;
|
||||
int *runp;
|
||||
int *runb;
|
||||
{
|
||||
struct inode *ip;
|
||||
struct buf *bp;
|
||||
struct ext2mount *ump;
|
||||
struct mount *mp;
|
||||
struct vnode *devvp;
|
||||
struct indir a[NIADDR+1], *ap;
|
||||
int32_t daddr;
|
||||
long metalbn;
|
||||
int error, num, maxrun = 0, bsize;
|
||||
int *nump;
|
||||
|
||||
ap = NULL;
|
||||
ip = VTOI(vp);
|
||||
mp = vp->v_mount;
|
||||
ump = VFSTOEXT2(mp);
|
||||
devvp = ump->um_devvp;
|
||||
|
||||
bsize = EXT2_BLOCK_SIZE(ump->um_e2fs);
|
||||
|
||||
if (runp) {
|
||||
maxrun = mp->mnt_iosize_max / bsize - 1;
|
||||
*runp = 0;
|
||||
}
|
||||
|
||||
if (runb) {
|
||||
*runb = 0;
|
||||
}
|
||||
|
||||
|
||||
ap = a;
|
||||
nump = #
|
||||
error = ext2_getlbns(vp, bn, ap, nump);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
num = *nump;
|
||||
if (num == 0) {
|
||||
*bnp = blkptrtodb(ump, ip->i_db[bn]);
|
||||
if (*bnp == 0) {
|
||||
*bnp = -1;
|
||||
} else if (runp) {
|
||||
int32_t bnb = bn;
|
||||
for (++bn; bn < NDADDR && *runp < maxrun &&
|
||||
is_sequential(ump, ip->i_db[bn - 1], ip->i_db[bn]);
|
||||
++bn, ++*runp);
|
||||
bn = bnb;
|
||||
if (runb && (bn > 0)) {
|
||||
for (--bn; (bn >= 0) && (*runb < maxrun) &&
|
||||
is_sequential(ump, ip->i_db[bn],
|
||||
ip->i_db[bn+1]);
|
||||
--bn, ++*runb);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* Get disk address out of indirect block array */
|
||||
daddr = ip->i_ib[ap->in_off];
|
||||
|
||||
for (bp = NULL, ++ap; --num; ++ap) {
|
||||
/*
|
||||
* Exit the loop if there is no disk address assigned yet and
|
||||
* the indirect block isn't in the cache, or if we were
|
||||
* looking for an indirect block and we've found it.
|
||||
*/
|
||||
|
||||
metalbn = ap->in_lbn;
|
||||
if ((daddr == 0 && !incore(&vp->v_bufobj, metalbn)) || metalbn == bn)
|
||||
break;
|
||||
/*
|
||||
* If we get here, we've either got the block in the cache
|
||||
* or we have a disk address for it, go fetch it.
|
||||
*/
|
||||
if (bp)
|
||||
bqrelse(bp);
|
||||
|
||||
ap->in_exists = 1;
|
||||
bp = getblk(vp, metalbn, bsize, 0, 0, 0);
|
||||
if ((bp->b_flags & B_CACHE) == 0) {
|
||||
#ifdef DIAGNOSTIC
|
||||
if (!daddr)
|
||||
panic("ufs_bmaparray: indirect block not in cache");
|
||||
#endif
|
||||
bp->b_blkno = blkptrtodb(ump, daddr);
|
||||
bp->b_iocmd = BIO_READ;
|
||||
bp->b_flags &= ~B_INVAL;
|
||||
bp->b_ioflags &= ~BIO_ERROR;
|
||||
vfs_busy_pages(bp, 0);
|
||||
bp->b_iooffset = dbtob(bp->b_blkno);
|
||||
bstrategy(bp);
|
||||
curproc->p_stats->p_ru.ru_inblock++; /* XXX */
|
||||
error = bufwait(bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
daddr = ((int32_t *)bp->b_data)[ap->in_off];
|
||||
if (num == 1 && daddr && runp) {
|
||||
for (bn = ap->in_off + 1;
|
||||
bn < MNINDIR(ump) && *runp < maxrun &&
|
||||
is_sequential(ump,
|
||||
((int32_t *)bp->b_data)[bn - 1],
|
||||
((int32_t *)bp->b_data)[bn]);
|
||||
++bn, ++*runp);
|
||||
bn = ap->in_off;
|
||||
if (runb && bn) {
|
||||
for(--bn; bn >= 0 && *runb < maxrun &&
|
||||
is_sequential(ump, ((int32_t *)bp->b_data)[bn],
|
||||
((int32_t *)bp->b_data)[bn+1]);
|
||||
--bn, ++*runb);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bp)
|
||||
bqrelse(bp);
|
||||
|
||||
/*
|
||||
* Since this is FFS independent code, we are out of scope for the
|
||||
* definitions of BLK_NOCOPY and BLK_SNAP, but we do know that they
|
||||
* will fall in the range 1..um_seqinc, so we use that test and
|
||||
* return a request for a zeroed out buffer if attempts are made
|
||||
* to read a BLK_NOCOPY or BLK_SNAP block.
|
||||
*/
|
||||
if ((ip->i_flags & SF_SNAPSHOT) && daddr > 0 && daddr < ump->um_seqinc){
|
||||
*bnp = -1;
|
||||
return (0);
|
||||
}
|
||||
*bnp = blkptrtodb(ump, daddr);
|
||||
if (*bnp == 0) {
|
||||
*bnp = -1;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an array of logical block number/offset pairs which represent the
|
||||
* path of indirect blocks required to access a data block. The first "pair"
|
||||
* contains the logical block number of the appropriate single, double or
|
||||
* triple indirect block and the offset into the inode indirect block array.
|
||||
* Note, the logical block number of the inode single/double/triple indirect
|
||||
* block appears twice in the array, once with the offset into the i_ib and
|
||||
* once with the offset into the page itself.
|
||||
*/
|
||||
int
|
||||
ext2_getlbns(vp, bn, ap, nump)
|
||||
struct vnode *vp;
|
||||
int32_t bn;
|
||||
struct indir *ap;
|
||||
int *nump;
|
||||
{
|
||||
long blockcnt, metalbn, realbn;
|
||||
struct ext2mount *ump;
|
||||
int i, numlevels, off;
|
||||
int64_t qblockcnt;
|
||||
|
||||
ump = VFSTOEXT2(vp->v_mount);
|
||||
if (nump)
|
||||
*nump = 0;
|
||||
numlevels = 0;
|
||||
realbn = bn;
|
||||
if ((long)bn < 0)
|
||||
bn = -(long)bn;
|
||||
|
||||
/* The first NDADDR blocks are direct blocks. */
|
||||
if (bn < NDADDR)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Determine the number of levels of indirection. After this loop
|
||||
* is done, blockcnt indicates the number of data blocks possible
|
||||
* at the previous level of indirection, and NIADDR - i is the number
|
||||
* of levels of indirection needed to locate the requested block.
|
||||
*/
|
||||
for (blockcnt = 1, i = NIADDR, bn -= NDADDR;; i--, bn -= blockcnt) {
|
||||
if (i == 0)
|
||||
return (EFBIG);
|
||||
/*
|
||||
* Use int64_t's here to avoid overflow for triple indirect
|
||||
* blocks when longs have 32 bits and the block size is more
|
||||
* than 4K.
|
||||
*/
|
||||
qblockcnt = (int64_t)blockcnt * MNINDIR(ump);
|
||||
if (bn < qblockcnt)
|
||||
break;
|
||||
blockcnt = qblockcnt;
|
||||
}
|
||||
|
||||
/* Calculate the address of the first meta-block. */
|
||||
if (realbn >= 0)
|
||||
metalbn = -(realbn - bn + NIADDR - i);
|
||||
else
|
||||
metalbn = -(-realbn - bn + NIADDR - i);
|
||||
|
||||
/*
|
||||
* At each iteration, off is the offset into the bap array which is
|
||||
* an array of disk addresses at the current level of indirection.
|
||||
* The logical block number and the offset in that block are stored
|
||||
* into the argument array.
|
||||
*/
|
||||
ap->in_lbn = metalbn;
|
||||
ap->in_off = off = NIADDR - i;
|
||||
ap->in_exists = 0;
|
||||
ap++;
|
||||
for (++numlevels; i <= NIADDR; i++) {
|
||||
/* If searching for a meta-data block, quit when found. */
|
||||
if (metalbn == realbn)
|
||||
break;
|
||||
|
||||
off = (bn / blockcnt) % MNINDIR(ump);
|
||||
|
||||
++numlevels;
|
||||
ap->in_lbn = metalbn;
|
||||
ap->in_off = off;
|
||||
ap->in_exists = 0;
|
||||
++ap;
|
||||
|
||||
metalbn -= -1 + off * blockcnt;
|
||||
blockcnt /= MNINDIR(ump);
|
||||
}
|
||||
if (nump)
|
||||
*nump = numlevels;
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1,104 +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
|
||||
*/
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)ffs_extern.h 8.3 (Berkeley) 4/16/94
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _SYS_GNU_EXT2FS_EXT2_EXTERN_H_
|
||||
#define _SYS_GNU_EXT2FS_EXT2_EXTERN_H_
|
||||
|
||||
struct ext2_inode;
|
||||
struct indir;
|
||||
struct inode;
|
||||
struct mount;
|
||||
struct vfsconf;
|
||||
struct vnode;
|
||||
|
||||
int ext2_alloc(struct inode *,
|
||||
int32_t, int32_t, int, struct ucred *, int32_t *);
|
||||
int ext2_balloc(struct inode *,
|
||||
int32_t, int, struct ucred *, struct buf **, int);
|
||||
int ext2_blkatoff(struct vnode *, off_t, char **, struct buf **);
|
||||
void ext2_blkfree(struct inode *, int32_t, long);
|
||||
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 *);
|
||||
int ext2_getlbns(struct vnode *, int32_t, struct indir *, int *);
|
||||
void ext2_i2ei(struct inode *, struct ext2_inode *);
|
||||
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);
|
||||
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 **);
|
||||
int ext2_vfree(struct vnode *, ino_t, int);
|
||||
int ext2_vinit(struct mount *, struct vop_vector *, struct vnode **vpp);
|
||||
int ext2_lookup(struct vop_cachedlookup_args *);
|
||||
int ext2_readdir(struct vop_readdir_args *);
|
||||
void ext2_print_inode(struct inode *);
|
||||
int ext2_direnter(struct inode *,
|
||||
struct vnode *, struct componentname *);
|
||||
int ext2_dirremove(struct vnode *, struct componentname *);
|
||||
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 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. */
|
||||
#define B_SYNC 0x02 /* Do all allocations synchronously. */
|
||||
#define B_METAONLY 0x04 /* Return indirect block buffer. */
|
||||
#define B_NOWAIT 0x08 /* do not sleep to await lock */
|
||||
|
||||
extern struct vop_vector ext2_vnodeops;
|
||||
extern struct vop_vector ext2_fifoops;
|
||||
|
||||
#endif /* !_SYS_GNU_EXT2FS_EXT2_EXTERN_H_ */
|
||||
|
|
@ -1,550 +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
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
/*
|
||||
* 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 inodes numbers
|
||||
*/
|
||||
#define EXT2_BAD_INO 1 /* Bad blocks inode */
|
||||
#define EXT2_ROOT_INO 2 /* Root inode */
|
||||
#define EXT2_ACL_IDX_INO 3 /* ACL inode */
|
||||
#define EXT2_ACL_DATA_INO 4 /* ACL 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
|
||||
|
||||
/*
|
||||
* Maximal count of links to a file
|
||||
*/
|
||||
#define EXT2_LINK_MAX 32000
|
||||
|
||||
/*
|
||||
* Note: under FreeBSD, the "user" versions of the following macros are
|
||||
* used (and must be used) in most cases, because ((s)->u.ext2_sb.s_es is
|
||||
* not accessible. This depends on __KERNEL__ not being defined for
|
||||
* kernel builds under FreeBSD.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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(__FreeBSD__) && 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_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
|
||||
#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
|
||||
#ifdef __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
|
||||
#ifdef notyet
|
||||
#ifdef __KERNEL__
|
||||
#define EXT2_ADDR_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_addr_per_block_bits)
|
||||
#define EXT2_INODE_SIZE(s) ((s)->u.ext2_sb.s_inode_size)
|
||||
#define EXT2_FIRST_INO(s) ((s)->u.ext2_sb.s_first_ino)
|
||||
#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
|
||||
#else /* !notyet */
|
||||
#define EXT2_INODES_PER_BLOCK(s) ((s)->s_inodes_per_block)
|
||||
/* Should be sizeof(struct ext2_inode): */
|
||||
#define EXT2_INODE_SIZE 128
|
||||
#define EXT2_FIRST_INO 11
|
||||
#endif /* notyet */
|
||||
|
||||
/*
|
||||
* 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
|
||||
#ifdef __KERNEL__
|
||||
# define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size)
|
||||
# define EXT2_FRAGS_PER_BLOCK(s) ((s)->u.ext2_sb.s_frags_per_block)
|
||||
#else
|
||||
# if defined(_KERNEL) && defined(__FreeBSD__)
|
||||
# define EXT2_FRAG_SIZE(s) ((s)->s_frag_size)
|
||||
# else
|
||||
# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
|
||||
# endif
|
||||
# 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
|
||||
*/
|
||||
#ifdef __KERNEL__
|
||||
# define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group)
|
||||
# define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block)
|
||||
# define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group)
|
||||
# define EXT2_DESC_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.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) ((sb)->u.ext2_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 */
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#define EXT2_SB(sb) (&((sb)->u.ext2_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
|
||||
|
||||
/*
|
||||
* 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_feature_compat & (mask) )
|
||||
#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
|
||||
( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
|
||||
#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
|
||||
( EXT2_SB(sb)->s_feature_incompat & (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,83 +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
|
||||
*/
|
||||
|
||||
#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_db_per_group; /* Number of descriptor blocks per group */
|
||||
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];
|
||||
int s_rename_lock;
|
||||
unsigned long s_mount_opt;
|
||||
unsigned short s_resuid;
|
||||
unsigned short s_resgid;
|
||||
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,536 +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_inode.c 8.5 (Berkeley) 12/30/93
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/bio.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_extern.h>
|
||||
|
||||
#include <gnu/ext2fs/inode.h>
|
||||
#include <gnu/ext2fs/ext2_mount.h>
|
||||
#include <gnu/ext2fs/ext2_fs.h>
|
||||
#include <gnu/ext2fs/ext2_fs_sb.h>
|
||||
#include <gnu/ext2fs/fs.h>
|
||||
#include <gnu/ext2fs/ext2_extern.h>
|
||||
|
||||
static int ext2_indirtrunc(struct inode *, int32_t, int32_t, int32_t, int,
|
||||
long *);
|
||||
|
||||
/*
|
||||
* Update the access, modified, and inode change times as specified by the
|
||||
* IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. Write the inode
|
||||
* to disk if the IN_MODIFIED flag is set (it may be set initially, or by
|
||||
* the timestamp update). The IN_LAZYMOD flag is set to force a write
|
||||
* later if not now. If we write now, then clear both IN_MODIFIED and
|
||||
* IN_LAZYMOD to reflect the presumably successful write, and if waitfor is
|
||||
* set, then wait for the write to complete.
|
||||
*/
|
||||
int
|
||||
ext2_update(vp, waitfor)
|
||||
struct vnode *vp;
|
||||
int waitfor;
|
||||
{
|
||||
struct ext2_sb_info *fs;
|
||||
struct buf *bp;
|
||||
struct inode *ip;
|
||||
int error;
|
||||
|
||||
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)
|
||||
return (0);
|
||||
fs = ip->i_e2fs;
|
||||
if ((error = bread(ip->i_devvp,
|
||||
fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
|
||||
(int)fs->s_blocksize, NOCRED, &bp)) != 0) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
ext2_i2ei(ip, (struct ext2_inode *)((char *)bp->b_data +
|
||||
EXT2_INODE_SIZE * ino_to_fsbo(fs, ip->i_number)));
|
||||
if (waitfor && (vp->v_mount->mnt_flag & MNT_ASYNC) == 0)
|
||||
return (bwrite(bp));
|
||||
else {
|
||||
bdwrite(bp);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
#define SINGLE 0 /* index of single indirect block */
|
||||
#define DOUBLE 1 /* index of double indirect block */
|
||||
#define TRIPLE 2 /* index of triple indirect block */
|
||||
/*
|
||||
* Truncate the inode oip to at most length size, freeing the
|
||||
* disk blocks.
|
||||
*/
|
||||
int
|
||||
ext2_truncate(vp, length, flags, cred, td)
|
||||
struct vnode *vp;
|
||||
off_t length;
|
||||
int flags;
|
||||
struct ucred *cred;
|
||||
struct thread *td;
|
||||
{
|
||||
struct vnode *ovp = vp;
|
||||
int32_t lastblock;
|
||||
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 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);
|
||||
if (ovp->v_type == VLNK &&
|
||||
oip->i_size < ovp->v_mount->mnt_maxsymlinklen) {
|
||||
#if DIAGNOSTIC
|
||||
if (length != 0)
|
||||
panic("ext2_truncate: partial truncate of symlink");
|
||||
#endif
|
||||
bzero((char *)&oip->i_shortlink, (u_int)oip->i_size);
|
||||
oip->i_size = 0;
|
||||
oip->i_flag |= IN_CHANGE | IN_UPDATE;
|
||||
return (ext2_update(ovp, 1));
|
||||
}
|
||||
if (oip->i_size == length) {
|
||||
oip->i_flag |= IN_CHANGE | IN_UPDATE;
|
||||
return (ext2_update(ovp, 0));
|
||||
}
|
||||
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.
|
||||
*/
|
||||
if (osize < length) {
|
||||
if (length > oip->i_e2fs->fs_maxfilesize)
|
||||
return (EFBIG);
|
||||
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)
|
||||
return (error);
|
||||
oip->i_size = length;
|
||||
if (aflags & IO_SYNC)
|
||||
bwrite(bp);
|
||||
else
|
||||
bawrite(bp);
|
||||
oip->i_flag |= IN_CHANGE | IN_UPDATE;
|
||||
return (ext2_update(ovp, 1));
|
||||
}
|
||||
/*
|
||||
* Shorten the size of the file. If the file is not being
|
||||
* truncated to a block boundry, the contents of the
|
||||
* partial block following the end of the file must be
|
||||
* zero'ed in case it ever become accessible again because
|
||||
* of subsequent file growth.
|
||||
*/
|
||||
/* I don't understand the comment above */
|
||||
offset = blkoff(fs, length);
|
||||
if (offset == 0) {
|
||||
oip->i_size = length;
|
||||
} else {
|
||||
lbn = lblkno(fs, length);
|
||||
aflags = B_CLRBUF;
|
||||
if (flags & IO_SYNC)
|
||||
aflags |= B_SYNC;
|
||||
if ((error = ext2_balloc(oip, lbn, offset, cred, &bp,
|
||||
aflags)) != 0)
|
||||
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)
|
||||
bwrite(bp);
|
||||
else
|
||||
bawrite(bp);
|
||||
}
|
||||
/*
|
||||
* Calculate index into inode's block list of
|
||||
* last direct and indirect blocks (if any)
|
||||
* which we want to keep. Lastblock is -1 when
|
||||
* the file is truncated to 0.
|
||||
*/
|
||||
lastblock = lblkno(fs, length + fs->s_blocksize - 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);
|
||||
/*
|
||||
* Update file and block pointers on disk before we start freeing
|
||||
* blocks. If we crash before free'ing blocks below, the blocks
|
||||
* will be returned to the free list. lastiblock values are also
|
||||
* normalized to -1 for calls to ext2_indirtrunc below.
|
||||
*/
|
||||
bcopy((caddr_t)&oip->i_db[0], (caddr_t)oldblks, sizeof oldblks);
|
||||
for (level = TRIPLE; level >= SINGLE; level--)
|
||||
if (lastiblock[level] < 0) {
|
||||
oip->i_ib[level] = 0;
|
||||
lastiblock[level] = -1;
|
||||
}
|
||||
for (i = NDADDR - 1; i > lastblock; i--)
|
||||
oip->i_db[i] = 0;
|
||||
oip->i_flag |= IN_CHANGE | IN_UPDATE;
|
||||
allerror = ext2_update(ovp, 1);
|
||||
|
||||
/*
|
||||
* Having written the new inode to disk, save its new configuration
|
||||
* and put back the old block pointers long enough to process them.
|
||||
* Note that we save the new block configuration so we can check it
|
||||
* when we are done.
|
||||
*/
|
||||
bcopy((caddr_t)&oip->i_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);
|
||||
if (error && (allerror == 0))
|
||||
allerror = error;
|
||||
|
||||
/*
|
||||
* Indirect blocks first.
|
||||
*/
|
||||
indir_lbn[SINGLE] = -NDADDR;
|
||||
indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
|
||||
indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
|
||||
for (level = TRIPLE; level >= SINGLE; level--) {
|
||||
bn = oip->i_ib[level];
|
||||
if (bn != 0) {
|
||||
error = ext2_indirtrunc(oip, indir_lbn[level],
|
||||
fsbtodb(fs, bn), lastiblock[level], level, &count);
|
||||
if (error)
|
||||
allerror = error;
|
||||
blocksreleased += count;
|
||||
if (lastiblock[level] < 0) {
|
||||
oip->i_ib[level] = 0;
|
||||
ext2_blkfree(oip, bn, fs->s_frag_size);
|
||||
blocksreleased += nblocks;
|
||||
}
|
||||
}
|
||||
if (lastiblock[level] >= 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* All whole direct blocks or frags.
|
||||
*/
|
||||
for (i = NDADDR - 1; i > lastblock; i--) {
|
||||
long bsize;
|
||||
|
||||
bn = oip->i_db[i];
|
||||
if (bn == 0)
|
||||
continue;
|
||||
oip->i_db[i] = 0;
|
||||
bsize = blksize(fs, oip, i);
|
||||
ext2_blkfree(oip, bn, bsize);
|
||||
blocksreleased += btodb(bsize);
|
||||
}
|
||||
if (lastblock < 0)
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Finally, look for a change in size of the
|
||||
* last direct block; release any frags.
|
||||
*/
|
||||
bn = oip->i_db[lastblock];
|
||||
if (bn != 0) {
|
||||
long oldspace, newspace;
|
||||
|
||||
/*
|
||||
* Calculate amount of space we're giving
|
||||
* back as old block size minus new block size.
|
||||
*/
|
||||
oldspace = blksize(fs, oip, lastblock);
|
||||
oip->i_size = length;
|
||||
newspace = blksize(fs, oip, lastblock);
|
||||
if (newspace == 0)
|
||||
panic("itrunc: newspace");
|
||||
if (oldspace - newspace > 0) {
|
||||
/*
|
||||
* Block number of space to be free'd is
|
||||
* the old block # plus the number of frags
|
||||
* required for the storage we're keeping.
|
||||
*/
|
||||
bn += numfrags(fs, newspace);
|
||||
ext2_blkfree(oip, bn, oldspace - newspace);
|
||||
blocksreleased += btodb(oldspace - newspace);
|
||||
}
|
||||
}
|
||||
done:
|
||||
#if DIAGNOSTIC
|
||||
for (level = SINGLE; level <= TRIPLE; level++)
|
||||
if (newblks[NDADDR + level] != oip->i_ib[level])
|
||||
panic("itrunc1");
|
||||
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))
|
||||
panic("itrunc3");
|
||||
VI_UNLOCK(ovp);
|
||||
#endif /* DIAGNOSTIC */
|
||||
/*
|
||||
* Put back the real size.
|
||||
*/
|
||||
oip->i_size = length;
|
||||
oip->i_blocks -= blocksreleased;
|
||||
if (oip->i_blocks < 0) /* sanity */
|
||||
oip->i_blocks = 0;
|
||||
oip->i_flag |= IN_CHANGE;
|
||||
vnode_pager_setsize(ovp, length);
|
||||
return (allerror);
|
||||
}
|
||||
|
||||
/*
|
||||
* Release blocks associated with the inode ip and stored in the indirect
|
||||
* block bn. Blocks are free'd in LIFO order up to (but not including)
|
||||
* lastbn. If level is greater than SINGLE, the block is an indirect block
|
||||
* and recursive calls to indirtrunc must be used to cleanse other indirect
|
||||
* blocks.
|
||||
*
|
||||
* NB: triple indirect blocks are untested.
|
||||
*/
|
||||
|
||||
static int
|
||||
ext2_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
|
||||
struct inode *ip;
|
||||
int32_t lbn, lastbn;
|
||||
int32_t dbn;
|
||||
int level;
|
||||
long *countp;
|
||||
{
|
||||
struct buf *bp;
|
||||
struct ext2_sb_info *fs = ip->i_e2fs;
|
||||
struct vnode *vp;
|
||||
int32_t *bap, *copy, nb, nlbn, last;
|
||||
long blkcount, factor;
|
||||
int i, nblocks, blocksreleased = 0;
|
||||
int error = 0, allerror = 0;
|
||||
|
||||
/*
|
||||
* Calculate index in current block of last
|
||||
* block to be kept. -1 indicates the entire
|
||||
* block so we need not calculate the index.
|
||||
*/
|
||||
factor = 1;
|
||||
for (i = SINGLE; i < level; i++)
|
||||
factor *= NINDIR(fs);
|
||||
last = lastbn;
|
||||
if (lastbn > 0)
|
||||
last /= factor;
|
||||
nblocks = btodb(fs->s_blocksize);
|
||||
/*
|
||||
* Get buffer of block pointers, zero those entries corresponding
|
||||
* to blocks to be free'd, and update on disk copy first. Since
|
||||
* double(triple) indirect before single(double) indirect, calls
|
||||
* to bmap on these blocks will fail. However, we already have
|
||||
* the on disk address, so we have to set the b_blkno field
|
||||
* explicitly instead of letting bread do everything for us.
|
||||
*/
|
||||
vp = ITOV(ip);
|
||||
bp = getblk(vp, lbn, (int)fs->s_blocksize, 0, 0, 0);
|
||||
if (bp->b_flags & (B_DONE | B_DELWRI)) {
|
||||
} else {
|
||||
bp->b_iocmd = BIO_READ;
|
||||
if (bp->b_bcount > bp->b_bufsize)
|
||||
panic("ext2_indirtrunc: bad buffer size");
|
||||
bp->b_blkno = dbn;
|
||||
vfs_busy_pages(bp, 0);
|
||||
bp->b_iooffset = dbtob(bp->b_blkno);
|
||||
bstrategy(bp);
|
||||
error = bufwait(bp);
|
||||
}
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
*countp = 0;
|
||||
return (error);
|
||||
}
|
||||
|
||||
bap = (int32_t *)bp->b_data;
|
||||
MALLOC(copy, int32_t *, fs->s_blocksize, M_TEMP, M_WAITOK);
|
||||
bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->s_blocksize);
|
||||
bzero((caddr_t)&bap[last + 1],
|
||||
(u_int)(NINDIR(fs) - (last + 1)) * sizeof (int32_t));
|
||||
if (last == -1)
|
||||
bp->b_flags |= B_INVAL;
|
||||
error = bwrite(bp);
|
||||
if (error)
|
||||
allerror = error;
|
||||
bap = copy;
|
||||
|
||||
/*
|
||||
* Recursively free totally unused blocks.
|
||||
*/
|
||||
for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
|
||||
i--, nlbn += factor) {
|
||||
nb = bap[i];
|
||||
if (nb == 0)
|
||||
continue;
|
||||
if (level > SINGLE) {
|
||||
if ((error = ext2_indirtrunc(ip, nlbn,
|
||||
fsbtodb(fs, nb), (int32_t)-1, level - 1, &blkcount)) != 0)
|
||||
allerror = error;
|
||||
blocksreleased += blkcount;
|
||||
}
|
||||
ext2_blkfree(ip, nb, fs->s_blocksize);
|
||||
blocksreleased += nblocks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursively free last partial block.
|
||||
*/
|
||||
if (level > SINGLE && lastbn >= 0) {
|
||||
last = lastbn % factor;
|
||||
nb = bap[i];
|
||||
if (nb != 0) {
|
||||
if ((error = ext2_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
|
||||
last, level - 1, &blkcount)) != 0)
|
||||
allerror = error;
|
||||
blocksreleased += blkcount;
|
||||
}
|
||||
}
|
||||
FREE(copy, M_TEMP);
|
||||
*countp = blocksreleased;
|
||||
return (allerror);
|
||||
}
|
||||
|
||||
/*
|
||||
* discard preallocated blocks
|
||||
*/
|
||||
int
|
||||
ext2_inactive(ap)
|
||||
struct vop_inactive_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct thread *a_td;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct inode *ip = VTOI(vp);
|
||||
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);
|
||||
|
||||
/*
|
||||
* Ignore inodes related to stale file handles.
|
||||
*/
|
||||
if (ip->i_mode == 0)
|
||||
goto out;
|
||||
if (ip->i_nlink <= 0) {
|
||||
(void) vn_write_suspend_wait(vp, NULL, V_WAIT);
|
||||
error = ext2_truncate(vp, (off_t)0, 0, NOCRED, td);
|
||||
ip->i_rdev = 0;
|
||||
mode = ip->i_mode;
|
||||
ip->i_mode = 0;
|
||||
ip->i_flag |= IN_CHANGE | IN_UPDATE;
|
||||
ext2_vfree(vp, ip->i_number, mode);
|
||||
}
|
||||
if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) {
|
||||
if ((ip->i_flag & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 &&
|
||||
vn_write_suspend_wait(vp, NULL, V_NOWAIT)) {
|
||||
ip->i_flag &= ~IN_ACCESS;
|
||||
} else {
|
||||
(void) vn_write_suspend_wait(vp, NULL, V_WAIT);
|
||||
ext2_update(vp, 0);
|
||||
}
|
||||
}
|
||||
out:
|
||||
/*
|
||||
* If we are done with the inode, reclaim it
|
||||
* so that it can be reused immediately.
|
||||
*/
|
||||
if (ip->i_mode == 0)
|
||||
vrecycle(vp, td);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reclaim an inode so that it can be used for other purposes.
|
||||
*/
|
||||
int
|
||||
ext2_reclaim(ap)
|
||||
struct vop_reclaim_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct thread *a_td;
|
||||
} */ *ap;
|
||||
{
|
||||
struct inode *ip;
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
if (prtactive && vrefcnt(vp) != 0)
|
||||
vprint("ufs_reclaim: pushing active", vp);
|
||||
ip = VTOI(vp);
|
||||
if (ip->i_flag & IN_LAZYMOD) {
|
||||
ip->i_flag |= IN_MODIFIED;
|
||||
ext2_update(vp, 0);
|
||||
}
|
||||
vfs_hash_remove(vp);
|
||||
FREE(vp->v_data, M_EXT2NODE);
|
||||
vp->v_data = 0;
|
||||
vnode_destroy_vobject(vp);
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 1995 The University of Utah and
|
||||
* the Computer Systems Laboratory at the University of Utah (CSL).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software is hereby
|
||||
* granted provided that (1) source code retains these copyright, permission,
|
||||
* and disclaimer notices, and (2) redistributions including binaries
|
||||
* reproduce the notices in supporting documentation, and (3) all advertising
|
||||
* materials mentioning features or use of this software display the following
|
||||
* acknowledgement: ``This product includes software developed by the
|
||||
* Computer Systems Laboratory at the University of Utah.''
|
||||
*
|
||||
* THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
|
||||
* IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
|
||||
* ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
*
|
||||
* CSL requests users of this software to return to csl-dist@cs.utah.edu any
|
||||
* improvements that they make and grant CSL redistribution rights.
|
||||
*
|
||||
* Utah $Hdr$
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* routines to convert on disk ext2 inodes into inodes and back
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <gnu/ext2fs/inode.h>
|
||||
#include <gnu/ext2fs/ext2_fs.h>
|
||||
#include <gnu/ext2fs/ext2_extern.h>
|
||||
|
||||
void
|
||||
ext2_print_inode( in )
|
||||
struct inode *in;
|
||||
{
|
||||
int i;
|
||||
|
||||
printf( "Inode: %5d", in->i_number);
|
||||
printf( /* "Inode: %5d" */
|
||||
" Type: %10s Mode: 0x%o Flags: 0x%x Version: %d\n",
|
||||
"n/a", in->i_mode, in->i_flags, in->i_gen);
|
||||
printf( "User: %5lu Group: %5lu Size: %lu\n",
|
||||
(unsigned long)in->i_uid, (unsigned long)in->i_gid,
|
||||
(unsigned long)in->i_size);
|
||||
printf( "Links: %3d Blockcount: %d\n",
|
||||
in->i_nlink, in->i_blocks);
|
||||
printf( "ctime: 0x%x", in->i_ctime);
|
||||
printf( "atime: 0x%x", in->i_atime);
|
||||
printf( "mtime: 0x%x", in->i_mtime);
|
||||
printf( "BLOCKS: ");
|
||||
for(i=0; i < (in->i_blocks <= 24 ? ((in->i_blocks+1)/2): 12); i++)
|
||||
printf("%d ", in->i_db[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* raw ext2 inode to inode
|
||||
*/
|
||||
void
|
||||
ext2_ei2i(ei, ip)
|
||||
struct ext2_inode *ei;
|
||||
struct inode *ip;
|
||||
{
|
||||
int i;
|
||||
|
||||
ip->i_nlink = ei->i_links_count;
|
||||
/* 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;
|
||||
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_flags = 0;
|
||||
ip->i_flags |= (ei->i_flags & EXT2_APPEND_FL) ? APPEND : 0;
|
||||
ip->i_flags |= (ei->i_flags & EXT2_IMMUTABLE_FL) ? IMMUTABLE : 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;
|
||||
/* XXX use memcpy */
|
||||
for(i = 0; i < NDADDR; i++)
|
||||
ip->i_db[i] = ei->i_block[i];
|
||||
for(i = 0; i < NIADDR; i++)
|
||||
ip->i_ib[i] = ei->i_block[EXT2_NDIR_BLOCKS + i];
|
||||
}
|
||||
|
||||
/*
|
||||
* inode to raw ext2 inode
|
||||
*/
|
||||
void
|
||||
ext2_i2ei(ip, ei)
|
||||
struct inode *ip;
|
||||
struct ext2_inode *ei;
|
||||
{
|
||||
int i;
|
||||
|
||||
ei->i_mode = ip->i_mode;
|
||||
ei->i_links_count = 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;
|
||||
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 & APPEND) ? EXT2_APPEND_FL: 0;
|
||||
ei->i_flags |= (ip->i_flags & IMMUTABLE) ? EXT2_IMMUTABLE_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;
|
||||
/* XXX use memcpy */
|
||||
for(i = 0; i < NDADDR; i++)
|
||||
ei->i_block[i] = ip->i_db[i];
|
||||
for(i = 0; i < NIADDR; i++)
|
||||
ei->i_block[EXT2_NDIR_BLOCKS + i] = ip->i_ib[i];
|
||||
}
|
||||
|
|
@ -1,610 +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
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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/ext2fs/inode.h>
|
||||
#include <gnu/ext2fs/ext2_mount.h>
|
||||
#include <gnu/ext2fs/ext2_extern.h>
|
||||
#include <gnu/ext2fs/ext2_fs.h>
|
||||
#include <gnu/ext2fs/ext2_fs_sb.h>
|
||||
#include <gnu/ext2fs/fs.h>
|
||||
|
||||
#ifdef __i386__
|
||||
#include <gnu/ext2fs/i386-bitops.h>
|
||||
#else
|
||||
#include <gnu/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,512 +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
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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/ext2fs/inode.h>
|
||||
#include <gnu/ext2fs/ext2_mount.h>
|
||||
#include <gnu/ext2fs/ext2_extern.h>
|
||||
#include <gnu/ext2fs/ext2_fs.h>
|
||||
#include <gnu/ext2fs/ext2_fs_sb.h>
|
||||
#include <gnu/ext2fs/fs.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef __i386__
|
||||
#include <gnu/ext2fs/i386-bitops.h>
|
||||
#else
|
||||
#include <gnu/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 ||
|
||||
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));
|
||||
}
|
||||
|
||||
#if 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 || 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
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,73 +0,0 @@
|
|||
/*-
|
||||
* 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.
|
||||
*
|
||||
* @(#)ufsmount.h 8.6 (Berkeley) 3/30/95
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _SYS_GNU_EXT2FS_EXT2_MOUNT_H_
|
||||
#define _SYS_GNU_EXT2FS_EXT2_MOUNT_H_
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#ifdef MALLOC_DECLARE
|
||||
MALLOC_DECLARE(M_EXT2NODE);
|
||||
#endif
|
||||
|
||||
struct vnode;
|
||||
|
||||
/* This structure describes the ext2fs specific mount structure data. */
|
||||
struct ext2mount {
|
||||
struct mount *um_mountp; /* filesystem vfs structure */
|
||||
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
|
||||
|
||||
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 g_consumer *um_cp;
|
||||
struct bufobj *um_bo;
|
||||
};
|
||||
|
||||
/* Convert mount ptr to ext2fsmount ptr. */
|
||||
#define VFSTOEXT2(mp) ((struct ext2mount *)((mp)->mnt_data))
|
||||
|
||||
/*
|
||||
* Macros to access file system parameters in the ufsmount structure.
|
||||
* Used by ufs_bmap.
|
||||
*/
|
||||
#define MNINDIR(ump) ((ump)->um_nindir)
|
||||
#define blkptrtodb(ump, b) ((b) << (ump)->um_bptrtodb)
|
||||
#define is_sequential(ump, a, b) ((b) == (a) + ump->um_seqinc)
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif
|
||||
|
|
@ -1,304 +0,0 @@
|
|||
/*-
|
||||
* modified for Lites 1.1
|
||||
*
|
||||
* Aug 1995, Godmar Back (gback@cs.utah.edu)
|
||||
* University of Utah, Department of Computer Science
|
||||
*/
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)ufs_readwrite.c 8.7 (Berkeley) 1/21/94
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#define BLKSIZE(a, b, c) blksize(a, b, c)
|
||||
#define FS struct ext2_sb_info
|
||||
#define I_FS i_e2fs
|
||||
#define READ ext2_read
|
||||
#define READ_S "ext2_read"
|
||||
#define WRITE ext2_write
|
||||
#define WRITE_S "ext2_write"
|
||||
|
||||
/*
|
||||
* Vnode op for reading.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
READ(ap)
|
||||
struct vop_read_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp;
|
||||
struct inode *ip;
|
||||
struct uio *uio;
|
||||
FS *fs;
|
||||
struct buf *bp;
|
||||
daddr_t lbn, nextlbn;
|
||||
off_t bytesinfile;
|
||||
long size, xfersize, blkoffset;
|
||||
int error, orig_resid;
|
||||
int seqcount = ap->a_ioflag >> IO_SEQSHIFT;
|
||||
u_short mode;
|
||||
|
||||
vp = ap->a_vp;
|
||||
ip = VTOI(vp);
|
||||
mode = ip->i_mode;
|
||||
uio = ap->a_uio;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (uio->uio_rw != UIO_READ)
|
||||
panic("%s: mode", READ_S);
|
||||
|
||||
if (vp->v_type == VLNK) {
|
||||
if ((int)ip->i_size < vp->v_mount->mnt_maxsymlinklen)
|
||||
panic("%s: short symlink", READ_S);
|
||||
} else if (vp->v_type != VREG && vp->v_type != VDIR)
|
||||
panic("%s: type %d", READ_S, vp->v_type);
|
||||
#endif
|
||||
fs = ip->I_FS;
|
||||
if ((uoff_t)uio->uio_offset > fs->fs_maxfilesize)
|
||||
return (EFBIG);
|
||||
|
||||
orig_resid = uio->uio_resid;
|
||||
for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
|
||||
if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
|
||||
break;
|
||||
lbn = lblkno(fs, uio->uio_offset);
|
||||
nextlbn = lbn + 1;
|
||||
size = BLKSIZE(fs, ip, lbn);
|
||||
blkoffset = blkoff(fs, uio->uio_offset);
|
||||
|
||||
xfersize = fs->s_frag_size - blkoffset;
|
||||
if (uio->uio_resid < xfersize)
|
||||
xfersize = uio->uio_resid;
|
||||
if (bytesinfile < xfersize)
|
||||
xfersize = bytesinfile;
|
||||
|
||||
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);
|
||||
else if (seqcount > 1) {
|
||||
int nextsize = BLKSIZE(fs, ip, nextlbn);
|
||||
error = breadn(vp, lbn,
|
||||
size, &nextlbn, &nextsize, 1, NOCRED, &bp);
|
||||
} else
|
||||
error = bread(vp, lbn, size, NOCRED, &bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
bp = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We should only get non-zero b_resid when an I/O error
|
||||
* has occurred, which should cause us to break above.
|
||||
* However, if the short read did not cause an error,
|
||||
* then we want to ensure that we do not uiomove bad
|
||||
* or uninitialized data.
|
||||
*/
|
||||
size -= bp->b_resid;
|
||||
if (size < xfersize) {
|
||||
if (size == 0)
|
||||
break;
|
||||
xfersize = size;
|
||||
}
|
||||
error =
|
||||
uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
|
||||
if (error)
|
||||
break;
|
||||
|
||||
bqrelse(bp);
|
||||
}
|
||||
if (bp != NULL)
|
||||
bqrelse(bp);
|
||||
if (orig_resid > 0 && (error == 0 || uio->uio_resid != orig_resid) &&
|
||||
(vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
|
||||
ip->i_flag |= IN_ACCESS;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vnode op for writing.
|
||||
*/
|
||||
static int
|
||||
WRITE(ap)
|
||||
struct vop_write_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp;
|
||||
struct uio *uio;
|
||||
struct inode *ip;
|
||||
FS *fs;
|
||||
struct buf *bp;
|
||||
struct thread *td;
|
||||
daddr_t lbn;
|
||||
off_t osize;
|
||||
int seqcount;
|
||||
int blkoffset, error, flags, ioflag, resid, size, xfersize;
|
||||
|
||||
ioflag = ap->a_ioflag;
|
||||
seqcount = ap->a_ioflag >> IO_SEQSHIFT;
|
||||
uio = ap->a_uio;
|
||||
vp = ap->a_vp;
|
||||
ip = VTOI(vp);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (uio->uio_rw != UIO_WRITE)
|
||||
panic("%s: mode", WRITE_S);
|
||||
#endif
|
||||
|
||||
switch (vp->v_type) {
|
||||
case VREG:
|
||||
if (ioflag & IO_APPEND)
|
||||
uio->uio_offset = ip->i_size;
|
||||
if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
|
||||
return (EPERM);
|
||||
/* FALLTHROUGH */
|
||||
case VLNK:
|
||||
break;
|
||||
case VDIR:
|
||||
if ((ioflag & IO_SYNC) == 0)
|
||||
panic("%s: nonsync dir write", WRITE_S);
|
||||
break;
|
||||
default:
|
||||
panic("%s: type", WRITE_S);
|
||||
}
|
||||
|
||||
fs = ip->I_FS;
|
||||
if (uio->uio_offset < 0 ||
|
||||
(uoff_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize)
|
||||
return (EFBIG);
|
||||
/*
|
||||
* Maybe this should be above the vnode op call, but so long as
|
||||
* file servers have no limits, I don't think it matters.
|
||||
*/
|
||||
td = uio->uio_td;
|
||||
if (vp->v_type == VREG && td != NULL) {
|
||||
PROC_LOCK(td->td_proc);
|
||||
if (uio->uio_offset + uio->uio_resid >
|
||||
lim_cur(td->td_proc, RLIMIT_FSIZE)) {
|
||||
psignal(td->td_proc, SIGXFSZ);
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
return (EFBIG);
|
||||
}
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
}
|
||||
|
||||
resid = uio->uio_resid;
|
||||
osize = ip->i_size;
|
||||
flags = ioflag & IO_SYNC ? B_SYNC : 0;
|
||||
|
||||
for (error = 0; uio->uio_resid > 0;) {
|
||||
lbn = lblkno(fs, uio->uio_offset);
|
||||
blkoffset = blkoff(fs, uio->uio_offset);
|
||||
xfersize = fs->s_frag_size - 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
|
||||
* 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)
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
error =
|
||||
uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
|
||||
if ((ioflag & IO_VMIO) &&
|
||||
(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) {
|
||||
if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0) {
|
||||
bp->b_flags |= B_CLUSTEROK;
|
||||
cluster_write(vp, bp, ip->i_size, seqcount);
|
||||
} else {
|
||||
bawrite(bp);
|
||||
}
|
||||
} else {
|
||||
bp->b_flags |= B_CLUSTEROK;
|
||||
bdwrite(bp);
|
||||
}
|
||||
if (error || xfersize == 0)
|
||||
break;
|
||||
ip->i_flag |= IN_CHANGE | IN_UPDATE;
|
||||
}
|
||||
/*
|
||||
* If we successfully wrote any data, and we are not the superuser
|
||||
* we clear the setuid and setgid bits as a precaution against
|
||||
* tampering.
|
||||
*/
|
||||
if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
|
||||
ip->i_mode &= ~(ISUID | ISGID);
|
||||
if (error) {
|
||||
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);
|
||||
return (error);
|
||||
}
|
||||
|
|
@ -1,120 +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_subr.c 8.2 (Berkeley) 9/21/93
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <sys/proc.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bio.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <gnu/ext2fs/inode.h>
|
||||
#include <gnu/ext2fs/ext2_extern.h>
|
||||
#include <gnu/ext2fs/ext2_fs_sb.h>
|
||||
#include <gnu/ext2fs/fs.h>
|
||||
|
||||
#ifdef KDB
|
||||
void ext2_checkoverlap(struct buf *, struct inode *);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return buffer with the contents of block "offset" from the beginning of
|
||||
* directory "ip". If "res" is non-zero, fill it in with a pointer to the
|
||||
* remaining space in the directory.
|
||||
*/
|
||||
int
|
||||
ext2_blkatoff(vp, offset, res, bpp)
|
||||
struct vnode *vp;
|
||||
off_t offset;
|
||||
char **res;
|
||||
struct buf **bpp;
|
||||
{
|
||||
struct inode *ip;
|
||||
struct ext2_sb_info *fs;
|
||||
struct buf *bp;
|
||||
int32_t lbn;
|
||||
int bsize, error;
|
||||
|
||||
ip = VTOI(vp);
|
||||
fs = ip->i_e2fs;
|
||||
lbn = lblkno(fs, offset);
|
||||
bsize = blksize(fs, ip, lbn);
|
||||
|
||||
*bpp = NULL;
|
||||
if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
if (res)
|
||||
*res = (char *)bp->b_data + blkoff(fs, offset);
|
||||
*bpp = bp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef KDB
|
||||
void
|
||||
ext2_checkoverlap(bp, ip)
|
||||
struct buf *bp;
|
||||
struct inode *ip;
|
||||
{
|
||||
struct buf *ebp, *ep;
|
||||
int32_t start, last;
|
||||
struct vnode *vp;
|
||||
|
||||
ebp = &buf[nbuf];
|
||||
start = bp->b_blkno;
|
||||
last = start + btodb(bp->b_bcount) - 1;
|
||||
for (ep = buf; ep < ebp; ep++) {
|
||||
if (ep == bp || (ep->b_flags & B_INVAL))
|
||||
continue;
|
||||
vp = ip->i_devvp;
|
||||
/* look for overlap */
|
||||
if (ep->b_bcount == 0 || ep->b_blkno > last ||
|
||||
ep->b_blkno + btodb(ep->b_bcount) <= start)
|
||||
continue;
|
||||
vprint("Disk overlap", vp);
|
||||
(void)printf("\tstart %d, end %d overlap start %lld, end %ld\n",
|
||||
start, last, (long long)ep->b_blkno,
|
||||
(long)(ep->b_blkno + btodb(ep->b_bcount) - 1));
|
||||
panic("Disk buffer overlap");
|
||||
}
|
||||
}
|
||||
#endif /* KDB */
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,170 +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
|
||||
*/
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)fs.h 8.7 (Berkeley) 4/19/94
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Each disk drive contains some number of file systems.
|
||||
* A file system consists of a number of cylinder groups.
|
||||
* Each cylinder group has inodes and data.
|
||||
*
|
||||
* A file system is described by its super-block, which in turn
|
||||
* describes the cylinder groups. The super-block is critical
|
||||
* data and is replicated in each cylinder group to protect against
|
||||
* catastrophic loss. This is done at `newfs' time and the critical
|
||||
* super-block data does not change, so the copies need not be
|
||||
* referenced further unless disaster strikes.
|
||||
*
|
||||
* The first boot and super blocks are given in absolute disk addresses.
|
||||
* The byte-offset forms are preferred, as they don't imply a sector size.
|
||||
*/
|
||||
#define SBSIZE 1024
|
||||
#define SBLOCK 2
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
/*
|
||||
* 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))
|
||||
|
||||
/* get group containing inode */
|
||||
#define ino_to_cg(fs, x) (((x) - 1) / EXT2_INODES_PER_GROUP(fs))
|
||||
|
||||
/* 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)
|
||||
|
||||
/* get offset for inode in block */
|
||||
#define ino_to_fsbo(fs, x) ((x-1) % EXT2_INODES_PER_BLOCK(fs))
|
||||
|
||||
/*
|
||||
* 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) / \
|
||||
EXT2_BLOCKS_PER_GROUP(fs))
|
||||
#define dtogd(fs, d) (((d) - fs->s_es->s_first_data_block) % \
|
||||
EXT2_BLOCKS_PER_GROUP(fs))
|
||||
|
||||
/*
|
||||
* The following macros optimize certain frequently calculated
|
||||
* quantities by using shifts and masks in place of divisions
|
||||
* modulos and multiplications.
|
||||
*/
|
||||
#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
|
||||
((loc) & (fs)->s_qbmask)
|
||||
|
||||
#define lblktosize(fs, blk) /* calculates (blk * fs->fs_bsize) */ \
|
||||
((blk) << (fs->s_bshift))
|
||||
|
||||
#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
|
||||
((loc) >> (fs->s_bshift))
|
||||
|
||||
/* no fragments -> logical block number equal # of frags */
|
||||
#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \
|
||||
((loc) >> (fs->s_bshift))
|
||||
|
||||
#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
|
||||
roundup(size, fs->s_frag_size)
|
||||
/* 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)
|
||||
|
||||
/*
|
||||
* INOPB is the number of inodes in a secondary storage block.
|
||||
*/
|
||||
#define INOPB(fs) EXT2_INODES_PER_BLOCK(fs)
|
||||
|
||||
/*
|
||||
* NINDIR is the number of indirects in a file system block.
|
||||
*/
|
||||
#define NINDIR(fs) (EXT2_ADDR_PER_BLOCK(fs))
|
||||
|
||||
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, curthread)
|
||||
#define unlock_super(devvp) VOP_UNLOCK(devvp, 0, curthread)
|
||||
|
||||
/*
|
||||
* Historically, ext2fs kept it's metadata buffers on the LOCKED queue. Now,
|
||||
* we simply change the lock owner to kern so that it may be released from
|
||||
* another context. Later, we release the buffer, and conditionally write it
|
||||
* when we're done.
|
||||
*/
|
||||
#define LCK_BUF(bp) BUF_KERNPROC(bp);
|
||||
|
||||
#define ULCK_BUF(bp) { \
|
||||
long flags; \
|
||||
int s; \
|
||||
s = splbio(); \
|
||||
flags = (bp)->b_flags; \
|
||||
(bp)->b_flags &= ~(B_DIRTY); \
|
||||
splx(s); \
|
||||
if (flags & B_DIRTY) \
|
||||
bwrite(bp); \
|
||||
else \
|
||||
brelse(bp); \
|
||||
}
|
||||
|
|
@ -1,162 +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
|
||||
*/
|
||||
#ifndef _SYS_GNU_EXT2FS_I386_BITOPS_H_
|
||||
#define _SYS_GNU_EXT2FS_I386_BITOPS_H_
|
||||
|
||||
/*-
|
||||
* Copyright 1992, Linus Torvalds.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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_ */
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 1982, 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 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.
|
||||
*
|
||||
* @(#)inode.h 8.9 (Berkeley) 5/14/95
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _SYS_GNU_EXT2FS_INODE_H_
|
||||
#define _SYS_GNU_EXT2FS_INODE_H_
|
||||
|
||||
#include <sys/lock.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#define ROOTINO ((ino_t)2)
|
||||
|
||||
#define NDADDR 12 /* Direct addresses in inode. */
|
||||
#define NIADDR 3 /* Indirect addresses in inode. */
|
||||
|
||||
/*
|
||||
* This must agree with the definition in <ufs/ufs/dir.h>.
|
||||
*/
|
||||
#define doff_t int32_t
|
||||
|
||||
/*
|
||||
* The inode is used to describe each active (or recently active) file in the
|
||||
* EXT2FS filesystem. It is composed of two types of information. The first
|
||||
* part is the information that is needed only while the file is active (such
|
||||
* as the identity of the file and linkage to speed its lookup). The second
|
||||
* part is the permanent meta-data associated with the file which is read in
|
||||
* from the permanent dinode from long term storage when the file becomes
|
||||
* active, and is put back when the file is no longer being used.
|
||||
*/
|
||||
struct inode {
|
||||
struct vnode *i_vnode;/* Vnode associated with this inode. */
|
||||
struct vnode *i_devvp;/* Vnode for block I/O. */
|
||||
u_int32_t i_flag; /* flags, see below */
|
||||
ino_t i_number; /* The identity of the inode. */
|
||||
|
||||
struct ext2_sb_info *i_e2fs; /* EXT2FS */
|
||||
u_quad_t i_modrev; /* Revision level for NFS lease. */
|
||||
struct lockf *i_lockf;/* Head of byte-level lock list. */
|
||||
/*
|
||||
* Side effects; used during directory lookup.
|
||||
*/
|
||||
int32_t i_count; /* Size of free slot in directory. */
|
||||
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;
|
||||
u_int32_t i_next_alloc_goal;
|
||||
u_int32_t i_prealloc_block;
|
||||
u_int32_t i_prealloc_count;
|
||||
|
||||
/* Fields from struct dinode in UFS. */
|
||||
u_int16_t i_mode; /* IFMT, permissions; see below. */
|
||||
int16_t i_nlink; /* File link count. */
|
||||
u_int64_t i_size; /* File byte count. */
|
||||
int32_t i_atime; /* Last access time. */
|
||||
int32_t i_atimensec; /* Last access time. */
|
||||
int32_t i_mtime; /* Last modified time. */
|
||||
int32_t i_mtimensec; /* Last modified time. */
|
||||
int32_t i_ctime; /* Last inode change time. */
|
||||
int32_t i_ctimensec; /* Last inode change time. */
|
||||
int32_t i_db[NDADDR]; /* Direct disk blocks. */
|
||||
int32_t i_ib[NIADDR]; /* Indirect disk blocks. */
|
||||
u_int32_t i_flags; /* Status flags (chflags). */
|
||||
int32_t i_blocks; /* Blocks actually held. */
|
||||
int32_t i_gen; /* Generation number. */
|
||||
u_int32_t i_uid; /* File owner. */
|
||||
u_int32_t i_gid; /* File group. */
|
||||
};
|
||||
|
||||
/*
|
||||
* The di_db fields may be overlaid with other information for
|
||||
* file types that do not have associated disk storage. Block
|
||||
* and character devices overlay the first data block with their
|
||||
* dev_t value. Short symbolic links place their path in the
|
||||
* di_db area.
|
||||
*/
|
||||
#define i_shortlink i_db
|
||||
#define i_rdev i_db[0]
|
||||
#define MAXSYMLINKLEN ((NDADDR + NIADDR) * sizeof(int32_t))
|
||||
|
||||
/* File permissions. */
|
||||
#define IEXEC 0000100 /* Executable. */
|
||||
#define IWRITE 0000200 /* Writeable. */
|
||||
#define IREAD 0000400 /* Readable. */
|
||||
#define ISVTX 0001000 /* Sticky bit. */
|
||||
#define ISGID 0002000 /* Set-gid. */
|
||||
#define ISUID 0004000 /* Set-uid. */
|
||||
|
||||
/* File types. */
|
||||
#define IFMT 0170000 /* Mask of file type. */
|
||||
#define IFIFO 0010000 /* Named pipe (fifo). */
|
||||
#define IFCHR 0020000 /* Character device. */
|
||||
#define IFDIR 0040000 /* Directory file. */
|
||||
#define IFBLK 0060000 /* Block device. */
|
||||
#define IFREG 0100000 /* Regular file. */
|
||||
#define IFLNK 0120000 /* Symbolic link. */
|
||||
#define IFSOCK 0140000 /* UNIX domain socket. */
|
||||
#define IFWHT 0160000 /* Whiteout. */
|
||||
|
||||
/* These flags are kept in i_flag. */
|
||||
#define IN_ACCESS 0x0001 /* Access time update request. */
|
||||
#define IN_CHANGE 0x0002 /* Inode change time update request. */
|
||||
#define IN_UPDATE 0x0004 /* Modification time update request. */
|
||||
#define IN_MODIFIED 0x0008 /* Inode has been modified. */
|
||||
#define IN_RENAME 0x0010 /* Inode is being renamed. */
|
||||
#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. */
|
||||
|
||||
#ifdef _KERNEL
|
||||
/*
|
||||
* Structure used to pass around logical block paths generated by
|
||||
* ext2_getlbns and used by truncate and bmap code.
|
||||
*/
|
||||
struct indir {
|
||||
int32_t in_lbn; /* Logical block number. */
|
||||
int in_off; /* Offset in buffer. */
|
||||
int in_exists; /* Flag if the block exists. */
|
||||
};
|
||||
|
||||
/* Convert between inode pointers and vnode pointers. */
|
||||
#define VTOI(vp) ((struct inode *)(vp)->v_data)
|
||||
#define ITOV(ip) ((ip)->i_vnode)
|
||||
|
||||
/* This overlays the fid structure (see mount.h). */
|
||||
struct ufid {
|
||||
u_int16_t ufid_len; /* Length of structure. */
|
||||
u_int16_t ufid_pad; /* Force 32-bit alignment. */
|
||||
ino_t ufid_ino; /* File number (ino). */
|
||||
int32_t ufid_gen; /* Generation number. */
|
||||
};
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* !_SYS_GNU_EXT2FS_INODE_H_ */
|
||||
|
|
@ -1,250 +0,0 @@
|
|||
/*-
|
||||
* $Id: bitops.h,v 1.31 2000/09/23 02:09:21 davem Exp $
|
||||
* bitops.h: Bit string operations on the V9.
|
||||
*
|
||||
* Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
|
||||
*/
|
||||
|
||||
/* $FreeBSD$ */
|
||||
#ifndef _SPARC64_BITOPS_H
|
||||
#define _SPARC64_BITOPS_H
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
extern long __test_and_set_bit(unsigned long nr, volatile void *addr);
|
||||
extern long __test_and_clear_bit(unsigned long nr, volatile void *addr);
|
||||
extern long __test_and_change_bit(unsigned long nr, volatile void *addr);
|
||||
|
||||
#define test_and_set_bit(nr,addr) (__test_and_set_bit(nr,addr)!=0)
|
||||
#define test_and_clear_bit(nr,addr) (__test_and_clear_bit(nr,addr)!=0)
|
||||
#define test_and_change_bit(nr,addr) (__test_and_change_bit(nr,addr)!=0)
|
||||
#define set_bit(nr,addr) ((void)__test_and_set_bit(nr,addr))
|
||||
#define clear_bit(nr,addr) ((void)__test_and_clear_bit(nr,addr))
|
||||
#define change_bit(nr,addr) ((void)__test_and_change_bit(nr,addr))
|
||||
|
||||
#define smp_mb__before_clear_bit() do { } while(0)
|
||||
#define smp_mb__after_clear_bit() do { } while(0)
|
||||
|
||||
extern __inline__ int test_bit(int nr, __const__ void *addr)
|
||||
{
|
||||
return (1UL & (((__const__ long *) addr)[nr >> 6] >> (nr & 63))) != 0UL;
|
||||
}
|
||||
|
||||
/* The easy/cheese version for now. */
|
||||
extern __inline__ unsigned long ffz(unsigned long word)
|
||||
{
|
||||
unsigned long result;
|
||||
|
||||
#ifdef ULTRA_HAS_POPULATION_COUNT /* Thanks for nothing Sun... */
|
||||
__asm__ __volatile__("
|
||||
brz,pn %0, 1f
|
||||
neg %0, %%g1
|
||||
xnor %0, %%g1, %%g2
|
||||
popc %%g2, %0
|
||||
1: " : "=&r" (result)
|
||||
: "0" (word)
|
||||
: "g1", "g2");
|
||||
#else
|
||||
#if 1 /* def EASY_CHEESE_VERSION */
|
||||
result = 0;
|
||||
while(word & 1) {
|
||||
result++;
|
||||
word >>= 1;
|
||||
}
|
||||
#else
|
||||
unsigned long tmp;
|
||||
|
||||
result = 0;
|
||||
tmp = ~word & -~word;
|
||||
if (!(unsigned)tmp) {
|
||||
tmp >>= 32;
|
||||
result = 32;
|
||||
}
|
||||
if (!(unsigned short)tmp) {
|
||||
tmp >>= 16;
|
||||
result += 16;
|
||||
}
|
||||
if (!(unsigned char)tmp) {
|
||||
tmp >>= 8;
|
||||
result += 8;
|
||||
}
|
||||
if (tmp & 0xf0) result += 4;
|
||||
if (tmp & 0xcc) result += 2;
|
||||
if (tmp & 0xaa) result ++;
|
||||
#endif
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/*
|
||||
* ffs: find first bit set. This is defined the same way as
|
||||
* the libc and compiler builtin ffs routines, therefore
|
||||
* differs in spirit from the above ffz (man ffs).
|
||||
*/
|
||||
|
||||
#define ffs(x) generic_ffs(x)
|
||||
|
||||
/*
|
||||
* hweightN: returns the hamming weight (i.e. the number
|
||||
* of bits set) of a N-bit word
|
||||
*/
|
||||
|
||||
#ifdef ULTRA_HAS_POPULATION_COUNT
|
||||
|
||||
extern __inline__ unsigned int hweight32(unsigned int w)
|
||||
{
|
||||
unsigned int res;
|
||||
|
||||
__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffffffff));
|
||||
return res;
|
||||
}
|
||||
|
||||
extern __inline__ unsigned int hweight16(unsigned int w)
|
||||
{
|
||||
unsigned int res;
|
||||
|
||||
__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffff));
|
||||
return res;
|
||||
}
|
||||
|
||||
extern __inline__ unsigned int hweight8(unsigned int w)
|
||||
{
|
||||
unsigned int res;
|
||||
|
||||
__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xff));
|
||||
return res;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define hweight32(x) generic_hweight32(x)
|
||||
#define hweight16(x) generic_hweight16(x)
|
||||
#define hweight8(x) generic_hweight8(x)
|
||||
|
||||
#endif
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
/* find_next_zero_bit() finds the first zero bit in a bit string of length
|
||||
* 'size' bits, starting the search at bit 'offset'. This is largely based
|
||||
* on Linus's ALPHA routines, which are pretty portable BTW.
|
||||
*/
|
||||
|
||||
extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
|
||||
{
|
||||
unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
|
||||
unsigned long result = offset & ~63UL;
|
||||
unsigned long tmp;
|
||||
|
||||
if (offset >= size)
|
||||
return size;
|
||||
size -= result;
|
||||
offset &= 63UL;
|
||||
if (offset) {
|
||||
tmp = *(p++);
|
||||
tmp |= ~0UL >> (64-offset);
|
||||
if (size < 64)
|
||||
goto found_first;
|
||||
if (~tmp)
|
||||
goto found_middle;
|
||||
size -= 64;
|
||||
result += 64;
|
||||
}
|
||||
while (size & ~63UL) {
|
||||
if (~(tmp = *(p++)))
|
||||
goto found_middle;
|
||||
result += 64;
|
||||
size -= 64;
|
||||
}
|
||||
if (!size)
|
||||
return result;
|
||||
tmp = *p;
|
||||
|
||||
found_first:
|
||||
tmp |= ~0UL << size;
|
||||
if (tmp == ~0UL) /* Are any bits zero? */
|
||||
return result + size; /* Nope. */
|
||||
found_middle:
|
||||
return result + ffz(tmp);
|
||||
}
|
||||
|
||||
#define find_first_zero_bit(addr, size) \
|
||||
find_next_zero_bit((addr), (size), 0)
|
||||
|
||||
extern long __test_and_set_le_bit(int nr, volatile void *addr);
|
||||
extern long __test_and_clear_le_bit(int nr, volatile void *addr);
|
||||
|
||||
#define test_and_set_le_bit(nr,addr) (__test_and_set_le_bit(nr,addr)!=0)
|
||||
#define test_and_clear_le_bit(nr,addr) (__test_and_clear_le_bit(nr,addr)!=0)
|
||||
#define set_le_bit(nr,addr) ((void)__test_and_set_le_bit(nr,addr))
|
||||
#define clear_le_bit(nr,addr) ((void)__test_and_clear_le_bit(nr,addr))
|
||||
|
||||
extern __inline__ int test_le_bit(int nr, __const__ void * addr)
|
||||
{
|
||||
int mask;
|
||||
__const__ unsigned char *ADDR = (__const__ unsigned char *) addr;
|
||||
|
||||
ADDR += nr >> 3;
|
||||
mask = 1 << (nr & 0x07);
|
||||
return ((mask & *ADDR) != 0);
|
||||
}
|
||||
|
||||
#define find_first_zero_le_bit(addr, size) \
|
||||
find_next_zero_le_bit((addr), (size), 0)
|
||||
|
||||
extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
|
||||
{
|
||||
unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
|
||||
unsigned long result = offset & ~63UL;
|
||||
unsigned long tmp;
|
||||
|
||||
if (offset >= size)
|
||||
return size;
|
||||
size -= result;
|
||||
offset &= 63UL;
|
||||
if(offset) {
|
||||
tmp = __swab64p(p++);
|
||||
tmp |= (~0UL >> (64-offset));
|
||||
if(size < 64)
|
||||
goto found_first;
|
||||
if(~tmp)
|
||||
goto found_middle;
|
||||
size -= 64;
|
||||
result += 64;
|
||||
}
|
||||
while(size & ~63) {
|
||||
if(~(tmp = __swab64p(p++)))
|
||||
goto found_middle;
|
||||
result += 64;
|
||||
size -= 64;
|
||||
}
|
||||
if(!size)
|
||||
return result;
|
||||
tmp = __swab64p(p);
|
||||
found_first:
|
||||
tmp |= (~0UL << size);
|
||||
if (tmp == ~0UL) /* Are any bits zero? */
|
||||
return result + size; /* Nope. */
|
||||
found_middle:
|
||||
return result + ffz(tmp);
|
||||
}
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ext2_set_bit test_and_set_le_bit
|
||||
#define ext2_clear_bit test_and_clear_le_bit
|
||||
#define ext2_test_bit test_le_bit
|
||||
#define ext2_find_first_zero_bit find_first_zero_le_bit
|
||||
#define ext2_find_next_zero_bit find_next_zero_le_bit
|
||||
|
||||
/* Bitmap functions for the minix filesystem. */
|
||||
#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
|
||||
#define minix_set_bit(nr,addr) set_bit(nr,addr)
|
||||
#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
|
||||
#define minix_test_bit(nr,addr) test_bit(nr,addr)
|
||||
#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* defined(_SPARC64_BITOPS_H) */
|
||||
Loading…
Reference in a new issue