tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
updated patch Re: buffer cache & ufs changes (preliminary ffsv2 extattr support)
On Sun, Jan 15, 2012 at 09:37:14PM +0100, Martin Husemann wrote:
> On Sun, Jan 15, 2012 at 08:37:37PM +0100, Manuel Bouyer wrote:
> > Althrough I've done 1 as a POC, I prefer solution 2 (the patch is mostly the
> > same, with bflag remplaced by b_type). What do other think ?
>
> (2) is conceptually what NTFS does IIUC. Consider a file to be a database
> table to which arbitrary columns may be added, with column 0 containing all
> the traditional octets, and some columns having special meaning.
>
> I am not sure I like the idea, but it clearly is superior to option (1).
So we're in agreement :)
Here's a new patch, with a type member added to struct buf.
More buffer functions have their prototype changed (bread2 and breadn2).
b_type is 0 by default.
There is more changes in sys/ufs; in the previous patch the information was
passed as part of an existing flags parameter, now an extra parameter is
needed. This includes UFS_BALLOC() macro and the associated uo_balloc()
function pointer (and related functions in ffs/ and lfs/).
I though sys/ufs/ufs was always compiled in kernel; in fact it's part
of the ffs module so we probably don't need to commit code now
in order to avoid a mess with filesystem modules when the changes
are pulled up to the branch: only adding the new fields to struct buf
and struct inode should be enough to ensure backward compat for
modules (the only users of UFS_BALLOC() are ffs and lfs; I consider lfs
second-class citizen at this time and if forward compat if broken for
the lfs module on the branch it's probably not a big deal).
What I propose to commit before the branch is limited to the netbsd6.diff
file attached. As the new fields are not used, it should cause only limited
issues (or something is really badly brocken).
--
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
NetBSD: 26 ans d'experience feront toujours la difference
--
Index: sys/kern/vfs_bio.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_bio.c,v
retrieving revision 1.232
diff -u -r1.232 vfs_bio.c
--- sys/kern/vfs_bio.c 5 Oct 2011 01:53:03 -0000 1.232
+++ sys/kern/vfs_bio.c 16 Jan 2012 20:36:27 -0000
@@ -172,7 +172,7 @@
static void *bufpool_page_alloc(struct pool *, int);
static void bufpool_page_free(struct pool *, void *);
static buf_t *bio_doread(struct vnode *, daddr_t, int,
- kauth_cred_t, int);
+ kauth_cred_t, int, int);
static buf_t *getnewbuf(int, int, int);
static int buf_lotsfree(void);
static int buf_canrelease(void);
@@ -656,12 +656,12 @@
*/
static buf_t *
bio_doread(struct vnode *vp, daddr_t blkno, int size, kauth_cred_t cred,
- int async)
+ int async, int type)
{
buf_t *bp;
struct mount *mp;
- bp = getblk(vp, blkno, size, 0, 0);
+ bp = getblk2(vp, blkno, size, 0, 0, type);
#ifdef DIAGNOSTIC
if (bp == NULL) {
@@ -716,11 +716,18 @@
bread(struct vnode *vp, daddr_t blkno, int size, kauth_cred_t cred,
int flags, buf_t **bpp)
{
+ return bread2(vp, blkno, size, cred, flags, 0, bpp);
+}
+
+int
+bread2(struct vnode *vp, daddr_t blkno, int size, kauth_cred_t cred,
+ int flags, int type, buf_t **bpp)
+{
buf_t *bp;
int error;
/* Get buffer for block. */
- bp = *bpp = bio_doread(vp, blkno, size, cred, 0);
+ bp = *bpp = bio_doread(vp, blkno, size, cred, 0, type);
/* Wait for the read to complete, and return result. */
error = biowait(bp);
@@ -738,10 +745,19 @@
breadn(struct vnode *vp, daddr_t blkno, int size, daddr_t *rablks,
int *rasizes, int nrablks, kauth_cred_t cred, int flags, buf_t **bpp)
{
+ return breadn2(vp, blkno, size, rablks, rasizes, nrablks, cred,
+ flags, 0, bpp);
+}
+
+int
+breadn2(struct vnode *vp, daddr_t blkno, int size, daddr_t *rablks,
+ int *rasizes, int nrablks, kauth_cred_t cred, int flags, int type,
+ buf_t **bpp)
+{
buf_t *bp;
int error, i;
- bp = *bpp = bio_doread(vp, blkno, size, cred, 0);
+ bp = *bpp = bio_doread(vp, blkno, size, cred, 0, type);
/*
* For each of the read-ahead blocks, start a read, if necessary.
@@ -749,12 +765,13 @@
mutex_enter(&bufcache_lock);
for (i = 0; i < nrablks; i++) {
/* If it's in the cache, just go on to next one. */
- if (incore(vp, rablks[i]))
+ if (incore2(vp, rablks[i], type))
continue;
/* Get a buffer for the read-ahead block */
mutex_exit(&bufcache_lock);
- (void) bio_doread(vp, rablks[i], rasizes[i], cred, B_ASYNC);
+ (void) bio_doread(vp, rablks[i], rasizes[i], cred,
+ B_ASYNC, type);
mutex_enter(&bufcache_lock);
}
mutex_exit(&bufcache_lock);
@@ -1099,6 +1116,12 @@
buf_t *
incore(struct vnode *vp, daddr_t blkno)
{
+ return incore2(vp, blkno, 0);
+}
+
+buf_t *
+incore2(struct vnode *vp, daddr_t blkno, int type)
+{
buf_t *bp;
KASSERT(mutex_owned(&bufcache_lock));
@@ -1106,6 +1129,7 @@
/* Search hash chain */
LIST_FOREACH(bp, BUFHASH(vp, blkno), b_hash) {
if (bp->b_lblkno == blkno && bp->b_vp == vp &&
+ bp->b_type == type &&
!ISSET(bp->b_cflags, BC_INVAL)) {
KASSERT(bp->b_objlock == vp->v_interlock);
return (bp);
@@ -1126,12 +1150,19 @@
buf_t *
getblk(struct vnode *vp, daddr_t blkno, int size, int slpflag, int slptimeo)
{
+ return getblk2(vp, blkno, size, slpflag, slptimeo, 0);
+}
+
+buf_t *
+getblk2(struct vnode *vp, daddr_t blkno, int size, int slpflag, int slptimeo,
+ int type)
+{
int err, preserve;
buf_t *bp;
mutex_enter(&bufcache_lock);
loop:
- bp = incore(vp, blkno);
+ bp = incore2(vp, blkno, type);
if (bp != NULL) {
err = bbusy(bp, ((slpflag & PCATCH) != 0), slptimeo, NULL);
if (err != 0) {
@@ -1152,7 +1183,7 @@
if ((bp = getnewbuf(slpflag, slptimeo, 0)) == NULL)
goto loop;
- if (incore(vp, blkno) != NULL) {
+ if (incore2(vp, blkno, type) != NULL) {
/* The block has come into memory in the meantime. */
brelsel(bp, 0);
goto loop;
@@ -1160,6 +1191,7 @@
LIST_INSERT_HEAD(BUFHASH(vp, blkno), bp, b_hash);
bp->b_blkno = bp->b_lblkno = bp->b_rawblkno = blkno;
+ bp->b_type = type;
mutex_enter(vp->v_interlock);
bgetvp(vp, bp);
mutex_exit(vp->v_interlock);
Index: sys/kern/vfs_subr.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_subr.c,v
retrieving revision 1.426
diff -u -r1.426 vfs_subr.c
--- sys/kern/vfs_subr.c 2 Dec 2011 12:32:38 -0000 1.426
+++ sys/kern/vfs_subr.c 16 Jan 2012 20:36:27 -0000
@@ -224,6 +224,12 @@
int
vtruncbuf(struct vnode *vp, daddr_t lbn, bool catch, int slptimeo)
{
+ return vtruncbuf2(vp, lbn, catch, slptimeo, 0);
+}
+
+int
+vtruncbuf2(struct vnode *vp, daddr_t lbn, bool catch, int slptimeo, int type)
+{
struct buf *bp, *nbp;
int error;
voff_t off;
@@ -240,6 +246,8 @@
for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
KASSERT(bp->b_vp == vp);
nbp = LIST_NEXT(bp, b_vnbufs);
+ if (bp->b_type != type)
+ continue;
if (bp->b_lblkno < lbn)
continue;
error = bbusy(bp, catch, slptimeo, NULL);
@@ -255,6 +263,8 @@
for (bp = LIST_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) {
KASSERT(bp->b_vp == vp);
nbp = LIST_NEXT(bp, b_vnbufs);
+ if (bp->b_type != type)
+ continue;
if (bp->b_lblkno < lbn)
continue;
error = bbusy(bp, catch, slptimeo, NULL);
Index: sys/sys/buf.h
===================================================================
RCS file: /cvsroot/src/sys/sys/buf.h,v
retrieving revision 1.118
diff -u -r1.118 buf.h
--- sys/sys/buf.h 21 Nov 2011 04:36:05 -0000 1.118
+++ sys/sys/buf.h 16 Jan 2012 20:36:39 -0000
@@ -113,6 +113,7 @@
int b_error; /* b: errno value. */
int b_resid; /* b: remaining I/O. */
u_int b_flags; /* b: B_* flags */
+ int b_type; /* b: data type */
int b_prio; /* b: priority for queue */
int b_bufsize; /* b: allocated size */
int b_bcount; /* b: valid bytes in buffer */
@@ -266,8 +267,11 @@
void biodone(buf_t *);
int biowait(buf_t *);
int bread(struct vnode *, daddr_t, int, struct kauth_cred *, int, buf_t **);
+int bread2(struct vnode *, daddr_t, int, struct kauth_cred *, int, int,
buf_t **);
int breadn(struct vnode *, daddr_t, int, daddr_t *, int *, int,
struct kauth_cred *, int, buf_t **);
+int breadn2(struct vnode *, daddr_t, int, daddr_t *, int *, int,
+ struct kauth_cred *, int, int, buf_t **);
void brelsel(buf_t *, int);
void brelse(buf_t *, int);
void bremfree(buf_t *);
@@ -275,8 +279,10 @@
void bufinit2(void);
int bwrite(buf_t *);
buf_t *getblk(struct vnode *, daddr_t, int, int, int);
+buf_t *getblk2(struct vnode *, daddr_t, int, int, int, int);
buf_t *geteblk(int);
buf_t *incore(struct vnode *, daddr_t);
+buf_t *incore2(struct vnode *, daddr_t, int);
void minphys(buf_t *);
int physio(void (*)(buf_t *), buf_t *, dev_t, int,
Index: sys/sys/vnode.h
===================================================================
RCS file: /cvsroot/src/sys/sys/vnode.h,v
retrieving revision 1.236
diff -u -r1.236 vnode.h
--- sys/sys/vnode.h 24 Nov 2011 15:51:30 -0000 1.236
+++ sys/sys/vnode.h 16 Jan 2012 20:36:39 -0000
@@ -564,6 +564,7 @@
void vrele_async(struct vnode *);
void vrele_flush(void);
int vtruncbuf(struct vnode *, daddr_t, bool, int);
+int vtruncbuf2(struct vnode *, daddr_t, bool, int, int);
void vwakeup(struct buf *);
void vwait(struct vnode *, int);
void vclean(struct vnode *, int);
Index: sys/ufs/ffs/ffs_alloc.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_alloc.c,v
retrieving revision 1.130
diff -u -r1.130 ffs_alloc.c
--- sys/ufs/ffs/ffs_alloc.c 28 Nov 2011 08:05:07 -0000 1.130
+++ sys/ufs/ffs/ffs_alloc.c 16 Jan 2012 20:36:39 -0000
@@ -303,7 +303,8 @@
*/
int
ffs_realloccg(struct inode *ip, daddr_t lbprev, daddr_t bpref, int osize,
- int nsize, kauth_cred_t cred, struct buf **bpp, daddr_t *blknop)
+ int nsize, kauth_cred_t cred, int type,
+ struct buf **bpp, daddr_t *blknop)
{
struct ufsmount *ump;
struct fs *fs;
@@ -364,10 +365,22 @@
mutex_exit(&ump->um_lock);
goto nospace;
}
- if (fs->fs_magic == FS_UFS2_MAGIC)
- bprev = ufs_rw64(ip->i_ffs2_db[lbprev], UFS_FSNEEDSWAP(fs));
- else
- bprev = ufs_rw32(ip->i_ffs1_db[lbprev], UFS_FSNEEDSWAP(fs));
+ if (type == BTYPE_EXTDATA) {
+ if (fs->fs_magic == FS_UFS2_MAGIC) {
+ bprev = ufs_rw64(ip->i_ffs2_extb[lbprev],
+ UFS_FSNEEDSWAP(fs));
+ } else {
+ panic("ffs_realloccg: BTYPE_EXTDATA");
+ }
+ } else {
+ if (fs->fs_magic == FS_UFS2_MAGIC) {
+ bprev = ufs_rw64(ip->i_ffs2_db[lbprev],
+ UFS_FSNEEDSWAP(fs));
+ } else {
+ bprev = ufs_rw32(ip->i_ffs1_db[lbprev],
+ UFS_FSNEEDSWAP(fs));
+ }
+ }
if (bprev == 0) {
printf("dev = 0x%llx, bsize = %d, bprev = %" PRId64 ", fs =
%s\n",
@@ -381,7 +394,8 @@
* Allocate the extra space in the buffer.
*/
if (bpp != NULL &&
- (error = bread(ITOV(ip), lbprev, osize, NOCRED, 0, &bp)) != 0) {
+ (error = bread2(ITOV(ip), lbprev, osize, NOCRED, 0,
+ type, &bp)) != 0) {
brelse(bp, 0);
return (error);
}
@@ -479,7 +493,7 @@
bno = ffs_hashalloc(ip, cg, bpref, request, 0, ffs_alloccg);
if (bno > 0) {
if ((ip->i_ump->um_mountp->mnt_wapbl) &&
- (ITOV(ip)->v_type != VREG)) {
+ ((ITOV(ip)->v_type != VREG) || type == BTYPE_EXTDATA)) {
UFS_WAPBL_REGISTER_DEALLOCATION(
ip->i_ump->um_mountp, fsbtodb(fs, bprev),
osize);
@@ -489,7 +503,8 @@
}
if (nsize < request) {
if ((ip->i_ump->um_mountp->mnt_wapbl) &&
- (ITOV(ip)->v_type != VREG)) {
+ ((ITOV(ip)->v_type != VREG) ||
+ type == BTYPE_EXTDATA)) {
UFS_WAPBL_REGISTER_DEALLOCATION(
ip->i_ump->um_mountp,
fsbtodb(fs, (bno + numfrags(fs, nsize))),
@@ -1333,7 +1348,7 @@
bp = NULL;
error = ffs_getblk(ip->i_devvp, fsbtodb(fs,
ino_to_fsba(fs, cg * fs->fs_ipg + initediblk)),
- FFS_NOBLK, fs->fs_bsize, false, &ibp);
+ FFS_NOBLK, fs->fs_bsize, false, BTYPE_DATA, &ibp);
if (error)
goto fail;
goto retry;
Index: sys/ufs/ffs/ffs_balloc.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_balloc.c,v
retrieving revision 1.54
diff -u -r1.54 ffs_balloc.c
--- sys/ufs/ffs/ffs_balloc.c 23 Apr 2011 07:36:02 -0000 1.54
+++ sys/ufs/ffs/ffs_balloc.c 16 Jan 2012 20:36:39 -0000
@@ -67,9 +67,9 @@
#include <uvm/uvm.h>
-static int ffs_balloc_ufs1(struct vnode *, off_t, int, kauth_cred_t, int,
+static int ffs_balloc_ufs1(struct vnode *, off_t, int, kauth_cred_t, int, int,
struct buf **);
-static int ffs_balloc_ufs2(struct vnode *, off_t, int, kauth_cred_t, int,
+static int ffs_balloc_ufs2(struct vnode *, off_t, int, kauth_cred_t, int, int,
struct buf **);
/*
@@ -80,14 +80,14 @@
int
ffs_balloc(struct vnode *vp, off_t off, int size, kauth_cred_t cred, int flags,
- struct buf **bpp)
+ int type, struct buf **bpp)
{
int error;
if (VTOI(vp)->i_fs->fs_magic == FS_UFS2_MAGIC)
- error = ffs_balloc_ufs2(vp, off, size, cred, flags, bpp);
+ error = ffs_balloc_ufs2(vp, off, size, cred, flags, type, bpp);
else
- error = ffs_balloc_ufs1(vp, off, size, cred, flags, bpp);
+ error = ffs_balloc_ufs1(vp, off, size, cred, flags, type, bpp);
if (error == 0 && bpp != NULL && (error = fscow_run(*bpp, false)) != 0)
brelse(*bpp, 0);
@@ -97,7 +97,7 @@
static int
ffs_balloc_ufs1(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
- int flags, struct buf **bpp)
+ int flags, int type, struct buf **bpp)
{
daddr_t lbn, lastlbn;
struct buf *bp, *nbp;
@@ -125,6 +125,9 @@
}
UVMHIST_LOG(ubchist, "vp %p lbn 0x%x size 0x%x", vp, lbn, size,0);
+ if (type != BTYPE_DATA)
+ return (EOPNOTSUPP);
+
if (lbn < 0)
return (EFBIG);
@@ -143,7 +146,8 @@
error = ffs_realloccg(ip, nb,
ffs_blkpref_ufs1(ip, lastlbn, nb, flags,
&ip->i_ffs1_db[0]),
- osize, (int)fs->fs_bsize, cred, bpp, &newb);
+ osize, (int)fs->fs_bsize, cred,
+ BTYPE_DATA, bpp, &newb);
if (error)
return (error);
ip->i_size = lblktosize(fs, nb + 1);
@@ -220,7 +224,8 @@
error = ffs_realloccg(ip, lbn,
ffs_blkpref_ufs1(ip, lbn, (int)lbn, flags,
&ip->i_ffs1_db[0]),
- osize, nsize, cred, bpp, &newb);
+ osize, nsize, cred,
+ BTYPE_DATA, bpp, &newb);
if (error)
return (error);
}
@@ -244,7 +249,8 @@
return (error);
if (bpp != NULL) {
error = ffs_getblk(vp, lbn, fsbtodb(fs, newb),
- nsize, (flags & B_CLRBUF) != 0, bpp);
+ nsize, (flags & B_CLRBUF) != 0,
+ BTYPE_DATA, bpp);
if (error)
return error;
}
@@ -280,7 +286,7 @@
nb = newb;
*allocblk++ = nb;
error = ffs_getblk(vp, indirs[1].in_lbn, fsbtodb(fs, nb),
- fs->fs_bsize, true, &bp);
+ fs->fs_bsize, true, BTYPE_DATA, &bp);
if (error)
goto fail;
/*
@@ -336,7 +342,7 @@
nb = newb;
*allocblk++ = nb;
error = ffs_getblk(vp, indirs[i].in_lbn, fsbtodb(fs, nb),
- fs->fs_bsize, true, &nbp);
+ fs->fs_bsize, true, BTYPE_DATA, &nbp);
if (error) {
brelse(bp, 0);
goto fail;
@@ -393,7 +399,8 @@
*allocblk++ = nb;
if (bpp != NULL) {
error = ffs_getblk(vp, lbn, fsbtodb(fs, nb),
- fs->fs_bsize, (flags & B_CLRBUF) != 0, bpp);
+ fs->fs_bsize, (flags & B_CLRBUF) != 0,
+ BTYPE_DATA, bpp);
if (error) {
brelse(bp, 0);
goto fail;
@@ -427,7 +434,7 @@
}
} else {
error = ffs_getblk(vp, lbn, fsbtodb(fs, nb),
- fs->fs_bsize, true, &nbp);
+ fs->fs_bsize, true, BTYPE_DATA, &nbp);
if (error)
goto fail;
}
@@ -455,14 +462,14 @@
break;
}
if (ffs_getblk(vp, indirs[i].in_lbn, FFS_NOBLK,
- fs->fs_bsize, false, &bp) != 0)
+ fs->fs_bsize, false, BTYPE_DATA, &bp) != 0)
continue;
if (bp->b_oflags & BO_DELWRI) {
nb = fsbtodb(fs, cgtod(fs, dtog(fs,
dbtofsb(fs, bp->b_blkno))));
bwrite(bp);
if (ffs_getblk(ip->i_devvp, nb, FFS_NOBLK,
- fs->fs_cgsize, false, &bp) != 0)
+ fs->fs_cgsize, false, BTYPE_DATA, &bp) != 0)
continue;
if (bp->b_oflags & BO_DELWRI) {
bwrite(bp);
@@ -496,7 +503,7 @@
}
for (i = unwindidx + 1; i <= num; i++) {
if (ffs_getblk(vp, indirs[i].in_lbn, FFS_NOBLK,
- fs->fs_bsize, false, &bp) == 0)
+ fs->fs_bsize, false, BTYPE_DATA, &bp) == 0)
brelse(bp, BC_INVAL);
}
}
@@ -519,7 +526,7 @@
static int
ffs_balloc_ufs2(struct vnode *vp, off_t off, int size, kauth_cred_t cred,
- int flags, struct buf **bpp)
+ int flags, int type, struct buf **bpp)
{
daddr_t lbn, lastlbn;
struct buf *bp, *nbp;
@@ -550,11 +557,10 @@
if (lbn < 0)
return (EFBIG);
-#ifdef notyet
/*
* Check for allocating external data.
*/
- if (flags & IO_EXT) {
+ if (type == BTYPE_EXTDATA) {
if (lbn >= NXADDR)
return (EFBIG);
/*
@@ -562,102 +568,109 @@
* and the data is currently composed of a fragment
* this fragment has to be extended to be a full block.
*/
- lastlbn = lblkno(fs, dp->di_extsize);
+ lastlbn = lblkno(fs, ip->i_ffs2_extsize);
if (lastlbn < lbn) {
nb = lastlbn;
- osize = sblksize(fs, dp->di_extsize, nb);
+ osize = extsize(fs, ip->i_ffs2_extsize, nb);
if (osize < fs->fs_bsize && osize > 0) {
mutex_enter(&ump->um_lock);
error = ffs_realloccg(ip, -1 - nb,
- dp->di_extb[nb],
ffs_blkpref_ufs2(ip, lastlbn, (int)nb,
- flags, &dp->di_extb[0]),
+ flags,
+ &ip->i_ffs2_extb[0]),
osize,
- (int)fs->fs_bsize, cred, &bp);
+ (int)fs->fs_bsize, cred,
+ BTYPE_EXTDATA, bpp, &newb);
if (error)
return (error);
- dp->di_extsize = smalllblktosize(fs, nb + 1);
- dp->di_extb[nb] = dbtofsb(fs, bp->b_blkno);
- bp->b_xflags |= BX_ALTDATA;
+ ip->i_ffs2_extsize = lblktosize(fs, nb + 1);
+ ip->i_ffs2_extb[nb] = ufs_rw64(newb, needswap);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
- if (flags & IO_SYNC)
- bwrite(bp);
- else
- bawrite(bp);
+ if (bpp) {
+ if (flags & B_SYNC)
+ bwrite(*bpp);
+ else
+ bawrite(*bpp);
+ }
}
}
/*
* All blocks are direct blocks
*/
- if (flags & BA_METAONLY)
+ if (flags & B_METAONLY)
panic("ffs_balloc_ufs2: BA_METAONLY for ext block");
- nb = dp->di_extb[lbn];
- if (nb != 0 && dp->di_extsize >= smalllblktosize(fs, lbn + 1)) {
- error = bread(vp, -1 - lbn, fs->fs_bsize,
- NOCRED, 0, &bp);
- if (error) {
- brelse(bp, 0);
- return (error);
+ nb = ufs_rw64(ip->i_ffs2_extb[lbn], needswap);
+ if (nb != 0 && ip->i_ffs2_extsize >= lblktosize(fs, lbn + 1)) {
+ if (bpp != NULL) {
+ error = bread2(vp, lbn, fs->fs_bsize,
+ NOCRED, 0, BTYPE_EXTDATA, bpp);
+ if (error) {
+ brelse(*bpp, 0);
+ return (error);
+ }
}
- mutex_enter(&bp->b_interlock);
- bp->b_blkno = fsbtodb(fs, nb);
- bp->b_xflags |= BX_ALTDATA;
- mutex_exit(&bp->b_interlock);
- *bpp = bp;
return (0);
}
if (nb != 0) {
/*
* Consider need to reallocate a fragment.
*/
- osize = fragroundup(fs, blkoff(fs, dp->di_extsize));
+ osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_extsize));
nsize = fragroundup(fs, size);
if (nsize <= osize) {
- error = bread(vp, -1 - lbn, osize,
- NOCRED, 0, &bp);
- if (error) {
- brelse(bp, 0);
- return (error);
+ if (bpp != NULL) {
+ error = bread2(vp, lbn, osize,
+ NOCRED, 0, BTYPE_EXTDATA, bpp);
+ if (error) {
+ brelse(*bpp, 0);
+ return (error);
+ }
}
- mutex_enter(&bp->b_interlock);
- bp->b_blkno = fsbtodb(fs, nb);
- bp->b_xflags |= BX_ALTDATA;
- mutex_exit(&bp->b_interlock);
} else {
+ /*
+ * The existing block is smaller than we want,
+ * grow it.
+ */
mutex_enter(&ump->um_lock);
- error = ffs_realloccg(ip, -1 - lbn,
- dp->di_extb[lbn],
+ error = ffs_realloccg(ip, lbn,
ffs_blkpref_ufs2(ip, lbn, (int)lbn, flags,
- &dp->di_extb[0]),
- osize, nsize, cred, &bp);
+ &ip->i_ffs2_extb[0]),
+ osize, nsize, cred,
+ BTYPE_EXTDATA, bpp, &newb);
if (error)
return (error);
- bp->b_xflags |= BX_ALTDATA;
}
} else {
- if (dp->di_extsize < smalllblktosize(fs, lbn + 1))
+ /*
+ * the block was not previously allocated,
+ * allocate a new block or fragment.
+ */
+ if (ip->i_ffs2_extsize < lblktosize(fs, lbn + 1))
nsize = fragroundup(fs, size);
else
nsize = fs->fs_bsize;
mutex_enter(&ump->um_lock);
error = ffs_alloc(ip, lbn,
ffs_blkpref_ufs2(ip, lbn, (int)lbn, flags,
- &dp->di_extb[0]),
+ &ip->i_ffs2_extb[0]),
nsize, flags, cred, &newb);
if (error)
return (error);
- error = ffs_getblk(vp, -1 - lbn, fsbtodb(fs, newb),
- nsize, (flags & BA_CLRBUF) != 0, &bp);
- if (error)
- return error;
- bp->b_xflags |= BX_ALTDATA;
+ if (bpp != NULL) {
+ error = ffs_getblk(vp, lbn,
+ fsbtodb(fs, newb),
+ nsize, (flags & B_CLRBUF) != 0,
+ BTYPE_EXTDATA, bpp);
+ if (error)
+ return error;
+ }
}
- dp->di_extb[lbn] = dbtofsb(fs, bp->b_blkno);
+ ip->i_ffs2_extb[lbn] = ufs_rw64(newb, needswap);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
- *bpp = bp;
return (0);
}
-#endif
+ if (type != BTYPE_DATA)
+ return EINVAL;
/*
* If the next write will extend the file into a new block,
* and the file is currently composed of a fragment
@@ -673,7 +686,8 @@
error = ffs_realloccg(ip, nb,
ffs_blkpref_ufs2(ip, lastlbn, nb, flags,
&ip->i_ffs2_db[0]),
- osize, (int)fs->fs_bsize, cred, bpp, &newb);
+ osize, (int)fs->fs_bsize, cred,
+ BTYPE_DATA, bpp, &newb);
if (error)
return (error);
ip->i_size = lblktosize(fs, nb + 1);
@@ -750,7 +764,8 @@
error = ffs_realloccg(ip, lbn,
ffs_blkpref_ufs2(ip, lbn, (int)lbn, flags,
&ip->i_ffs2_db[0]),
- osize, nsize, cred, bpp, &newb);
+ osize, nsize, cred,
+ BTYPE_DATA, bpp, &newb);
if (error)
return (error);
}
@@ -774,7 +789,8 @@
return (error);
if (bpp != NULL) {
error = ffs_getblk(vp, lbn, fsbtodb(fs, newb),
- nsize, (flags & B_CLRBUF) != 0, bpp);
+ nsize, (flags & B_CLRBUF) != 0,
+ BTYPE_DATA, bpp);
if (error)
return error;
}
@@ -810,7 +826,7 @@
nb = newb;
*allocblk++ = nb;
error = ffs_getblk(vp, indirs[1].in_lbn, fsbtodb(fs, nb),
- fs->fs_bsize, true, &bp);
+ fs->fs_bsize, true, BTYPE_DATA, &bp);
if (error)
goto fail;
/*
@@ -866,7 +882,7 @@
nb = newb;
*allocblk++ = nb;
error = ffs_getblk(vp, indirs[i].in_lbn, fsbtodb(fs, nb),
- fs->fs_bsize, true, &nbp);
+ fs->fs_bsize, true, BTYPE_DATA, &nbp);
if (error) {
brelse(bp, 0);
goto fail;
@@ -923,7 +939,8 @@
*allocblk++ = nb;
if (bpp != NULL) {
error = ffs_getblk(vp, lbn, fsbtodb(fs, nb),
- fs->fs_bsize, (flags & B_CLRBUF) != 0, bpp);
+ fs->fs_bsize, (flags & B_CLRBUF) != 0,
+ BTYPE_DATA, bpp);
if (error) {
brelse(bp, 0);
goto fail;
@@ -957,7 +974,7 @@
}
} else {
error = ffs_getblk(vp, lbn, fsbtodb(fs, nb),
- fs->fs_bsize, true, &nbp);
+ fs->fs_bsize, true, BTYPE_DATA, &nbp);
if (error)
goto fail;
}
@@ -985,14 +1002,14 @@
break;
}
if (ffs_getblk(vp, indirs[i].in_lbn, FFS_NOBLK,
- fs->fs_bsize, false, &bp) != 0)
+ fs->fs_bsize, false, BTYPE_DATA, &bp) != 0)
continue;
if (bp->b_oflags & BO_DELWRI) {
nb = fsbtodb(fs, cgtod(fs, dtog(fs,
dbtofsb(fs, bp->b_blkno))));
bwrite(bp);
if (ffs_getblk(ip->i_devvp, nb, FFS_NOBLK,
- fs->fs_cgsize, false, &bp) != 0)
+ fs->fs_cgsize, false, BTYPE_DATA, &bp) != 0)
continue;
if (bp->b_oflags & BO_DELWRI) {
bwrite(bp);
@@ -1028,7 +1045,7 @@
}
for (i = unwindidx + 1; i <= num; i++) {
if (ffs_getblk(vp, indirs[i].in_lbn, FFS_NOBLK,
- fs->fs_bsize, false, &bp) == 0)
+ fs->fs_bsize, false, BTYPE_DATA, &bp) == 0)
brelse(bp, BC_INVAL);
}
}
Index: sys/ufs/ffs/ffs_extern.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_extern.h,v
retrieving revision 1.78
diff -u -r1.78 ffs_extern.h
--- sys/ufs/ffs/ffs_extern.h 17 Jun 2011 14:23:52 -0000 1.78
+++ sys/ufs/ffs/ffs_extern.h 16 Jan 2012 20:36:39 -0000
@@ -91,7 +91,7 @@
int ffs_alloc(struct inode *, daddr_t, daddr_t , int, int, kauth_cred_t,
daddr_t *);
int ffs_realloccg(struct inode *, daddr_t, daddr_t, int, int ,
- kauth_cred_t, struct buf **, daddr_t *);
+ kauth_cred_t, int, struct buf **, daddr_t *);
int ffs_valloc(struct vnode *, int, kauth_cred_t, struct vnode **);
daddr_t ffs_blkpref_ufs1(struct inode *, daddr_t, int, int, int32_t *);
daddr_t ffs_blkpref_ufs2(struct inode *, daddr_t, int, int, int64_t *);
@@ -105,13 +105,14 @@
int ffs_freefile_snap(struct fs *, struct vnode *, ino_t, int);
/* ffs_balloc.c */
-int ffs_balloc(struct vnode *, off_t, int, kauth_cred_t, int,
+int ffs_balloc(struct vnode *, off_t, int, kauth_cred_t, int, int,
struct buf **);
/* ffs_inode.c */
int ffs_update(struct vnode *, const struct timespec *,
const struct timespec *, int);
int ffs_truncate(struct vnode *, off_t, int, kauth_cred_t);
+int ffs_extattr_truncate(struct vnode *, off_t, int, kauth_cred_t);
/* ffs_vfsops.c */
VFS_PROTOS(ffs);
@@ -192,7 +193,7 @@
/* ffs_subr.c */
#if defined(_KERNEL)
void ffs_load_inode(struct buf *, struct inode *, struct fs *, ino_t);
-int ffs_getblk(struct vnode *, daddr_t, daddr_t, int, bool, buf_t **);
+int ffs_getblk(struct vnode *, daddr_t, daddr_t, int, bool, int, buf_t **);
#endif /* defined(_KERNEL) */
void ffs_fragacct(struct fs *, int, int32_t[], int, int);
int ffs_isblock(struct fs *, u_char *, int32_t);
Index: sys/ufs/ffs/ffs_inode.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_inode.c,v
retrieving revision 1.108
diff -u -r1.108 ffs_inode.c
--- sys/ufs/ffs/ffs_inode.c 23 Nov 2011 19:42:10 -0000 1.108
+++ sys/ufs/ffs/ffs_inode.c 16 Jan 2012 20:36:39 -0000
@@ -209,7 +209,7 @@
struct inode *oip = VTOI(ovp);
daddr_t bn, lastiblock[NIADDR], indir_lbn[NIADDR];
daddr_t blks[NDADDR + NIADDR];
- struct fs *fs;
+ struct fs *fs = oip->i_fs;
int offset, pgoffset, level;
int64_t count, blocksreleased = 0;
int i, aflag, nblocks;
@@ -218,6 +218,15 @@
int sync;
struct ufsmount *ump = oip->i_ump;
+ if (ioflag & IO_EXT) {
+ if (fs->fs_magic == FS_UFS1_MAGIC)
+ return 0;
+ if (oip->i_ffs2_extsize <= length)
+ return 0;
+ return ffs_extattr_truncate(ovp, length, ioflag, cred);
+ }
+
+
if (ovp->v_type == VCHR || ovp->v_type == VBLK ||
ovp->v_type == VFIFO || ovp->v_type == VSOCK) {
KASSERT(oip->i_size == 0);
@@ -243,7 +252,6 @@
oip->i_flag |= IN_CHANGE | IN_UPDATE;
return (ffs_update(ovp, NULL, NULL, 0));
}
- fs = oip->i_fs;
if (length > ump->um_maxfilesize)
return (EFBIG);
@@ -588,7 +596,8 @@
* explicitly instead of letting bread do everything for us.
*/
vp = ITOV(ip);
- error = ffs_getblk(vp, lbn, FFS_NOBLK, fs->fs_bsize, false, &bp);
+ error = ffs_getblk(vp, lbn, FFS_NOBLK, fs->fs_bsize, false,
+ BTYPE_DATA, &bp);
if (error) {
*countp = 0;
return error;
@@ -685,6 +694,96 @@
return (allerror);
}
+/* truncate extended attr data */
+int
+ffs_extattr_truncate(struct vnode *ovp, off_t length,
+ int ioflag, kauth_cred_t cred)
+{
+ daddr_t lastblock, bn;
+ struct inode *oip = VTOI(ovp);
+ struct fs *fs = oip->i_fs;
+ int offset;
+ int blocksreleased = 0;
+ int i;
+ int error, allerror = 0;
+ off_t osize;
+
+ if (ovp->v_type == VCHR || ovp->v_type == VBLK)
+ return (EOPNOTSUPP);
+
+ if (length < 0)
+ return (EINVAL);
+
+ if (length > oip->i_ffs2_extsize)
+ return (EINVAL);
+
+ offset = blkoff(fs, length);
+ lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
+
+ genfs_node_wrlock(ovp);
+ osize = oip->i_ffs2_extsize;
+ oip->i_ffs2_extsize = length;
+ error = vtruncbuf2(ovp, lastblock + 1, 0, 0, BTYPE_EXTDATA);
+ if (error && !allerror)
+ allerror = error;
+
+ for (i = NXADDR - 1; i > lastblock; i--) {
+ long bsize;
+ bn = ufs_rw64(oip->i_ffs2_extb[i], UFS_FSNEEDSWAP(fs));
+ if (bn == 0)
+ continue;
+ oip->i_ffs2_extb[i] = 0;
+ bsize = extsize(fs, length, i);
+ if (oip->i_ump->um_mountp->mnt_wapbl) {
+ UFS_WAPBL_REGISTER_DEALLOCATION(oip->i_ump->um_mountp,
+ fsbtodb(fs, bn), bsize);
+ } else {
+ ffs_blkfree(fs, oip->i_devvp, bn, bsize, oip->i_number);
+ }
+ blocksreleased += btodb(bsize);
+ }
+ if (lastblock < 0)
+ goto done;
+ /*
+ * Finally, look for a change in size of the
+ * last direct block; release any frags.
+ */
+
+ bn = ufs_rw64(oip->i_ffs2_extb[lastblock], UFS_FSNEEDSWAP(fs));
+ if (bn != 0) {
+ long oldspace, newspace;
+ oldspace = extsize(fs, osize, lastblock);
+ newspace = extsize(fs, length, lastblock);
+ if (newspace == 0)
+ panic("extitrunc: 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);
+ if (oip->i_ump->um_mountp->mnt_wapbl) {
+ UFS_WAPBL_REGISTER_DEALLOCATION(
+ oip->i_ump->um_mountp, fsbtodb(fs, bn),
+ oldspace - newspace);
+ } else
+ ffs_blkfree(fs, oip->i_devvp, bn,
+ oldspace - newspace, oip->i_number);
+ blocksreleased += btodb(oldspace - newspace);
+ }
+ }
+done:
+ DIP_ADD(oip, blocks, -blocksreleased);
+ genfs_node_unlock(ovp);
+ oip->i_flag |= IN_CHANGE;
+ UFS_WAPBL_UPDATE(ovp, NULL, NULL, 0);
+#if defined(QUOTA) || defined(QUOTA2)
+ (void) chkdq(oip, -blocksreleased, NOCRED, 0);
+#endif
+ return (allerror);
+}
+
void
ffs_itimes(struct inode *ip, const struct timespec *acc,
const struct timespec *mod, const struct timespec *cre)
Index: sys/ufs/ffs/ffs_snapshot.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_snapshot.c,v
retrieving revision 1.118
diff -u -r1.118 ffs_snapshot.c
--- sys/ufs/ffs/ffs_snapshot.c 7 Oct 2011 09:35:06 -0000 1.118
+++ sys/ufs/ffs/ffs_snapshot.c 16 Jan 2012 20:36:39 -0000
@@ -478,7 +478,7 @@
return error;
for (blkno = NDADDR, n = 0; blkno < numblks; blkno += NINDIR(fs)) {
error = ffs_balloc(vp, lblktosize(fs, (off_t)blkno),
- fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
+ fs->fs_bsize, l->l_cred, B_METAONLY, BTYPE_DATA, &ibp);
if (error)
goto out;
brelse(ibp, 0);
@@ -493,7 +493,7 @@
* Allocate copies for the superblock and its summary information.
*/
error = ffs_balloc(vp, fs->fs_sblockloc, fs->fs_sbsize, l->l_cred,
- 0, &nbp);
+ 0, BTYPE_DATA, &nbp);
if (error)
goto out;
bawrite(nbp);
@@ -501,7 +501,7 @@
len = howmany(fs->fs_cssize, fs->fs_bsize);
for (loc = 0; loc < len; loc++) {
error = ffs_balloc(vp, lblktosize(fs, (off_t)(blkno + loc)),
- fs->fs_bsize, l->l_cred, 0, &nbp);
+ fs->fs_bsize, l->l_cred, 0, BTYPE_DATA, &nbp);
if (error)
goto out;
bawrite(nbp);
@@ -517,7 +517,7 @@
*/
for (cg = 0; cg < fs->fs_ncg; cg++) {
error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)),
- fs->fs_bsize, l->l_cred, 0, &nbp);
+ fs->fs_bsize, l->l_cred, 0, BTYPE_DATA, &nbp);
if (error)
goto out;
bawrite(nbp);
@@ -883,7 +883,7 @@
if (db_get(ip, loc) != 0)
continue;
error = ffs_balloc(vp, lblktosize(fs, (off_t)loc),
- fs->fs_bsize, l->l_cred, 0, &bp);
+ fs->fs_bsize, l->l_cred, 0, BTYPE_DATA, &bp);
if (error)
break;
error = rwfsblk(vp, B_READ, bp->b_data, loc);
@@ -924,7 +924,7 @@
if (error)
return error;
error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)),
- fs->fs_bsize, curlwp->l_cred, 0, &nbp);
+ fs->fs_bsize, curlwp->l_cred, 0, BTYPE_DATA, &nbp);
if (error) {
UFS_WAPBL_END(vp->v_mount);
break;
@@ -997,7 +997,7 @@
}
}
if ((error = ffs_balloc(vp, lblktosize(fs, (off_t)(base + loc)),
- fs->fs_bsize, l->l_cred, B_METAONLY, &ibp)) != 0)
+ fs->fs_bsize, l->l_cred, B_METAONLY, BTYPE_DATA, &ibp)) != 0)
return (error);
indiroff = (base + loc - NDADDR) % NINDIR(fs);
for ( ; loc < len; loc++, indiroff++) {
@@ -1005,7 +1005,8 @@
bawrite(ibp);
if ((error = ffs_balloc(vp,
lblktosize(fs, (off_t)(base + loc)),
- fs->fs_bsize, l->l_cred, B_METAONLY, &ibp)) != 0)
+ fs->fs_bsize, l->l_cred, B_METAONLY, BTYPE_DATA,
+ &ibp)) != 0)
return (error);
indiroff = 0;
}
@@ -1062,7 +1063,7 @@
B_MODIFY, &bp);
} else {
error = ffs_balloc(snapvp, lblktosize(fs, (off_t)lbn),
- fs->fs_bsize, l->l_cred, 0, &bp);
+ fs->fs_bsize, l->l_cred, 0, BTYPE_DATA, &bp);
if (! error)
error = rwfsblk(snapvp, B_READ, bp->b_data, lbn);
}
@@ -1170,7 +1171,7 @@
* up the block number for any blocks that are not in the cache.
*/
error = ffs_getblk(cancelvp, lbn, fsbtodb(fs, blkno), fs->fs_bsize,
- false, &bp);
+ false, BTYPE_DATA, &bp);
if (error)
return error;
if ((bp->b_oflags & (BO_DONE | BO_DELWRI)) == 0 && (error =
@@ -1256,7 +1257,8 @@
ip->i_flag |= IN_CHANGE | IN_UPDATE;
} else {
error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn),
- fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
+ fs->fs_bsize, l->l_cred, B_METAONLY, BTYPE_DATA,
+ &ibp);
if (error)
break;
blkno = idb_get(ip, ibp->b_data,
@@ -1482,7 +1484,7 @@
numblks = howmany(ip->i_size, fs->fs_bsize);
for (blkno = NDADDR; blkno < numblks; blkno += NINDIR(fs)) {
error = ffs_balloc(vp, lblktosize(fs, (off_t)blkno),
- fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
+ fs->fs_bsize, l->l_cred, B_METAONLY, BTYPE_DATA, &ibp);
if (error)
continue;
if (fs->fs_size - blkno > NINDIR(fs))
@@ -1568,7 +1570,7 @@
} else {
mutex_exit(&si->si_lock);
error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn),
- fs->fs_bsize, FSCRED, B_METAONLY, &ibp);
+ fs->fs_bsize, FSCRED, B_METAONLY, BTYPE_DATA, &ibp);
if (error) {
mutex_enter(&si->si_lock);
break;
@@ -2242,7 +2244,7 @@
int error;
error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn), fs->fs_bsize,
- FSCRED, (ip->i_nlink > 0 ? B_SYNC : 0), &bp);
+ FSCRED, (ip->i_nlink > 0 ? B_SYNC : 0), BTYPE_DATA, &bp);
if (error)
return error;
memcpy(bp->b_data, data, fs->fs_bsize);
Index: sys/ufs/ffs/ffs_subr.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_subr.c,v
retrieving revision 1.47
diff -u -r1.47 ffs_subr.c
--- sys/ufs/ffs/ffs_subr.c 14 Aug 2011 12:37:09 -0000 1.47
+++ sys/ufs/ffs/ffs_subr.c 16 Jan 2012 20:36:39 -0000
@@ -115,13 +115,13 @@
int
ffs_getblk(struct vnode *vp, daddr_t lblkno, daddr_t blkno, int size,
- bool clearbuf, buf_t **bpp)
+ bool clearbuf, int type, buf_t **bpp)
{
int error = 0;
KASSERT(blkno >= 0 || blkno == FFS_NOBLK);
- if ((*bpp = getblk(vp, lblkno, size, 0, 0)) == NULL)
+ if ((*bpp = getblk2(vp, lblkno, size, 0, 0, type)) == NULL)
return ENOMEM;
if (blkno != FFS_NOBLK)
(*bpp)->b_blkno = blkno;
Index: sys/ufs/ffs/ffs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.272
diff -u -r1.272 ffs_vfsops.c
--- sys/ufs/ffs/ffs_vfsops.c 3 Jan 2012 15:44:00 -0000 1.272
+++ sys/ufs/ffs/ffs_vfsops.c 16 Jan 2012 20:36:39 -0000
@@ -1797,6 +1797,7 @@
ip->i_fs = fs = ump->um_fs;
ip->i_dev = dev;
ip->i_number = ino;
+ ip->i_ffs_ea_refs = 0;
#if defined(QUOTA) || defined(QUOTA2)
ufsquota_init(ip);
#endif
@@ -1969,7 +1970,7 @@
error = ffs_getblk(mp->um_devvp,
fs->fs_sblockloc / DEV_BSIZE, FFS_NOBLK,
- fs->fs_sbsize, false, &bp);
+ fs->fs_sbsize, false, BTYPE_DATA, &bp);
if (error)
return error;
saveflag = fs->fs_flags & FS_INTERNAL;
@@ -2008,7 +2009,7 @@
if (i + fs->fs_frag > blks)
size = (blks - i) * fs->fs_fsize;
error = ffs_getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
- FFS_NOBLK, size, false, &bp);
+ FFS_NOBLK, size, false, BTYPE_DATA, &bp);
if (error)
break;
#ifdef FFS_EI
Index: sys/ufs/ffs/ffs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vnops.c,v
retrieving revision 1.120
diff -u -r1.120 ffs_vnops.c
--- sys/ufs/ffs/ffs_vnops.c 27 Jun 2011 16:34:47 -0000 1.120
+++ sys/ufs/ffs/ffs_vnops.c 16 Jan 2012 20:36:39 -0000
@@ -76,6 +76,7 @@
#include <sys/stat.h>
#include <sys/buf.h>
#include <sys/event.h>
+#include <sys/kauth.h>
#include <sys/proc.h>
#include <sys/mount.h>
#include <sys/vnode.h>
@@ -84,6 +85,8 @@
#include <sys/kauth.h>
#include <sys/wapbl.h>
#include <sys/fstrans.h>
+#include <sys/extattr.h>
+#include <sys/malloc.h>
#include <miscfs/fifofs/fifo.h>
#include <miscfs/genfs/genfs.h>
@@ -100,6 +103,19 @@
#include <uvm/uvm.h>
+static MALLOC_JUSTDEFINE(M_FFS_EXTATTR, "ufs_extattr","ufs extended
attribute");
+
+static int ffs_extread(struct vnode *, struct uio *, int);
+static int ffs_extwrite(struct vnode *, struct uio *, int ,
+ kauth_cred_t);
+static int ffs_findextattr(u_char *, u_int, int, const char *, u_char **,
+ u_char **);
+static int ffs_rdextattr(u_char **, struct vnode *, int);
+static void ffs_lock_ea(struct vnode *);
+static void ffs_unlock_ea(struct vnode *);
+static int ffs_open_ea(struct vnode *, kauth_cred_t);
+static int ffs_close_ea(struct vnode *, int, kauth_cred_t);
+
/* Global vfs data structures for ufs. */
int (**ffs_vnodeop_p)(void *);
const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
@@ -573,6 +589,7 @@
fstrans_done(mp);
return (error);
}
+ KASSERT(ip->i_ffs_ea_refs == 0);
if (ip->i_din.ffs1_din != NULL) {
if (ump->um_fstype == UFS1)
pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din);
@@ -626,15 +643,18 @@
kauth_cred_t a_cred;
struct proc *a_p;
} */ *ap = v;
- struct inode *ip = VTOI(ap->a_vp);
+ struct vnode *vp = ap->a_vp;
+ struct inode *ip = VTOI(vp);
struct fs *fs = ip->i_fs;
/* Not supported for UFS1 file systems. */
if (fs->fs_magic == FS_UFS1_MAGIC)
return (EOPNOTSUPP);
- /* XXX Not implemented for UFS2 file systems. */
- return (EOPNOTSUPP);
+ if (vp->v_type == VCHR || vp->v_type == VBLK)
+ return (EOPNOTSUPP);
+
+ return (ffs_open_ea(vp, ap->a_cred));
}
int
@@ -646,15 +666,21 @@
kauth_cred_t a_cred;
struct proc *a_p;
} */ *ap = v;
- struct inode *ip = VTOI(ap->a_vp);
+ struct vnode *vp = ap->a_vp;
+ struct inode *ip = VTOI(vp);
struct fs *fs = ip->i_fs;
/* Not supported for UFS1 file systems. */
if (fs->fs_magic == FS_UFS1_MAGIC)
return (EOPNOTSUPP);
- /* XXX Not implemented for UFS2 file systems. */
- return (EOPNOTSUPP);
+ if (vp->v_type == VCHR || vp->v_type == VBLK)
+ return (EOPNOTSUPP);
+
+ if (ap->a_commit && (vp->v_mount->mnt_flag & MNT_RDONLY))
+ return (EROFS);
+
+ return (ffs_close_ea(vp, ap->a_commit, ap->a_cred));
}
int
@@ -672,11 +698,13 @@
struct vnode *vp = ap->a_vp;
struct inode *ip = VTOI(vp);
struct fs *fs = ip->i_fs;
+ int error;
+ u_char *eae, *p;
+ size_t easize;
+ ssize_t ealen;
if (fs->fs_magic == FS_UFS1_MAGIC) {
#ifdef UFS_EXTATTR
- int error;
-
fstrans_start(vp->v_mount, FSTRANS_SHARED);
error = ufs_getextattr(ap);
fstrans_done(vp->v_mount);
@@ -686,8 +714,33 @@
#endif
}
- /* XXX Not implemented for UFS2 file systems. */
- return (EOPNOTSUPP);
+ if (vp->v_type == VCHR || vp->v_type == VBLK)
+ return (EOPNOTSUPP);
+
+ error = extattr_check_cred(vp, ap->a_attrnamespace,
+ ap->a_cred, curlwp, IREAD);
+ if (error)
+ return (error);
+
+ error = ffs_open_ea(vp, ap->a_cred);
+ if (error)
+ return (error);
+
+ eae = ip->i_ffs_ea_area;
+ easize = ip->i_ffs_ea_len;
+
+ ealen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name,
+ NULL, &p);
+ if (ealen >= 0) {
+ error = 0;
+ if (ap->a_size != NULL)
+ *ap->a_size = ealen;
+ else if (ap->a_uio != NULL)
+ error = uiomove(p, ealen, ap->a_uio);
+ }
+ error = ENOATTR;
+ ffs_close_ea(ap->a_vp, 0, ap->a_cred);
+ return error;
}
int
@@ -704,11 +757,13 @@
struct vnode *vp = ap->a_vp;
struct inode *ip = VTOI(vp);
struct fs *fs = ip->i_fs;
+ uint32_t ealength, ul;
+ int error, i;
+ ssize_t ealen, olen, eapad1, eapad2, easize;
+ u_char *eae, *p;
if (fs->fs_magic == FS_UFS1_MAGIC) {
#ifdef UFS_EXTATTR
- int error;
-
fstrans_start(vp->v_mount, FSTRANS_SHARED);
error = ufs_setextattr(ap);
fstrans_done(vp->v_mount);
@@ -718,8 +773,95 @@
#endif
}
- /* XXX Not implemented for UFS2 file systems. */
- return (EOPNOTSUPP);
+ if (vp->v_type == VCHR || vp->v_type == VBLK)
+ return (EOPNOTSUPP);
+
+ if (strlen(ap->a_name) == 0)
+ return (EINVAL);
+
+ if (ap->a_uio == NULL)
+ return (EOPNOTSUPP);
+
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+
+ error = extattr_check_cred(vp, ap->a_attrnamespace,
+ ap->a_cred, curlwp, IWRITE);
+ if (error) {
+ /*
+ * ffs_lock_ea is not needed there, because the vnode
+ * must be exclusively locked.
+ */
+ if (ip->i_ffs_ea_area != NULL && ip->i_ffs_ea_error == 0)
+ ip->i_ffs_ea_error = error;
+ return (error);
+ }
+ error = ffs_open_ea(vp, ap->a_cred);
+ if (error)
+ return (error);
+
+ ealen = ap->a_uio->uio_resid;
+ ealength = sizeof(uint32_t) + 3 + strlen(ap->a_name);
+ eapad1 = 8 - (ealength % 8);
+ if (eapad1 == 8)
+ eapad1 = 0;
+ eapad2 = 8 - (ealen % 8);
+ if (eapad2 == 8)
+ eapad2 = 0;
+ ealength += eapad1 + ealen + eapad2;
+
+ eae = malloc(ip->i_ffs_ea_len + ealength, M_FFS_EXTATTR, M_WAITOK);
+ memcpy(eae, ip->i_ffs_ea_area, ip->i_ffs_ea_len);
+ easize = ip->i_ffs_ea_len;
+
+ olen = ffs_findextattr(eae, easize,
+ ap->a_attrnamespace, ap->a_name, &p, NULL);
+
+ if (olen == -1) {
+ /* new, append at end */
+ p = eae + easize;
+ easize += ealength;
+ } else {
+ memcpy(&ul, p, sizeof(ul));
+ i = p - eae + ul;
+ if (ul != ealength) {
+ memcpy(p + ealength, p + ul, easize - i);
+ easize += (ealength - ul);
+ }
+ }
+ if (easize > NXADDR * fs->fs_bsize) {
+ free(eae, M_FFS_EXTATTR);
+ ffs_close_ea(vp, 0, ap->a_cred);
+ if (ip->i_ffs_ea_area != NULL && ip->i_ffs_ea_error == 0)
+ ip->i_ffs_ea_error = ENOSPC;
+ return (ENOSPC);
+ }
+ memcpy(p, &ealength, sizeof(ealength));
+ p += sizeof(ealength);
+ *p++ = ap->a_attrnamespace;
+ *p++ = eapad2;
+ *p++ = strlen(ap->a_name);
+ strcpy(p, ap->a_name);
+ p += strlen(ap->a_name);
+ memset(p, 0, eapad1);
+ p += eapad1;
+ error = uiomove(p, ealen, ap->a_uio);
+ if (error) {
+ free(eae, M_FFS_EXTATTR);
+ ffs_close_ea(vp, 0, ap->a_cred);
+ if (ip->i_ffs_ea_area != NULL && ip->i_ffs_ea_error == 0)
+ ip->i_ffs_ea_error = error;
+ return(error);
+ }
+ p += ealen;
+ memset(p, 0, eapad2);
+
+ p = ip->i_ffs_ea_area;
+ ip->i_ffs_ea_area = eae;
+ ip->i_ffs_ea_len = easize;
+ free(p, M_FFS_EXTATTR);
+ error = ffs_close_ea(vp, 1, ap->a_cred);
+ return(error);
}
int
@@ -733,14 +875,17 @@
kauth_cred_t a_cred;
struct proc *a_p;
} */ *ap = v;
- struct inode *ip = VTOI(ap->a_vp);
+ struct vnode *vp = ap->a_vp;
+ struct inode *ip = VTOI(vp);
struct fs *fs = ip->i_fs;
+ u_char *eae, *p, *pe, *pn;
+ size_t easize;
+ uint32_t ul;
+ ssize_t ealen;
+ int error;
if (fs->fs_magic == FS_UFS1_MAGIC) {
#ifdef UFS_EXTATTR
- struct vnode *vp = ap->a_vp;
- int error;
-
fstrans_start(vp->v_mount, FSTRANS_SHARED);
error = ufs_listextattr(ap);
fstrans_done(vp->v_mount);
@@ -750,8 +895,44 @@
#endif
}
- /* XXX Not implemented for UFS2 file systems. */
- return (EOPNOTSUPP);
+ if (vp->v_type == VCHR || vp->v_type == VBLK)
+ return (EOPNOTSUPP);
+
+ error = extattr_check_cred(vp, ap->a_attrnamespace,
+ ap->a_cred, curlwp, IREAD);
+ if (error)
+ return (error);
+
+ error = ffs_open_ea(vp, ap->a_cred);
+ if (error)
+ return (error);
+
+ eae = ip->i_ffs_ea_area;
+ easize = ip->i_ffs_ea_len;
+
+ error = 0;
+ if (ap->a_size != NULL)
+ *ap->a_size = 0;
+ pe = eae + easize;
+
+ for(p = eae; error == 0 && p < pe; p = pn) {
+ memcpy(&ul, p, sizeof(ul));
+ pn = p + ul;
+ if (pn > pe)
+ break;
+ p += sizeof(ul);
+ if (*p++ != ap->a_attrnamespace)
+ continue;
+ p++; /* pad2 */
+ ealen = *p;
+ if (ap->a_size != NULL) {
+ *ap->a_size += ealen + 1;
+ } else if (ap->a_uio != NULL) {
+ error = uiomove(p, ealen + 1, ap->a_uio);
+ }
+ }
+ ffs_close_ea(vp, 0, ap->a_cred);
+ return(error);
}
int
@@ -766,11 +947,14 @@
struct vnode *vp = ap->a_vp;
struct inode *ip = VTOI(vp);
struct fs *fs = ip->i_fs;
+ uint32_t ealength, ul;
+ ssize_t ealen, olen, eapad1, eapad2, easize;
+ int error, i;
+ u_char *eae, *p;
+
if (fs->fs_magic == FS_UFS1_MAGIC) {
#ifdef UFS_EXTATTR
- int error;
-
fstrans_start(vp->v_mount, FSTRANS_SHARED);
error = ufs_deleteextattr(ap);
fstrans_done(vp->v_mount);
@@ -779,7 +963,501 @@
return (EOPNOTSUPP);
#endif
}
+ if (vp->v_type == VCHR || vp->v_type == VBLK)
+ return (EOPNOTSUPP);
+
+ if (strlen(ap->a_name) == 0)
+ return (EINVAL);
+
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+
+ error = extattr_check_cred(vp, ap->a_attrnamespace,
+ ap->a_cred, curlwp, IWRITE);
+ if (error) {
+
+ /*
+ * ffs_lock_ea is not needed there, because the vnode
+ * must be exclusively locked.
+ */
+ if (ip->i_ffs_ea_area != NULL && ip->i_ffs_ea_error == 0)
+ ip->i_ffs_ea_error = error;
+ return (error);
+ }
+
+ error = ffs_open_ea(vp, ap->a_cred);
+ if (error)
+ return (error);
+
+ ealength = eapad1 = ealen = eapad2 = 0;
+
+ eae = malloc(ip->i_ffs_ea_len, M_FFS_EXTATTR, M_WAITOK);
+ memcpy(eae, ip->i_ffs_ea_area, ip->i_ffs_ea_len);
+ easize = ip->i_ffs_ea_len;
+
+ olen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name,
+ &p, NULL);
+ if (olen == -1) {
+ /* delete but nonexistent */
+ free(eae, M_FFS_EXTATTR);
+ ffs_close_ea(vp, 0, ap->a_cred);
+ return(ENOATTR);
+ }
+ memcpy(&ul, p, sizeof ul);
+ i = p - eae + ul;
+ if (ul != ealength) {
+ memmove(p + ealength, p + ul, easize - i);
+ easize += (ealength - ul);
+ }
+ KASSERT(easize <= NXADDR * fs->fs_bsize);
+ p = ip->i_ffs_ea_area;
+ ip->i_ffs_ea_area = eae;
+ ip->i_ffs_ea_len = easize;
+ free(p, M_FFS_EXTATTR);
+ error = ffs_close_ea(vp, 1, ap->a_cred);
+ return(error);
+}
+
+
+/*
+ * Extended attribute area reading.
+ */
+static int
+ffs_extread(struct vnode *vp, struct uio *uio, int ioflag)
+{
+ struct inode *ip;
+ struct ufs2_dinode *dp;
+ struct fs *fs;
+ struct buf *bp;
+ daddr_t lbn, nextlbn;
+ off_t bytesinfile;
+ long size, xfersize, blkoffset;
+ int error, orig_resid;
+
+ ip = VTOI(vp);
+ fs = ip->i_fs;
+ dp = ip->i_din.ffs2_din;
+
+#ifdef DIAGNOSTIC
+ if (uio->uio_rw != UIO_READ || fs->fs_magic != FS_UFS2_MAGIC)
+ panic("ffs_extread: mode");
+
+#endif
+ orig_resid = uio->uio_resid;
+ KASSERT(orig_resid >= 0);
+ if (orig_resid == 0)
+ return (0);
+ KASSERT(uio->uio_offset >= 0);
+
+ for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
+ if ((bytesinfile = dp->di_extsize - uio->uio_offset) <= 0)
+ break;
+ lbn = lblkno(fs, uio->uio_offset);
+ nextlbn = lbn + 1;
+
+ /*
+ * size of buffer. The buffer representing the
+ * end of the file is rounded up to the size of
+ * the block type ( fragment or full block,
+ * depending ).
+ */
+ size = sblksize(fs, dp->di_extsize, lbn);
+ blkoffset = blkoff(fs, uio->uio_offset);
+
+ /*
+ * The amount we want to transfer in this iteration is
+ * one FS block less the amount of the data before
+ * our startpoint (duh!)
+ */
+ xfersize = fs->fs_bsize - blkoffset;
+
+ /*
+ * But if we actually want less than the block,
+ * or the file doesn't have a whole block more of data,
+ * then use the lesser number.
+ */
+ if (uio->uio_resid < xfersize)
+ xfersize = uio->uio_resid;
+ if (bytesinfile < xfersize)
+ xfersize = bytesinfile;
+
+ if (lblktosize(fs, nextlbn) >= dp->di_extsize) {
+ /*
+ * Don't do readahead if this is the end of the info.
+ */
+ error = bread2(vp, lbn, size, NOCRED, 0,
+ BTYPE_EXTDATA, &bp);
+ } else {
+ /*
+ * If we have a second block, then
+ * fire off a request for a readahead
+ * as well as a read. Note that the 4th and 5th
+ * arguments point to arrays of the size specified in
+ * the 6th argument.
+ */
+ int nextsize = sblksize(fs, dp->di_extsize, nextlbn);
+
+ error = breadn2(vp, lbn,
+ size, &nextlbn, &nextsize, 1, NOCRED,
+ 0, BTYPE_EXTDATA, &bp);
+ }
+ if (error) {
+ brelse(bp, 0);
+ bp = NULL;
+ break;
+ }
+
+#ifdef notyet
+ /*
+ * If IO_DIRECT then set B_DIRECT for the buffer. This
+ * will cause us to attempt to release the buffer later on
+ * and will cause the buffer cache to attempt to free the
+ * underlying pages.
+ */
+ if (ioflag & IO_DIRECT)
+ bp->b_flags |= B_DIRECT;
+#endif
+
+ /*
+ * 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;
+
+#ifdef notyet
+ if ((ioflag & (IO_VMIO|IO_DIRECT)) &&
+ (LIST_EMPTY(&bp->b_dep))) {
+ /*
+ * If there are no dependencies, and it's VMIO,
+ * then we don't need the buf, mark it available
+ * for freeing. For non-direct VMIO reads, the VM
+ * has the data.
+ */
+ bp->b_flags |= B_RELBUF;
+ brelse(bp);
+ } else {
+ /*
+ * Otherwise let whoever
+ * made the request take care of
+ * freeing it. We just queue
+ * it onto another list.
+ */
+ bqrelse(bp);
+ }
+#else
+ brelse(bp, 0);
+#endif
+ }
+
+ /*
+ * This can only happen in the case of an error
+ * because the loop above resets bp to NULL on each iteration
+ * and on normal completion has not set a new value into it.
+ * so it must have come from a 'break' statement
+ */
+ if (bp != NULL) {
+#ifdef notyet
+ if ((ioflag & (IO_VMIO|IO_DIRECT)) &&
+ (LIST_EMPTY(&bp->b_dep))) {
+ bp->b_flags |= B_RELBUF;
+ brelse(bp);
+ } else {
+ bqrelse(bp);
+ }
+#else
+ brelse(bp, BC_INVAL);
+#endif
+ }
+ return (error);
+}
+
+/*
+ * Extended attribute area writing.
+ */
+static int
+ffs_extwrite(struct vnode *vp, struct uio *uio, int ioflag,
+ kauth_cred_t cred)
+{
+ struct inode *ip;
+ struct ufs2_dinode *dp;
+ struct fs *fs;
+ struct buf *bp;
+ daddr_t lbn;
+ off_t osize;
+ ssize_t blkoffset, resid, size, xfersize;
+ int error, flags;
+
+ ip = VTOI(vp);
+ fs = ip->i_fs;
+ dp = ip->i_din.ffs2_din;
+
+#ifdef DIAGNOSTIC
+ if (uio->uio_rw != UIO_WRITE || fs->fs_magic != FS_UFS2_MAGIC)
+ panic("ffs_extwrite: mode");
+#endif
+
+ if (ioflag & IO_APPEND)
+ uio->uio_offset = dp->di_extsize;
+ KASSERT(uio->uio_offset >= 0);
+ if (uio->uio_offset + uio->uio_resid > NXADDR * fs->fs_bsize)
+ return (EFBIG);
+
+ resid = uio->uio_resid;
+ osize = dp->di_extsize;
+ 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->fs_bsize - blkoffset;
+ if (uio->uio_resid < xfersize)
+ xfersize = uio->uio_resid;
- /* XXX Not implemented for UFS2 file systems. */
- return (EOPNOTSUPP);
+ /*
+ * We must perform a read-before-write if the transfer size
+ * does not cover the entire buffer.
+ */
+ if (fs->fs_bsize > xfersize)
+ flags |= B_CLRBUF;
+ else
+ flags &= ~B_CLRBUF;
+ error = ffs_balloc(vp, uio->uio_offset, xfersize,
+ cred, flags, BTYPE_EXTDATA, &bp);
+ if (error != 0)
+ break;
+#ifdef notyet
+ if (ioflag & IO_DIRECT)
+ bp->b_flags |= B_DIRECT;
+#endif
+
+ if (uio->uio_offset + xfersize > dp->di_extsize)
+ dp->di_extsize = uio->uio_offset + xfersize;
+
+ size = sblksize(fs, dp->di_extsize, lbn) - bp->b_resid;
+ if (size < xfersize)
+ xfersize = size;
+
+ error =
+ uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
+
+ if (ioflag & IO_SYNC)
+ (void)bwrite(bp);
+ else
+ bdwrite(bp);
+ if (error || xfersize == 0)
+ break;
+ ip->i_flag |= IN_CHANGE;
+ }
+ /*
+ * 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 ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid && cred) {
+ if (kauth_authorize_generic(cred,
+ KAUTH_GENERIC_ISSUSER, NULL)) {
+ ip->i_mode &= ~(ISUID | ISGID);
+ DIP_ASSIGN(ip, mode, ip->i_mode);
+ }
+ }
+ if (error) {
+ if (ioflag & IO_UNIT) {
+ (void)ffs_extattr_truncate(vp, osize,
+ (ioflag&IO_SYNC), cred);
+ uio->uio_offset -= resid - uio->uio_resid;
+ uio->uio_resid = resid;
+ }
+ } else if (resid > uio->uio_resid && (ioflag & IO_SYNC))
+ error = ffs_update(vp, NULL, NULL, UPDATE_WAIT);
+ return (error);
+}
+
+
+/*
+ * Vnode operating to retrieve a named extended attribute.
+ *
+ * Locate a particular EA (nspace:name) in the area (ptr:length), and return
+ * the length of the EA, and possibly the pointer to the entry and to the data.
+ */
+static int
+ffs_findextattr(u_char *ptr, u_int length, int nspace, const char *name,
+ u_char **eap, u_char **eac)
+{
+ u_char *p, *pe, *pn, *p0;
+ ssize_t eapad1, eapad2, ealength, ealen, nlen;
+ uint32_t ul;
+
+ pe = ptr + length;
+ nlen = strlen(name);
+
+ for (p = ptr; p < pe; p = pn) {
+ p0 = p;
+ memcpy(&ul, p, sizeof(ul));
+ pn = p + ul;
+ /* make sure this entry is complete */
+ if (pn > pe)
+ break;
+ p += sizeof(uint32_t);
+ if (*p != nspace)
+ continue;
+ p++;
+ eapad2 = *p++;
+ if (*p != nlen)
+ continue;
+ p++;
+ if (bcmp(p, name, nlen))
+ continue;
+ ealength = sizeof(uint32_t) + 3 + nlen;
+ eapad1 = 8 - (ealength % 8);
+ if (eapad1 == 8)
+ eapad1 = 0;
+ ealength += eapad1;
+ ealen = ul - ealength - eapad2;
+ p += nlen + eapad1;
+ if (eap != NULL)
+ *eap = p0;
+ if (eac != NULL)
+ *eac = p;
+ return (ealen);
+ }
+ return(-1);
+}
+
+static int
+ffs_rdextattr(u_char **p, struct vnode *vp, int extra)
+{
+ struct inode *ip;
+ struct ufs2_dinode *dp;
+ struct fs *fs;
+ struct uio luio;
+ struct iovec liovec;
+ ssize_t easize;
+ int error;
+ u_char *eae;
+
+ ip = VTOI(vp);
+ fs = ip->i_fs;
+ dp = ip->i_din.ffs2_din;
+ easize = dp->di_extsize;
+ if (easize + extra > NXADDR * fs->fs_bsize)
+ return (EFBIG);
+
+ eae = malloc(easize + extra, M_FFS_EXTATTR, M_WAITOK);
+
+ liovec.iov_base = eae;
+ liovec.iov_len = easize;
+ luio.uio_iov = &liovec;
+ luio.uio_iovcnt = 1;
+ luio.uio_offset = 0;
+ luio.uio_resid = easize;
+ UIO_SETUP_SYSSPACE(&luio);
+ luio.uio_rw = UIO_READ;
+
+ error = ffs_extread(vp, &luio, IO_SYNC);
+ if (error) {
+ free(eae, M_FFS_EXTATTR);
+ return(error);
+ }
+ *p = eae;
+ return (0);
+}
+
+static void
+ffs_lock_ea(struct vnode *vp)
+{
+ KASSERT(VOP_ISLOCKED(vp));
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+}
+
+static void
+ffs_unlock_ea(struct vnode *vp)
+{
+ /* nothing */
+}
+
+static int
+ffs_open_ea(struct vnode *vp, kauth_cred_t cred)
+{
+ struct inode *ip;
+ struct ufs2_dinode *dp;
+ int error;
+
+ ip = VTOI(vp);
+
+ ffs_lock_ea(vp);
+ if (ip->i_ffs_ea_area != NULL) {
+ ip->i_ffs_ea_refs++;
+ ffs_unlock_ea(vp);
+ return (0);
+ }
+ dp = ip->i_din.ffs2_din;
+ error = ffs_rdextattr(&ip->i_ffs_ea_area, vp, 0);
+ if (error) {
+ ffs_unlock_ea(vp);
+ return (error);
+ }
+ ip->i_ffs_ea_len = dp->di_extsize;
+ ip->i_ffs_ea_error = 0;
+ ip->i_ffs_ea_refs++;
+ ffs_unlock_ea(vp);
+ return (0);
+}
+
+/*
+ * Vnode extattr transaction commit/abort
+ */
+static int
+ffs_close_ea(struct vnode *vp, int commit, kauth_cred_t cred)
+{
+ struct inode *ip;
+ struct uio luio;
+ struct iovec liovec;
+ int error;
+ struct ufs2_dinode *dp;
+
+ ip = VTOI(vp);
+
+ ffs_lock_ea(vp);
+ if (ip->i_ffs_ea_area == NULL) {
+ ffs_unlock_ea(vp);
+ return (EINVAL);
+ }
+ dp = ip->i_din.ffs2_din;
+ error = ip->i_ffs_ea_error;
+ if (commit && error == 0) {
+ liovec.iov_base = ip->i_ffs_ea_area;
+ liovec.iov_len = ip->i_ffs_ea_len;
+ luio.uio_iov = &liovec;
+ luio.uio_iovcnt = 1;
+ luio.uio_offset = 0;
+ luio.uio_resid = ip->i_ffs_ea_len;
+ UIO_SETUP_SYSSPACE(&luio);
+ luio.uio_rw = UIO_WRITE;
+ if (ip->i_ffs_ea_len < dp->di_extsize)
+ error = ffs_extattr_truncate(vp, ip->i_ffs_ea_len,
+ 0, cred);
+ if (error == 0)
+ error = ffs_extwrite(vp, &luio, IO_SYNC, cred);
+ }
+ if (--ip->i_ffs_ea_refs == 0) {
+ free(ip->i_ffs_ea_area, M_TEMP);
+ ip->i_ffs_ea_area = NULL;
+ ip->i_ffs_ea_len = 0;
+ ip->i_ffs_ea_error = 0;
+ }
+ ffs_unlock_ea(vp);
+ return (error);
}
Index: sys/ufs/ffs/fs.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/fs.h,v
retrieving revision 1.56
diff -u -r1.56 fs.h
--- sys/ufs/ffs/fs.h 6 Mar 2011 17:08:38 -0000 1.56
+++ sys/ufs/ffs/fs.h 16 Jan 2012 20:36:39 -0000
@@ -712,6 +712,10 @@
? (fs)->fs_bsize \
: (fragroundup(fs, blkoff(fs, (size)))))
+#define extsize(fs, size, lbn) \
+ (((size) >= ((lbn) + 1) << (fs)->fs_bshift) \
+ ? (fs)->fs_bsize \
+ : (fragroundup(fs, blkoff(fs, (size)))))
/*
* Number of inodes in a secondary storage block/fragment.
Index: sys/ufs/lfs/lfs_alloc.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_alloc.c,v
retrieving revision 1.111
diff -u -r1.111 lfs_alloc.c
--- sys/ufs/lfs/lfs_alloc.c 12 Jun 2011 03:36:01 -0000 1.111
+++ sys/ufs/lfs/lfs_alloc.c 16 Jan 2012 20:36:39 -0000
@@ -128,7 +128,7 @@
ip = VTOI(vp);
blkno = lblkno(fs, ip->i_size);
if ((error = lfs_balloc(vp, ip->i_size, fs->lfs_bsize, cred, 0,
- &bp)) != 0) {
+ BTYPE_DATA, &bp)) != 0) {
return (error);
}
ip->i_size += fs->lfs_bsize;
Index: sys/ufs/lfs/lfs_balloc.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_balloc.c,v
retrieving revision 1.70
diff -u -r1.70 lfs_balloc.c
--- sys/ufs/lfs/lfs_balloc.c 11 Jul 2011 08:27:40 -0000 1.70
+++ sys/ufs/lfs/lfs_balloc.c 16 Jan 2012 20:36:39 -0000
@@ -109,7 +109,7 @@
/* VOP_BWRITE NIADDR+2 times */
int
lfs_balloc(struct vnode *vp, off_t startoffset, int iosize, kauth_cred_t cred,
- int flags, struct buf **bpp)
+ int flags, int type, struct buf **bpp)
{
int offset;
daddr_t daddr, idaddr;
@@ -130,6 +130,8 @@
ASSERT_MAYBE_SEGLOCK(fs);
+ KASSERT(type == BTYPE_DATA);
+
/*
* Three cases: it's a block beyond the end of file, it's a block in
* the file that may or may not have been assigned a disk address or
Index: sys/ufs/lfs/lfs_extern.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_extern.h,v
retrieving revision 1.97
diff -u -r1.97 lfs_extern.h
--- sys/ufs/lfs/lfs_extern.h 2 Jan 2012 22:10:44 -0000 1.97
+++ sys/ufs/lfs/lfs_extern.h 16 Jan 2012 20:36:39 -0000
@@ -130,7 +130,8 @@
void lfs_orphan(struct lfs *, ino_t);
/* lfs_balloc.c */
-int lfs_balloc(struct vnode *, off_t, int, kauth_cred_t, int, struct buf **);
+int lfs_balloc(struct vnode *, off_t, int, kauth_cred_t, int, int,
+ struct buf **);
void lfs_register_block(struct vnode *, daddr_t);
void lfs_deregister_block(struct vnode *, daddr_t);
void lfs_deregister_all(struct vnode *);
Index: sys/ufs/lfs/lfs_inode.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_inode.c,v
retrieving revision 1.126
diff -u -r1.126 lfs_inode.c
--- sys/ufs/lfs/lfs_inode.c 23 Nov 2011 19:42:10 -0000 1.126
+++ sys/ufs/lfs/lfs_inode.c 16 Jan 2012 20:36:39 -0000
@@ -214,6 +214,9 @@
int usepc;
struct ufsmount *ump = oip->i_ump;
+ if (ioflag & IO_EXT)
+ return 0;
+
if (ovp->v_type == VCHR || ovp->v_type == VBLK ||
ovp->v_type == VFIFO || ovp->v_type == VSOCK) {
KASSERT(oip->i_size == 0);
@@ -308,7 +311,7 @@
if (error)
return (error);
error = lfs_balloc(ovp, length - 1, 1, cred,
- aflags, &bp);
+ aflags, BTYPE_DATA, &bp);
lfs_reserve(fs, ovp, NULL,
-btofsb(fs, (NIADDR + 2) << fs->lfs_bshift));
if (error)
@@ -347,7 +350,8 @@
aflags = B_CLRBUF;
if (ioflag & IO_SYNC)
aflags |= B_SYNC;
- error = lfs_balloc(ovp, length - 1, 1, cred, aflags, &bp);
+ error = lfs_balloc(ovp, length - 1, 1, cred, aflags,
+ BTYPE_DATA, &bp);
if (error) {
lfs_reserve(fs, ovp, NULL,
-btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift));
Index: sys/ufs/lfs/lfs_rfw.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_rfw.c,v
retrieving revision 1.12
diff -u -r1.12 lfs_rfw.c
--- sys/ufs/lfs/lfs_rfw.c 22 Feb 2009 20:28:07 -0000 1.12
+++ sys/ufs/lfs/lfs_rfw.c 16 Jan 2012 20:36:39 -0000
@@ -232,7 +232,7 @@
}
if ((error = lfs_balloc(vp, (lbn << fs->lfs_bshift), size,
- NOCRED, 0, &bp)) != 0) {
+ NOCRED, 0, BTYPE_DATA, &bp)) != 0) {
vput(vp);
return (error);
}
Index: sys/ufs/lfs/lfs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_vfsops.c,v
retrieving revision 1.293
diff -u -r1.293 lfs_vfsops.c
--- sys/ufs/lfs/lfs_vfsops.c 4 Jan 2012 02:48:58 -0000 1.293
+++ sys/ufs/lfs/lfs_vfsops.c 16 Jan 2012 20:36:39 -0000
@@ -2098,7 +2098,7 @@
/* Allocate new Ifile blocks */
for (i = ilast; i < ilast + noff; i++) {
if (lfs_balloc(ivp, i * fs->lfs_bsize, fs->lfs_bsize, NOCRED, 0,
- &bp) != 0)
+ BTYPE_DATA, &bp) != 0)
panic("balloc extending ifile");
memset(bp->b_data, 0, fs->lfs_bsize);
VOP_BWRITE(bp->b_vp, bp);
Index: sys/ufs/ufs/inode.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/inode.h,v
retrieving revision 1.59
diff -u -r1.59 inode.h
--- sys/ufs/ufs/inode.h 2 Jan 2012 22:10:45 -0000 1.59
+++ sys/ufs/ufs/inode.h 16 Jan 2012 20:36:39 -0000
@@ -70,6 +70,13 @@
/* follow two fields are used by contiguous allocation code only. */
daddr_t ffs_first_data_blk; /* first data block on disk. */
daddr_t ffs_first_indir_blk; /* first indirect block on disk. */
+ /*
+ * Data for extended attribute modification.
+ */
+ u_char *ffs_ea_area; /* Pointer to malloced copy of EA area */
+ unsigned ffs_ea_len; /* Length of i_ea_area */
+ int ffs_ea_error; /* First errno in transaction */
+ int ffs_ea_refs; /* Number of users of EA area */
};
struct ext2fs_inode_ext {
@@ -132,6 +139,10 @@
#define i_snapblklist inode_ext.ffs.ffs_snapblklist
#define i_ffs_first_data_blk inode_ext.ffs.ffs_first_data_blk
#define i_ffs_first_indir_blk inode_ext.ffs.ffs_first_indir_blk
+#define i_ffs_ea_area inode_ext.ffs.ffs_ea_area
+#define i_ffs_ea_len inode_ext.ffs.ffs_ea_len
+#define i_ffs_ea_error inode_ext.ffs.ffs_ea_error
+#define i_ffs_ea_refs inode_ext.ffs.ffs_ea_refs
#define i_e2fs_last_lblk inode_ext.e2fs.ext2fs_last_lblk
#define i_e2fs_last_blk inode_ext.e2fs.ext2fs_last_blk
/*
@@ -242,7 +253,7 @@
#define IN_ADIROP 0x0200 /* LFS: dirop in progress */
#define IN_SPACECOUNTED 0x0400 /* Blocks to be freed in free
count. */
#define IN_PAGING 0x1000 /* LFS: file is on paging queue
*/
-#define IN_CDIROP 0x4000 /* LFS: dirop completed pending i/o */
+#define IN_CDIROP 0x4000 /* LFS: dirop completed pending i/o */
#if defined(_KERNEL)
/*
@@ -295,6 +306,11 @@
u_int32_t ufid_ino; /* File number (ino). */
int32_t ufid_gen; /* Generation number. */
};
+
+/* different buffer types */
+#define BTYPE_DATA 0 /* regular data, has to be 0 */
+/* reserve 1-3 for indirect blocks eventually */
+#define BTYPE_EXTDATA 4 /* extended attribute data */
#endif /* _KERNEL */
#endif /* !_UFS_UFS_INODE_H_ */
Index: sys/ufs/ufs/ufs_bmap.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_bmap.c,v
retrieving revision 1.49
diff -u -r1.49 ufs_bmap.c
--- sys/ufs/ufs/ufs_bmap.c 6 Mar 2011 17:08:39 -0000 1.49
+++ sys/ufs/ufs/ufs_bmap.c 16 Jan 2012 20:36:39 -0000
@@ -403,3 +403,21 @@
*nump = numlevels;
return (0);
}
+
+int
+ufs_extbmap(struct vnode *vp, daddr_t bn, daddr_t *bnp)
+{
+ struct inode *ip = VTOI(vp);
+ struct ufsmount *ump = ip->i_ump;
+ daddr_t daddr;
+
+ KASSERT(ump->um_fstype == UFS2);
+ KASSERT(bnp != NULL);
+ if (bn >= 0 && bn < NXADDR) {
+ daddr = ufs_rw64(ip->i_ffs2_extb[bn], UFS_MPNEEDSWAP(ump));
+ *bnp = blkptrtodb(ump, daddr);
+ } else {
+ *bnp = -1;
+ }
+ return 0;
+}
Index: sys/ufs/ufs/ufs_extern.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_extern.h,v
retrieving revision 1.66
diff -u -r1.66 ufs_extern.h
--- sys/ufs/ufs/ufs_extern.h 17 Jul 2011 22:07:59 -0000 1.66
+++ sys/ufs/ufs/ufs_extern.h 16 Jan 2012 20:36:39 -0000
@@ -107,6 +107,7 @@
int ufs_bmaparray(struct vnode *, daddr_t, daddr_t *, struct indir *,
int *, int *, ufs_issequential_callback_t);
int ufs_getlbns(struct vnode *, daddr_t, struct indir *, int *);
+int ufs_extbmap(struct vnode *, daddr_t, daddr_t *);
/* ufs_ihash.c */
void ufs_ihashinit(void);
Index: sys/ufs/ufs/ufs_inode.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_inode.c,v
retrieving revision 1.88
diff -u -r1.88 ufs_inode.c
--- sys/ufs/ufs/ufs_inode.c 20 Sep 2011 14:01:33 -0000 1.88
+++ sys/ufs/ufs/ufs_inode.c 16 Jan 2012 20:36:39 -0000
@@ -106,6 +106,10 @@
if (error)
goto out;
logged = 1;
+ /* trucate extended data if any */
+ error = UFS_TRUNCATE(vp, (off_t)0, IO_EXT, NOCRED);
+ if (error)
+ goto out;
if (ip->i_size != 0) {
/*
* When journaling, only truncate one indirect block
Index: sys/ufs/ufs/ufs_lookup.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_lookup.c,v
retrieving revision 1.111
diff -u -r1.111 ufs_lookup.c
--- sys/ufs/ufs/ufs_lookup.c 17 Jul 2011 22:07:59 -0000 1.111
+++ sys/ufs/ufs/ufs_lookup.c 16 Jan 2012 20:36:39 -0000
@@ -813,7 +813,7 @@
if (ulr->ulr_offset & (dirblksiz - 1))
panic("ufs_direnter: newblk");
if ((error = UFS_BALLOC(dvp, (off_t)ulr->ulr_offset, dirblksiz,
- cr, B_CLRBUF | B_SYNC, &bp)) != 0) {
+ cr, B_CLRBUF | B_SYNC, BTYPE_DATA, &bp)) != 0) {
return (error);
}
dp->i_size = ulr->ulr_offset + dirblksiz;
Index: sys/ufs/ufs/ufs_quota2.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_quota2.c,v
retrieving revision 1.4
diff -u -r1.4 ufs_quota2.c
--- sys/ufs/ufs/ufs_quota2.c 7 Jun 2011 14:56:13 -0000 1.4
+++ sys/ufs/ufs/ufs_quota2.c 16 Jan 2012 20:36:39 -0000
@@ -326,7 +326,7 @@
uint64_t size = ip->i_size;
/* need to alocate a new disk block */
error = UFS_BALLOC(vp, size, ump->umq2_bsize,
- ump->um_cred[type], B_CLRBUF | B_SYNC, &bp);
+ ump->um_cred[type], B_CLRBUF | B_SYNC, BTYPE_DATA, &bp);
if (error) {
brelse(hbp, 0);
return error;
Index: sys/ufs/ufs/ufs_readwrite.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_readwrite.c,v
retrieving revision 1.101
diff -u -r1.101 ufs_readwrite.c
--- sys/ufs/ufs/ufs_readwrite.c 2 Jan 2012 22:10:45 -0000 1.101
+++ sys/ufs/ufs/ufs_readwrite.c 16 Jan 2012 20:36:39 -0000
@@ -453,7 +453,7 @@
need_unreserve = true;
#endif
error = UFS_BALLOC(vp, uio->uio_offset, xfersize,
- ap->a_cred, flags, &bp);
+ ap->a_cred, flags, BTYPE_DATA, &bp);
if (error)
break;
Index: sys/ufs/ufs/ufs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_vnops.c,v
retrieving revision 1.206
diff -u -r1.206 ufs_vnops.c
--- sys/ufs/ufs/ufs_vnops.c 18 Nov 2011 21:18:52 -0000 1.206
+++ sys/ufs/ufs/ufs_vnops.c 16 Jan 2012 20:36:39 -0000
@@ -2091,7 +2091,7 @@
dirtemplate.dot_type = dirtemplate.dotdot_type = 0;
}
if ((error = UFS_BALLOC(tvp, (off_t)0, dirblksiz, cnp->cn_cred,
- B_CLRBUF, &bp)) != 0)
+ B_CLRBUF, BTYPE_DATA, &bp)) != 0)
goto bad;
ip->i_size = dirblksiz;
DIP_ASSIGN(ip, size, dirblksiz);
@@ -2500,8 +2500,12 @@
panic("ufs_strategy: spec");
KASSERT(bp->b_bcount != 0);
if (bp->b_blkno == bp->b_lblkno) {
- error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno,
- NULL);
+ if (bp->b_type == BTYPE_EXTDATA) {
+ error = ufs_extbmap(vp, bp->b_lblkno, &bp->b_blkno);
+ } else {
+ error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno,
+ NULL);
+ }
if (error) {
bp->b_error = error;
biodone(bp);
@@ -2940,7 +2944,7 @@
while (len > 0) {
bsize = MIN(bsize, len);
- error = UFS_BALLOC(vp, off, bsize, cred, flags, NULL);
+ error = UFS_BALLOC(vp, off, bsize, cred, flags, BTYPE_DATA,
NULL);
if (error) {
goto out;
}
Index: sys/ufs/ufs/ufsmount.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufsmount.h,v
retrieving revision 1.37
diff -u -r1.37 ufsmount.h
--- sys/ufs/ufs/ufsmount.h 24 Nov 2011 15:51:32 -0000 1.37
+++ sys/ufs/ufs/ufsmount.h 16 Jan 2012 20:36:39 -0000
@@ -134,7 +134,7 @@
int (*uo_truncate)(struct vnode *, off_t, int, kauth_cred_t);
int (*uo_valloc)(struct vnode *, int, kauth_cred_t, struct vnode **);
int (*uo_vfree)(struct vnode *, ino_t, int);
- int (*uo_balloc)(struct vnode *, off_t, int, kauth_cred_t, int,
+ int (*uo_balloc)(struct vnode *, off_t, int, kauth_cred_t, int, int,
struct buf **);
void (*uo_unmark_vnode)(struct vnode *);
};
@@ -151,8 +151,8 @@
(*UFS_OPS(vp)->uo_valloc)((vp), (mode), (cr), (vpp))
#define UFS_VFREE(vp, ino, mode) \
(*UFS_OPS(vp)->uo_vfree)((vp), (ino), (mode))
-#define UFS_BALLOC(vp, off, size, cr, flags, bpp) \
- (*UFS_OPS(vp)->uo_balloc)((vp), (off), (size), (cr), (flags), (bpp))
+#define UFS_BALLOC(vp, off, size, cr, flags, type, bpp) \
+ (*UFS_OPS(vp)->uo_balloc)((vp), (off), (size), (cr), (flags), (type),
(bpp))
#define UFS_UNMARK_VNODE(vp) \
(*UFS_OPS(vp)->uo_unmark_vnode)((vp))
Index: sys/sys/buf.h
===================================================================
RCS file: /cvsroot/src/sys/sys/buf.h,v
retrieving revision 1.118
diff -u -r1.118 buf.h
--- sys/sys/buf.h 21 Nov 2011 04:36:05 -0000 1.118
+++ sys/sys/buf.h 16 Jan 2012 20:36:39 -0000
@@ -113,6 +113,7 @@
int b_error; /* b: errno value. */
int b_resid; /* b: remaining I/O. */
u_int b_flags; /* b: B_* flags */
+ int b_type; /* b: data type */
int b_prio; /* b: priority for queue */
int b_bufsize; /* b: allocated size */
int b_bcount; /* b: valid bytes in buffer */
Index: sys/ufs/ufs/inode.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/inode.h,v
retrieving revision 1.59
diff -u -r1.59 inode.h
--- sys/ufs/ufs/inode.h 2 Jan 2012 22:10:45 -0000 1.59
+++ sys/ufs/ufs/inode.h 16 Jan 2012 20:36:39 -0000
@@ -70,6 +70,13 @@
/* follow two fields are used by contiguous allocation code only. */
daddr_t ffs_first_data_blk; /* first data block on disk. */
daddr_t ffs_first_indir_blk; /* first indirect block on disk. */
+ /*
+ * Data for extended attribute modification.
+ */
+ u_char *ffs_ea_area; /* Pointer to malloced copy of EA area */
+ unsigned ffs_ea_len; /* Length of i_ea_area */
+ int ffs_ea_error; /* First errno in transaction */
+ int ffs_ea_refs; /* Number of users of EA area */
};
struct ext2fs_inode_ext {
@@ -132,6 +139,10 @@
#define i_snapblklist inode_ext.ffs.ffs_snapblklist
#define i_ffs_first_data_blk inode_ext.ffs.ffs_first_data_blk
#define i_ffs_first_indir_blk inode_ext.ffs.ffs_first_indir_blk
+#define i_ffs_ea_area inode_ext.ffs.ffs_ea_area
+#define i_ffs_ea_len inode_ext.ffs.ffs_ea_len
+#define i_ffs_ea_error inode_ext.ffs.ffs_ea_error
+#define i_ffs_ea_refs inode_ext.ffs.ffs_ea_refs
#define i_e2fs_last_lblk inode_ext.e2fs.ext2fs_last_lblk
#define i_e2fs_last_blk inode_ext.e2fs.ext2fs_last_blk
/*
@@ -242,7 +253,7 @@
#define IN_ADIROP 0x0200 /* LFS: dirop in progress */
#define IN_SPACECOUNTED 0x0400 /* Blocks to be freed in free
count. */
#define IN_PAGING 0x1000 /* LFS: file is on paging queue
*/
-#define IN_CDIROP 0x4000 /* LFS: dirop completed pending i/o */
+#define IN_CDIROP 0x4000 /* LFS: dirop completed pending i/o */
#if defined(_KERNEL)
/*
Home |
Main Index |
Thread Index |
Old Index