summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_subr.c
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2002-07-19 07:29:39 +0000
committermckusick <mckusick@FreeBSD.org>2002-07-19 07:29:39 +0000
commitb44cb5787c401c1aaf5bbd0e42c211579b8efc31 (patch)
treeab6d723eb551696589894f8c55d99db82233b8c0 /sys/kern/vfs_subr.c
parent083a6fe2b0dce41b375be7f611b37e64ec218129 (diff)
downloadFreeBSD-src-b44cb5787c401c1aaf5bbd0e42c211579b8efc31.zip
FreeBSD-src-b44cb5787c401c1aaf5bbd0e42c211579b8efc31.tar.gz
Add support to UFS2 to provide storage for extended attributes.
As this code is not actually used by any of the existing interfaces, it seems unlikely to break anything (famous last words). The internal kernel interface to manipulate these attributes is invoked using two new IO_ flags: IO_NORMAL and IO_EXT. These flags may be specified in the ioflags word of VOP_READ, VOP_WRITE, and VOP_TRUNCATE. Specifying IO_NORMAL means that you want to do I/O to the normal data part of the file and IO_EXT means that you want to do I/O to the extended attributes part of the file. IO_NORMAL and IO_EXT are mutually exclusive for VOP_READ and VOP_WRITE, but may be specified individually or together in the case of VOP_TRUNCATE. For example, when removing a file, VOP_TRUNCATE is called with both IO_NORMAL and IO_EXT set. For backward compatibility, if neither IO_NORMAL nor IO_EXT is set, then IO_NORMAL is assumed. Note that the BA_ and IO_ flags have been `merged' so that they may both be used in the same flags word. This merger is possible by assigning the IO_ flags to the low sixteen bits and the BA_ flags the high sixteen bits. This works because the high sixteen bits of the IO_ word is reserved for read-ahead and help with write clustering so will never be used for flags. This merge lets us get away from code of the form: if (ioflags & IO_SYNC) flags |= BA_SYNC; For the future, I have considered adding a new field to the vattr structure, va_extsize. This addition could then be exported through the stat structure to allow applications to find out the size of the extended attribute storage and also would provide a more standard interface for truncating them (via VOP_SETATTR rather than VOP_TRUNCATE). I am also contemplating adding a pathconf parameter (for concreteness, lets call it _PC_MAX_EXTSIZE) which would let an application determine the maximum size of the extended atribute storage. Sponsored by: DARPA & NAI Labs.
Diffstat (limited to 'sys/kern/vfs_subr.c')
-rw-r--r--sys/kern/vfs_subr.c136
1 files changed, 85 insertions, 51 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 9fd2b0f..e620d4a 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -76,6 +76,8 @@ static void addalias(struct vnode *vp, dev_t nvp_rdev);
static void insmntque(struct vnode *vp, struct mount *mp);
static void vclean(struct vnode *vp, int flags, struct thread *td);
static void vlruvp(struct vnode *vp);
+static int flushbuflist(struct buf *blist, int flags, struct vnode *vp,
+ int slpflag, int slptimeo, int *errorp);
/*
* Number of vnodes in existence. Increased whenever getnewvnode()
@@ -898,14 +900,13 @@ vwakeup(bp)
*/
int
vinvalbuf(vp, flags, cred, td, slpflag, slptimeo)
- register struct vnode *vp;
+ struct vnode *vp;
int flags;
struct ucred *cred;
struct thread *td;
int slpflag, slptimeo;
{
- register struct buf *bp;
- struct buf *nbp, *blist;
+ struct buf *blist;
int s, error;
vm_object_t object;
@@ -934,55 +935,24 @@ vinvalbuf(vp, flags, cred, td, slpflag, slptimeo)
splx(s);
}
s = splbio();
- for (;;) {
- blist = TAILQ_FIRST(&vp->v_cleanblkhd);
- if (!blist)
- blist = TAILQ_FIRST(&vp->v_dirtyblkhd);
- if (!blist)
- break;
-
- for (bp = blist; bp; bp = nbp) {
- nbp = TAILQ_NEXT(bp, b_vnbufs);
- if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) {
- error = BUF_TIMELOCK(bp,
- LK_EXCLUSIVE | LK_SLEEPFAIL,
- "vinvalbuf", slpflag, slptimeo);
- if (error == ENOLCK)
- break;
- splx(s);
- return (error);
- }
- /*
- * XXX Since there are no node locks for NFS, I
- * believe there is a slight chance that a delayed
- * write will occur while sleeping just above, so
- * check for it. Note that vfs_bio_awrite expects
- * buffers to reside on a queue, while BUF_WRITE and
- * brelse do not.
- */
- if (((bp->b_flags & (B_DELWRI | B_INVAL)) == B_DELWRI) &&
- (flags & V_SAVE)) {
-
- if (bp->b_vp == vp) {
- if (bp->b_flags & B_CLUSTEROK) {
- BUF_UNLOCK(bp);
- vfs_bio_awrite(bp);
- } else {
- bremfree(bp);
- bp->b_flags |= B_ASYNC;
- BUF_WRITE(bp);
- }
- } else {
- bremfree(bp);
- (void) BUF_WRITE(bp);
- }
+ for (error = 0;;) {
+ if ((blist = TAILQ_FIRST(&vp->v_cleanblkhd)) != 0 &&
+ flushbuflist(blist, flags, vp, slpflag, slptimeo, &error)) {
+ if (error)
break;
- }
- bremfree(bp);
- bp->b_flags |= (B_INVAL | B_NOCACHE | B_RELBUF);
- bp->b_flags &= ~B_ASYNC;
- brelse(bp);
+ continue;
+ }
+ if ((blist = TAILQ_FIRST(&vp->v_dirtyblkhd)) != 0 &&
+ flushbuflist(blist, flags, vp, slpflag, slptimeo, &error)) {
+ if (error)
+ break;
+ continue;
}
+ break;
+ }
+ if (error) {
+ splx(s);
+ return (error);
}
/*
@@ -1013,12 +983,76 @@ vinvalbuf(vp, flags, cred, td, slpflag, slptimeo)
}
mtx_unlock(&vp->v_interlock);
- if (!TAILQ_EMPTY(&vp->v_dirtyblkhd) || !TAILQ_EMPTY(&vp->v_cleanblkhd))
+ if ((flags & (V_ALT | V_NORMAL)) == 0 &&
+ (!TAILQ_EMPTY(&vp->v_dirtyblkhd) ||
+ !TAILQ_EMPTY(&vp->v_cleanblkhd)))
panic("vinvalbuf: flush failed");
return (0);
}
/*
+ * Flush out buffers on the specified list.
+ */
+static int
+flushbuflist(blist, flags, vp, slpflag, slptimeo, errorp)
+ struct buf *blist;
+ int flags;
+ struct vnode *vp;
+ int slpflag, slptimeo;
+ int *errorp;
+{
+ struct buf *bp, *nbp;
+ int found, error;
+
+ for (found = 0, bp = blist; bp; bp = nbp) {
+ nbp = TAILQ_NEXT(bp, b_vnbufs);
+ if (((flags & V_NORMAL) && (bp->b_xflags & BX_ALTDATA)) ||
+ ((flags & V_ALT) && (bp->b_xflags & BX_ALTDATA) == 0))
+ continue;
+ found += 1;
+ if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) {
+ error = BUF_TIMELOCK(bp,
+ LK_EXCLUSIVE | LK_SLEEPFAIL,
+ "flushbuf", slpflag, slptimeo);
+ if (error != ENOLCK)
+ *errorp = error;
+ return (found);
+ }
+ /*
+ * XXX Since there are no node locks for NFS, I
+ * believe there is a slight chance that a delayed
+ * write will occur while sleeping just above, so
+ * check for it. Note that vfs_bio_awrite expects
+ * buffers to reside on a queue, while BUF_WRITE and
+ * brelse do not.
+ */
+ if (((bp->b_flags & (B_DELWRI | B_INVAL)) == B_DELWRI) &&
+ (flags & V_SAVE)) {
+
+ if (bp->b_vp == vp) {
+ if (bp->b_flags & B_CLUSTEROK) {
+ BUF_UNLOCK(bp);
+ vfs_bio_awrite(bp);
+ } else {
+ bremfree(bp);
+ bp->b_flags |= B_ASYNC;
+ BUF_WRITE(bp);
+ }
+ } else {
+ bremfree(bp);
+ (void) BUF_WRITE(bp);
+ }
+ return (found);
+ }
+ bremfree(bp);
+ bp->b_flags |= (B_INVAL | B_NOCACHE | B_RELBUF);
+ bp->b_flags &= ~B_ASYNC;
+ brelse(bp);
+ }
+ return (found);
+}
+
+/*
* Truncate a file's buffer and pages to a specified length. This
* is in lieu of the old vinvalbuf mechanism, which performed unneeded
* sync activity.
OpenPOWER on IntegriCloud