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