summaryrefslogtreecommitdiffstats
path: root/sys/miscfs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/miscfs')
-rw-r--r--sys/miscfs/deadfs/dead_vnops.c28
-rw-r--r--sys/miscfs/fdesc/fdesc.h5
-rw-r--r--sys/miscfs/fdesc/fdesc_vfsops.c71
-rw-r--r--sys/miscfs/fdesc/fdesc_vnops.c162
-rw-r--r--sys/miscfs/fifofs/fifo.h10
-rw-r--r--sys/miscfs/fifofs/fifo_vnops.c177
-rw-r--r--sys/miscfs/kernfs/kernfs.h15
-rw-r--r--sys/miscfs/kernfs/kernfs_vfsops.c153
-rw-r--r--sys/miscfs/kernfs/kernfs_vnops.c397
-rw-r--r--sys/miscfs/nullfs/null.h5
-rw-r--r--sys/miscfs/nullfs/null_subr.c61
-rw-r--r--sys/miscfs/nullfs/null_vfsops.c19
-rw-r--r--sys/miscfs/nullfs/null_vnops.c223
-rw-r--r--sys/miscfs/portal/portal_vfsops.c97
-rw-r--r--sys/miscfs/portal/portal_vnops.c57
-rw-r--r--sys/miscfs/procfs/procfs.h50
-rw-r--r--sys/miscfs/procfs/procfs_ctl.c24
-rw-r--r--sys/miscfs/procfs/procfs_fpregs.c3
-rw-r--r--sys/miscfs/procfs/procfs_map.c2
-rw-r--r--sys/miscfs/procfs/procfs_mem.c10
-rw-r--r--sys/miscfs/procfs/procfs_regs.c3
-rw-r--r--sys/miscfs/procfs/procfs_status.c5
-rw-r--r--sys/miscfs/procfs/procfs_subr.c55
-rw-r--r--sys/miscfs/procfs/procfs_vfsops.c109
-rw-r--r--sys/miscfs/procfs/procfs_vnops.c466
-rw-r--r--sys/miscfs/specfs/spec_vnops.c91
-rw-r--r--sys/miscfs/specfs/specdev.h12
-rw-r--r--sys/miscfs/umapfs/umap.h5
-rw-r--r--sys/miscfs/umapfs/umap_subr.c61
-rw-r--r--sys/miscfs/umapfs/umap_vfsops.c21
-rw-r--r--sys/miscfs/umapfs/umap_vnops.c49
-rw-r--r--sys/miscfs/union/union.h22
-rw-r--r--sys/miscfs/union/union_subr.c538
-rw-r--r--sys/miscfs/union/union_vfsops.c238
-rw-r--r--sys/miscfs/union/union_vnops.c798
35 files changed, 2274 insertions, 1768 deletions
diff --git a/sys/miscfs/deadfs/dead_vnops.c b/sys/miscfs/deadfs/dead_vnops.c
index f22425c..6d83c61 100644
--- a/sys/miscfs/deadfs/dead_vnops.c
+++ b/sys/miscfs/deadfs/dead_vnops.c
@@ -77,11 +77,11 @@ static int dead_select __P((struct vop_select_args *));
#define dead_inactive ((int (*) __P((struct vop_inactive_args *)))nullop)
#define dead_reclaim ((int (*) __P((struct vop_reclaim_args *)))nullop)
static int dead_lock __P((struct vop_lock_args *));
-#define dead_unlock ((int (*) __P((struct vop_unlock_args *)))nullop)
+#define dead_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock)
static int dead_bmap __P((struct vop_bmap_args *));
static int dead_strategy __P((struct vop_strategy_args *));
static int dead_print __P((struct vop_print_args *));
-#define dead_islocked ((int (*) __P((struct vop_islocked_args *)))nullop)
+#define dead_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked)
#define dead_pathconf ((int (*) __P((struct vop_pathconf_args *)))dead_ebadf)
#define dead_advlock ((int (*) __P((struct vop_advlock_args *)))dead_ebadf)
#define dead_blkatoff ((int (*) __P((struct vop_blkatoff_args *)))dead_badop)
@@ -191,11 +191,20 @@ dead_read(ap)
if (chkvnlock(ap->a_vp))
panic("dead_read: lock");
+#if 0
+ /* Lite2 behaviour */
+ /*
+ * Return EOF for tty devices, EIO for others
+ */
+ if ((ap->a_vp->v_flag & VISTTY) == 0)
+ return (EIO);
+#else
/*
* Return EOF for character devices, EIO for others
*/
if (ap->a_vp->v_type != VCHR)
return (EIO);
+#endif
return (0);
}
@@ -282,12 +291,23 @@ static int
dead_lock(ap)
struct vop_lock_args /* {
struct vnode *a_vp;
+ int a_flags;
+ struct proc *a_p;
} */ *ap;
{
+ struct vnode *vp = ap->a_vp;
- if (!chkvnlock(ap->a_vp))
+ /*
+ * Since we are not using the lock manager, we must clear
+ * the interlock here.
+ */
+ if (ap->a_flags & LK_INTERLOCK) {
+ simple_unlock(&vp->v_interlock);
+ ap->a_flags &= ~LK_INTERLOCK;
+ }
+ if (!chkvnlock(vp))
return (0);
- return (VCALL(ap->a_vp, VOFFSET(vop_lock), ap));
+ return (VCALL(vp, VOFFSET(vop_lock), ap));
}
/*
diff --git a/sys/miscfs/fdesc/fdesc.h b/sys/miscfs/fdesc/fdesc.h
index d754655..b4eff1f 100644
--- a/sys/miscfs/fdesc/fdesc.h
+++ b/sys/miscfs/fdesc/fdesc.h
@@ -61,8 +61,7 @@ typedef enum {
} fdntype;
struct fdescnode {
- struct fdescnode *fd_forw; /* Hash chain */
- struct fdescnode *fd_back;
+ LIST_ENTRY(fdescnode) fd_hash; /* Hash list */
struct vnode *fd_vnode; /* Back ptr to vnode */
fdntype fd_type; /* Type of this node */
unsigned fd_fd; /* Fd to be dup'ed */
@@ -74,7 +73,7 @@ struct fdescnode {
#define VTOFDESC(vp) ((struct fdescnode *)(vp)->v_data)
extern dev_t devctty;
-extern int fdesc_init __P((void));
+extern int fdesc_init __P((struct vfsconf *));
extern int fdesc_root __P((struct mount *, struct vnode **));
extern int fdesc_allocvp __P((fdntype, int, struct mount *, struct vnode **));
extern vop_t **fdesc_vnodeop_p;
diff --git a/sys/miscfs/fdesc/fdesc_vfsops.c b/sys/miscfs/fdesc/fdesc_vfsops.c
index 5f6703b..135052e 100644
--- a/sys/miscfs/fdesc/fdesc_vfsops.c
+++ b/sys/miscfs/fdesc/fdesc_vfsops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software donated to Berkeley by
@@ -108,7 +108,7 @@ fdesc_mount(mp, path, data, ndp, p)
/* XXX -- don't mark as local to work around fts() problems */
/*mp->mnt_flag |= MNT_LOCAL;*/
mp->mnt_data = (qaddr_t) fmp;
- getnewfsid(mp, MOUNT_FDESC);
+ vfs_getnewfsid(mp);
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
@@ -137,12 +137,8 @@ fdesc_unmount(mp, mntflags, p)
int flags = 0;
struct vnode *rootvp = VFSTOFDESC(mp)->f_root;
- if (mntflags & MNT_FORCE) {
- /* fdesc can never be rootfs so don't check for it */
- if (!doforce)
- return (EINVAL);
+ if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- }
/*
* Clear out buffer cache. I don't think we
@@ -176,6 +172,7 @@ fdesc_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
+ struct proc *p = curproc; /* XXX */
struct vnode *vp;
/*
@@ -183,24 +180,12 @@ fdesc_root(mp, vpp)
*/
vp = VFSTOFDESC(mp)->f_root;
VREF(vp);
- VOP_LOCK(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
*vpp = vp;
return (0);
}
static int
-fdesc_quotactl(mp, cmd, uid, arg, p)
- struct mount *mp;
- int cmd;
- uid_t uid;
- caddr_t arg;
- struct proc *p;
-{
-
- return (EOPNOTSUPP);
-}
-
-static int
fdesc_statfs(mp, sbp, p)
struct mount *mp;
struct statfs *sbp;
@@ -233,7 +218,6 @@ fdesc_statfs(mp, sbp, p)
if (fdp->fd_nfiles < lim)
freefd += (lim - fdp->fd_nfiles);
- sbp->f_type = MOUNT_FDESC;
sbp->f_flags = 0;
sbp->f_bsize = DEV_BSIZE;
sbp->f_iosize = DEV_BSIZE;
@@ -243,6 +227,7 @@ fdesc_statfs(mp, sbp, p)
sbp->f_files = lim + 1; /* Allow for "." */
sbp->f_ffree = freefd; /* See comments above */
if (sbp != &mp->mnt_stat) {
+ sbp->f_type = mp->mnt_vfc->vfc_typenum;
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
@@ -261,41 +246,15 @@ fdesc_sync(mp, waitfor, cred, p)
return (0);
}
-/*
- * Fdesc flat namespace lookup.
- * Currently unsupported.
- */
-static int
-fdesc_vget(mp, ino, vpp)
- struct mount *mp;
- ino_t ino;
- struct vnode **vpp;
-{
-
- return (EOPNOTSUPP);
-}
-
-static int
-fdesc_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
- struct mount *mp;
- struct fid *fhp;
- struct mbuf *nam;
- struct vnode **vpp;
- int *exflagsp;
- struct ucred **credanonp;
-{
-
- return (EOPNOTSUPP);
-}
-
-static int
-fdesc_vptofh(vp, fhp)
- struct vnode *vp;
- struct fid *fhp;
-{
-
- return (EOPNOTSUPP);
-}
+#define fdesc_fhtovp ((int (*) __P((struct mount *, struct fid *, \
+ struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp)
+#define fdesc_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
+ struct proc *)))eopnotsupp)
+#define fdesc_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
+ size_t, struct proc *)))eopnotsupp)
+#define fdesc_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
+ eopnotsupp)
+#define fdesc_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp)
static struct vfsops fdesc_vfsops = {
fdesc_mount,
diff --git a/sys/miscfs/fdesc/fdesc_vnops.c b/sys/miscfs/fdesc/fdesc_vnops.c
index 1fe511b..795dfd8 100644
--- a/sys/miscfs/fdesc/fdesc_vnops.c
+++ b/sys/miscfs/fdesc/fdesc_vnops.c
@@ -77,22 +77,14 @@ FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2
#endif
#define NFDCACHE 4
-#define FD_NHASH(ix) ((ix) & NFDCACHE-1)
-
-/*
- * Cache head
- */
-struct fdcache {
- struct fdescnode *fc_forw;
- struct fdescnode *fc_back;
-};
-
-static struct fdcache fdcache[NFDCACHE];
+#define FD_NHASH(ix) \
+ (&fdhashtbl[(ix) & fdhash])
+LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl;
+u_long fdhash;
static int fdesc_attr __P((int fd, struct vattr *vap, struct ucred *cred,
struct proc *p));
static int fdesc_badop __P((void));
-static int fdesc_enotsupp __P((void));
static int fdesc_getattr __P((struct vop_getattr_args *ap));
static struct fdcache *
fdesc_hash __P((int ix));
@@ -115,28 +107,15 @@ static int fdesc_write __P((struct vop_write_args *ap));
* Initialise cache headers
*/
int
-fdesc_init()
+fdesc_init(vfsp)
+ struct vfsconf *vfsp;
{
- struct fdcache *fc;
devctty = makedev(nchrdev, 0);
-
- for (fc = fdcache; fc < fdcache + NFDCACHE; fc++)
- fc->fc_forw = fc->fc_back = (struct fdescnode *) fc;
+ fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash);
return (0);
}
-/*
- * Compute hash list for given target vnode
- */
-static struct fdcache *
-fdesc_hash(ix)
- int ix;
-{
-
- return (&fdcache[FD_NHASH(ix)]);
-}
-
int
fdesc_allocvp(ftype, ix, mp, vpp)
fdntype ftype;
@@ -144,15 +123,16 @@ fdesc_allocvp(ftype, ix, mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
- struct fdcache *fc;
+ struct proc *p = curproc; /* XXX */
+ struct fdhashhead *fc;
struct fdescnode *fd;
int error = 0;
+ fc = FD_NHASH(ix);
loop:
- fc = fdesc_hash(ix);
- for (fd = fc->fc_forw; fd != (struct fdescnode *) fc; fd = fd->fd_forw) {
+ for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) {
if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {
- if (vget(fd->fd_vnode, 0))
+ if (vget(fd->fd_vnode, 0, p))
goto loop;
*vpp = fd->fd_vnode;
return (error);
@@ -188,8 +168,7 @@ loop:
fd->fd_fd = -1;
fd->fd_link = 0;
fd->fd_ix = ix;
- fc = fdesc_hash(ix);
- insque(fd, fc);
+ LIST_INSERT_HEAD(fc, fd, fd_hash);
out:;
fdcache_lock &= ~FDL_LOCKED;
@@ -216,31 +195,28 @@ fdesc_lookup(ap)
{
struct vnode **vpp = ap->a_vpp;
struct vnode *dvp = ap->a_dvp;
- char *pname;
- struct proc *p;
- int nfiles;
- unsigned fd = 0;
+ struct componentname *cnp = ap->a_cnp;
+ char *pname = cnp->cn_nameptr;
+ struct proc *p = cnp->cn_proc;
+ int nfiles = p->p_fd->fd_nfiles;
+ unsigned fd;
int error;
struct vnode *fvp;
char *ln;
- if (ap->a_cnp->cn_nameiop == DELETE ||
- ap->a_cnp->cn_nameiop == RENAME) {
+ if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
error = EROFS;
goto bad;
}
- pname = ap->a_cnp->cn_nameptr;
- if (ap->a_cnp->cn_namelen == 1 && *pname == '.') {
+ VOP_UNLOCK(dvp, 0, p);
+ if (cnp->cn_namelen == 1 && *pname == '.') {
*vpp = dvp;
- VREF(dvp);
- VOP_LOCK(dvp);
+ VREF(dvp);
+ vn_lock(dvp, LK_SHARED | LK_RETRY, p);
return (0);
}
- p = ap->a_cnp->cn_proc;
- nfiles = p->p_fd->fd_nfiles;
-
switch (VTOFDESC(dvp)->fd_type) {
default:
case Flink:
@@ -250,17 +226,17 @@ fdesc_lookup(ap)
goto bad;
case Froot:
- if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) {
+ if (cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) {
error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp);
if (error)
goto bad;
*vpp = fvp;
fvp->v_type = VDIR;
- VOP_LOCK(fvp);
+ vn_lock(fvp, LK_SHARED | LK_RETRY, p);
return (0);
}
- if (ap->a_cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) {
+ if (cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) {
struct vnode *ttyvp = cttyvp(p);
if (ttyvp == NULL) {
error = ENXIO;
@@ -271,12 +247,12 @@ fdesc_lookup(ap)
goto bad;
*vpp = fvp;
fvp->v_type = VFIFO;
- VOP_LOCK(fvp);
+ vn_lock(fvp, LK_SHARED | LK_RETRY, p);
return (0);
}
ln = 0;
- switch (ap->a_cnp->cn_namelen) {
+ switch (cnp->cn_namelen) {
case 5:
if (bcmp(pname, "stdin", 5) == 0) {
ln = "fd/0";
@@ -302,7 +278,7 @@ fdesc_lookup(ap)
VTOFDESC(fvp)->fd_link = ln;
*vpp = fvp;
fvp->v_type = VLNK;
- VOP_LOCK(fvp);
+ vn_lock(fvp, LK_SHARED | LK_RETRY, p);
return (0);
} else {
error = ENOENT;
@@ -312,9 +288,10 @@ fdesc_lookup(ap)
/* FALL THROUGH */
case Fdevfd:
- if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) {
- error = fdesc_root(dvp->v_mount, vpp);
- return (error);
+ if (cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) {
+ if (error = fdesc_root(dvp->v_mount, vpp))
+ goto bad;
+ return (0);
}
fd = 0;
@@ -338,11 +315,13 @@ fdesc_lookup(ap)
if (error)
goto bad;
VTOFDESC(fvp)->fd_fd = fd;
+ vn_lock(fvp, LK_SHARED | LK_RETRY, p);
*vpp = fvp;
return (0);
}
bad:;
+ vn_lock(dvp, LK_SHARED | LK_RETRY, p);
*vpp = NULL;
return (error);
}
@@ -402,10 +381,10 @@ fdesc_attr(fd, vap, cred, p)
error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p);
if (error == 0 && vap->va_type == VDIR) {
/*
- * don't allow directories to show up because
- * that causes loops in the namespace.
+ * directories can cause loops in the namespace,
+ * so turn off the 'x' bits to avoid trouble.
*/
- vap->va_type = VFIFO;
+ vap->va_mode &= ~((VEXEC)|(VEXEC>>3)|(VEXEC>>6));
}
break;
@@ -591,6 +570,9 @@ fdesc_readdir(ap)
struct vnode *a_vp;
struct uio *a_uio;
struct ucred *a_cred;
+ int *a_eofflag;
+ u_long *a_cookies;
+ int a_ncookies;
} */ *ap;
{
struct uio *uio = ap->a_uio;
@@ -598,6 +580,13 @@ fdesc_readdir(ap)
int i;
int error;
+ /*
+ * We don't allow exporting fdesc mounts, and currently local
+ * requests do not need cookies.
+ */
+ if (ap->a_ncookies)
+ panic("fdesc_readdir: not hungry");
+
switch (VTOFDESC(ap->a_vp)->fd_type) {
case Fctty:
return (0);
@@ -814,6 +803,7 @@ static int
fdesc_inactive(ap)
struct vop_inactive_args /* {
struct vnode *a_vp;
+ struct proc *a_p;
} */ *ap;
{
struct vnode *vp = ap->a_vp;
@@ -822,6 +812,7 @@ fdesc_inactive(ap)
* Clear out the v_type field to avoid
* nasty things happening in vgone().
*/
+ VOP_UNLOCK(vp, 0, ap->a_p);
vp->v_type = VNON;
return (0);
}
@@ -833,8 +824,9 @@ fdesc_reclaim(ap)
} */ *ap;
{
struct vnode *vp = ap->a_vp;
+ struct fdescnode *fd = VTOFDESC(vp);
- remque(VTOFDESC(vp));
+ LIST_REMOVE(fd, fd_hash);
FREE(vp->v_data, M_TEMP);
vp->v_data = 0;
@@ -907,16 +899,6 @@ fdesc_vfree(ap)
}
/*
- * /dev/fd vnode unsupported operation
- */
-static int
-fdesc_enotsupp()
-{
-
- return (EOPNOTSUPP);
-}
-
-/*
* /dev/fd "should never get here" operation
*/
static int
@@ -927,38 +909,39 @@ fdesc_badop()
/* NOTREACHED */
}
-#define fdesc_create ((int (*) __P((struct vop_create_args *)))fdesc_enotsupp)
-#define fdesc_mknod ((int (*) __P((struct vop_mknod_args *)))fdesc_enotsupp)
+#define fdesc_create ((int (*) __P((struct vop_create_args *)))eopnotsupp)
+#define fdesc_mknod ((int (*) __P((struct vop_mknod_args *)))eopnotsupp)
#define fdesc_close ((int (*) __P((struct vop_close_args *)))nullop)
#define fdesc_access ((int (*) __P((struct vop_access_args *)))nullop)
-#define fdesc_mmap ((int (*) __P((struct vop_mmap_args *)))fdesc_enotsupp)
+#define fdesc_mmap ((int (*) __P((struct vop_mmap_args *)))eopnotsupp)
+#define fdesc_revoke vop_revoke
#define fdesc_fsync ((int (*) __P((struct vop_fsync_args *)))nullop)
#define fdesc_seek ((int (*) __P((struct vop_seek_args *)))nullop)
-#define fdesc_remove ((int (*) __P((struct vop_remove_args *)))fdesc_enotsupp)
-#define fdesc_link ((int (*) __P((struct vop_link_args *)))fdesc_enotsupp)
-#define fdesc_rename ((int (*) __P((struct vop_rename_args *)))fdesc_enotsupp)
-#define fdesc_mkdir ((int (*) __P((struct vop_mkdir_args *)))fdesc_enotsupp)
-#define fdesc_rmdir ((int (*) __P((struct vop_rmdir_args *)))fdesc_enotsupp)
-#define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))fdesc_enotsupp)
+#define fdesc_remove ((int (*) __P((struct vop_remove_args *)))eopnotsupp)
+#define fdesc_link ((int (*) __P((struct vop_link_args *)))eopnotsupp)
+#define fdesc_rename ((int (*) __P((struct vop_rename_args *)))eopnotsupp)
+#define fdesc_mkdir ((int (*) __P((struct vop_mkdir_args *)))eopnotsupp)
+#define fdesc_rmdir ((int (*) __P((struct vop_rmdir_args *)))eopnotsupp)
+#define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))eopnotsupp)
#define fdesc_abortop ((int (*) __P((struct vop_abortop_args *)))nullop)
-#define fdesc_lock ((int (*) __P((struct vop_lock_args *)))nullop)
-#define fdesc_unlock ((int (*) __P((struct vop_unlock_args *)))nullop)
+#define fdesc_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock)
+#define fdesc_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock)
#define fdesc_bmap ((int (*) __P((struct vop_bmap_args *)))fdesc_badop)
#define fdesc_strategy ((int (*) __P((struct vop_strategy_args *)))fdesc_badop)
-#define fdesc_islocked ((int (*) __P((struct vop_islocked_args *)))nullop)
-#define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))fdesc_enotsupp)
+#define fdesc_islocked \
+ ((int (*) __P((struct vop_islocked_args *)))vop_noislocked)
+#define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))eopnotsupp)
#define fdesc_blkatoff \
- ((int (*) __P((struct vop_blkatoff_args *)))fdesc_enotsupp)
-#define fdesc_vget ((int (*) __P((struct vop_vget_args *)))fdesc_enotsupp)
+ ((int (*) __P((struct vop_blkatoff_args *)))eopnotsupp)
#define fdesc_valloc ((int(*) __P(( \
struct vnode *pvp, \
int mode, \
struct ucred *cred, \
- struct vnode **vpp))) fdesc_enotsupp)
+ struct vnode **vpp))) eopnotsupp)
#define fdesc_truncate \
- ((int (*) __P((struct vop_truncate_args *)))fdesc_enotsupp)
-#define fdesc_update ((int (*) __P((struct vop_update_args *)))fdesc_enotsupp)
-#define fdesc_bwrite ((int (*) __P((struct vop_bwrite_args *)))fdesc_enotsupp)
+ ((int (*) __P((struct vop_truncate_args *)))eopnotsupp)
+#define fdesc_update ((int (*) __P((struct vop_update_args *)))eopnotsupp)
+#define fdesc_bwrite ((int (*) __P((struct vop_bwrite_args *)))eopnotsupp)
static vop_t **fdesc_vnodeop_p;
static struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = {
@@ -975,6 +958,7 @@ static struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = {
{ &vop_write_desc, (vop_t *)fdesc_write }, /* write */
{ &vop_ioctl_desc, (vop_t *)fdesc_ioctl }, /* ioctl */
{ &vop_select_desc, (vop_t *)fdesc_select }, /* select */
+ { &vop_revoke_desc, (vop_t *)fdesc_revoke }, /* revoke */
{ &vop_mmap_desc, (vop_t *)fdesc_mmap }, /* mmap */
{ &vop_fsync_desc, (vop_t *)fdesc_fsync }, /* fsync */
{ &vop_seek_desc, (vop_t *)fdesc_seek }, /* seek */
diff --git a/sys/miscfs/fifofs/fifo.h b/sys/miscfs/fifofs/fifo.h
index efeaf85..6562159 100644
--- a/sys/miscfs/fifofs/fifo.h
+++ b/sys/miscfs/fifofs/fifo.h
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)fifo.h 8.2 (Berkeley) 2/2/94
+ * @(#)fifo.h 8.6 (Berkeley) 5/21/95
* $FreeBSD$
*/
@@ -51,8 +51,10 @@ int fifo_close __P((struct vop_close_args *));
#define fifo_setattr ((int (*) __P((struct vop_setattr_args *)))fifo_ebadf)
int fifo_read __P((struct vop_read_args *));
int fifo_write __P((struct vop_write_args *));
+#define fifo_lease_check ((int (*) __P((struct vop_lease_args *)))nullop)
int fifo_ioctl __P((struct vop_ioctl_args *));
int fifo_select __P((struct vop_select_args *));
+#define fifo_revoke vop_revoke
#define fifo_mmap ((int (*) __P((struct vop_mmap_args *)))fifo_badop)
#define fifo_fsync ((int (*) __P((struct vop_fsync_args *)))nullop)
#define fifo_seek ((int (*) __P((struct vop_seek_args *)))fifo_badop)
@@ -65,11 +67,13 @@ int fifo_select __P((struct vop_select_args *));
#define fifo_readdir ((int (*) __P((struct vop_readdir_args *)))fifo_badop)
#define fifo_readlink ((int (*) __P((struct vop_readlink_args *)))fifo_badop)
#define fifo_abortop ((int (*) __P((struct vop_abortop_args *)))fifo_badop)
-#define fifo_inactive ((int (*) __P((struct vop_inactive_args *)))nullop)
+int fifo_inactive __P((struct vop_inactive_args *));
#define fifo_reclaim ((int (*) __P((struct vop_reclaim_args *)))nullop)
+#define fifo_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock)
+#define fifo_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock)
int fifo_bmap __P((struct vop_bmap_args *));
#define fifo_strategy ((int (*) __P((struct vop_strategy_args *)))fifo_badop)
-#define fifo_islocked ((int (*) __P((struct vop_islocked_args *)))nullop)
+#define fifo_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked)
int fifo_pathconf __P((struct vop_pathconf_args *));
int fifo_advlock __P((struct vop_advlock_args *));
#define fifo_blkatoff ((int (*) __P((struct vop_blkatoff_args *)))fifo_badop)
diff --git a/sys/miscfs/fifofs/fifo_vnops.c b/sys/miscfs/fifofs/fifo_vnops.c
index 240354f..8f915ec 100644
--- a/sys/miscfs/fifofs/fifo_vnops.c
+++ b/sys/miscfs/fifofs/fifo_vnops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1990, 1993
+ * Copyright (c) 1990, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,12 +30,12 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)fifo_vnops.c 8.2 (Berkeley) 1/4/94
+ * @(#)fifo_vnops.c 8.10 (Berkeley) 5/27/95
* $FreeBSD$
*/
#include <sys/param.h>
-#include <sys/kernel.h>
+#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/time.h>
#include <sys/namei.h>
@@ -44,7 +44,6 @@
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/stat.h>
-#include <sys/systm.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/errno.h>
@@ -64,8 +63,6 @@ struct fifoinfo {
};
static int fifo_ebadf __P((void));
-static int fifo_unlock __P((struct vop_unlock_args *));
-static int fifo_lock __P((struct vop_lock_args *));
static int fifo_print __P((struct vop_print_args *));
vop_t **fifo_vnodeop_p;
@@ -81,8 +78,10 @@ static struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
{ &vop_setattr_desc, (vop_t *)fifo_setattr }, /* setattr */
{ &vop_read_desc, (vop_t *)fifo_read }, /* read */
{ &vop_write_desc, (vop_t *)fifo_write }, /* write */
+ { &vop_lease_desc, (vop_t *)fifo_lease_check }, /* lease */
{ &vop_ioctl_desc, (vop_t *)fifo_ioctl }, /* ioctl */
{ &vop_select_desc, (vop_t *)fifo_select }, /* select */
+ { &vop_revoke_desc, (vop_t *)fifo_revoke }, /* revoke */
{ &vop_mmap_desc, (vop_t *)fifo_mmap }, /* mmap */
{ &vop_fsync_desc, (vop_t *)fifo_fsync }, /* fsync */
{ &vop_seek_desc, (vop_t *)fifo_seek }, /* seek */
@@ -149,8 +148,9 @@ fifo_open(ap)
struct proc *a_p;
} */ *ap;
{
- register struct vnode *vp = ap->a_vp;
- register struct fifoinfo *fip;
+ struct vnode *vp = ap->a_vp;
+ struct fifoinfo *fip;
+ struct proc *p = ap->a_p;
struct socket *rso, *wso;
int error;
static char openstr[] = "fifo";
@@ -158,14 +158,14 @@ fifo_open(ap)
if ((fip = vp->v_fifoinfo) == NULL) {
MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK);
vp->v_fifoinfo = fip;
- error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0, ap->a_p);
+ error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, ap->a_p);
if (error) {
free(fip, M_VNODE);
vp->v_fifoinfo = NULL;
return (error);
}
fip->fi_readsock = rso;
- error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0, ap->a_p);
+ error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, ap->a_p);
if (error) {
(void)soclose(rso);
free(fip, M_VNODE);
@@ -185,60 +185,52 @@ fifo_open(ap)
wso->so_state |= SS_CANTRCVMORE;
rso->so_state |= SS_CANTSENDMORE;
}
- error = 0;
- if ((ap->a_mode & (FREAD|FWRITE)) == (FREAD|FWRITE)) {
- if (fip->fi_readers == 0) {
+ if (ap->a_mode & FREAD) {
+ fip->fi_readers++;
+ if (fip->fi_readers == 1) {
fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
if (fip->fi_writers > 0)
wakeup((caddr_t)&fip->fi_writers);
}
- if (fip->fi_writers == 0) {
+ }
+ if (ap->a_mode & FWRITE) {
+ fip->fi_writers++;
+ if (fip->fi_writers == 1) {
fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
if (fip->fi_readers > 0)
wakeup((caddr_t)&fip->fi_readers);
}
- fip->fi_readers++;
- fip->fi_writers++;
}
- else if (ap->a_mode & FREAD) {
- fip->fi_readers++;
- if (fip->fi_readers == 1) {
- fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
- if (fip->fi_writers > 0)
- wakeup((caddr_t)&fip->fi_writers);
+ if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) {
+ while (fip->fi_writers == 0) {
+ VOP_UNLOCK(vp, 0, p);
+ error = tsleep((caddr_t)&fip->fi_readers,
+ PCATCH | PSOCK, openstr, 0);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ if (error)
+ goto bad;
}
- if (!(ap->a_mode & O_NONBLOCK))
- while (fip->fi_writers == 0) {
- VOP_UNLOCK(vp);
- error = tsleep((caddr_t)&fip->fi_readers,
- PCATCH | PSOCK, openstr, 0);
- VOP_LOCK(vp);
- if (error)
- break;
- }
}
- else {
- fip->fi_writers++;
- if (fip->fi_readers == 0 && (ap->a_mode & O_NONBLOCK)) {
- error = ENXIO;
- } else {
- if (fip->fi_writers == 1) {
- fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
- if (fip->fi_readers > 0)
- wakeup((caddr_t)&fip->fi_readers);
+ if (ap->a_mode & FWRITE) {
+ if (ap->a_mode & O_NONBLOCK) {
+ if (fip->fi_readers == 0) {
+ error = ENXIO;
+ goto bad;
}
+ } else {
while (fip->fi_readers == 0) {
- VOP_UNLOCK(vp);
+ VOP_UNLOCK(vp, 0, p);
error = tsleep((caddr_t)&fip->fi_writers,
PCATCH | PSOCK, openstr, 0);
- VOP_LOCK(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
if (error)
- break;
+ goto bad;
}
}
}
- if (error)
- VOP_CLOSE(vp, ap->a_mode, ap->a_cred, ap->a_p);
+ return (0);
+bad:
+ VOP_CLOSE(vp, ap->a_mode, ap->a_cred, p);
return (error);
}
@@ -255,8 +247,9 @@ fifo_read(ap)
struct ucred *a_cred;
} */ *ap;
{
- register struct uio *uio = ap->a_uio;
- register struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
+ struct uio *uio = ap->a_uio;
+ struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
+ struct proc *p = uio->uio_procp;
int error, startresid;
#ifdef DIAGNOSTIC
@@ -268,10 +261,10 @@ fifo_read(ap)
if (ap->a_ioflag & IO_NDELAY)
rso->so_state |= SS_NBIO;
startresid = uio->uio_resid;
- VOP_UNLOCK(ap->a_vp);
- error = soreceive(rso, (struct mbuf **)0, uio,
- (struct mbuf **)0, (struct mbuf **)0, (int*)0);
- VOP_LOCK(ap->a_vp);
+ VOP_UNLOCK(ap->a_vp, 0, p);
+ error = soreceive(rso, (struct mbuf **)0, uio, (struct mbuf **)0,
+ (struct mbuf **)0, (int *)0);
+ vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
/*
* Clear EOF indication after first such return.
*/
@@ -296,6 +289,7 @@ fifo_write(ap)
} */ *ap;
{
struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
+ struct proc *p = ap->a_uio->uio_procp;
int error;
#ifdef DIAGNOSTIC
@@ -304,9 +298,9 @@ fifo_write(ap)
#endif
if (ap->a_ioflag & IO_NDELAY)
wso->so_state |= SS_NBIO;
- VOP_UNLOCK(ap->a_vp);
+ VOP_UNLOCK(ap->a_vp, 0, p);
error = sosend(wso, (struct mbuf *)0, ap->a_uio, 0, (struct mbuf *)0, 0);
- VOP_LOCK(ap->a_vp);
+ vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
if (ap->a_ioflag & IO_NDELAY)
wso->so_state &= ~SS_NBIO;
return (error);
@@ -328,14 +322,23 @@ fifo_ioctl(ap)
} */ *ap;
{
struct file filetmp;
+ int error;
if (ap->a_command == FIONBIO)
return (0);
- if (ap->a_fflag & FREAD)
+ if (ap->a_fflag & FREAD) {
filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
- else
+ error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
+ if (error)
+ return (error);
+ }
+ if (ap->a_fflag & FWRITE) {
filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
- return (soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p));
+ error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
+ if (error)
+ return (error);
+ }
+ return (0);
}
/* ARGSUSED */
@@ -350,12 +353,33 @@ fifo_select(ap)
} */ *ap;
{
struct file filetmp;
+ int ready;
- if (ap->a_fflags & FREAD)
+ if (ap->a_fflags & FREAD) {
filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
- else
+ ready = soo_select(&filetmp, ap->a_which, ap->a_p);
+ if (ready)
+ return (ready);
+ }
+ if (ap->a_fflags & FWRITE) {
filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
- return (soo_select(&filetmp, ap->a_which, ap->a_p));
+ ready = soo_select(&filetmp, ap->a_which, ap->a_p);
+ if (ready)
+ return (ready);
+ }
+ return (0);
+}
+
+int
+fifo_inactive(ap)
+ struct vop_inactive_args /* {
+ struct vnode *a_vp;
+ struct proc *a_p;
+ } */ *ap;
+{
+
+ VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
+ return (0);
}
/*
@@ -385,31 +409,6 @@ fifo_bmap(ap)
}
/*
- * At the moment we do not do any locking.
- */
-/* ARGSUSED */
-static int
-fifo_lock(ap)
- struct vop_lock_args /* {
- struct vnode *a_vp;
- } */ *ap;
-{
-
- return (0);
-}
-
-/* ARGSUSED */
-static int
-fifo_unlock(ap)
- struct vop_unlock_args /* {
- struct vnode *a_vp;
- } */ *ap;
-{
-
- return (0);
-}
-
-/*
* Device close routine
*/
/* ARGSUSED */
@@ -426,16 +425,16 @@ fifo_close(ap)
register struct fifoinfo *fip = vp->v_fifoinfo;
int error1, error2;
- if (ap->a_fflag & FWRITE) {
- fip->fi_writers--;
- if (fip->fi_writers == 0)
- socantrcvmore(fip->fi_readsock);
- }
if (ap->a_fflag & FREAD) {
fip->fi_readers--;
if (fip->fi_readers == 0)
socantsendmore(fip->fi_writesock);
}
+ if (ap->a_fflag & FWRITE) {
+ fip->fi_writers--;
+ if (fip->fi_writers == 0)
+ socantrcvmore(fip->fi_readsock);
+ }
if (vp->v_usecount > 1)
return (0);
error1 = soclose(fip->fi_readsock);
diff --git a/sys/miscfs/kernfs/kernfs.h b/sys/miscfs/kernfs/kernfs.h
index 69496a4..2795bb3 100644
--- a/sys/miscfs/kernfs/kernfs.h
+++ b/sys/miscfs/kernfs/kernfs.h
@@ -33,7 +33,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)kernfs.h 8.4 (Berkeley) 1/21/94
+ * @(#)kernfs.h 8.6 (Berkeley) 3/29/95
* $FreeBSD$
*/
@@ -51,7 +51,18 @@ struct kernfs_node {
#define VFSTOKERNFS(mp) ((struct kernfs_mount *)((mp)->mnt_data))
#define VTOKERN(vp) ((struct kernfs_node *)(vp)->v_data)
+#define kernfs_fhtovp ((int (*) __P((struct mount *, struct fid *, \
+ struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp)
+#define kernfs_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
+ struct proc *)))eopnotsupp)
+#define kernfs_sync ((int (*) __P((struct mount *, int, struct ucred *, \
+ struct proc *)))nullop)
+#define kernfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
+ size_t, struct proc *)))eopnotsupp)
+#define kernfs_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
+ eopnotsupp)
+#define kernfs_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp)
extern vop_t **kernfs_vnodeop_p;
extern struct vfsops kernfs_vfsops;
-extern struct vnode *rrootvp;
+extern dev_t rrootdev;
#endif /* KERNEL */
diff --git a/sys/miscfs/kernfs/kernfs_vfsops.c b/sys/miscfs/kernfs/kernfs_vfsops.c
index 4c045e7..b774487 100644
--- a/sys/miscfs/kernfs/kernfs_vfsops.c
+++ b/sys/miscfs/kernfs/kernfs_vfsops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software donated to Berkeley by
@@ -33,7 +33,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)kernfs_vfsops.c 8.4 (Berkeley) 1/21/94
+ * @(#)kernfs_vfsops.c 8.10 (Berkeley) 5/14/95
* $FreeBSD$
*/
@@ -55,88 +55,52 @@
#include <miscfs/specfs/specdev.h>
#include <miscfs/kernfs/kernfs.h>
-struct vnode *rrootvp;
+dev_t rrootdev = NODEV;
static int cdevvp __P((dev_t dev, struct vnode **vpp));
-static int kernfs_init __P((void));
+static int kernfs_init __P((struct vfsconf *vfsp));
static int kernfs_mount __P((struct mount *mp, char *path, caddr_t data,
struct nameidata *ndp, struct proc *p));
static int kernfs_start __P((struct mount *mp, int flags, struct proc *p));
static int kernfs_unmount __P((struct mount *mp, int mntflags,
struct proc *p));
static int kernfs_root __P((struct mount *mp, struct vnode **vpp));
-static int kernfs_quotactl __P((struct mount *mp, int cmd, uid_t uid,
- caddr_t arg, struct proc *p));
static int kernfs_statfs __P((struct mount *mp, struct statfs *sbp,
struct proc *p));
-static int kernfs_sync __P((struct mount *mp, int waitfor,
- struct ucred *cred, struct proc *p));
-static int kernfs_vget __P((struct mount *mp, ino_t ino,
- struct vnode **vpp));
-static int kernfs_fhtovp __P((struct mount *mp, struct fid *fhp,
- struct mbuf *nam, struct vnode **vpp,
- int *exflagsp, struct ucred **credanonp));
-static int kernfs_vptofh __P((struct vnode *vp, struct fid *fhp));
-/*
- * Create a vnode for a character device.
- */
static int
-cdevvp(dev, vpp)
- dev_t dev;
- struct vnode **vpp;
+kernfs_init(vfsp)
+ struct vfsconf *vfsp;
{
- register struct vnode *vp;
- struct vnode *nvp;
- int error;
- if (dev == NODEV)
- return (0);
- error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp);
- if (error) {
- *vpp = 0;
- return (error);
- }
- vp = nvp;
- vp->v_type = VCHR;
- nvp = checkalias(vp, dev, (struct mount *)0);
- if (nvp) {
- vput(vp);
- vp = nvp;
- }
- *vpp = vp;
return (0);
}
-static int
-kernfs_init()
+void
+kernfs_get_rrootdev()
{
- int cmaj;
+ static int tried = 0;
int bmaj = major(rootdev);
- int error = ENXIO;
+ int cmaj;
-#ifdef KERNFS_DIAGNOSTIC
- printf("kernfs_init\n"); /* printed during system boot */
-#endif
+ if (tried) {
+ /* Already did it once. */
+ return;
+ }
+ tried = 1;
if (!bdevsw[bmaj]) {
panic("root dev has no bdevsw");
}
+ if (rootdev == NODEV)
+ return;
for (cmaj = 0; cmaj < nchrdev; cmaj++) {
- if (cdevsw[cmaj]
- && (cdevsw[cmaj]->d_open == bdevsw[bmaj]->d_open)) {
- dev_t cdev = makedev(cmaj, minor(rootdev));
- error = cdevvp(cdev, &rrootvp);
- if (error == 0)
- break;
- }
+ rrootdev = makedev(cmaj, minor(rootdev));
+ if (chrtoblk(rrootdev) == rootdev)
+ return;
}
-
- if (error) {
- printf("kernfs: no raw boot device\n");
- rrootvp = 0;
- }
- return (0);
+ rrootdev = NODEV;
+ printf("kernfs_get_rrootdev: no raw root device\n");
}
/*
@@ -182,7 +146,7 @@ kernfs_mount(mp, path, data, ndp, p)
fmp->kf_root = rvp;
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_data = (qaddr_t) fmp;
- getnewfsid(mp, MOUNT_KERNFS);
+ vfs_getnewfsid(mp);
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
@@ -192,6 +156,8 @@ kernfs_mount(mp, path, data, ndp, p)
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_mount: at %s\n", mp->mnt_stat.f_mntonname);
#endif
+
+ kernfs_get_rrootdev();
return (0);
}
@@ -218,12 +184,8 @@ kernfs_unmount(mp, mntflags, p)
printf("kernfs_unmount(mp = %x)\n", mp);
#endif
- if (mntflags & MNT_FORCE) {
- /* kernfs can never be rootfs so don't check for it */
- if (!doforce)
- return (EINVAL);
+ if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- }
/*
* Clear out buffer cache. I don't think we
@@ -263,6 +225,7 @@ kernfs_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
+ struct proc *p = curproc; /* XXX */
struct vnode *vp;
#ifdef KERNFS_DIAGNOSTIC
@@ -274,23 +237,12 @@ kernfs_root(mp, vpp)
*/
vp = VFSTOKERNFS(mp)->kf_root;
VREF(vp);
- VOP_LOCK(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
*vpp = vp;
return (0);
}
static int
-kernfs_quotactl(mp, cmd, uid, arg, p)
- struct mount *mp;
- int cmd;
- uid_t uid;
- caddr_t arg;
- struct proc *p;
-{
- return (EOPNOTSUPP);
-}
-
-static int
kernfs_statfs(mp, sbp, p)
struct mount *mp;
struct statfs *sbp;
@@ -300,7 +252,6 @@ kernfs_statfs(mp, sbp, p)
printf("kernfs_statfs(mp = %x)\n", mp);
#endif
- sbp->f_type = MOUNT_KERNFS;
sbp->f_flags = 0;
sbp->f_bsize = DEV_BSIZE;
sbp->f_iosize = DEV_BSIZE;
@@ -310,6 +261,7 @@ kernfs_statfs(mp, sbp, p)
sbp->f_files = 0;
sbp->f_ffree = 0;
if (sbp != &mp->mnt_stat) {
+ sbp->f_type = mp->mnt_vfc->vfc_typenum;
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
@@ -317,53 +269,6 @@ kernfs_statfs(mp, sbp, p)
return (0);
}
-static int
-kernfs_sync(mp, waitfor, cred, p)
- struct mount *mp;
- int waitfor;
- struct ucred *cred;
- struct proc *p;
-{
-
- return (0);
-}
-
-/*
- * Kernfs flat namespace lookup.
- * Currently unsupported.
- */
-static int
-kernfs_vget(mp, ino, vpp)
- struct mount *mp;
- ino_t ino;
- struct vnode **vpp;
-{
-
- return (EOPNOTSUPP);
-}
-
-
-static int
-kernfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
- struct mount *mp;
- struct fid *fhp;
- struct mbuf *nam;
- struct vnode **vpp;
- int *exflagsp;
- struct ucred **credanonp;
-{
-
- return (EOPNOTSUPP);
-}
-
-static int
-kernfs_vptofh(vp, fhp)
- struct vnode *vp;
- struct fid *fhp;
-{
- return (EOPNOTSUPP);
-}
-
static struct vfsops kernfs_vfsops = {
kernfs_mount,
kernfs_start,
diff --git a/sys/miscfs/kernfs/kernfs_vnops.c b/sys/miscfs/kernfs/kernfs_vnops.c
index afd30e7..108c443 100644
--- a/sys/miscfs/kernfs/kernfs_vnops.c
+++ b/sys/miscfs/kernfs/kernfs_vnops.c
@@ -33,7 +33,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)kernfs_vnops.c 8.6 (Berkeley) 2/10/94
+ * @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95
* $FreeBSD$
*/
@@ -67,41 +67,44 @@
#define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
static struct kern_target {
+ u_char kt_type;
+ u_char kt_namlen;
char *kt_name;
void *kt_data;
-#define KTT_NULL 1
-#define KTT_TIME 5
-#define KTT_INT 17
-#define KTT_STRING 31
-#define KTT_HOSTNAME 47
-#define KTT_BOOTFILE 49
-#define KTT_AVENRUN 53
- int kt_tag;
- int kt_rw;
- int kt_vtype;
- struct vnode **kt_vp;
+#define KTT_NULL 1
+#define KTT_TIME 5
+#define KTT_INT 17
+#define KTT_STRING 31
+#define KTT_HOSTNAME 47
+#define KTT_BOOTFILE 49
+#define KTT_AVENRUN 53
+#define KTT_DEVICE 71
+ u_char kt_tag;
+ u_char kt_vtype;
+ mode_t kt_mode;
} kern_targets[] = {
/* NOTE: The name must be less than UIO_MX-16 chars in length */
- /* name data tag ro/rw type vnodep*/
- { ".", 0, KTT_NULL, VREAD, VDIR, NULL },
- { "..", 0, KTT_NULL, VREAD, VDIR, NULL },
- { "boottime", &boottime.tv_sec, KTT_INT, VREAD, VREG, NULL },
- { "copyright", copyright, KTT_STRING, VREAD, VREG, NULL },
- { "hostname", 0, KTT_HOSTNAME,VREAD|VWRITE,VREG, NULL },
- { "bootfile", 0, KTT_BOOTFILE, VREAD, VREG, NULL },
- { "hz", &hz, KTT_INT, VREAD, VREG, NULL },
- { "loadavg", 0, KTT_AVENRUN, VREAD, VREG, NULL },
- { "pagesize", &cnt.v_page_size, KTT_INT, VREAD, VREG, NULL },
- { "physmem", &physmem, KTT_INT, VREAD, VREG, NULL },
+#define N(s) sizeof(s)-1, s
+ /* name data tag type ro/rw */
+ { DT_DIR, N("."), 0, KTT_NULL, VDIR, DIR_MODE },
+ { DT_DIR, N(".."), 0, KTT_NULL, VDIR, DIR_MODE },
+ { DT_REG, N("boottime"), &boottime.tv_sec, KTT_INT, VREG, READ_MODE },
+ { DT_REG, N("copyright"), copyright, KTT_STRING, VREG, READ_MODE },
+ { DT_REG, N("hostname"), 0, KTT_HOSTNAME, VREG, WRITE_MODE },
+ { DT_REG, N("bootfile"), 0, KTT_BOOTFILE, VREG, READ_MODE },
+ { DT_REG, N("hz"), &hz, KTT_INT, VREG, READ_MODE },
+ { DT_REG, N("loadavg"), 0, KTT_AVENRUN, VREG, READ_MODE },
+ { DT_REG, N("pagesize"), &cnt.v_page_size, KTT_INT, VREG, READ_MODE },
+ { DT_REG, N("physmem"), &physmem, KTT_INT, VREG, READ_MODE },
#if 0
- { "root", 0, KTT_NULL, VREAD, VDIR, &rootdir},
- { "rootdev", 0, KTT_NULL, VREAD, VBLK, &rootvp },
- { "rrootdev", 0, KTT_NULL, VREAD, VCHR, &rrootvp},
+ { DT_DIR, N("root"), 0, KTT_NULL, VDIR, DIR_MODE },
+ { DT_BLK, N("rootdev"), &rootdev, KTT_DEVICE, VBLK, READ_MODE },
+ { DT_CHR, N("rrootdev"), &rrootdev, KTT_DEVICE, VCHR, READ_MODE },
#endif
- { "time", 0, KTT_TIME, VREAD, VREG, NULL },
- { "version", version, KTT_STRING, VREAD, VREG, NULL },
+ { DT_REG, N("time"), 0, KTT_TIME, VREG, READ_MODE },
+ { DT_REG, N("version"), version, KTT_STRING, VREG, READ_MODE },
+#undef N
};
-
static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]);
static int kernfs_access __P((struct vop_access_args *ap));
@@ -130,6 +133,7 @@ kernfs_xread(kt, buf, len, lenp)
int len;
int *lenp;
{
+
switch (kt->kt_tag) {
case KTT_TIME: {
struct timeval tv;
@@ -183,14 +187,12 @@ kernfs_xread(kt, buf, len, lenp)
case KTT_AVENRUN:
sprintf(buf, "%ld %ld %ld %ld\n",
- averunnable.ldavg[0],
- averunnable.ldavg[1],
- averunnable.ldavg[2],
- averunnable.fscale);
+ averunnable.ldavg[0], averunnable.ldavg[1],
+ averunnable.ldavg[2], averunnable.fscale);
break;
default:
- return (EINVAL);
+ return (EIO);
}
*lenp = strlen(buf);
@@ -203,15 +205,15 @@ kernfs_xwrite(kt, buf, len)
char *buf;
int len;
{
+
switch (kt->kt_tag) {
- case KTT_HOSTNAME: {
+ case KTT_HOSTNAME:
/* XXX BOGUS !!! no check for the length */
if (buf[len-1] == '\n')
--len;
bcopy(buf, hostname, len);
hostname[len] = '\0';
return (0);
- }
default:
return (EIO);
@@ -231,26 +233,32 @@ kernfs_lookup(ap)
struct componentname * a_cnp;
} */ *ap;
{
+ struct componentname *cnp = ap->a_cnp;
struct vnode **vpp = ap->a_vpp;
struct vnode *dvp = ap->a_dvp;
- struct componentname *cnp = ap->a_cnp;
+ char *pname = cnp->cn_nameptr;
+ struct proc *p = cnp->cn_proc;
+ struct kern_target *kt;
struct vnode *fvp;
int nameiop = cnp->cn_nameiop;
int error, i;
- char *pname;
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_lookup(%x)\n", ap);
printf("kernfs_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp, vpp, ap->a_cnp);
-#endif
- pname = cnp->cn_nameptr;
-#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_lookup(%s)\n", pname);
#endif
+
+ *vpp = NULLVP;
+
+ if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
+ return (EROFS);
+
+ VOP_UNLOCK(dvp, 0, p);
if (cnp->cn_namelen == 1 && *pname == '.') {
*vpp = dvp;
VREF(dvp);
- /*VOP_LOCK(dvp);*/
+ vn_lock(dvp, LK_SHARED | LK_RETRY, p);
return (0);
}
@@ -258,91 +266,58 @@ kernfs_lookup(ap)
if (cnp->cn_namelen == 4 && bcmp(pname, "root", 4) == 0) {
*vpp = rootdir;
VREF(rootdir);
- VOP_LOCK(rootdir);
+ vn_lock(rootdir, LK_SHARED | LK_RETRY, p)
return (0);
}
#endif
- error = ENOENT;
-
- for (i = 0; i < nkern_targets; i++) {
- struct kern_target *kt = &kern_targets[i];
- if (cnp->cn_namelen == strlen(kt->kt_name) &&
- bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) {
- error = 0;
- break;
- }
+ for (kt = kern_targets, i = 0; i < nkern_targets; kt++, i++) {
+ if (cnp->cn_namelen == kt->kt_namlen &&
+ bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0)
+ goto found;
}
#ifdef KERNFS_DIAGNOSTIC
- printf("kernfs_lookup: i = %d, error = %d\n", i, error);
+ printf("kernfs_lookup: i = %d, failed", i);
#endif
- /*
- * If the name wasn't found, and this is not a LOOKUP
- * request, we return EOPNOTSUPP so that the initial namei()
- * fails and the higher level routines will not try to call
- * our VOP_* functions.
- */
- if (error) {
- if (nameiop != LOOKUP)
- error = EOPNOTSUPP;
- goto bad;
- }
-
- /*
- * DELETE requests are not supported.
- */
- if (nameiop == DELETE) {
- error = EOPNOTSUPP;
- goto bad;
- }
+ vn_lock(dvp, LK_SHARED | LK_RETRY, p);
+ return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
- /*
- * Allow CREATE requests if the name in question can
- * be written to. This allows open(name, O_RDWR | O_CREAT)
- * to work. Otherwise CREATE requests are not supported.
- */
- if (nameiop == CREATE && (kern_targets[i].kt_rw & VWRITE == 0)) {
- error = EOPNOTSUPP;
- goto bad;
- }
-
- /*
- * Check if this name has already has a vnode associated with it.
- */
- if (kern_targets[i].kt_vp) {
- if (*kern_targets[i].kt_vp) {
- *vpp = *kern_targets[i].kt_vp;
- VREF(*vpp);
- VOP_LOCK(*vpp);
- return (0);
+found:
+ if (kt->kt_tag == KTT_DEVICE) {
+ dev_t *dp = kt->kt_data;
+ loop:
+ if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) {
+ vn_lock(dvp, LK_SHARED | LK_RETRY, p);
+ return (ENOENT);
}
- error = ENXIO;
- goto bad;
+ *vpp = fvp;
+ if (vget(fvp, LK_EXCLUSIVE, p))
+ goto loop;
+ return (0);
}
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_lookup: allocate new vnode\n");
#endif
- error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p, &fvp);
- if (error)
- goto bad;
- MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP, M_WAITOK);
- VTOKERN(fvp)->kf_kt = &kern_targets[i];
- fvp->v_type = VTOKERN(fvp)->kf_kt->kt_vtype;
+ if (error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p,
+ &fvp)) {
+ vn_lock(dvp, LK_SHARED | LK_RETRY, p);
+ return (error);
+ }
+
+ MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP,
+ M_WAITOK);
+ VTOKERN(fvp)->kf_kt = kt;
+ fvp->v_type = kt->kt_vtype;
+ vn_lock(fvp, LK_SHARED | LK_RETRY, p);
*vpp = fvp;
+
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_lookup: newvp = %x\n", fvp);
#endif
return (0);
-
-bad:;
- *vpp = NULL;
-#ifdef KERNFS_DIAGNOSTIC
- printf("kernfs_lookup: error = %d\n", error);
-#endif
- return (error);
}
static int
@@ -354,22 +329,8 @@ kernfs_open(ap)
struct proc *a_p;
} */ *ap;
{
- struct vnode *vp = ap->a_vp;
-
- /*
- * Can always open the root (modulo perms)
- */
- if (vp->v_flag & VROOT)
- return (0);
-
-#ifdef KERNFS_DIAGNOSTIC
- printf("kernfs_open, mode = %x, file = %s\n",
- ap->a_mode, VTOKERN(vp)->kf_kt->kt_name);
-#endif
-
- if ((ap->a_mode & FWRITE) && !(VTOKERN(vp)->kf_kt->kt_rw & VWRITE))
- return (EOPNOTSUPP);
+ /* Only need to check access permissions. */
return (0);
}
@@ -382,33 +343,45 @@ kernfs_access(ap)
struct proc *a_p;
} */ *ap;
{
- struct vnode *vp = ap->a_vp;
- struct ucred *cred = ap->a_cred;
- mode_t mode = ap->a_mode;
-
- if (mode & VEXEC) {
- if (vp->v_flag & VROOT)
- return (0);
- return (EACCES);
- }
+ register struct vnode *vp = ap->a_vp;
+ register struct ucred *cred = ap->a_cred;
+ mode_t amode = ap->a_mode;
+ mode_t fmode =
+ (vp->v_flag & VROOT) ? DIR_MODE : VTOKERN(vp)->kf_kt->kt_mode;
+ mode_t mask = 0;
+ register gid_t *gp;
+ int i;
- if (cred->cr_uid == 0) {
- if ((vp->v_flag & VROOT) == 0) {
- struct kern_target *kt = VTOKERN(vp)->kf_kt;
+ /* Some files are simply not modifiable. */
+ if ((amode & VWRITE) && (fmode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0)
+ return (EPERM);
- if ((mode & VWRITE) && !(kt->kt_rw & VWRITE))
- return (EROFS);
- }
+ /* Root can do anything else. */
+ if (cred->cr_uid == 0)
return (0);
- }
- if (mode & VWRITE)
- return (EACCES);
+ /* Check for group 0 (wheel) permissions. */
+ for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
+ if (*gp == 0) {
+ if (amode & VEXEC)
+ mask |= S_IXGRP;
+ if (amode & VREAD)
+ mask |= S_IRGRP;
+ if (amode & VWRITE)
+ mask |= S_IWGRP;
+ return ((fmode & mask) == mask ? 0 : EACCES);
+ }
- return (0);
+ /* Otherwise, check everyone else. */
+ if (amode & VEXEC)
+ mask |= S_IXOTH;
+ if (amode & VREAD)
+ mask |= S_IROTH;
+ if (amode & VWRITE)
+ mask |= S_IWOTH;
+ return ((fmode & mask) == mask ? 0 : EACCES);
}
-
static int
kernfs_getattr(ap)
struct vop_getattr_args /* {
@@ -420,6 +393,7 @@ kernfs_getattr(ap)
{
struct vnode *vp = ap->a_vp;
struct vattr *vap = ap->a_vap;
+ struct timeval tv;
int error = 0;
char strbuf[KSTRING];
@@ -428,7 +402,7 @@ kernfs_getattr(ap)
vap->va_uid = 0;
vap->va_gid = 0;
vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
- /* vap->va_qsize = 0; */
+ vap->va_size = 0;
vap->va_blocksize = DEV_BSIZE;
{
struct timeval tv;
@@ -440,7 +414,6 @@ kernfs_getattr(ap)
vap->va_gen = 0;
vap->va_flags = 0;
vap->va_rdev = 0;
- /* vap->va_qbytes = 0; */
vap->va_bytes = 0;
if (vp->v_flag & VROOT) {
@@ -459,14 +432,13 @@ kernfs_getattr(ap)
printf("kernfs_getattr: stat target %s\n", kt->kt_name);
#endif
vap->va_type = kt->kt_vtype;
- vap->va_mode = (kt->kt_rw & VWRITE ? WRITE_MODE : READ_MODE);
+ vap->va_mode = kt->kt_mode;
vap->va_nlink = 1;
- vap->va_fileid = 3 + (kt - kern_targets) / sizeof(*kt);
+ vap->va_fileid = 1 + (kt - kern_targets) / sizeof(*kt);
error = kernfs_xread(kt, strbuf, sizeof(strbuf), &nbytes);
vap->va_size = nbytes;
}
- vp->v_type = vap->va_type;
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_getattr: return error %d\n", error);
#endif
@@ -509,7 +481,7 @@ kernfs_read(ap)
int error, len;
char *cp;
- if (vp->v_flag & VROOT)
+ if (vp->v_type == VDIR)
return (EOPNOTSUPP);
kt = VTOKERN(vp)->kf_kt;
@@ -519,12 +491,11 @@ kernfs_read(ap)
#endif
len = 0;
- error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len);
- if (error)
+ if (error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len))
return (error);
- cp = strbuf + off;
- len -= off;
- return (uiomove(cp, len, uio));
+ if (len <= off)
+ return (0);
+ return (uiomove(&strbuf[off], len - off, uio));
}
static int
@@ -542,8 +513,8 @@ kernfs_write(ap)
int error, xlen;
char strbuf[KSTRING];
- if (vp->v_flag & VROOT)
- return (0);
+ if (vp->v_type == VDIR)
+ return (EOPNOTSUPP);
kt = VTOKERN(vp)->kf_kt;
@@ -551,8 +522,7 @@ kernfs_write(ap)
return (EINVAL);
xlen = min(uio->uio_resid, KSTRING-1);
- error = uiomove(strbuf, xlen, uio);
- if (error)
+ if (error = uiomove(strbuf, xlen, uio))
return (error);
if (uio->uio_resid != 0)
@@ -563,33 +533,52 @@ kernfs_write(ap)
return (kernfs_xwrite(kt, strbuf, xlen));
}
-
static int
kernfs_readdir(ap)
struct vop_readdir_args /* {
struct vnode *a_vp;
struct uio *a_uio;
struct ucred *a_cred;
+ int *a_eofflag;
+ u_long *a_cookies;
+ int a_ncookies;
} */ *ap;
{
+ int error, i;
struct uio *uio = ap->a_uio;
- int i;
- int error;
+ struct kern_target *kt;
+ struct dirent d;
+
+ if (ap->a_vp->v_type != VDIR)
+ return (ENOTDIR);
+
+ /*
+ * We don't allow exporting kernfs mounts, and currently local
+ * requests do not need cookies.
+ */
+ if (ap->a_ncookies != NULL)
+ panic("kernfs_readdir: not hungry");
i = uio->uio_offset / UIO_MX;
error = 0;
- while (uio->uio_resid > 0 && i < nkern_targets) {
- struct dirent d;
+ for (kt = &kern_targets[i];
+ uio->uio_resid >= UIO_MX && i < nkern_targets; kt++, i++) {
struct dirent *dp = &d;
- struct kern_target *kt = &kern_targets[i];
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_readdir: i = %d\n", i);
#endif
- bzero((caddr_t) dp, UIO_MX);
+ if (kt->kt_tag == KTT_DEVICE) {
+ dev_t *dp = kt->kt_data;
+ struct vnode *fvp;
+
+ if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp))
+ continue;
+ }
- dp->d_namlen = strlen(kt->kt_name);
- bcopy(kt->kt_name, dp->d_name, dp->d_namlen+1);
+ bzero((caddr_t)dp, UIO_MX);
+ dp->d_namlen = kt->kt_namlen;
+ bcopy(kt->kt_name, dp->d_name, kt->kt_namlen+1);
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_readdir: name = %s, len = %d\n",
@@ -600,14 +589,12 @@ kernfs_readdir(ap)
*/
dp->d_reclen = UIO_MX;
dp->d_fileno = i + 3;
- dp->d_type = DT_UNKNOWN; /* XXX */
+ dp->d_type = kt->kt_type;
/*
* And ship to userland
*/
- error = uiomove((caddr_t) dp, UIO_MX, uio);
- if (error)
+ if (error = uiomove((caddr_t)dp, UIO_MX, uio))
break;
- i++;
}
uio->uio_offset = i * UIO_MX;
@@ -619,18 +606,20 @@ static int
kernfs_inactive(ap)
struct vop_inactive_args /* {
struct vnode *a_vp;
+ struct proc *a_p;
} */ *ap;
{
struct vnode *vp = ap->a_vp;
+#ifdef KERNFS_DIAGNOSTIC
+ printf("kernfs_inactive(%x)\n", vp);
+#endif
/*
* Clear out the v_type field to avoid
* nasty things happening in vgone().
*/
+ VOP_UNLOCK(vp, 0, ap->a_p);
vp->v_type = VNON;
-#ifdef KERNFS_DIAGNOSTIC
- printf("kernfs_inactive(%x)\n", vp);
-#endif
return (0);
}
@@ -641,6 +630,7 @@ kernfs_reclaim(ap)
} */ *ap;
{
struct vnode *vp = ap->a_vp;
+
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_reclaim(%x)\n", vp);
#endif
@@ -717,16 +707,6 @@ kernfs_vfree(ap)
}
/*
- * Kernfs vnode unsupported operation
- */
-static int
-kernfs_enotsupp()
-{
-
- return (EOPNOTSUPP);
-}
-
-/*
* Kernfs "should never get here" operation
*/
static int
@@ -735,42 +715,42 @@ kernfs_badop()
return (EIO);
}
-#define kernfs_create ((int (*) __P((struct vop_create_args *)))kernfs_enotsupp)
-#define kernfs_mknod ((int (*) __P((struct vop_mknod_args *)))kernfs_enotsupp)
+#define kernfs_create ((int (*) __P((struct vop_create_args *)))eopnotsupp)
+#define kernfs_mknod ((int (*) __P((struct vop_mknod_args *)))eopnotsupp)
#define kernfs_close ((int (*) __P((struct vop_close_args *)))nullop)
-#define kernfs_ioctl ((int (*) __P((struct vop_ioctl_args *)))kernfs_enotsupp)
-#define kernfs_select ((int (*) __P((struct vop_select_args *)))kernfs_enotsupp)
-#define kernfs_mmap ((int (*) __P((struct vop_mmap_args *)))kernfs_enotsupp)
+#define kernfs_ioctl ((int (*) __P((struct vop_ioctl_args *)))eopnotsupp)
+#define kernfs_select ((int (*) __P((struct vop_select_args *)))eopnotsupp)
+#define kernfs_revoke vop_revoke
+#define kernfs_mmap ((int (*) __P((struct vop_mmap_args *)))eopnotsupp)
#define kernfs_fsync ((int (*) __P((struct vop_fsync_args *)))nullop)
#define kernfs_seek ((int (*) __P((struct vop_seek_args *)))nullop)
-#define kernfs_remove ((int (*) __P((struct vop_remove_args *)))kernfs_enotsupp)
-#define kernfs_link ((int (*) __P((struct vop_link_args *)))kernfs_enotsupp)
-#define kernfs_rename ((int (*) __P((struct vop_rename_args *)))kernfs_enotsupp)
-#define kernfs_mkdir ((int (*) __P((struct vop_mkdir_args *)))kernfs_enotsupp)
-#define kernfs_rmdir ((int (*) __P((struct vop_rmdir_args *)))kernfs_enotsupp)
-#define kernfs_symlink ((int (*) __P((struct vop_symlink_args *)))kernfs_enotsupp)
-#define kernfs_readlink \
- ((int (*) __P((struct vop_readlink_args *)))kernfs_enotsupp)
+#define kernfs_remove ((int (*) __P((struct vop_remove_args *)))eopnotsupp)
+#define kernfs_link ((int (*) __P((struct vop_link_args *)))eopnotsupp)
+#define kernfs_rename ((int (*) __P((struct vop_rename_args *)))eopnotsupp)
+#define kernfs_mkdir ((int (*) __P((struct vop_mkdir_args *)))eopnotsupp)
+#define kernfs_rmdir ((int (*) __P((struct vop_rmdir_args *)))eopnotsupp)
+#define kernfs_symlink ((int (*) __P((struct vop_symlink_args *)))eopnotsupp)
+#define kernfs_readlink ((int (*) __P((struct vop_readlink_args *)))eopnotsupp)
#define kernfs_abortop ((int (*) __P((struct vop_abortop_args *)))nullop)
-#define kernfs_lock ((int (*) __P((struct vop_lock_args *)))nullop)
-#define kernfs_unlock ((int (*) __P((struct vop_unlock_args *)))nullop)
+#define kernfs_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock)
+#define kernfs_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock)
#define kernfs_bmap ((int (*) __P((struct vop_bmap_args *)))kernfs_badop)
-#define kernfs_strategy ((int (*) __P((struct vop_strategy_args *)))kernfs_badop)
-#define kernfs_islocked ((int (*) __P((struct vop_islocked_args *)))nullop)
-#define kernfs_advlock ((int (*) __P((struct vop_advlock_args *)))kernfs_enotsupp)
-#define kernfs_blkatoff \
- ((int (*) __P((struct vop_blkatoff_args *)))kernfs_enotsupp)
+#define kernfs_strategy \
+ ((int (*) __P((struct vop_strategy_args *)))kernfs_badop)
+#define kernfs_islocked \
+ ((int (*) __P((struct vop_islocked_args *)))vop_noislocked)
+#define kernfs_advlock ((int (*) __P((struct vop_advlock_args *)))eopnotsupp)
+#define kernfs_blkatoff ((int (*) __P((struct vop_blkatoff_args *)))eopnotsupp)
#define kernfs_valloc ((int(*) __P(( \
struct vnode *pvp, \
int mode, \
struct ucred *cred, \
- struct vnode **vpp))) kernfs_enotsupp)
-#define kernfs_truncate \
- ((int (*) __P((struct vop_truncate_args *)))kernfs_enotsupp)
-#define kernfs_update ((int (*) __P((struct vop_update_args *)))kernfs_enotsupp)
-#define kernfs_bwrite ((int (*) __P((struct vop_bwrite_args *)))kernfs_enotsupp)
+ struct vnode **vpp))) eopnotsupp)
+#define kernfs_truncate ((int (*) __P((struct vop_truncate_args *)))eopnotsupp)
+#define kernfs_update ((int (*) __P((struct vop_update_args *)))eopnotsupp)
+#define kernfs_bwrite ((int (*) __P((struct vop_bwrite_args *)))eopnotsupp)
-vop_t **kernfs_vnodeop_p;
+vop_t **kernfs_vnodeop_p;
static struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = {
{ &vop_default_desc, (vop_t *)vn_default_error },
{ &vop_lookup_desc, (vop_t *)kernfs_lookup }, /* lookup */
@@ -785,6 +765,7 @@ static struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = {
{ &vop_write_desc, (vop_t *)kernfs_write }, /* write */
{ &vop_ioctl_desc, (vop_t *)kernfs_ioctl }, /* ioctl */
{ &vop_select_desc, (vop_t *)kernfs_select }, /* select */
+ { &vop_revoke_desc, (vop_t *)kernfs_revoke }, /* revoke */
{ &vop_mmap_desc, (vop_t *)kernfs_mmap }, /* mmap */
{ &vop_fsync_desc, (vop_t *)kernfs_fsync }, /* fsync */
{ &vop_seek_desc, (vop_t *)kernfs_seek }, /* seek */
diff --git a/sys/miscfs/nullfs/null.h b/sys/miscfs/nullfs/null.h
index beadb42..70a81b2 100644
--- a/sys/miscfs/nullfs/null.h
+++ b/sys/miscfs/nullfs/null.h
@@ -33,7 +33,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)null.h 8.2 (Berkeley) 1/21/94
+ * @(#)null.h 8.3 (Berkeley) 8/20/94
*
* $FreeBSD$
*/
@@ -52,8 +52,7 @@ struct null_mount {
* A cache of vnode references
*/
struct null_node {
- struct null_node *null_forw; /* Hash chain */
- struct null_node *null_back;
+ LIST_ENTRY(null_node) null_hash; /* Hash list */
struct vnode *null_lowervp; /* VREFed once */
struct vnode *null_vnode; /* Back pointer */
};
diff --git a/sys/miscfs/nullfs/null_subr.c b/sys/miscfs/nullfs/null_subr.c
index a14a7e4..4418631 100644
--- a/sys/miscfs/nullfs/null_subr.c
+++ b/sys/miscfs/nullfs/null_subr.c
@@ -33,13 +33,14 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)null_subr.c 8.4 (Berkeley) 1/21/94
+ * @(#)null_subr.c 8.7 (Berkeley) 5/14/95
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/proc.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/vnode.h>
@@ -48,11 +49,8 @@
#include <sys/malloc.h>
#include <miscfs/nullfs/null.h>
-extern int nullfs_init __P((void));
-
#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
#define NNULLNODECACHE 16
-#define NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1))
/*
* Null layer cache:
@@ -62,51 +60,32 @@ extern int nullfs_init __P((void));
* alias is removed the lower vnode is vrele'd.
*/
-/*
- * Cache head
- */
-struct null_node_cache {
- struct null_node *ac_forw;
- struct null_node *ac_back;
-};
-
-static struct null_node_cache null_node_cache[NNULLNODECACHE];
+#define NULL_NHASH(vp) \
+ (&null_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & null_node_hash])
+LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl;
+u_long null_node_hash;
static int null_node_alloc __P((struct mount *mp, struct vnode *lowervp,
struct vnode **vpp));
static struct vnode *
null_node_find __P((struct mount *mp, struct vnode *lowervp));
-static struct null_node_cache *
- null_node_hash __P((struct vnode *lowervp));
/*
* Initialise cache headers
*/
int
-nullfs_init()
+nullfs_init(vfsp)
+ struct vfsconf *vfsp;
{
- struct null_node_cache *ac;
+
#ifdef NULLFS_DIAGNOSTIC
printf("nullfs_init\n"); /* printed during system boot */
#endif
-
- for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++)
- ac->ac_forw = ac->ac_back = (struct null_node *) ac;
+ null_node_hashtbl = hashinit(NNULLNODECACHE, M_CACHE, &null_node_hash);
return (0);
}
/*
- * Compute hash list for given lower vnode
- */
-static struct null_node_cache *
-null_node_hash(lowervp)
-struct vnode *lowervp;
-{
-
- return (&null_node_cache[NULL_NHASH(lowervp)]);
-}
-
-/*
* Return a VREF'ed alias for lower vnode if already exists, else 0.
*/
static struct vnode *
@@ -114,7 +93,8 @@ null_node_find(mp, lowervp)
struct mount *mp;
struct vnode *lowervp;
{
- struct null_node_cache *hd;
+ struct proc *p = curproc; /* XXX */
+ struct null_node_hashhead *hd;
struct null_node *a;
struct vnode *vp;
@@ -124,9 +104,9 @@ null_node_find(mp, lowervp)
* the lower vnode. If found, the increment the null_node
* reference count (but NOT the lower vnode's VREF counter).
*/
- hd = null_node_hash(lowervp);
+ hd = NULL_NHASH(lowervp);
loop:
- for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) {
+ for (a = hd->lh_first; a != 0; a = a->null_hash.le_next) {
if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
vp = NULLTOV(a);
/*
@@ -134,7 +114,7 @@ loop:
* stuff, but we don't want to lock
* the lower node.
*/
- if (vget(vp, 0)) {
+ if (vget(vp, 0, p)) {
printf ("null_node_find: vget failed.\n");
goto loop;
};
@@ -157,7 +137,7 @@ null_node_alloc(mp, lowervp, vpp)
struct vnode *lowervp;
struct vnode **vpp;
{
- struct null_node_cache *hd;
+ struct null_node_hashhead *hd;
struct null_node *xp;
struct vnode *othervp, *vp;
int error;
@@ -194,8 +174,8 @@ null_node_alloc(mp, lowervp, vpp)
return 0;
};
VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */
- hd = null_node_hash(lowervp);
- insque(xp, hd);
+ hd = NULL_NHASH(lowervp);
+ LIST_INSERT_HEAD(hd, xp, null_hash);
return 0;
}
@@ -250,9 +230,8 @@ null_node_create(mp, lowervp, newvpp)
#ifdef DIAGNOSTIC
if (lowervp->v_usecount < 1) {
/* Should never happen... */
- vprint ("null_node_create: alias ",aliasvp);
- vprint ("null_node_create: lower ",lowervp);
- printf ("null_node_create: lower has 0 usecount.\n");
+ vprint ("null_node_create: alias ", aliasvp);
+ vprint ("null_node_create: lower ", lowervp);
panic ("null_node_create: lower has 0 usecount.");
};
#endif
diff --git a/sys/miscfs/nullfs/null_vfsops.c b/sys/miscfs/nullfs/null_vfsops.c
index e2aeeba..339b7c1 100644
--- a/sys/miscfs/nullfs/null_vfsops.c
+++ b/sys/miscfs/nullfs/null_vfsops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software donated to Berkeley by
@@ -46,7 +46,7 @@
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/kernel.h>
+#include <sys/proc.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/vnode.h>
@@ -55,7 +55,7 @@
#include <sys/malloc.h>
#include <miscfs/nullfs/null.h>
-extern int nullfs_init __P((void));
+extern int nullfs_init __P((struct vfsconf *));
static int nullfs_fhtovp __P((struct mount *mp, struct fid *fidp,
struct mbuf *nam, struct vnode **vpp,
@@ -146,7 +146,7 @@ nullfs_mount(mp, path, data, ndp, p)
/*
* Unlock the node (either the lower or the alias)
*/
- VOP_UNLOCK(vp);
+ VOP_UNLOCK(vp, 0, p);
/*
* Make sure the node alias worked
*/
@@ -166,7 +166,7 @@ nullfs_mount(mp, path, data, ndp, p)
if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_data = (qaddr_t) xmp;
- getnewfsid(mp, MOUNT_LOFS);
+ vfs_getnewfsid(mp);
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
@@ -212,12 +212,8 @@ nullfs_unmount(mp, mntflags, p)
printf("nullfs_unmount(mp = %x)\n", mp);
#endif
- if (mntflags & MNT_FORCE) {
- /* lofs can never be rootfs so don't check for it */
- if (!doforce)
- return (EINVAL);
+ if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- }
/*
* Clear out buffer cache. I don't think we
@@ -259,6 +255,7 @@ nullfs_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
+ struct proc *p = curproc; /* XXX */
struct vnode *vp;
#ifdef NULLFS_DIAGNOSTIC
@@ -273,7 +270,7 @@ nullfs_root(mp, vpp)
*/
vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
VREF(vp);
- VOP_LOCK(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
*vpp = vp;
return 0;
}
diff --git a/sys/miscfs/nullfs/null_vnops.c b/sys/miscfs/nullfs/null_vnops.c
index ec279bc..c1af96f 100644
--- a/sys/miscfs/nullfs/null_vnops.c
+++ b/sys/miscfs/nullfs/null_vnops.c
@@ -33,7 +33,13 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)null_vnops.c 8.1 (Berkeley) 6/10/93
+ * @(#)null_vnops.c 8.6 (Berkeley) 5/27/95
+ *
+ * Ancestors:
+ * @(#)lofs_vnops.c 1.2 (Berkeley) 6/18/92
+ * $Id: null_vnops.c,v 1.11.2000.1 1996/09/17 14:32:31 peter Exp $
+ * ...and...
+ * @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project
*
* $FreeBSD$
*/
@@ -88,13 +94,21 @@
* in the arguments and, if a vnode is return by the operation,
* stacks a null-node on top of the returned vnode.
*
- * Although bypass handles most operations,
- * vop_getattr, _inactive, _reclaim, and _print are not bypassed.
- * Vop_getattr must change the fsid being returned.
+ * Although bypass handles most operations, vop_getattr, vop_lock,
+ * vop_unlock, vop_inactive, vop_reclaim, and vop_print are not
+ * bypassed. Vop_getattr must change the fsid being returned.
+ * Vop_lock and vop_unlock must handle any locking for the
+ * current vnode as well as pass the lock request down.
* Vop_inactive and vop_reclaim are not bypassed so that
- * they can handle freeing null-layer specific data.
- * Vop_print is not bypassed to avoid excessive debugging
- * information.
+ * they can handle freeing null-layer specific data. Vop_print
+ * is not bypassed to avoid excessive debugging information.
+ * Also, certain vnode operations change the locking state within
+ * the operation (create, mknod, remove, link, rename, mkdir, rmdir,
+ * and symlink). Ideally these operations should not change the
+ * lock state, but should be changed to let the caller of the
+ * function unlock them. Otherwise all intermediate vnode layers
+ * (such as union, umapfs, etc) must catch these functions to do
+ * the necessary locking at their layer.
*
*
* INSTANTIATING VNODE STACKS
@@ -178,7 +192,7 @@ static int null_bug_bypass = 0; /* for debugging: enables bypass printf'ing */
SYSCTL_INT(_debug, OID_AUTO, nullfs_bug_bypass, CTLFLAG_RW,
&null_bug_bypass, 0, "");
-static int null_bypass __P((struct vop_generic_args *ap));
+int null_bypass __P((struct vop_generic_args *ap));
static int null_bwrite __P((struct vop_bwrite_args *ap));
static int null_getattr __P((struct vop_getattr_args *ap));
static int null_inactive __P((struct vop_inactive_args *ap));
@@ -211,7 +225,7 @@ static int null_strategy __P((struct vop_strategy_args *ap));
* - all mapped vnodes are of our vnode-type (NEEDSWORK:
* problems on rmdir'ing mount points and renaming?)
*/
-static int
+int
null_bypass(ap)
struct vop_generic_args /* {
struct vnodeop_desc *a_desc;
@@ -254,7 +268,8 @@ null_bypass(ap)
* are of our type. Check for and don't map any
* that aren't. (We must always map first vp or vclean fails.)
*/
- if (i && (*this_vp_p)->v_op != null_vnodeop_p) {
+ if (i && (*this_vp_p == NULL ||
+ (*this_vp_p)->v_op != null_vnodeop_p)) {
old_vps[i] = NULL;
} else {
old_vps[i] = *this_vp_p;
@@ -317,6 +332,105 @@ null_bypass(ap)
return (error);
}
+/*
+ * We have to carry on the locking protocol on the null layer vnodes
+ * as we progress through the tree. We also have to enforce read-only
+ * if this layer is mounted read-only.
+ */
+static int
+null_lookup(ap)
+ struct vop_lookup_args /* {
+ struct vnode * a_dvp;
+ struct vnode ** a_vpp;
+ struct componentname * a_cnp;
+ } */ *ap;
+{
+ struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
+ int flags = cnp->cn_flags;
+ struct vop_lock_args lockargs;
+ struct vop_unlock_args unlockargs;
+ struct vnode *dvp, *vp;
+ int error;
+
+ if ((flags & ISLASTCN) && (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) &&
+ (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
+ return (EROFS);
+ error = null_bypass(ap);
+ if (error == EJUSTRETURN && (flags & ISLASTCN) &&
+ (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) &&
+ (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME))
+ error = EROFS;
+ /*
+ * We must do the same locking and unlocking at this layer as
+ * is done in the layers below us. We could figure this out
+ * based on the error return and the LASTCN, LOCKPARENT, and
+ * LOCKLEAF flags. However, it is more expidient to just find
+ * out the state of the lower level vnodes and set ours to the
+ * same state.
+ */
+ dvp = ap->a_dvp;
+ vp = *ap->a_vpp;
+ if (dvp == vp)
+ return (error);
+ if (!VOP_ISLOCKED(dvp)) {
+ unlockargs.a_vp = dvp;
+ unlockargs.a_flags = 0;
+ unlockargs.a_p = p;
+ vop_nounlock(&unlockargs);
+ }
+ if (vp != NULL && VOP_ISLOCKED(vp)) {
+ lockargs.a_vp = vp;
+ lockargs.a_flags = LK_SHARED;
+ lockargs.a_p = p;
+ vop_nolock(&lockargs);
+ }
+ return (error);
+}
+
+/*
+ * Setattr call. Disallow write attempts if the layer is mounted read-only.
+ */
+int
+null_setattr(ap)
+ struct vop_setattr_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct vattr *vap = ap->a_vap;
+
+ if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
+ vap->va_gid != (gid_t)VNOVAL || vap->va_atime.ts_sec != VNOVAL ||
+ vap->va_mtime.ts_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
+ (vp->v_mount->mnt_flag & MNT_RDONLY))
+ return (EROFS);
+ if (vap->va_size != VNOVAL) {
+ switch (vp->v_type) {
+ case VDIR:
+ return (EISDIR);
+ case VCHR:
+ case VBLK:
+ case VSOCK:
+ case VFIFO:
+ return (0);
+ case VREG:
+ case VLNK:
+ default:
+ /*
+ * Disallow write attempts if the filesystem is
+ * mounted read-only.
+ */
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+ }
+ }
+ return (null_bypass(ap));
+}
/*
* We handle getattr only to change the fsid.
@@ -331,19 +445,90 @@ null_getattr(ap)
} */ *ap;
{
int error;
- error = null_bypass(ap);
- if (error)
+
+ if (error = null_bypass(ap))
return (error);
/* Requires that arguments be restored. */
ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
return (0);
}
-
static int
+null_access(ap)
+ struct vop_access_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ mode_t mode = ap->a_mode;
+
+ /*
+ * Disallow write attempts on read-only layers;
+ * unless the file is a socket, fifo, or a block or
+ * character device resident on the file system.
+ */
+ if (mode & VWRITE) {
+ switch (vp->v_type) {
+ case VDIR:
+ case VLNK:
+ case VREG:
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+ break;
+ }
+ }
+ return (null_bypass(ap));
+}
+
+/*
+ * We need to process our own vnode lock and then clear the
+ * interlock flag as it applies only to our vnode, not the
+ * vnodes below us on the stack.
+ */
+int
+null_lock(ap)
+ struct vop_lock_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ struct proc *a_p;
+ } */ *ap;
+{
+
+ vop_nolock(ap);
+ if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN)
+ return (0);
+ ap->a_flags &= ~LK_INTERLOCK;
+ return (null_bypass(ap));
+}
+
+/*
+ * We need to process our own vnode unlock and then clear the
+ * interlock flag as it applies only to our vnode, not the
+ * vnodes below us on the stack.
+ */
+int
+null_unlock(ap)
+ struct vop_unlock_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+
+ vop_nounlock(ap);
+ ap->a_flags &= ~LK_INTERLOCK;
+ return (null_bypass(ap));
+}
+
+int
null_inactive(ap)
struct vop_inactive_args /* {
struct vnode *a_vp;
+ struct proc *a_p;
} */ *ap;
{
/*
@@ -358,6 +543,7 @@ null_inactive(ap)
* like they do in the name lookup cache code.
* That's too much work for now.
*/
+ VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
return (0);
}
@@ -365,6 +551,7 @@ static int
null_reclaim(ap)
struct vop_reclaim_args /* {
struct vnode *a_vp;
+ struct proc *a_p;
} */ *ap;
{
struct vnode *vp = ap->a_vp;
@@ -377,14 +564,13 @@ null_reclaim(ap)
*/
/* After this assignment, this node will not be re-used. */
xp->null_lowervp = NULL;
- remque(xp);
+ LIST_REMOVE(xp, null_hash);
FREE(vp->v_data, M_TEMP);
vp->v_data = NULL;
vrele (lowervp);
return (0);
}
-
static int
null_print(ap)
struct vop_print_args /* {
@@ -396,7 +582,6 @@ null_print(ap)
return (0);
}
-
/*
* XXX - vop_strategy must be hand coded because it has no
* vnode in its arguments.
@@ -422,7 +607,6 @@ null_strategy(ap)
return (error);
}
-
/*
* XXX - like vop_strategy, vop_bwrite must be hand coded because it has no
* vnode in its arguments.
@@ -455,7 +639,12 @@ vop_t **null_vnodeop_p;
static struct vnodeopv_entry_desc null_vnodeop_entries[] = {
{ &vop_default_desc, (vop_t *)null_bypass },
+ { &vop_lookup_desc, (vop_t *)null_lookup },
+ { &vop_setattr_desc, (vop_t *)null_setattr },
{ &vop_getattr_desc, (vop_t *)null_getattr },
+ { &vop_access_desc, (vop_t *)null_access },
+ { &vop_lock_desc, (vop_t *)null_lock },
+ { &vop_unlock_desc, (vop_t *)null_unlock },
{ &vop_inactive_desc, (vop_t *)null_inactive },
{ &vop_reclaim_desc, (vop_t *)null_reclaim },
{ &vop_print_desc, (vop_t *)null_print },
diff --git a/sys/miscfs/portal/portal_vfsops.c b/sys/miscfs/portal/portal_vfsops.c
index a980f65..74e1542 100644
--- a/sys/miscfs/portal/portal_vfsops.c
+++ b/sys/miscfs/portal/portal_vfsops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software donated to Berkeley by
@@ -33,7 +33,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)portal_vfsops.c 8.6 (Berkeley) 1/21/94
+ * @(#)portal_vfsops.c 8.11 (Berkeley) 5/14/95
*
* $FreeBSD$
*/
@@ -62,28 +62,18 @@
#include <sys/un.h>
#include <miscfs/portal/portal.h>
-static int portal_init __P((void));
static int portal_mount __P((struct mount *mp, char *path, caddr_t data,
struct nameidata *ndp, struct proc *p));
static int portal_start __P((struct mount *mp, int flags, struct proc *p));
static int portal_unmount __P((struct mount *mp, int mntflags,
struct proc *p));
static int portal_root __P((struct mount *mp, struct vnode **vpp));
-static int portal_quotactl __P((struct mount *mp, int cmd, uid_t uid,
- caddr_t arg, struct proc *p));
static int portal_statfs __P((struct mount *mp, struct statfs *sbp,
struct proc *p));
-static int portal_sync __P((struct mount *mp, int waitfor,
- struct ucred *cred, struct proc *p));
-static int portal_vget __P((struct mount *mp, ino_t ino,
- struct vnode **vpp));
-static int portal_fhtovp __P((struct mount *mp, struct fid *fhp,
- struct mbuf *nam, struct vnode **vpp,
- int *exflagsp, struct ucred **credanonp));
-static int portal_vptofh __P((struct vnode *vp, struct fid *fhp));
static int
-portal_init()
+portal_init(vfsp)
+ struct vfsconf *vfsp;
{
return (0);
@@ -150,7 +140,7 @@ portal_mount(mp, path, data, ndp, p)
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_data = (qaddr_t) fmp;
- getnewfsid(mp, MOUNT_PORTAL);
+ vfs_getnewfsid(mp);
(void)copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
@@ -186,12 +176,8 @@ portal_unmount(mp, mntflags, p)
int error, flags = 0;
- if (mntflags & MNT_FORCE) {
- /* portal can never be rootfs so don't check for it */
- if (!doforce)
- return (EINVAL);
+ if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- }
/*
* Clear out buffer cache. I don't think we
@@ -241,39 +227,26 @@ portal_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
+ struct proc *p = curproc; /* XXX */
struct vnode *vp;
-
/*
* Return locked reference to root.
*/
vp = VFSTOPORTAL(mp)->pm_root;
VREF(vp);
- VOP_LOCK(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
*vpp = vp;
return (0);
}
static int
-portal_quotactl(mp, cmd, uid, arg, p)
- struct mount *mp;
- int cmd;
- uid_t uid;
- caddr_t arg;
- struct proc *p;
-{
-
- return (EOPNOTSUPP);
-}
-
-static int
portal_statfs(mp, sbp, p)
struct mount *mp;
struct statfs *sbp;
struct proc *p;
{
- sbp->f_type = MOUNT_PORTAL;
sbp->f_flags = 0;
sbp->f_bsize = DEV_BSIZE;
sbp->f_iosize = DEV_BSIZE;
@@ -283,6 +256,7 @@ portal_statfs(mp, sbp, p)
sbp->f_files = 1; /* Allow for "." */
sbp->f_ffree = 0; /* See comments above */
if (sbp != &mp->mnt_stat) {
+ sbp->f_type = mp->mnt_vfc->vfc_typenum;
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
@@ -290,48 +264,17 @@ portal_statfs(mp, sbp, p)
return (0);
}
-static int
-portal_sync(mp, waitfor, cred, p)
- struct mount *mp;
- int waitfor;
- struct ucred *cred;
- struct proc *p;
-{
-
- return (0);
-}
-
-static int
-portal_vget(mp, ino, vpp)
- struct mount *mp;
- ino_t ino;
- struct vnode **vpp;
-{
-
- return (EOPNOTSUPP);
-}
-
-static int
-portal_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
- struct mount *mp;
- struct fid *fhp;
- struct mbuf *nam;
- struct vnode **vpp;
- int *exflagsp;
- struct ucred **credanonp;
-{
-
- return (EOPNOTSUPP);
-}
-
-static int
-portal_vptofh(vp, fhp)
- struct vnode *vp;
- struct fid *fhp;
-{
-
- return (EOPNOTSUPP);
-}
+#define portal_fhtovp ((int (*) __P((struct mount *, struct fid *, \
+ struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp)
+#define portal_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
+ struct proc *)))eopnotsupp)
+#define portal_sync ((int (*) __P((struct mount *, int, struct ucred *, \
+ struct proc *)))nullop)
+#define portal_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
+ size_t, struct proc *)))eopnotsupp)
+#define portal_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
+ eopnotsupp)
+#define portal_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp)
static struct vfsops portal_vfsops = {
portal_mount,
diff --git a/sys/miscfs/portal/portal_vnops.c b/sys/miscfs/portal/portal_vnops.c
index 8135a5e..19b439c 100644
--- a/sys/miscfs/portal/portal_vnops.c
+++ b/sys/miscfs/portal/portal_vnops.c
@@ -33,7 +33,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)portal_vnops.c 8.8 (Berkeley) 1/21/94
+ * @(#)portal_vnops.c 8.14 (Berkeley) 5/21/95
*
* $FreeBSD$
*/
@@ -112,17 +112,25 @@ portal_lookup(ap)
struct componentname * a_cnp;
} */ *ap;
{
- char *pname = ap->a_cnp->cn_nameptr;
+ struct componentname *cnp = ap->a_cnp;
+ struct vnode **vpp = ap->a_vpp;
+ struct vnode *dvp = ap->a_dvp;
+ char *pname = cnp->cn_nameptr;
struct portalnode *pt;
int error;
struct vnode *fvp = 0;
char *path;
int size;
- if (ap->a_cnp->cn_namelen == 1 && *pname == '.') {
- *ap->a_vpp = ap->a_dvp;
- VREF(ap->a_dvp);
- /*VOP_LOCK(ap->a_dvp);*/
+ *vpp = NULLVP;
+
+ if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
+ return (EROFS);
+
+ if (cnp->cn_namelen == 1 && *pname == '.') {
+ *vpp = dvp;
+ VREF(dvp);
+ /*VOP_LOCK(dvp);*/
return (0);
}
@@ -134,7 +142,7 @@ portal_lookup(ap)
MALLOC(pt, struct portalnode *, sizeof(struct portalnode),
M_TEMP, M_WAITOK);
- error = getnewvnode(VT_PORTAL, ap->a_dvp->v_mount, portal_vnodeop_p, &fvp);
+ error = getnewvnode(VT_PORTAL, dvp->v_mount, portal_vnodeop_p, &fvp);
if (error) {
FREE(pt, M_TEMP);
goto bad;
@@ -148,22 +156,20 @@ portal_lookup(ap)
*/
for (size = 0, path = pname; *path; path++)
size++;
- ap->a_cnp->cn_consume = size - ap->a_cnp->cn_namelen;
+ cnp->cn_consume = size - cnp->cn_namelen;
pt->pt_arg = malloc(size+1, M_TEMP, M_WAITOK);
pt->pt_size = size+1;
bcopy(pname, pt->pt_arg, pt->pt_size);
pt->pt_fileid = portal_fileid++;
- *ap->a_vpp = fvp;
+ *vpp = fvp;
/*VOP_LOCK(fvp);*/
return (0);
bad:;
- if (fvp) {
+ if (fvp)
vrele(fvp);
- }
- *ap->a_vpp = NULL;
return (error);
}
@@ -444,6 +450,7 @@ portal_getattr(ap)
{
struct vnode *vp = ap->a_vp;
struct vattr *vap = ap->a_vap;
+ struct timeval tv;
bzero(vap, sizeof(*vap));
vattr_null(vap);
@@ -452,8 +459,8 @@ portal_getattr(ap)
vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
vap->va_size = DEV_BSIZE;
vap->va_blocksize = DEV_BSIZE;
- microtime((struct timeval *)&vap->va_atime);
- TIMEVAL_TO_TIMESPEC((struct timeval *)&vap->va_atime, (struct timespec *)&vap->va_atime);
+ microtime(&tv);
+ TIMEVAL_TO_TIMESPEC(&tv, &vap->va_atime);
vap->va_mtime = vap->va_atime;
vap->va_ctime = vap->va_ctime;
vap->va_gen = 0;
@@ -509,9 +516,19 @@ portal_readdir(ap)
struct vnode *a_vp;
struct uio *a_uio;
struct ucred *a_cred;
+ int *a_eofflag;
+ u_long *a_cookies;
+ int a_ncookies;
} */ *ap;
{
+ /*
+ * We don't allow exporting portal mounts, and currently local
+ * requests do not need cookies.
+ */
+ if (ap->a_ncookies)
+ panic("portal_readdir: not hungry");
+
return (0);
}
@@ -519,9 +536,11 @@ static int
portal_inactive(ap)
struct vop_inactive_args /* {
struct vnode *a_vp;
+ struct proc *a_p;
} */ *ap;
{
+ VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
return (0);
}
@@ -639,6 +658,7 @@ portal_badop()
#define portal_ioctl ((int (*) __P((struct vop_ioctl_args *)))portal_enotsupp)
#define portal_select ((int (*) __P((struct vop_select_args *)))portal_enotsupp)
#define portal_mmap ((int (*) __P((struct vop_mmap_args *)))portal_enotsupp)
+#define portal_revoke vop_revoke
#define portal_fsync ((int (*) __P((struct vop_fsync_args *)))nullop)
#define portal_seek ((int (*) __P((struct vop_seek_args *)))nullop)
#define portal_remove ((int (*) __P((struct vop_remove_args *)))portal_enotsupp)
@@ -651,12 +671,14 @@ portal_badop()
#define portal_readlink \
((int (*) __P((struct vop_readlink_args *)))portal_enotsupp)
#define portal_abortop ((int (*) __P((struct vop_abortop_args *)))nullop)
-#define portal_lock ((int (*) __P((struct vop_lock_args *)))nullop)
-#define portal_unlock ((int (*) __P((struct vop_unlock_args *)))nullop)
+#define portal_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock)
+#define portal_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock)
#define portal_bmap ((int (*) __P((struct vop_bmap_args *)))portal_badop)
#define portal_strategy \
((int (*) __P((struct vop_strategy_args *)))portal_badop)
-#define portal_islocked ((int (*) __P((struct vop_islocked_args *)))nullop)
+#define portal_islocked \
+ ((int (*) __P((struct vop_islocked_args *)))vop_noislocked)
+#define fifo_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked)
#define portal_advlock \
((int (*) __P((struct vop_advlock_args *)))portal_enotsupp)
#define portal_blkatoff \
@@ -687,6 +709,7 @@ static struct vnodeopv_entry_desc portal_vnodeop_entries[] = {
{ &vop_ioctl_desc, (vop_t *)portal_ioctl }, /* ioctl */
{ &vop_select_desc, (vop_t *)portal_select }, /* select */
{ &vop_mmap_desc, (vop_t *)portal_mmap }, /* mmap */
+ { &vop_revoke_desc, (vop_t *)portal_revoke }, /* revoke */
{ &vop_fsync_desc, (vop_t *)portal_fsync }, /* fsync */
{ &vop_seek_desc, (vop_t *)portal_seek }, /* seek */
{ &vop_remove_desc, (vop_t *)portal_remove }, /* remove */
diff --git a/sys/miscfs/procfs/procfs.h b/sys/miscfs/procfs/procfs.h
index df01a39..ef0d7eb 100644
--- a/sys/miscfs/procfs/procfs.h
+++ b/sys/miscfs/procfs/procfs.h
@@ -34,8 +34,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)procfs.h 8.6 (Berkeley) 2/3/94
+ * @(#)procfs.h 8.9 (Berkeley) 5/14/95
*
+ * From:
* $FreeBSD$
*/
@@ -44,6 +45,7 @@
*/
typedef enum {
Proot, /* the filesystem root */
+ Pcurproc, /* symbolic link for curproc */
Pproc, /* a process-specific sub-directory */
Pfile, /* the executable file */
Pmem, /* the process's memory image */
@@ -97,9 +99,9 @@ struct pfsdent {
};
#define UIO_MX sizeof(struct pfsdent)
#define PROCFS_FILENO(pid, type) \
- (((type) == Proot) ? \
- 2 : \
- ((((pid)+1) << 3) + ((int) (type))))
+ (((type) < Pproc) ? \
+ ((type) + 2) : \
+ ((((pid)+1) << 4) + ((int) (type))))
/*
* Convert between pfsnode vnode
@@ -113,33 +115,33 @@ struct vfs_namemap {
int nm_val;
};
-extern int vfs_getuserstr __P((struct uio *, char *, int *));
-extern vfs_namemap_t *vfs_findname __P((vfs_namemap_t *, char *, int));
+int vfs_getuserstr __P((struct uio *, char *, int *));
+vfs_namemap_t *vfs_findname __P((vfs_namemap_t *, char *, int));
/* <machine/reg.h> */
struct reg;
struct fpreg;
#define PFIND(pid) ((pid) ? pfind(pid) : &proc0)
-extern int procfs_freevp __P((struct vnode *));
-extern int procfs_allocvp __P((struct mount *, struct vnode **, long, pfstype));
-extern struct vnode *procfs_findtextvp __P((struct proc *));
-extern int procfs_sstep __P((struct proc *));
-extern void procfs_fix_sstep __P((struct proc *));
-extern int procfs_read_regs __P((struct proc *, struct reg *));
-extern int procfs_write_regs __P((struct proc *, struct reg *));
-extern int procfs_read_fpregs __P((struct proc *, struct fpreg *));
-extern int procfs_write_fpregs __P((struct proc *, struct fpreg *));
-extern int procfs_donote __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
-extern int procfs_doregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
-extern int procfs_dofpregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
-extern int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
-extern int procfs_doctl __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
-extern int procfs_dostatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
-extern int procfs_domap __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
-extern int procfs_dotype __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
+int procfs_freevp __P((struct vnode *));
+int procfs_allocvp __P((struct mount *, struct vnode **, long, pfstype));
+struct vnode *procfs_findtextvp __P((struct proc *));
+int procfs_sstep __P((struct proc *));
+void procfs_fix_sstep __P((struct proc *));
+int procfs_read_regs __P((struct proc *, struct reg *));
+int procfs_write_regs __P((struct proc *, struct reg *));
+int procfs_read_fpregs __P((struct proc *, struct fpreg *));
+int procfs_write_fpregs __P((struct proc *, struct fpreg *));
+int procfs_donote __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
+int procfs_doregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
+int procfs_dofpregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
+int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
+int procfs_doctl __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
+int procfs_dostatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
+int procfs_domap __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
+int procfs_dotype __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
-/* check to see if the process has the "items" (regs/file) */
+/* functions to check whether or not files should be displayed */
int procfs_validfile __P((struct proc *));
int procfs_validfpregs __P((struct proc *));
int procfs_validregs __P((struct proc *));
diff --git a/sys/miscfs/procfs/procfs_ctl.c b/sys/miscfs/procfs/procfs_ctl.c
index 4ddf7a7..68b93dd 100644
--- a/sys/miscfs/procfs/procfs_ctl.c
+++ b/sys/miscfs/procfs/procfs_ctl.c
@@ -34,8 +34,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)procfs_ctl.c 8.3 (Berkeley) 1/21/94
+ * @(#)procfs_ctl.c 8.4 (Berkeley) 6/15/94
*
+ * From:
* $FreeBSD$
*/
@@ -51,13 +52,13 @@
#include <sys/resourcevar.h>
#include <sys/signal.h>
#include <sys/signalvar.h>
-
-#include <vm/vm.h>
-#include <vm/vm_param.h>
-#include <vm/vm_extern.h>
-
+#include <sys/ptrace.h>
#include <miscfs/procfs/procfs.h>
+#ifndef FIX_SSTEP
+#define FIX_SSTEP(p)
+#endif
+
/*
* True iff process (p) is in trace wait state
* relative to process (curp)
@@ -67,13 +68,6 @@
(p)->p_pptr == (curp) && \
((p)->p_flag & P_TRACED))
-#ifdef notdef
-#define FIX_SSTEP(p) { \
- procfs_fix_sstep(p); \
- } \
-}
-#endif
-
#define PROCFS_CTL_ATTACH 1
#define PROCFS_CTL_DETACH 2
#define PROCFS_CTL_STEP 3
@@ -220,8 +214,10 @@ procfs_control(curp, p, op)
*/
case PROCFS_CTL_STEP:
PHOLD(p);
- procfs_sstep(p);
+ error = procfs_sstep(p);
PRELE(p);
+ if (error)
+ return (error);
break;
/*
diff --git a/sys/miscfs/procfs/procfs_fpregs.c b/sys/miscfs/procfs/procfs_fpregs.c
index a3cad5f..841cf76 100644
--- a/sys/miscfs/procfs/procfs_fpregs.c
+++ b/sys/miscfs/procfs/procfs_fpregs.c
@@ -34,8 +34,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)procfs_fpregs.c 8.1 (Berkeley) 1/27/94
+ * @(#)procfs_fpregs.c 8.2 (Berkeley) 6/15/94
*
+ * From:
* $FreeBSD$
*/
diff --git a/sys/miscfs/procfs/procfs_map.c b/sys/miscfs/procfs/procfs_map.c
index 27c44fa..40c40d8 100644
--- a/sys/miscfs/procfs/procfs_map.c
+++ b/sys/miscfs/procfs/procfs_map.c
@@ -59,7 +59,7 @@
#include <vm/vm_param.h>
#include <vm/vm_prot.h>
#include <vm/vm_inherit.h>
-#include <vm/lock.h>
+#include <sys/lock.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <vm/vm_page.h>
diff --git a/sys/miscfs/procfs/procfs_mem.c b/sys/miscfs/procfs/procfs_mem.c
index 4e8fac6..06364e5 100644
--- a/sys/miscfs/procfs/procfs_mem.c
+++ b/sys/miscfs/procfs/procfs_mem.c
@@ -35,7 +35,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)procfs_mem.c 8.4 (Berkeley) 1/21/94
+ * @(#)procfs_mem.c 8.5 (Berkeley) 6/15/94
*
* $FreeBSD$
*/
@@ -55,7 +55,7 @@
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/vm_prot.h>
-#include <vm/lock.h>
+#include <sys/lock.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <vm/vm_kern.h>
@@ -295,14 +295,11 @@ procfs_domem(curp, p, pfs, uio)
struct pfsnode *pfs;
struct uio *uio;
{
- int error;
if (uio->uio_resid == 0)
return (0);
- error = procfs_rwmem(p, uio);
-
- return (error);
+ return (procfs_rwmem(p, uio));
}
/*
@@ -320,5 +317,6 @@ struct vnode *
procfs_findtextvp(p)
struct proc *p;
{
+
return (p->p_textvp);
}
diff --git a/sys/miscfs/procfs/procfs_regs.c b/sys/miscfs/procfs/procfs_regs.c
index 9282a3a..56ef233 100644
--- a/sys/miscfs/procfs/procfs_regs.c
+++ b/sys/miscfs/procfs/procfs_regs.c
@@ -34,8 +34,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)procfs_regs.c 8.3 (Berkeley) 1/27/94
+ * @(#)procfs_regs.c 8.4 (Berkeley) 6/15/94
*
+ * From:
* $FreeBSD$
*/
diff --git a/sys/miscfs/procfs/procfs_status.c b/sys/miscfs/procfs/procfs_status.c
index 432918d..76974b5 100644
--- a/sys/miscfs/procfs/procfs_status.c
+++ b/sys/miscfs/procfs/procfs_status.c
@@ -34,8 +34,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)procfs_status.c 8.3 (Berkeley) 2/17/94
+ * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
*
+ * From:
* $FreeBSD$
*/
@@ -142,7 +143,7 @@ procfs_dostatus(curp, p, pfs, uio)
xlen = ps - psbuf;
xlen -= uio->uio_offset;
ps = psbuf + uio->uio_offset;
- xlen = min(xlen, uio->uio_resid);
+ xlen = imin(xlen, uio->uio_resid);
if (xlen <= 0)
error = 0;
else
diff --git a/sys/miscfs/procfs/procfs_subr.c b/sys/miscfs/procfs/procfs_subr.c
index d9b3d2f..5ee78f0 100644
--- a/sys/miscfs/procfs/procfs_subr.c
+++ b/sys/miscfs/procfs/procfs_subr.c
@@ -34,7 +34,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)procfs_subr.c 8.4 (Berkeley) 1/27/94
+ * @(#)procfs_subr.c 8.6 (Berkeley) 5/14/95
*
* $FreeBSD$
*/
@@ -84,18 +84,21 @@ procfs_allocvp(mp, vpp, pid, pfs_type)
long pid;
pfstype pfs_type;
{
- int error;
+ struct proc *p = curproc; /* XXX */
struct pfsnode *pfs;
+ struct vnode *vp;
struct pfsnode **pp;
+ int error;
loop:
for (pfs = pfshead; pfs != 0; pfs = pfs->pfs_next) {
+ vp = PFSTOV(pfs);
if (pfs->pfs_pid == pid &&
pfs->pfs_type == pfs_type &&
- PFSTOV(pfs)->v_mount == mp) {
- if (vget(pfs->pfs_vnode, 0))
+ vp->v_mount == mp) {
+ if (vget(vp, 0, p))
goto loop;
- *vpp = pfs->pfs_vnode;
+ *vpp = vp;
return (0);
}
}
@@ -118,17 +121,18 @@ loop:
*/
MALLOC(pfs, struct pfsnode *, sizeof(struct pfsnode), M_TEMP, M_WAITOK);
- error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp);
- if (error) {
+ if (error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp)) {
FREE(pfs, M_TEMP);
goto out;
}
+ vp = *vpp;
+
+ vp->v_data = pfs;
- (*vpp)->v_data = pfs;
pfs->pfs_next = 0;
pfs->pfs_pid = (pid_t) pid;
pfs->pfs_type = pfs_type;
- pfs->pfs_vnode = *vpp;
+ pfs->pfs_vnode = vp;
pfs->pfs_flags = 0;
pfs->pfs_lockowner = 0;
pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type);
@@ -138,33 +142,41 @@ loop:
pfs->pfs_mode = (VREAD|VEXEC) |
(VREAD|VEXEC) >> 3 |
(VREAD|VEXEC) >> 6;
+ vp->v_type = VDIR;
+ vp->v_flag = VROOT;
+ break;
+
+ case Pcurproc: /* /proc/curproc = lr--r--r-- */
+ pfs->pfs_mode = (VREAD) |
+ (VREAD >> 3) |
+ (VREAD >> 6);
+ vp->v_type = VLNK;
break;
case Pproc:
pfs->pfs_mode = (VREAD|VEXEC) |
(VREAD|VEXEC) >> 3 |
(VREAD|VEXEC) >> 6;
+ vp->v_type = VDIR;
break;
case Pfile:
- pfs->pfs_mode = (VREAD|VWRITE);
- break;
-
case Pmem:
pfs->pfs_mode = (VREAD|VWRITE) |
(VREAD) >> 3;;
break;
case Pregs:
- pfs->pfs_mode = (VREAD|VWRITE);
- break;
-
case Pfpregs:
pfs->pfs_mode = (VREAD|VWRITE);
+ vp->v_type = VREG;
break;
case Pctl:
+ case Pnote:
+ case Pnotepg:
pfs->pfs_mode = (VWRITE);
+ vp->v_type = VREG;
break;
case Ptype:
@@ -173,14 +185,7 @@ loop:
pfs->pfs_mode = (VREAD) |
(VREAD >> 3) |
(VREAD >> 6);
- break;
-
- case Pnote:
- pfs->pfs_mode = (VWRITE);
- break;
-
- case Pnotepg:
- pfs->pfs_mode = (VWRITE);
+ vp->v_type = VREG;
break;
default:
@@ -316,8 +321,7 @@ vfs_getuserstr(uio, buf, buflenp)
return (EMSGSIZE);
xlen = uio->uio_resid;
- error = uiomove(buf, xlen, uio);
- if (error)
+ if (error = uiomove(buf, xlen, uio))
return (error);
/* allow multiple writes without seeks */
@@ -339,6 +343,7 @@ vfs_findname(nm, buf, buflen)
char *buf;
int buflen;
{
+
for (; nm->nm_name; nm++)
if (bcmp(buf, nm->nm_name, buflen+1) == 0)
return (nm);
diff --git a/sys/miscfs/procfs/procfs_vfsops.c b/sys/miscfs/procfs/procfs_vfsops.c
index 433b391..5387126 100644
--- a/sys/miscfs/procfs/procfs_vfsops.c
+++ b/sys/miscfs/procfs/procfs_vfsops.c
@@ -34,7 +34,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)procfs_vfsops.c 8.4 (Berkeley) 1/21/94
+ * @(#)procfs_vfsops.c 8.7 (Berkeley) 5/10/95
*
* $FreeBSD$
*/
@@ -56,24 +56,14 @@
#include <miscfs/procfs/procfs.h>
#include <vm/vm.h> /* for PAGE_SIZE */
-static int procfs_fhtovp __P((struct mount *mp, struct fid *fhp,
- struct mbuf *nam, struct vnode **vpp,
- int *exflagsp, struct ucred **credanonp));
-static int procfs_init __P((void));
+static int procfs_init __P((struct vfsconf *vfsp));
static int procfs_mount __P((struct mount *mp, char *path, caddr_t data,
struct nameidata *ndp, struct proc *p));
-static int procfs_quotactl __P((struct mount *mp, int cmds, uid_t uid,
- caddr_t arg, struct proc *p));
static int procfs_start __P((struct mount *mp, int flags, struct proc *p));
static int procfs_statfs __P((struct mount *mp, struct statfs *sbp,
struct proc *p));
-static int procfs_sync __P((struct mount *mp, int waitfor,
- struct ucred *cred, struct proc *p));
static int procfs_unmount __P((struct mount *mp, int mntflags,
struct proc *p));
-static int procfs_vget __P((struct mount *mp, ino_t ino,
- struct vnode **vpp));
-static int procfs_vptofh __P((struct vnode *vp, struct fid *fhp));
/*
* VFS Operations.
@@ -101,7 +91,7 @@ procfs_mount(mp, path, data, ndp, p)
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_data = 0;
- getnewfsid(mp, MOUNT_PROCFS);
+ vfs_getnewfsid(mp);
(void) copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname, MNAMELEN, &size);
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
@@ -125,12 +115,8 @@ procfs_unmount(mp, mntflags, p)
int error;
int flags = 0;
- if (mntflags & MNT_FORCE) {
- /* procfs can never be rootfs so don't check for it */
- if (!doforce)
- return (EINVAL);
+ if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- }
error = vflush(mp, 0, flags);
if (error)
@@ -144,24 +130,10 @@ procfs_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
- struct pfsnode *pfs;
- struct vnode *vp;
- int error;
-
- error = procfs_allocvp(mp, &vp, (pid_t) 0, Proot);
- if (error)
- return (error);
-
- vp->v_type = VDIR;
- vp->v_flag = VROOT;
- pfs = VTOPFS(vp);
- *vpp = vp;
- return (0);
+ return (procfs_allocvp(mp, vpp, 0, Proot));
}
-/*
- */
/* ARGSUSED */
static int
procfs_start(mp, flags, p)
@@ -182,7 +154,6 @@ procfs_statfs(mp, sbp, p)
struct statfs *sbp;
struct proc *p;
{
- sbp->f_type = MOUNT_PROCFS;
sbp->f_bsize = PAGE_SIZE;
sbp->f_iosize = PAGE_SIZE;
sbp->f_blocks = 1; /* avoid divide by zero in some df's */
@@ -192,6 +163,7 @@ procfs_statfs(mp, sbp, p)
sbp->f_ffree = maxproc - nprocs; /* approx */
if (sbp != &mp->mnt_stat) {
+ sbp->f_type = mp->mnt_vfc->vfc_typenum;
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
@@ -200,68 +172,25 @@ procfs_statfs(mp, sbp, p)
return (0);
}
-
-static int
-procfs_quotactl(mp, cmds, uid, arg, p)
- struct mount *mp;
- int cmds;
- uid_t uid;
- caddr_t arg;
- struct proc *p;
-{
-
- return (EOPNOTSUPP);
-}
-
static int
-procfs_sync(mp, waitfor, cred, p)
- struct mount *mp;
- int waitfor;
- struct ucred *cred;
- struct proc *p;
+procfs_init(vfsp)
+ struct vfsconf *vfsp;
{
return (0);
}
-static int
-procfs_vget(mp, ino, vpp)
- struct mount *mp;
- ino_t ino;
- struct vnode **vpp;
-{
-
- return (EOPNOTSUPP);
-}
-
-static int
-procfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
- struct mount *mp;
- struct fid *fhp;
- struct mbuf *nam;
- struct vnode **vpp;
- int *exflagsp;
- struct ucred **credanonp;
-{
-
- return (EINVAL);
-}
-
-static int
-procfs_vptofh(vp, fhp)
- struct vnode *vp;
- struct fid *fhp;
-{
-
- return EINVAL;
-}
-
-static int
-procfs_init()
-{
-
- return (0);
-}
+#define procfs_fhtovp ((int (*) __P((struct mount *, struct fid *, \
+ struct mbuf *, struct vnode **, int *, struct ucred **)))einval)
+#define procfs_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
+ struct proc *)))eopnotsupp)
+#define procfs_sync ((int (*) __P((struct mount *, int, struct ucred *, \
+ struct proc *)))nullop)
+#define procfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
+ size_t, struct proc *)))eopnotsupp)
+#define procfs_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
+ eopnotsupp)
+#define procfs_vptofh ((int (*) __P((struct vnode *, struct fid *)))einval)
static struct vfsops procfs_vfsops = {
procfs_mount,
diff --git a/sys/miscfs/procfs/procfs_vnops.c b/sys/miscfs/procfs/procfs_vnops.c
index f497563..85be3ea 100644
--- a/sys/miscfs/procfs/procfs_vnops.c
+++ b/sys/miscfs/procfs/procfs_vnops.c
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1993 Jan-Simon Pendry
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1995 Jan-Simon Pendry
+ * Copyright (c) 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
@@ -34,7 +34,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)procfs_vnops.c 8.6 (Berkeley) 2/7/94
+ * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95
*
* $FreeBSD$
*/
@@ -55,8 +55,9 @@
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/resourcevar.h>
-#include <miscfs/procfs/procfs.h>
#include <vm/vm.h> /* for PAGE_SIZE */
+#include <machine/reg.h>
+#include <miscfs/procfs/procfs.h>
static int procfs_abortop __P((struct vop_abortop_args *));
static int procfs_access __P((struct vop_access_args *));
@@ -78,29 +79,30 @@ static int procfs_setattr __P((struct vop_setattr_args *));
* process-specific sub-directories. It is
* used in procfs_lookup and procfs_readdir
*/
-static struct pfsnames {
- u_short d_namlen;
- char d_name[PROCFS_NAMELEN];
- pfstype d_pfstype;
- int (*d_valid) __P((struct proc *));
-} procent[] = {
+struct proc_target {
+ u_char pt_type;
+ u_char pt_namlen;
+ char *pt_name;
+ pfstype pt_pfstype;
+ int (*pt_valid) __P((struct proc *p));
+} proc_targets[] = {
#define N(s) sizeof(s)-1, s
- /* namlen, nam, type validp */
- { N("."), Pproc, NULL },
- { N(".."), Proot, NULL },
- { N("file"), Pfile, procfs_validfile },
- { N("mem"), Pmem, NULL },
- { N("regs"), Pregs, procfs_validregs },
- { N("fpregs"), Pfpregs, procfs_validfpregs },
- { N("ctl"), Pctl, NULL },
- { N("status"), Pstatus, NULL },
- { N("note"), Pnote, NULL },
- { N("notepg"), Pnotepg, NULL },
- { N("map"), Pmap, procfs_validmap },
- { N("etype"), Ptype, procfs_validtype },
+ /* name type validp */
+ { DT_DIR, N("."), Pproc, NULL },
+ { DT_DIR, N(".."), Proot, NULL },
+ { DT_REG, N("file"), Pfile, procfs_validfile },
+ { DT_REG, N("mem"), Pmem, NULL },
+ { DT_REG, N("regs"), Pregs, procfs_validregs },
+ { DT_REG, N("fpregs"), Pfpregs, procfs_validfpregs },
+ { DT_REG, N("ctl"), Pctl, NULL },
+ { DT_REG, N("status"), Pstatus, NULL },
+ { DT_REG, N("note"), Pnote, NULL },
+ { DT_REG, N("notepg"), Pnotepg, NULL },
+ { DT_REG, N("map"), Pmap, procfs_validmap },
+ { DT_REG, N("etype"), Ptype, procfs_validtype },
#undef N
};
-#define Nprocent (sizeof(procent)/sizeof(procent[0]))
+static const int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]);
static pid_t atopid __P((const char *, u_int));
@@ -117,7 +119,12 @@ static pid_t atopid __P((const char *, u_int));
*/
static int
procfs_open(ap)
- struct vop_open_args *ap;
+ struct vop_open_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
{
struct pfsnode *pfs = VTOPFS(ap->a_vp);
@@ -126,11 +133,10 @@ procfs_open(ap)
if (PFIND(pfs->pfs_pid) == 0)
return (ENOENT); /* was ESRCH, jsp */
- if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
- ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)))
+ if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) ||
+ (pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))
return (EBUSY);
-
if (ap->a_mode & FWRITE)
pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
@@ -152,7 +158,12 @@ procfs_open(ap)
*/
static int
procfs_close(ap)
- struct vop_close_args *ap;
+ struct vop_close_args /* {
+ struct vnode *a_vp;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
{
struct pfsnode *pfs = VTOPFS(ap->a_vp);
@@ -174,14 +185,51 @@ procfs_close(ap)
*/
static int
procfs_ioctl(ap)
- struct vop_ioctl_args *ap;
+ struct vop_ioctl_args /* {
+ struct vnode *a_vp;
+ int a_command;
+ caddr_t a_data;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
{
return (ENOTTY);
}
/*
- * _inactive is called when the pfsnode
+ * do block mapping for pfsnode (vp).
+ * since we don't use the buffer cache
+ * for procfs this function should never
+ * be called. in any case, it's not clear
+ * what part of the kernel ever makes use
+ * of this function. for sanity, this is the
+ * usual no-op bmap, although returning
+ * (EIO) would be a reasonable alternative.
+ */
+int
+procfs_bmap(ap)
+ struct vop_bmap_args /* {
+ struct vnode *a_vp;
+ daddr_t a_bn;
+ struct vnode **a_vpp;
+ daddr_t *a_bnp;
+ int *a_runp;
+ } */ *ap;
+{
+
+ if (ap->a_vpp != NULL)
+ *ap->a_vpp = ap->a_vp;
+ if (ap->a_bnp != NULL)
+ *ap->a_bnp = ap->a_bn;
+ if (ap->a_runp != NULL)
+ *ap->a_runp = 0;
+ return (0);
+}
+
+/*
+ * procfs_inactive is called when the pfsnode
* is vrele'd and the reference count goes
* to zero. (vp) will be on the vnode free
* list, so to get it back vget() must be
@@ -194,16 +242,20 @@ procfs_ioctl(ap)
* chances are that the process will still be
* there and PFIND is not free.
*
- * (vp) is not locked on entry or exit.
+ * (vp) is locked on entry, but must be unlocked on exit.
*/
static int
procfs_inactive(ap)
- struct vop_inactive_args *ap;
+ struct vop_inactive_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
{
- struct pfsnode *pfs = VTOPFS(ap->a_vp);
+ struct vnode *vp = ap->a_vp;
+ struct pfsnode *pfs = VTOPFS(vp);
+ VOP_UNLOCK(vp, 0, ap->a_p);
if (PFIND(pfs->pfs_pid) == 0)
- vgone(ap->a_vp);
+ vgone(vp);
return (0);
}
@@ -217,12 +269,12 @@ procfs_inactive(ap)
*/
static int
procfs_reclaim(ap)
- struct vop_reclaim_args *ap;
+ struct vop_reclaim_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
{
- int error;
- error = procfs_freevp(ap->a_vp);
- return (error);
+ return (procfs_freevp(ap->a_vp));
}
/*
@@ -269,13 +321,14 @@ procfs_pathconf(ap)
*/
static int
procfs_print(ap)
- struct vop_print_args *ap;
+ struct vop_print_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
{
struct pfsnode *pfs = VTOPFS(ap->a_vp);
- printf("tag VT_PROCFS, pid %lu, mode %x, flags %lx\n",
- pfs->pfs_pid,
- pfs->pfs_mode, pfs->pfs_flags);
+ printf("tag VT_PROCFS, type %s, pid %d, mode %x, flags %x\n",
+ pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags);
return (0);
}
@@ -287,7 +340,10 @@ procfs_print(ap)
*/
static int
procfs_abortop(ap)
- struct vop_abortop_args *ap;
+ struct vop_abortop_args /* {
+ struct vnode *a_dvp;
+ struct componentname *a_cnp;
+ } */ *ap;
{
if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
@@ -316,7 +372,12 @@ procfs_badop()
*/
static int
procfs_getattr(ap)
- struct vop_getattr_args *ap;
+ struct vop_getattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
{
struct pfsnode *pfs = VTOPFS(ap->a_vp);
struct vattr *vap = ap->a_vap;
@@ -329,6 +390,7 @@ procfs_getattr(ap)
*/
switch (pfs->pfs_type) {
case Proot:
+ case Pcurproc:
procp = 0;
break;
@@ -353,6 +415,21 @@ procfs_getattr(ap)
vap->va_bytes = vap->va_size = 0;
/*
+ * Make all times be current TOD.
+ * It would be possible to get the process start
+ * time from the p_stat structure, but there's
+ * no "file creation" time stamp anyway, and the
+ * p_stat structure is not addressible if u. gets
+ * swapped out for that process.
+ */
+ {
+ struct timeval tv;
+ microtime(&tv);
+ TIMEVAL_TO_TIMESPEC(&tv, &vap->va_ctime);
+ }
+ vap->va_atime = vap->va_mtime = vap->va_ctime;
+
+ /*
* If the process has exercised some setuid or setgid
* privilege, then rip away read/write permission so
* that only root can gain access.
@@ -376,21 +453,6 @@ procfs_getattr(ap)
}
/*
- * Make all times be current TOD.
- * It would be possible to get the process start
- * time from the p_stat structure, but there's
- * no "file creation" time stamp anyway, and the
- * p_stat structure is not addressible if u. gets
- * swapped out for that process.
- */
- {
- struct timeval tv;
- microtime(&tv);
- TIMEVAL_TO_TIMESPEC(&tv, &vap->va_ctime);
- }
- vap->va_atime = vap->va_mtime = vap->va_ctime;
-
- /*
* now do the object specific fields
*
* The size could be set from struct reg, but it's hardly
@@ -402,17 +464,30 @@ procfs_getattr(ap)
switch (pfs->pfs_type) {
case Proot:
- vap->va_nlink = nprocs + 3;
+ /*
+ * Set nlink to 1 to tell fts(3) we don't actually know.
+ */
+ vap->va_nlink = 1;
+ vap->va_uid = 0;
+ vap->va_gid = 0;
+ vap->va_size = vap->va_bytes = DEV_BSIZE;
+ break;
+
+ case Pcurproc: {
+ char buf[16]; /* should be enough */
+ vap->va_nlink = 1;
vap->va_uid = 0;
vap->va_gid = 0;
- vap->va_bytes = vap->va_size = DEV_BSIZE;
+ vap->va_size = vap->va_bytes =
+ sprintf(buf, "%ld", (long)curproc->p_pid);
break;
+ }
case Pproc:
- vap->va_nlink = Nprocent;
+ vap->va_nlink = nproc_targets;
vap->va_uid = procp->p_ucred->cr_uid;
vap->va_gid = procp->p_ucred->cr_gid;
- vap->va_bytes = vap->va_size = DEV_BSIZE;
+ vap->va_size = vap->va_bytes = DEV_BSIZE;
break;
case Pfile:
@@ -436,7 +511,15 @@ procfs_getattr(ap)
case Ptype:
case Pmap:
case Pregs:
+ vap->va_bytes = vap->va_size = sizeof(struct reg);
+ vap->va_nlink = 1;
+ vap->va_uid = procp->p_ucred->cr_uid;
+ vap->va_gid = procp->p_ucred->cr_gid;
+ break;
+
case Pfpregs:
+ vap->va_bytes = vap->va_size = sizeof(struct fpreg);
+
case Pctl:
case Pstatus:
case Pnote:
@@ -455,7 +538,12 @@ procfs_getattr(ap)
static int
procfs_setattr(ap)
- struct vop_setattr_args *ap;
+ struct vop_setattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
{
/*
* just fake out attribute setting
@@ -484,7 +572,12 @@ procfs_setattr(ap)
*/
static int
procfs_access(ap)
- struct vop_access_args *ap;
+ struct vop_access_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
{
struct vattr *vap;
struct vattr vattr;
@@ -494,8 +587,9 @@ procfs_access(ap)
* If you're the super-user,
* you always get access.
*/
- if (ap->a_cred->cr_uid == (uid_t) 0)
+ if (ap->a_cred->cr_uid == 0)
return (0);
+
vap = &vattr;
error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p);
if (error)
@@ -510,7 +604,7 @@ procfs_access(ap)
gid_t *gp;
int i;
- (ap->a_mode) >>= 3;
+ ap->a_mode >>= 3;
gp = ap->a_cred->cr_groups;
for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++)
if (vap->va_gid == *gp)
@@ -537,18 +631,23 @@ found:
*/
static int
procfs_lookup(ap)
- struct vop_lookup_args *ap;
+ struct vop_lookup_args /* {
+ struct vnode * a_dvp;
+ struct vnode ** a_vpp;
+ struct componentname * a_cnp;
+ } */ *ap;
{
struct componentname *cnp = ap->a_cnp;
struct vnode **vpp = ap->a_vpp;
struct vnode *dvp = ap->a_dvp;
char *pname = cnp->cn_nameptr;
+ struct proc *curp = cnp->cn_proc;
int error = 0;
+ struct proc_target *pt;
+ struct vnode *fvp;
pid_t pid;
- struct vnode *nvp;
struct pfsnode *pfs;
- struct proc *procp;
- pfstype pfs_type;
+ struct proc *p;
int i;
*vpp = NULL;
@@ -559,7 +658,7 @@ procfs_lookup(ap)
if (cnp->cn_namelen == 1 && *pname == '.') {
*vpp = dvp;
VREF(dvp);
- /*VOP_LOCK(dvp);*/
+ /* vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, curp); */
return (0);
}
@@ -570,72 +669,52 @@ procfs_lookup(ap)
return (EIO);
if (CNEQ(cnp, "curproc", 7))
- pid = cnp->cn_proc->p_pid;
- else
- pid = atopid(pname, cnp->cn_namelen);
- if (pid == NO_PID)
- return (ENOENT);
+ return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc));
- procp = PFIND(pid);
- if (procp == 0)
- return (ENOENT);
-
- error = procfs_allocvp(dvp->v_mount, &nvp, pid, Pproc);
- if (error)
- return (error);
+ pid = atopid(pname, cnp->cn_namelen);
+ if (pid == NO_PID)
+ break;
- nvp->v_type = VDIR;
- pfs = VTOPFS(nvp);
+ p = PFIND(pid);
+ if (p == 0)
+ break;
- *vpp = nvp;
- return (0);
+ return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc));
case Pproc:
- if (cnp->cn_flags & ISDOTDOT) {
- error = procfs_root(dvp->v_mount, vpp);
- return (error);
- }
-
- procp = PFIND(pfs->pfs_pid);
- if (procp == 0)
- return (ENOENT);
+ if (cnp->cn_flags & ISDOTDOT)
+ return (procfs_root(dvp->v_mount, vpp));
- for (i = 0; i < Nprocent; i++) {
- struct pfsnames *dp = &procent[i];
+ p = PFIND(pfs->pfs_pid);
+ if (p == 0)
+ break;
- if (cnp->cn_namelen == dp->d_namlen &&
- bcmp(pname, dp->d_name, dp->d_namlen) == 0 &&
- (dp->d_valid == NULL || (*dp->d_valid)(procp))) {
- pfs_type = dp->d_pfstype;
+ for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
+ if (cnp->cn_namelen == pt->pt_namlen &&
+ bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
+ (pt->pt_valid == NULL || (*pt->pt_valid)(p)))
goto found;
- }
}
- return (ENOENT);
+ break;
found:
- if (pfs_type == Pfile) {
- nvp = procfs_findtextvp(procp);
- if (nvp) {
- VREF(nvp);
- VOP_LOCK(nvp);
- } else {
- error = ENXIO;
- }
- } else {
- error = procfs_allocvp(dvp->v_mount, &nvp,
- pfs->pfs_pid, pfs_type);
- if (error)
- return (error);
-
- nvp->v_type = VREG;
- pfs = VTOPFS(nvp);
+ if (pt->pt_pfstype == Pfile) {
+ fvp = procfs_findtextvp(p);
+ /* We already checked that it exists. */
+ VREF(fvp);
+ vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curp);
+ *vpp = fvp;
+ return (0);
}
- *vpp = nvp;
- return (error);
+
+ return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
+ pt->pt_pfstype));
default:
return (ENOTDIR);
}
+
+ return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
}
/*
@@ -645,6 +724,7 @@ int
procfs_validfile(p)
struct proc *p;
{
+
return (procfs_findtextvp(p) != NULLVP);
}
@@ -662,7 +742,14 @@ procfs_validfile(p)
*/
static int
procfs_readdir(ap)
- struct vop_readdir_args *ap;
+ struct vop_readdir_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ int *a_eofflag;
+ u_long *a_cookies;
+ int a_ncookies;
+ } */ *ap;
{
struct uio *uio = ap->a_uio;
struct pfsdent d;
@@ -672,6 +759,13 @@ procfs_readdir(ap)
int count;
int i;
+ /*
+ * We don't allow exporting procfs mounts, and currently local
+ * requests do not need cookies.
+ */
+ if (ap->a_ncookies)
+ panic("procfs_readdir: not hungry");
+
pfs = VTOPFS(ap->a_vp);
if (uio->uio_resid < UIO_MX)
@@ -693,39 +787,28 @@ procfs_readdir(ap)
*/
case Pproc: {
struct proc *p;
+ struct proc_target *pt;
p = PFIND(pfs->pfs_pid);
if (p == NULL)
break;
- while (uio->uio_resid >= UIO_MX) {
- struct pfsnames *dt;
-
- if (i >= Nprocent)
- break;
-
- dt = &procent[i];
-
- /* see if we should show this one. */
- if (dt->d_valid && (*dt->d_valid)(p) == 0) {
- i++;
+ for (pt = &proc_targets[i];
+ uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) {
+ if (pt->pt_valid && (*pt->pt_valid)(p) == 0)
continue;
- }
dp->d_reclen = UIO_MX;
- dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, dt->d_pfstype);
- dp->d_type = DT_REG;
- dp->d_namlen = dt->d_namlen;
- bcopy(dt->d_name, dp->d_name, sizeof(dt->d_name)-1);
- error = uiomove((caddr_t) dp, UIO_MX, uio);
- if (error)
+ dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype);
+ dp->d_namlen = pt->pt_namlen;
+ bcopy(pt->pt_name, dp->d_name, pt->pt_namlen + 1);
+ dp->d_type = pt->pt_type;
+
+ if (error = uiomove((caddr_t)dp, UIO_MX, uio))
break;
- count += UIO_MX;
- i++;
}
break;
-
}
/*
@@ -738,63 +821,61 @@ procfs_readdir(ap)
*/
case Proot: {
- int pcnt;
#ifdef PROCFS_ZOMBIE
int doingzomb = 0;
#endif
+ int pcnt = 0;
volatile struct proc *p = allproc.lh_first;
-#define PROCFS_XFILES 3 /* number of other entries, like "curproc" */
- pcnt = PROCFS_XFILES;
-
- while (p && uio->uio_resid >= UIO_MX) {
+ again:
+ for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) {
bzero((char *) dp, UIO_MX);
- dp->d_type = DT_DIR;
dp->d_reclen = UIO_MX;
switch (i) {
- case 0:
+ case 0: /* `.' */
+ case 1: /* `..' */
dp->d_fileno = PROCFS_FILENO(0, Proot);
- dp->d_namlen = sprintf(dp->d_name, ".");
- break;
-
- case 1:
- dp->d_fileno = PROCFS_FILENO(0, Proot);
- dp->d_namlen = sprintf(dp->d_name, "..");
+ dp->d_namlen = i + 1;
+ bcopy("..", dp->d_name, dp->d_namlen);
+ dp->d_name[i + 1] = '\0';
+ dp->d_type = DT_DIR;
break;
case 2:
- /* ship out entry for "curproc" */
- dp->d_fileno = PROCFS_FILENO(PID_MAX+1, Pproc);
- dp->d_namlen = sprintf(dp->d_name, "curproc");
+ dp->d_fileno = PROCFS_FILENO(0, Pcurproc);
+ dp->d_namlen = 7;
+ bcopy("curproc", dp->d_name, 8);
+ dp->d_type = DT_LNK;
break;
default:
- if (pcnt >= i) {
- dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc);
- dp->d_namlen = sprintf(dp->d_name, "%ld", (long) p->p_pid);
+ while (pcnt < i) {
+ pcnt++;
+ p = p->p_list.le_next;
+ if (!p)
+ goto done;
}
-
+ dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc);
+ dp->d_namlen = sprintf(dp->d_name, "%ld",
+ (long)p->p_pid);
+ dp->d_type = DT_REG;
p = p->p_list.le_next;
-
-#ifdef PROCFS_ZOMBIE
- if (p == 0 && doingzomb == 0) {
- doingzomb = 1;
- p = zombproc.lh_first;
- }
-#endif
-
- if (pcnt++ < i)
- continue;
-
break;
}
- error = uiomove((caddr_t) dp, UIO_MX, uio);
- if (error)
+
+ if (error = uiomove((caddr_t)dp, UIO_MX, uio))
break;
- count += UIO_MX;
- i++;
}
+ done:
+
+#ifdef PROCFS_ZOMBIE
+ if (p == 0 && doingzomb == 0) {
+ doingzomb = 1;
+ p = zombproc.lh_first;
+ goto again;
+ }
+#endif
break;
@@ -811,6 +892,25 @@ procfs_readdir(ap)
}
/*
+ * readlink reads the link of `curproc'
+ */
+int
+procfs_readlink(ap)
+ struct vop_readlink_args *ap;
+{
+ struct uio *uio = ap->a_uio;
+ char buf[16]; /* should be enough */
+ int len;
+
+ if (VTOPFS(ap->a_vp)->pfs_fileno != PROCFS_FILENO(0, Pcurproc))
+ return (EINVAL);
+
+ len = sprintf(buf, "%ld", (long)curproc->p_pid);
+
+ return (uiomove((caddr_t)buf, len, ap->a_uio));
+}
+
+/*
* convert decimal ascii to pid_t
*/
static pid_t
@@ -838,6 +938,7 @@ atopid(b, len)
#define procfs_write procfs_rw
#define procfs_select ((int (*) __P((struct vop_select_args *))) procfs_badop)
#define procfs_mmap ((int (*) __P((struct vop_mmap_args *))) procfs_badop)
+#define procfs_revoke vop_revoke
#define procfs_fsync ((int (*) __P((struct vop_fsync_args *))) procfs_badop)
#define procfs_seek ((int (*) __P((struct vop_seek_args *))) procfs_badop)
#define procfs_remove ((int (*) __P((struct vop_remove_args *))) procfs_badop)
@@ -849,7 +950,6 @@ atopid(b, len)
#define procfs_readlink ((int (*) __P((struct vop_readlink_args *))) procfs_badop)
#define procfs_lock ((int (*) __P((struct vop_lock_args *))) nullop)
#define procfs_unlock ((int (*) __P((struct vop_unlock_args *))) nullop)
-#define procfs_bmap ((int (*) __P((struct vop_bmap_args *))) procfs_badop)
#define procfs_strategy ((int (*) __P((struct vop_strategy_args *))) procfs_badop)
#define procfs_islocked ((int (*) __P((struct vop_islocked_args *))) nullop)
#define procfs_advlock ((int (*) __P((struct vop_advlock_args *))) procfs_badop)
@@ -859,6 +959,9 @@ atopid(b, len)
#define procfs_truncate ((int (*) __P((struct vop_truncate_args *))) procfs_badop)
#define procfs_update ((int (*) __P((struct vop_update_args *))) nullop)
+/*
+ * procfs vnode operations.
+ */
vop_t **procfs_vnodeop_p;
static struct vnodeopv_entry_desc procfs_vnodeop_entries[] = {
{ &vop_default_desc, (vop_t *)vn_default_error },
@@ -875,6 +978,7 @@ static struct vnodeopv_entry_desc procfs_vnodeop_entries[] = {
{ &vop_ioctl_desc, (vop_t *)procfs_ioctl }, /* ioctl */
{ &vop_select_desc, (vop_t *)procfs_select }, /* select */
{ &vop_mmap_desc, (vop_t *)procfs_mmap }, /* mmap */
+ { &vop_revoke_desc, (vop_t *)procfs_revoke }, /* revoke */
{ &vop_fsync_desc, (vop_t *)procfs_fsync }, /* fsync */
{ &vop_seek_desc, (vop_t *)procfs_seek }, /* seek */
{ &vop_remove_desc, (vop_t *)procfs_remove }, /* remove */
diff --git a/sys/miscfs/specfs/spec_vnops.c b/sys/miscfs/specfs/spec_vnops.c
index 049f41e..2e8cc04 100644
--- a/sys/miscfs/specfs/spec_vnops.c
+++ b/sys/miscfs/specfs/spec_vnops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1989, 1993
+ * Copyright (c) 1989, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)spec_vnops.c 8.6 (Berkeley) 4/9/94
+ * @(#)spec_vnops.c 8.14 (Berkeley) 5/21/95
* $FreeBSD$
*/
@@ -79,8 +79,10 @@ static struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
{ &vop_setattr_desc, (vop_t *)spec_setattr }, /* setattr */
{ &vop_read_desc, (vop_t *)spec_read }, /* read */
{ &vop_write_desc, (vop_t *)spec_write }, /* write */
+ { &vop_lease_desc, (vop_t *)spec_lease_check }, /* lease */
{ &vop_ioctl_desc, (vop_t *)spec_ioctl }, /* ioctl */
{ &vop_select_desc, (vop_t *)spec_select }, /* select */
+ { &vop_revoke_desc, (vop_t *)spec_revoke }, /* revoke */
{ &vop_mmap_desc, (vop_t *)spec_mmap }, /* mmap */
{ &vop_fsync_desc, (vop_t *)spec_fsync }, /* fsync */
{ &vop_seek_desc, (vop_t *)spec_seek }, /* seek */
@@ -148,9 +150,10 @@ spec_open(ap)
struct proc *a_p;
} */ *ap;
{
+ struct proc *p = ap->a_p;
struct vnode *bvp, *vp = ap->a_vp;
dev_t bdev, dev = (dev_t)vp->v_rdev;
- register int maj = major(dev);
+ int maj = major(dev);
int error;
/*
@@ -171,7 +174,9 @@ spec_open(ap)
* When running in very secure mode, do not allow
* opens for writing of any disk character devices.
*/
- if (securelevel >= 2 && isdisk(dev, VCHR))
+ if (securelevel >= 2
+ && cdevsw[maj]->d_bdev
+ && cdevsw[maj]->d_bdev->d_flags == D_DISK)
return (EPERM);
/*
* When running in secure mode, do not allow opens
@@ -189,9 +194,20 @@ spec_open(ap)
return (EPERM);
}
}
- VOP_UNLOCK(vp);
- error = (*cdevsw[maj]->d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p);
- VOP_LOCK(vp);
+#if 0
+ /*
+ * Lite2 stuff. We will almost certainly do this
+ * differently with devfs. The only use of this flag
+ * is in dead_read to make ttys return EOF instead of
+ * EIO when they are dead. Pre-lite2 FreeBSD returns
+ * EOF for all character devices.
+ */
+ if (cdevsw[maj]->d_type == D_TTY)
+ vp->v_flag |= VISTTY;
+#endif
+ VOP_UNLOCK(vp, 0, p);
+ error = (*cdevsw[maj]->d_open)(dev, ap->a_mode, S_IFCHR, p);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
return (error);
case VBLK:
@@ -204,7 +220,7 @@ spec_open(ap)
* opens for writing of any disk block devices.
*/
if (securelevel >= 2 && ap->a_cred != FSCRED &&
- (ap->a_mode & FWRITE) && isdisk(dev, VBLK))
+ (ap->a_mode & FWRITE) && bdevsw[maj]->d_flags == D_DISK)
return (EPERM);
/*
* Do not allow opens of block devices that are
@@ -213,9 +229,7 @@ spec_open(ap)
error = vfs_mountedon(vp);
if (error)
return (error);
- return ((*bdevsw[maj]->d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p));
- default:
- break;
+ return ((*bdevsw[maj]->d_open)(dev, ap->a_mode, S_IFBLK, p));
}
return (0);
}
@@ -257,10 +271,10 @@ spec_read(ap)
switch (vp->v_type) {
case VCHR:
- VOP_UNLOCK(vp);
+ VOP_UNLOCK(vp, 0, p);
error = (*cdevsw[major(vp->v_rdev)]->d_read)
(vp->v_rdev, uio, ap->a_ioflag);
- VOP_LOCK(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
return (error);
case VBLK:
@@ -335,10 +349,10 @@ spec_write(ap)
switch (vp->v_type) {
case VCHR:
- VOP_UNLOCK(vp);
+ VOP_UNLOCK(vp, 0, p);
error = (*cdevsw[major(vp->v_rdev)]->d_write)
(vp->v_rdev, uio, ap->a_ioflag);
- VOP_LOCK(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
return (error);
case VBLK:
@@ -408,7 +422,7 @@ spec_ioctl(ap)
case VBLK:
if (ap->a_command == 0 && (int)ap->a_data == B_TAPE)
- if (bdevsw[major(dev)]->d_flags & B_TAPE)
+ if (bdevsw[major(dev)]->d_flags == D_TAPE)
return (0);
else
return (1);
@@ -498,6 +512,18 @@ loop:
return (0);
}
+int
+spec_inactive(ap)
+ struct vop_inactive_args /* {
+ struct vnode *a_vp;
+ struct proc *a_p;
+ } */ *ap;
+{
+
+ VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
+ return (0);
+}
+
/*
* Just call the device strategy routine
*/
@@ -539,31 +565,6 @@ spec_bmap(ap)
}
/*
- * At the moment we do not do any locking.
- */
-/* ARGSUSED */
-int
-spec_lock(ap)
- struct vop_lock_args /* {
- struct vnode *a_vp;
- } */ *ap;
-{
-
- return (0);
-}
-
-/* ARGSUSED */
-int
-spec_unlock(ap)
- struct vop_unlock_args /* {
- struct vnode *a_vp;
- } */ *ap;
-{
-
- return (0);
-}
-
-/*
* Device close routine
*/
/* ARGSUSED */
@@ -577,6 +578,7 @@ spec_close(ap)
} */ *ap;
{
register struct vnode *vp = ap->a_vp;
+ struct proc *p = ap->a_p;
dev_t dev = vp->v_rdev;
d_close_t *devclose;
int mode, error;
@@ -631,8 +633,11 @@ spec_close(ap)
(vp->v_flag & VXLOCK) == 0)
return (0);
- if (vp->v_object)
- vnode_pager_uncache(vp);
+ if (vp->v_object) {
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ vnode_pager_uncache(vp, p);
+ VOP_UNLOCK(vp, 0, p);
+ }
devclose = bdevsw[major(dev)]->d_close;
mode = S_IFBLK;
diff --git a/sys/miscfs/specfs/specdev.h b/sys/miscfs/specfs/specdev.h
index 8960040..091d628 100644
--- a/sys/miscfs/specfs/specdev.h
+++ b/sys/miscfs/specfs/specdev.h
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)specdev.h 8.2 (Berkeley) 2/2/94
+ * @(#)specdev.h 8.6 (Berkeley) 5/21/95
* $FreeBSD$
*/
@@ -91,8 +91,10 @@ int spec_close __P((struct vop_close_args *));
#define spec_setattr ((int (*) __P((struct vop_setattr_args *)))spec_ebadf)
int spec_read __P((struct vop_read_args *));
int spec_write __P((struct vop_write_args *));
+#define spec_lease_check ((int (*) __P((struct vop_lease_args *)))nullop)
int spec_ioctl __P((struct vop_ioctl_args *));
int spec_select __P((struct vop_select_args *));
+#define spec_revoke vop_revoke
#define spec_mmap ((int (*) __P((struct vop_mmap_args *)))spec_badop)
int spec_fsync __P((struct vop_fsync_args *));
#define spec_seek ((int (*) __P((struct vop_seek_args *)))spec_badop)
@@ -105,14 +107,14 @@ int spec_fsync __P((struct vop_fsync_args *));
#define spec_readdir ((int (*) __P((struct vop_readdir_args *)))spec_badop)
#define spec_readlink ((int (*) __P((struct vop_readlink_args *)))spec_badop)
#define spec_abortop ((int (*) __P((struct vop_abortop_args *)))spec_badop)
-#define spec_inactive ((int (*) __P((struct vop_inactive_args *)))nullop)
+int spec_inactive __P((struct vop_inactive_args *));
#define spec_reclaim ((int (*) __P((struct vop_reclaim_args *)))nullop)
-int spec_lock __P((struct vop_lock_args *));
-int spec_unlock __P((struct vop_unlock_args *));
+#define spec_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock)
+#define spec_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock)
int spec_bmap __P((struct vop_bmap_args *));
int spec_strategy __P((struct vop_strategy_args *));
int spec_print __P((struct vop_print_args *));
-#define spec_islocked ((int (*) __P((struct vop_islocked_args *)))nullop)
+#define spec_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked)
int spec_pathconf __P((struct vop_pathconf_args *));
int spec_advlock __P((struct vop_advlock_args *));
int spec_getpages __P((struct vop_getpages_args *));
diff --git a/sys/miscfs/umapfs/umap.h b/sys/miscfs/umapfs/umap.h
index db1efd4..54ae097 100644
--- a/sys/miscfs/umapfs/umap.h
+++ b/sys/miscfs/umapfs/umap.h
@@ -33,7 +33,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)umap.h 8.3 (Berkeley) 1/21/94
+ * @(#)umap.h 8.4 (Berkeley) 8/20/94
*
* $FreeBSD$
*/
@@ -67,8 +67,7 @@ struct umap_mount {
* A cache of vnode references
*/
struct umap_node {
- struct umap_node *umap_forw; /* Hash chain */
- struct umap_node *umap_back;
+ LIST_ENTRY(umap_node) umap_hash; /* Hash list */
struct vnode *umap_lowervp; /* Aliased vnode - VREFed once */
struct vnode *umap_vnode; /* Back pointer to vnode/umap_node */
};
diff --git a/sys/miscfs/umapfs/umap_subr.c b/sys/miscfs/umapfs/umap_subr.c
index 8333943..3b3629d 100644
--- a/sys/miscfs/umapfs/umap_subr.c
+++ b/sys/miscfs/umapfs/umap_subr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software donated to Berkeley by
@@ -33,13 +33,14 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)umap_subr.c 8.6 (Berkeley) 1/26/94
+ * @(#)umap_subr.c 8.9 (Berkeley) 5/14/95
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/proc.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/vnode.h>
@@ -48,11 +49,8 @@
#include <sys/malloc.h>
#include <miscfs/umapfs/umap.h>
-extern int umapfs_init __P((void));
-
#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
#define NUMAPNODECACHE 16
-#define UMAP_NHASH(vp) ((((u_long) vp)>>LOG2_SIZEVNODE) & (NUMAPNODECACHE-1))
/*
* Null layer cache:
@@ -62,52 +60,33 @@ extern int umapfs_init __P((void));
* alias is removed the target vnode is vrele'd.
*/
-/*
- * Cache head
- */
-struct umap_node_cache {
- struct umap_node *ac_forw;
- struct umap_node *ac_back;
-};
-
-static struct umap_node_cache umap_node_cache[NUMAPNODECACHE];
+#define UMAP_NHASH(vp) \
+ (&umap_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & umap_node_hash])
+LIST_HEAD(umap_node_hashhead, umap_node) *umap_node_hashtbl;
+u_long umap_node_hash;
static u_long umap_findid __P((u_long id, u_long map[][2], int nentries));
static int umap_node_alloc __P((struct mount *mp, struct vnode *lowervp,
struct vnode **vpp));
static struct vnode *
umap_node_find __P((struct mount *mp, struct vnode *targetvp));
-static struct umap_node_cache *
- umap_node_hash __P((struct vnode *targetvp));
/*
* Initialise cache headers
*/
int
-umapfs_init()
+umapfs_init(vfsp)
+ struct vfsconf *vfsp;
{
- struct umap_node_cache *ac;
+
#ifdef UMAPFS_DIAGNOSTIC
printf("umapfs_init\n"); /* printed during system boot */
#endif
-
- for (ac = umap_node_cache; ac < umap_node_cache + NUMAPNODECACHE; ac++)
- ac->ac_forw = ac->ac_back = (struct umap_node *) ac;
+ umap_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, &umap_node_hash);
return (0);
}
/*
- * Compute hash list for given target vnode
- */
-static struct umap_node_cache *
-umap_node_hash(targetvp)
- struct vnode *targetvp;
-{
-
- return (&umap_node_cache[UMAP_NHASH(targetvp)]);
-}
-
-/*
* umap_findid is called by various routines in umap_vnodeops.c to
* find a user or group id in a map.
*/
@@ -163,7 +142,8 @@ umap_node_find(mp, targetvp)
struct mount *mp;
struct vnode *targetvp;
{
- struct umap_node_cache *hd;
+ struct proc *p = curproc; /* XXX */
+ struct umap_node_hashhead *hd;
struct umap_node *a;
struct vnode *vp;
@@ -177,10 +157,9 @@ umap_node_find(mp, targetvp)
* the target vnode. If found, the increment the umap_node
* reference count (but NOT the target vnode's VREF counter).
*/
- hd = umap_node_hash(targetvp);
-
- loop:
- for (a = hd->ac_forw; a != (struct umap_node *) hd; a = a->umap_forw) {
+ hd = UMAP_NHASH(targetvp);
+loop:
+ for (a = hd->lh_first; a != 0; a = a->umap_hash.le_next) {
if (a->umap_lowervp == targetvp &&
a->umap_vnode->v_mount == mp) {
vp = UMAPTOV(a);
@@ -189,7 +168,7 @@ umap_node_find(mp, targetvp)
* stuff, but we don't want to lock
* the lower node.
*/
- if (vget(vp, 0)) {
+ if (vget(vp, 0, p)) {
#ifdef UMAPFS_DIAGNOSTIC
printf ("umap_node_find: vget failed.\n");
#endif
@@ -217,7 +196,7 @@ umap_node_alloc(mp, lowervp, vpp)
struct vnode *lowervp;
struct vnode **vpp;
{
- struct umap_node_cache *hd;
+ struct umap_node_hashhead *hd;
struct umap_node *xp;
struct vnode *othervp, *vp;
int error;
@@ -257,8 +236,8 @@ umap_node_alloc(mp, lowervp, vpp)
return (0);
}
VREF(lowervp); /* Extra VREF will be vrele'd in umap_node_create */
- hd = umap_node_hash(lowervp);
- insque(xp, hd);
+ hd = UMAP_NHASH(lowervp);
+ LIST_INSERT_HEAD(hd, xp, umap_hash);
return (0);
}
diff --git a/sys/miscfs/umapfs/umap_vfsops.c b/sys/miscfs/umapfs/umap_vfsops.c
index 517c291..897e2ce 100644
--- a/sys/miscfs/umapfs/umap_vfsops.c
+++ b/sys/miscfs/umapfs/umap_vfsops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1992, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software donated to Berkeley by
@@ -33,7 +33,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)umap_vfsops.c 8.3 (Berkeley) 1/21/94
+ * @(#)umap_vfsops.c 8.8 (Berkeley) 5/14/95
*
* $FreeBSD$
*/
@@ -46,6 +46,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
+#include <sys/proc.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/vnode.h>
@@ -54,7 +55,7 @@
#include <sys/malloc.h>
#include <miscfs/umapfs/umap.h>
-extern int umapfs_init __P((void));
+extern int umapfs_init __P((struct vfsconf *));
static int umapfs_fhtovp __P((struct mount *mp, struct fid *fidp,
struct mbuf *nam, struct vnode **vpp,
@@ -187,7 +188,7 @@ umapfs_mount(mp, path, data, ndp, p)
/*
* Unlock the node (either the lower or the alias)
*/
- VOP_UNLOCK(vp);
+ VOP_UNLOCK(vp, 0, p);
/*
* Make sure the node alias worked
*/
@@ -207,7 +208,7 @@ umapfs_mount(mp, path, data, ndp, p)
if (UMAPVPTOLOWERVP(umapm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_data = (qaddr_t) amp;
- getnewfsid(mp, MOUNT_LOFS);
+ vfs_getnewfsid(mp);
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
@@ -253,12 +254,8 @@ umapfs_unmount(mp, mntflags, p)
printf("umapfs_unmount(mp = %x)\n", mp);
#endif
- if (mntflags & MNT_FORCE) {
- /* lofs can never be rootfs so don't check for it */
- if (!doforce)
- return (EINVAL);
+ if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- }
/*
* Clear out buffer cache. I don't think we
@@ -300,6 +297,7 @@ umapfs_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
+ struct proc *p = curproc; /* XXX */
struct vnode *vp;
#ifdef UMAPFS_DIAGNOSTIC
@@ -314,7 +312,7 @@ umapfs_root(mp, vpp)
*/
vp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp;
VREF(vp);
- VOP_LOCK(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
*vpp = vp;
return (0);
}
@@ -429,4 +427,3 @@ static struct vfsops umap_vfsops = {
};
VFS_SET(umap_vfsops, umap, MOUNT_UMAP, VFCF_LOOPBACK);
-
diff --git a/sys/miscfs/umapfs/umap_vnops.c b/sys/miscfs/umapfs/umap_vnops.c
index 7c14cda..17064f4 100644
--- a/sys/miscfs/umapfs/umap_vnops.c
+++ b/sys/miscfs/umapfs/umap_vnops.c
@@ -33,7 +33,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)umap_vnops.c 8.3 (Berkeley) 1/5/94
+ * @(#)umap_vnops.c 8.6 (Berkeley) 5/22/95
* $FreeBSD$
*/
@@ -336,10 +336,52 @@ umap_getattr(ap)
return (0);
}
+/*
+ * We need to process our own vnode lock and then clear the
+ * interlock flag as it applies only to our vnode, not the
+ * vnodes below us on the stack.
+ */
+int
+umap_lock(ap)
+ struct vop_lock_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ struct proc *a_p;
+ } */ *ap;
+{
+
+ vop_nolock(ap);
+ if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN)
+ return (0);
+ ap->a_flags &= ~LK_INTERLOCK;
+ return (null_bypass(ap));
+}
+
+/*
+ * We need to process our own vnode unlock and then clear the
+ * interlock flag as it applies only to our vnode, not the
+ * vnodes below us on the stack.
+ */
+int
+umap_unlock(ap)
+ struct vop_unlock_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+
+ vop_nounlock(ap);
+ ap->a_flags &= ~LK_INTERLOCK;
+ return (null_bypass(ap));
+}
+
static int
umap_inactive(ap)
struct vop_inactive_args /* {
struct vnode *a_vp;
+ struct proc *a_p;
} */ *ap;
{
/*
@@ -349,6 +391,7 @@ umap_inactive(ap)
* cache and reusable.
*
*/
+ VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
return (0);
}
@@ -364,7 +407,7 @@ umap_reclaim(ap)
/* After this assignment, this node will not be re-used. */
xp->umap_lowervp = NULL;
- remque(xp);
+ LIST_REMOVE(xp, umap_hash);
FREE(vp->v_data, M_TEMP);
vp->v_data = NULL;
vrele(lowervp);
@@ -487,6 +530,8 @@ static struct vnodeopv_entry_desc umap_vnodeop_entries[] = {
{ &vop_default_desc, (vop_t *)umap_bypass },
{ &vop_getattr_desc, (vop_t *)umap_getattr },
+ { &vop_lock_desc, (vop_t *)umap_lock },
+ { &vop_unlock_desc, (vop_t *)umap_unlock },
{ &vop_inactive_desc, (vop_t *)umap_inactive },
{ &vop_reclaim_desc, (vop_t *)umap_reclaim },
{ &vop_print_desc, (vop_t *)umap_print },
diff --git a/sys/miscfs/union/union.h b/sys/miscfs/union/union.h
index 9c740d3..c956921 100644
--- a/sys/miscfs/union/union.h
+++ b/sys/miscfs/union/union.h
@@ -34,7 +34,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)union.h 8.2 (Berkeley) 2/17/94
+ * @(#)union.h 8.9 (Berkeley) 12/10/94
* $FreeBSD$
*/
@@ -75,10 +75,14 @@ struct union_node {
struct vnode *un_uppervp; /* overlaying object */
struct vnode *un_lowervp; /* underlying object */
struct vnode *un_dirvp; /* Parent dir of uppervp */
+ struct vnode *un_pvp; /* Parent vnode */
char *un_path; /* saved component name */
int un_hash; /* saved un_path hash value */
int un_openl; /* # of opens on lowervp */
- int un_flags;
+ unsigned int un_flags;
+ struct vnode **un_dircache; /* cached union stack */
+ off_t un_uppersz; /* size of upper object */
+ off_t un_lowersz; /* size of lower object */
#ifdef DIAGNOSTIC
pid_t un_pid;
#endif
@@ -88,16 +92,23 @@ struct union_node {
#define UN_LOCKED 0x02
#define UN_ULOCK 0x04 /* Upper node is locked */
#define UN_KLOCK 0x08 /* Keep upper node locked on vput */
+#define UN_CACHED 0x10 /* In union cache */
extern int union_allocvp __P((struct vnode **, struct mount *,
struct vnode *, struct vnode *,
struct componentname *, struct vnode *,
- struct vnode *));
+ struct vnode *, int));
extern int union_freevp __P((struct vnode *));
-extern int union_copyfile __P((struct proc *, struct ucred *,
- struct vnode *, struct vnode *));
+extern int union_copyfile __P((struct vnode *, struct vnode *,
+ struct ucred *, struct proc *));
+extern int union_copyup __P((struct union_node *, int, struct ucred *,
+ struct proc *));
+extern int union_dowhiteout __P((struct union_node *, struct ucred *,
+ struct proc *));
extern int union_mkshadow __P((struct union_mount *, struct vnode *,
struct componentname *, struct vnode **));
+extern int union_mkwhiteout __P((struct union_mount *, struct vnode *,
+ struct componentname *, char *));
extern int union_vn_create __P((struct vnode **, struct union_node *,
struct proc *));
extern int union_vn_close __P((struct vnode *, int, struct ucred *,
@@ -108,6 +119,7 @@ extern void union_removed_upper __P((struct union_node *un));
extern struct vnode *union_lowervp __P((struct vnode *));
extern void union_newlower __P((struct union_node *, struct vnode *));
extern void union_newupper __P((struct union_node *, struct vnode *));
+extern void union_newsize __P((struct vnode *, off_t, off_t));
#define MOUNTTOUNIONMOUNT(mp) ((struct union_mount *)((mp)->mnt_data))
#define VTOUNION(vp) ((struct union_node *)(vp)->v_data)
diff --git a/sys/miscfs/union/union_subr.c b/sys/miscfs/union/union_subr.c
index 6549f7d..63e25e6 100644
--- a/sys/miscfs/union/union_subr.c
+++ b/sys/miscfs/union/union_subr.c
@@ -34,7 +34,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)union_subr.c 8.4 (Berkeley) 2/17/94
+ * @(#)union_subr.c 8.20 (Berkeley) 5/20/95
* $FreeBSD$
*/
@@ -48,6 +48,9 @@
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/queue.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <vm/vm.h> /* for vnode_pager_setsize */
#include <miscfs/union/union.h>
#include <sys/proc.h>
@@ -118,31 +121,38 @@ union_updatevp(un, uppervp, lowervp)
{
int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp);
int nhash = UNION_HASH(uppervp, lowervp);
+ int docache = (lowervp != NULLVP || uppervp != NULLVP);
+ int lhash, hhash, uhash;
- if (ohash != nhash) {
- /*
- * Ensure locking is ordered from lower to higher
- * to avoid deadlocks.
- */
- if (nhash < ohash) {
- int t = ohash;
- ohash = nhash;
- nhash = t;
- }
+ /*
+ * Ensure locking is ordered from lower to higher
+ * to avoid deadlocks.
+ */
+ if (nhash < ohash) {
+ lhash = nhash;
+ uhash = ohash;
+ } else {
+ lhash = ohash;
+ uhash = nhash;
+ }
- while (union_list_lock(ohash))
+ if (lhash != uhash)
+ while (union_list_lock(lhash))
continue;
- while (union_list_lock(nhash))
- continue;
+ while (union_list_lock(uhash))
+ continue;
- LIST_REMOVE(un, un_cache);
- union_list_unlock(ohash);
- } else {
- while (union_list_lock(nhash))
- continue;
+ if (ohash != nhash || !docache) {
+ if (un->un_flags & UN_CACHED) {
+ un->un_flags &= ~UN_CACHED;
+ LIST_REMOVE(un, un_cache);
+ }
}
+ if (ohash != nhash)
+ union_list_unlock(ohash);
+
if (un->un_lowervp != lowervp) {
if (un->un_lowervp) {
vrele(un->un_lowervp);
@@ -156,6 +166,7 @@ union_updatevp(un, uppervp, lowervp)
}
}
un->un_lowervp = lowervp;
+ un->un_lowersz = VNOVAL;
}
if (un->un_uppervp != uppervp) {
@@ -163,10 +174,13 @@ union_updatevp(un, uppervp, lowervp)
vrele(un->un_uppervp);
un->un_uppervp = uppervp;
+ un->un_uppersz = VNOVAL;
}
- if (ohash != nhash)
+ if (docache && (ohash != nhash)) {
LIST_INSERT_HEAD(&unhead[nhash], un, un_cache);
+ un->un_flags |= UN_CACHED;
+ }
union_list_unlock(nhash);
}
@@ -190,6 +204,47 @@ union_newupper(un, uppervp)
}
/*
+ * Keep track of size changes in the underlying vnodes.
+ * If the size changes, then callback to the vm layer
+ * giving priority to the upper layer size.
+ */
+void
+union_newsize(vp, uppersz, lowersz)
+ struct vnode *vp;
+ off_t uppersz, lowersz;
+{
+ struct union_node *un;
+ off_t sz;
+
+ /* only interested in regular files */
+ if (vp->v_type != VREG)
+ return;
+
+ un = VTOUNION(vp);
+ sz = VNOVAL;
+
+ if ((uppersz != VNOVAL) && (un->un_uppersz != uppersz)) {
+ un->un_uppersz = uppersz;
+ if (sz == VNOVAL)
+ sz = un->un_uppersz;
+ }
+
+ if ((lowersz != VNOVAL) && (un->un_lowersz != lowersz)) {
+ un->un_lowersz = lowersz;
+ if (sz == VNOVAL)
+ sz = un->un_lowersz;
+ }
+
+ if (sz != VNOVAL) {
+#ifdef UNION_DIAGNOSTIC
+ printf("union: %s size now %ld\n",
+ uppersz != VNOVAL ? "upper" : "lower", (long) sz);
+#endif
+ vnode_pager_setsize(vp, sz);
+ }
+}
+
+/*
* allocate a union_node/vnode pair. the vnode is
* referenced and locked. the new vnode is returned
* via (vpp). (mp) is the mountpoint of the union filesystem,
@@ -221,19 +276,22 @@ union_newupper(un, uppervp)
* the vnode free list.
*/
int
-union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp)
+union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp, docache)
struct vnode **vpp;
struct mount *mp;
- struct vnode *undvp;
+ struct vnode *undvp; /* parent union vnode */
struct vnode *dvp; /* may be null */
struct componentname *cnp; /* may be null */
struct vnode *uppervp; /* may be null */
struct vnode *lowervp; /* may be null */
+ int docache;
{
int error;
struct union_node *un = 0;
struct vnode *xlowervp = NULLVP;
- int hash = 0;
+ struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
+ int hash;
+ int vflag;
int try;
if (uppervp == NULLVP && lowervp == NULLVP)
@@ -244,8 +302,22 @@ union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp)
lowervp = NULLVP;
}
+ /* detect the root vnode (and aliases) */
+ vflag = 0;
+ if ((uppervp == um->um_uppervp) &&
+ ((lowervp == NULLVP) || lowervp == um->um_lowervp)) {
+ if (lowervp == NULLVP) {
+ lowervp = um->um_lowervp;
+ if (lowervp != NULLVP)
+ VREF(lowervp);
+ }
+ vflag = VROOT;
+ }
+
loop:
- for (try = 0; try < 3; try++) {
+ if (!docache) {
+ un = 0;
+ } else for (try = 0; try < 3; try++) {
switch (try) {
case 0:
if (lowervp == NULLVP)
@@ -276,7 +348,8 @@ loop:
(un->un_uppervp == uppervp ||
un->un_uppervp == NULLVP) &&
(UNIONTOV(un)->v_mount == mp)) {
- if (vget(UNIONTOV(un), 0)) {
+ if (vget(UNIONTOV(un), 0,
+ cnp ? cnp->cn_proc : NULL)) {
union_list_unlock(hash);
goto loop;
}
@@ -359,8 +432,7 @@ loop:
*/
if (lowervp != un->un_lowervp) {
union_newlower(un, lowervp);
- if (cnp && (lowervp != NULLVP) &&
- (lowervp->v_type == VREG)) {
+ if (cnp && (lowervp != NULLVP)) {
un->un_hash = cnp->cn_hash;
un->un_path = malloc(cnp->cn_namelen+1,
M_TEMP, M_WAITOK);
@@ -377,14 +449,16 @@ loop:
return (0);
}
- /*
- * otherwise lock the vp list while we call getnewvnode
- * since that can block.
- */
- hash = UNION_HASH(uppervp, lowervp);
+ if (docache) {
+ /*
+ * otherwise lock the vp list while we call getnewvnode
+ * since that can block.
+ */
+ hash = UNION_HASH(uppervp, lowervp);
- if (union_list_lock(hash))
- goto loop;
+ if (union_list_lock(hash))
+ goto loop;
+ }
error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp);
if (error) {
@@ -403,6 +477,7 @@ loop:
MALLOC((*vpp)->v_data, void *, sizeof(struct union_node),
M_TEMP, M_WAITOK);
+ (*vpp)->v_flag |= vflag;
if (uppervp)
(*vpp)->v_type = uppervp->v_type;
else
@@ -410,7 +485,13 @@ loop:
un = VTOUNION(*vpp);
un->un_vnode = *vpp;
un->un_uppervp = uppervp;
+ un->un_uppersz = VNOVAL;
un->un_lowervp = lowervp;
+ un->un_lowersz = VNOVAL;
+ un->un_pvp = undvp;
+ if (undvp != NULLVP)
+ VREF(undvp);
+ un->un_dircache = 0;
un->un_openl = 0;
un->un_flags = UN_LOCKED;
if (un->un_uppervp)
@@ -421,7 +502,7 @@ loop:
else
un->un_pid = -1;
#endif
- if (cnp && (lowervp != NULLVP) && (lowervp->v_type == VREG)) {
+ if (cnp && (lowervp != NULLVP)) {
un->un_hash = cnp->cn_hash;
un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK);
bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen);
@@ -434,13 +515,17 @@ loop:
un->un_dirvp = 0;
}
- LIST_INSERT_HEAD(&unhead[hash], un, un_cache);
+ if (docache) {
+ LIST_INSERT_HEAD(&unhead[hash], un, un_cache);
+ un->un_flags |= UN_CACHED;
+ }
if (xlowervp)
vrele(xlowervp);
out:
- union_list_unlock(hash);
+ if (docache)
+ union_list_unlock(hash);
return (error);
}
@@ -451,13 +536,18 @@ union_freevp(vp)
{
struct union_node *un = VTOUNION(vp);
- LIST_REMOVE(un, un_cache);
+ if (un->un_flags & UN_CACHED) {
+ un->un_flags &= ~UN_CACHED;
+ LIST_REMOVE(un, un_cache);
+ }
- if (un->un_uppervp)
+ if (un->un_pvp != NULLVP)
+ vrele(un->un_pvp);
+ if (un->un_uppervp != NULLVP)
vrele(un->un_uppervp);
- if (un->un_lowervp)
+ if (un->un_lowervp != NULLVP)
vrele(un->un_lowervp);
- if (un->un_dirvp)
+ if (un->un_dirvp != NULLVP)
vrele(un->un_dirvp);
if (un->un_path)
free(un->un_path, M_TEMP);
@@ -474,11 +564,11 @@ union_freevp(vp)
* and (tvp) are locked on entry and exit.
*/
int
-union_copyfile(p, cred, fvp, tvp)
- struct proc *p;
- struct ucred *cred;
+union_copyfile(fvp, tvp, cred, p)
struct vnode *fvp;
struct vnode *tvp;
+ struct ucred *cred;
+ struct proc *p;
{
char *buf;
struct uio uio;
@@ -497,12 +587,12 @@ union_copyfile(p, cred, fvp, tvp)
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_offset = 0;
- VOP_UNLOCK(fvp); /* XXX */
- LEASE_CHECK(fvp, p, cred, LEASE_READ);
- VOP_LOCK(fvp); /* XXX */
- VOP_UNLOCK(tvp); /* XXX */
- LEASE_CHECK(tvp, p, cred, LEASE_WRITE);
- VOP_LOCK(tvp); /* XXX */
+ VOP_UNLOCK(fvp, 0, p); /* XXX */
+ VOP_LEASE(fvp, p, cred, LEASE_READ);
+ vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
+ VOP_UNLOCK(tvp, 0, p); /* XXX */
+ VOP_LEASE(tvp, p, cred, LEASE_WRITE);
+ vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);
@@ -542,6 +632,123 @@ union_copyfile(p, cred, fvp, tvp)
}
/*
+ * (un) is assumed to be locked on entry and remains
+ * locked on exit.
+ */
+int
+union_copyup(un, docopy, cred, p)
+ struct union_node *un;
+ int docopy;
+ struct ucred *cred;
+ struct proc *p;
+{
+ int error;
+ struct vnode *lvp, *uvp;
+
+ error = union_vn_create(&uvp, un, p);
+ if (error)
+ return (error);
+
+ /* at this point, uppervp is locked */
+ union_newupper(un, uvp);
+ un->un_flags |= UN_ULOCK;
+
+ lvp = un->un_lowervp;
+
+ if (docopy) {
+ /*
+ * XX - should not ignore errors
+ * from VOP_CLOSE
+ */
+ vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, p);
+ error = VOP_OPEN(lvp, FREAD, cred, p);
+ if (error == 0) {
+ error = union_copyfile(lvp, uvp, cred, p);
+ VOP_UNLOCK(lvp, 0, p);
+ (void) VOP_CLOSE(lvp, FREAD, cred, p);
+ }
+#ifdef UNION_DIAGNOSTIC
+ if (error == 0)
+ uprintf("union: copied up %s\n", un->un_path);
+#endif
+
+ }
+ un->un_flags &= ~UN_ULOCK;
+ VOP_UNLOCK(uvp, 0, p);
+ union_vn_close(uvp, FWRITE, cred, p);
+ vn_lock(uvp, LK_EXCLUSIVE | LK_RETRY, p);
+ un->un_flags |= UN_ULOCK;
+
+ /*
+ * Subsequent IOs will go to the top layer, so
+ * call close on the lower vnode and open on the
+ * upper vnode to ensure that the filesystem keeps
+ * its references counts right. This doesn't do
+ * the right thing with (cred) and (FREAD) though.
+ * Ignoring error returns is not right, either.
+ */
+ if (error == 0) {
+ int i;
+
+ for (i = 0; i < un->un_openl; i++) {
+ (void) VOP_CLOSE(lvp, FREAD, cred, p);
+ (void) VOP_OPEN(uvp, FREAD, cred, p);
+ }
+ un->un_openl = 0;
+ }
+
+ return (error);
+
+}
+
+static int
+union_relookup(um, dvp, vpp, cnp, cn, path, pathlen)
+ struct union_mount *um;
+ struct vnode *dvp;
+ struct vnode **vpp;
+ struct componentname *cnp;
+ struct componentname *cn;
+ char *path;
+ int pathlen;
+{
+ int error;
+
+ /*
+ * A new componentname structure must be faked up because
+ * there is no way to know where the upper level cnp came
+ * from or what it is being used for. This must duplicate
+ * some of the work done by NDINIT, some of the work done
+ * by namei, some of the work done by lookup and some of
+ * the work done by VOP_LOOKUP when given a CREATE flag.
+ * Conclusion: Horrible.
+ *
+ * The pathname buffer will be FREEed by VOP_MKDIR.
+ */
+ cn->cn_namelen = pathlen;
+ cn->cn_pnbuf = malloc(cn->cn_namelen+1, M_NAMEI, M_WAITOK);
+ bcopy(path, cn->cn_pnbuf, cn->cn_namelen);
+ cn->cn_pnbuf[cn->cn_namelen] = '\0';
+
+ cn->cn_nameiop = CREATE;
+ cn->cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);
+ cn->cn_proc = cnp->cn_proc;
+ if (um->um_op == UNMNT_ABOVE)
+ cn->cn_cred = cnp->cn_cred;
+ else
+ cn->cn_cred = um->um_cred;
+ cn->cn_nameptr = cn->cn_pnbuf;
+ cn->cn_hash = cnp->cn_hash;
+ cn->cn_consume = cnp->cn_consume;
+
+ VREF(dvp);
+ error = relookup(dvp, vpp, cn);
+ if (!error)
+ vrele(dvp);
+
+ return (error);
+}
+
+/*
* Create a shadow directory in the upper layer.
* The new vnode is returned locked.
*
@@ -565,6 +772,19 @@ union_mkshadow(um, dvp, cnp, vpp)
struct proc *p = cnp->cn_proc;
struct componentname cn;
+ error = union_relookup(um, dvp, vpp, cnp, &cn,
+ cnp->cn_nameptr, cnp->cn_namelen);
+ if (error)
+ return (error);
+
+ if (*vpp) {
+ VOP_ABORTOP(dvp, &cn);
+ VOP_UNLOCK(dvp, 0, p);
+ vrele(*vpp);
+ *vpp = NULLVP;
+ return (EEXIST);
+ }
+
/*
* policy: when creating the shadow directory in the
* upper layer, create it owned by the user who did
@@ -573,55 +793,62 @@ union_mkshadow(um, dvp, cnp, vpp)
* mkdir syscall). (jsp, kb)
*/
- /*
- * A new componentname structure must be faked up because
- * there is no way to know where the upper level cnp came
- * from or what it is being used for. This must duplicate
- * some of the work done by NDINIT, some of the work done
- * by namei, some of the work done by lookup and some of
- * the work done by VOP_LOOKUP when given a CREATE flag.
- * Conclusion: Horrible.
- *
- * The pathname buffer will be FREEed by VOP_MKDIR.
- */
- cn.cn_pnbuf = malloc(cnp->cn_namelen+1, M_NAMEI, M_WAITOK);
- bcopy(cnp->cn_nameptr, cn.cn_pnbuf, cnp->cn_namelen);
- cn.cn_pnbuf[cnp->cn_namelen] = '\0';
+ VATTR_NULL(&va);
+ va.va_type = VDIR;
+ va.va_mode = um->um_cmode;
- cn.cn_nameiop = CREATE;
- cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);
- cn.cn_proc = cnp->cn_proc;
- if (um->um_op == UNMNT_ABOVE)
- cn.cn_cred = cnp->cn_cred;
- else
- cn.cn_cred = um->um_cred;
- cn.cn_nameptr = cn.cn_pnbuf;
- cn.cn_namelen = cnp->cn_namelen;
- cn.cn_hash = cnp->cn_hash;
- cn.cn_consume = cnp->cn_consume;
+ /* VOP_LEASE: dvp is locked */
+ VOP_LEASE(dvp, p, cn.cn_cred, LEASE_WRITE);
- VREF(dvp);
- error = relookup(dvp, vpp, &cn);
- if (error)
+ error = VOP_MKDIR(dvp, vpp, &cn, &va);
+ return (error);
+}
+
+/*
+ * Create a whiteout entry in the upper layer.
+ *
+ * (um) points to the union mount structure for access to the
+ * the mounting process's credentials.
+ * (dvp) is the directory in which to create the whiteout.
+ * it is locked on entry and exit.
+ * (cnp) is the componentname to be created.
+ */
+int
+union_mkwhiteout(um, dvp, cnp, path)
+ struct union_mount *um;
+ struct vnode *dvp;
+ struct componentname *cnp;
+ char *path;
+{
+ int error;
+ struct vattr va;
+ struct proc *p = cnp->cn_proc;
+ struct vnode *wvp;
+ struct componentname cn;
+
+ VOP_UNLOCK(dvp, 0, p);
+ error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path));
+ if (error) {
+ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
return (error);
- vrele(dvp);
+ }
- if (*vpp) {
+ if (wvp) {
VOP_ABORTOP(dvp, &cn);
- VOP_UNLOCK(dvp);
- vrele(*vpp);
- *vpp = NULLVP;
+ vrele(dvp);
+ vrele(wvp);
return (EEXIST);
}
- VATTR_NULL(&va);
- va.va_type = VDIR;
- va.va_mode = um->um_cmode;
+ /* VOP_LEASE: dvp is locked */
+ VOP_LEASE(dvp, p, p->p_ucred, LEASE_WRITE);
+
+ error = VOP_WHITEOUT(dvp, &cn, CREATE);
+ if (error)
+ VOP_ABORTOP(dvp, &cn);
- /* LEASE_CHECK: dvp is locked */
- LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE);
+ vrele(dvp);
- error = VOP_MKDIR(dvp, vpp, &cn, &va);
return (error);
}
@@ -699,9 +926,8 @@ union_vn_create(vpp, un, p)
VATTR_NULL(vap);
vap->va_type = VREG;
vap->va_mode = cmode;
- LEASE_CHECK(un->un_dirvp, p, cred, LEASE_WRITE);
- error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap);
- if (error)
+ VOP_LEASE(un->un_dirvp, p, cred, LEASE_WRITE);
+ if (error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap))
return (error);
error = VOP_OPEN(vp, fmode, cred, p);
@@ -722,6 +948,7 @@ union_vn_close(vp, fmode, cred, p)
struct ucred *cred;
struct proc *p;
{
+
if (fmode & FWRITE)
--vp->v_writecount;
return (VOP_CLOSE(vp, fmode, cred, p));
@@ -731,24 +958,137 @@ void
union_removed_upper(un)
struct union_node *un;
{
+ struct proc *p = curproc; /* XXX */
+
+ union_newupper(un, NULLVP);
+ if (un->un_flags & UN_CACHED) {
+ un->un_flags &= ~UN_CACHED;
+ LIST_REMOVE(un, un_cache);
+ }
+
if (un->un_flags & UN_ULOCK) {
un->un_flags &= ~UN_ULOCK;
- VOP_UNLOCK(un->un_uppervp);
+ VOP_UNLOCK(un->un_uppervp, 0, p);
}
-
- union_newupper(un, NULLVP);
}
+#if 0
struct vnode *
union_lowervp(vp)
struct vnode *vp;
{
struct union_node *un = VTOUNION(vp);
- if (un->un_lowervp && (vp->v_type == un->un_lowervp->v_type)) {
- if (vget(un->un_lowervp, 0))
- return (NULLVP);
+ if ((un->un_lowervp != NULLVP) &&
+ (vp->v_type == un->un_lowervp->v_type)) {
+ if (vget(un->un_lowervp, 0) == 0)
+ return (un->un_lowervp);
}
- return (un->un_lowervp);
+ return (NULLVP);
+}
+#endif
+
+/*
+ * determine whether a whiteout is needed
+ * during a remove/rmdir operation.
+ */
+int
+union_dowhiteout(un, cred, p)
+ struct union_node *un;
+ struct ucred *cred;
+ struct proc *p;
+{
+ struct vattr va;
+
+ if (un->un_lowervp != NULLVP)
+ return (1);
+
+ if (VOP_GETATTR(un->un_uppervp, &va, cred, p) == 0 &&
+ (va.va_flags & OPAQUE))
+ return (1);
+
+ return (0);
+}
+
+static void
+union_dircache_r(vp, vppp, cntp)
+ struct vnode *vp;
+ struct vnode ***vppp;
+ int *cntp;
+{
+ struct union_node *un;
+
+ if (vp->v_op != union_vnodeop_p) {
+ if (vppp) {
+ VREF(vp);
+ *(*vppp)++ = vp;
+ if (--(*cntp) == 0)
+ panic("union: dircache table too small");
+ } else {
+ (*cntp)++;
+ }
+
+ return;
+ }
+
+ un = VTOUNION(vp);
+ if (un->un_uppervp != NULLVP)
+ union_dircache_r(un->un_uppervp, vppp, cntp);
+ if (un->un_lowervp != NULLVP)
+ union_dircache_r(un->un_lowervp, vppp, cntp);
+}
+
+struct vnode *
+union_dircache(vp, p)
+ struct vnode *vp;
+ struct proc *p;
+{
+ int cnt;
+ struct vnode *nvp;
+ struct vnode **vpp;
+ struct vnode **dircache;
+ struct union_node *un;
+ int error;
+
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ dircache = VTOUNION(vp)->un_dircache;
+
+ nvp = NULLVP;
+
+ if (dircache == 0) {
+ cnt = 0;
+ union_dircache_r(vp, 0, &cnt);
+ cnt++;
+ dircache = (struct vnode **)
+ malloc(cnt * sizeof(struct vnode *),
+ M_TEMP, M_WAITOK);
+ vpp = dircache;
+ union_dircache_r(vp, &vpp, &cnt);
+ *vpp = NULLVP;
+ vpp = dircache + 1;
+ } else {
+ vpp = dircache;
+ do {
+ if (*vpp++ == VTOUNION(vp)->un_uppervp)
+ break;
+ } while (*vpp != NULLVP);
+ }
+
+ if (*vpp == NULLVP)
+ goto out;
+
+ vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, p);
+ VREF(*vpp);
+ error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, 0, *vpp, NULLVP, 0);
+ if (error)
+ goto out;
+
+ VTOUNION(vp)->un_dircache = 0;
+ un = VTOUNION(nvp);
+ un->un_dircache = dircache;
+
+out:
+ VOP_UNLOCK(vp, 0, p);
+ return (nvp);
}
diff --git a/sys/miscfs/union/union_vfsops.c b/sys/miscfs/union/union_vfsops.c
index a1a6a0d..0295961 100644
--- a/sys/miscfs/union/union_vfsops.c
+++ b/sys/miscfs/union/union_vfsops.c
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1994 The Regents of the University of California.
- * Copyright (c) 1994 Jan-Simon Pendry.
+ * Copyright (c) 1994, 1995 The Regents of the University of California.
+ * Copyright (c) 1994, 1995 Jan-Simon Pendry.
* All rights reserved.
*
* This code is derived from software donated to Berkeley by
@@ -34,7 +34,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)union_vfsops.c 8.7 (Berkeley) 3/5/94
+ * @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95
* $FreeBSD$
*/
@@ -56,7 +56,7 @@
#include <sys/queue.h>
#include <miscfs/union/union.h>
-extern int union_init __P((void));
+extern int union_init __P((struct vfsconf *));
extern int union_fhtovp __P((struct mount *mp, struct fid *fidp,
struct mbuf *nam, struct vnode **vpp,
@@ -92,7 +92,7 @@ union_mount(mp, path, data, ndp, p)
struct union_args args;
struct vnode *lowerrootvp = NULLVP;
struct vnode *upperrootvp = NULLVP;
- struct union_mount *um;
+ struct union_mount *um = 0;
struct ucred *cred = 0;
struct ucred *scred;
struct vattr va;
@@ -118,34 +118,6 @@ union_mount(mp, path, data, ndp, p)
}
/*
- * Take a copy of the process's credentials. This isn't
- * quite right since the euid will always be zero and we
- * want to get the "real" users credentials. So fix up
- * the uid field after taking the copy.
- */
- cred = crdup(p->p_ucred);
- cred->cr_uid = p->p_cred->p_ruid;
-
- /*
- * Ensure the *real* user has write permission on the
- * mounted-on directory. This allows the mount_union
- * command to be made setuid root so allowing anyone
- * to do union mounts onto any directory on which they
- * have write permission and which they also own.
- */
- error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p);
- if (error)
- goto bad;
- if ((va.va_uid != cred->cr_uid) &&
- (cred->cr_uid != 0)) {
- error = EACCES;
- goto bad;
- }
- error = VOP_ACCESS(mp->mnt_vnodecovered, VWRITE, cred, p);
- if (error)
- goto bad;
-
- /*
* Get argument
*/
error = copyin(data, (caddr_t)&args, sizeof(struct union_args));
@@ -156,18 +128,10 @@ union_mount(mp, path, data, ndp, p)
VREF(lowerrootvp);
/*
- * Find upper node. Use the real process credentials,
- * not the effective ones since this will have come
- * through a setuid process (mount_union). All this
- * messing around with permissions is entirely bogus
- * and should be removed by allowing any user straight
- * past the mount system call.
+ * Find upper node.
*/
- scred = p->p_ucred;
- p->p_ucred = cred;
NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT,
UIO_USERSPACE, args.target, p);
- p->p_ucred = scred;
error = namei(ndp);
if (error)
@@ -218,7 +182,18 @@ union_mount(mp, path, data, ndp, p)
goto bad;
}
- um->um_cred = cred;
+ /*
+ * Unless the mount is readonly, ensure that the top layer
+ * supports whiteout operations
+ */
+ if ((mp->mnt_flag & MNT_RDONLY) == 0) {
+ error = VOP_WHITEOUT(um->um_uppervp, (struct componentname *) 0, LOOKUP);
+ if (error)
+ goto bad;
+ }
+
+ um->um_cred = p->p_ucred;
+ crhold(um->um_cred);
um->um_cmode = UN_DIRMODE &~ p->p_fd->fd_cmask;
/*
@@ -246,24 +221,18 @@ union_mount(mp, path, data, ndp, p)
*/
mp->mnt_flag |= (um->um_uppervp->v_mount->mnt_flag & MNT_RDONLY);
- /*
- * This is a user mount. Privilege check for unmount
- * will be done in union_unmount.
- */
- mp->mnt_flag |= MNT_USER;
-
mp->mnt_data = (qaddr_t) um;
- getnewfsid(mp, MOUNT_UNION);
+ vfs_getnewfsid(mp);
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
switch (um->um_op) {
case UNMNT_ABOVE:
- cp = "<above>";
+ cp = "<above>:";
break;
case UNMNT_BELOW:
- cp = "<below>";
+ cp = "<below>:";
break;
case UNMNT_REPLACE:
cp = "";
@@ -287,6 +256,8 @@ union_mount(mp, path, data, ndp, p)
return (0);
bad:
+ if (um)
+ free(um, M_UFSMNT);
if (cred)
crfree(cred);
if (upperrootvp)
@@ -323,40 +294,55 @@ union_unmount(mp, mntflags, p)
struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
struct vnode *um_rootvp;
int error;
+ int freeing;
int flags = 0;
#ifdef UNION_DIAGNOSTIC
printf("union_unmount(mp = %x)\n", mp);
#endif
- /* only the mounter, or superuser can unmount */
- if ((p->p_cred->p_ruid != um->um_cred->cr_uid) &&
- (error = suser(p->p_ucred, &p->p_acflag)))
+ if (mntflags & MNT_FORCE)
+ flags |= FORCECLOSE;
+
+ if (error = union_root(mp, &um_rootvp))
return (error);
- if (mntflags & MNT_FORCE) {
- /* union can never be rootfs so don't check for it */
- if (!doforce)
- return (EINVAL);
- flags |= FORCECLOSE;
+ /*
+ * Keep flushing vnodes from the mount list.
+ * This is needed because of the un_pvp held
+ * reference to the parent vnode.
+ * If more vnodes have been freed on a given pass,
+ * the try again. The loop will iterate at most
+ * (d) times, where (d) is the maximum tree depth
+ * in the filesystem.
+ */
+ for (freeing = 0; vflush(mp, um_rootvp, flags) != 0;) {
+ struct vnode *vp;
+ int n;
+
+ /* count #vnodes held on mount list */
+ for (n = 0, vp = mp->mnt_vnodelist.lh_first;
+ vp != NULLVP;
+ vp = vp->v_mntvnodes.le_next)
+ n++;
+
+ /* if this is unchanged then stop */
+ if (n == freeing)
+ break;
+
+ /* otherwise try once more time */
+ freeing = n;
}
- error = union_root(mp, &um_rootvp);
- if (error)
- return (error);
+ /* At this point the root vnode should have a single reference */
if (um_rootvp->v_usecount > 1) {
vput(um_rootvp);
return (EBUSY);
}
- error = vflush(mp, um_rootvp, flags);
- if (error) {
- vput(um_rootvp);
- return (error);
- }
#ifdef UNION_DIAGNOSTIC
- vprint("alias root of lower", um_rootvp);
-#endif
+ vprint("union root", um_rootvp);
+#endif
/*
* Discard references to upper and lower target vnodes.
*/
@@ -385,16 +371,11 @@ union_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
+ struct proc *p = curproc; /* XXX */
struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
int error;
int loselock;
-#ifdef UNION_DIAGNOSTIC
- printf("union_root(mp = %x, lvp = %x, uvp = %x)\n", mp,
- um->um_lowervp,
- um->um_uppervp);
-#endif
-
/*
* Return locked reference to root.
*/
@@ -403,7 +384,7 @@ union_root(mp, vpp)
VOP_ISLOCKED(um->um_uppervp)) {
loselock = 1;
} else {
- VOP_LOCK(um->um_uppervp);
+ vn_lock(um->um_uppervp, LK_EXCLUSIVE | LK_RETRY, p);
loselock = 0;
}
if (um->um_lowervp)
@@ -413,16 +394,17 @@ union_root(mp, vpp)
(struct vnode *) 0,
(struct componentname *) 0,
um->um_uppervp,
- um->um_lowervp);
+ um->um_lowervp,
+ 1);
if (error) {
- if (!loselock)
- VOP_UNLOCK(um->um_uppervp);
- vrele(um->um_uppervp);
+ if (loselock)
+ vrele(um->um_uppervp);
+ else
+ vput(um->um_uppervp);
if (um->um_lowervp)
vrele(um->um_lowervp);
} else {
- (*vpp)->v_flag |= VROOT;
if (loselock)
VTOUNION(*vpp)->un_flags &= ~UN_ULOCK;
}
@@ -431,18 +413,6 @@ union_root(mp, vpp)
}
int
-union_quotactl(mp, cmd, uid, arg, p)
- struct mount *mp;
- int cmd;
- uid_t uid;
- caddr_t arg;
- struct proc *p;
-{
-
- return (EOPNOTSUPP);
-}
-
-int
union_statfs(mp, sbp, p)
struct mount *mp;
struct statfs *sbp;
@@ -485,7 +455,6 @@ union_statfs(mp, sbp, p)
if (error)
return (error);
- sbp->f_type = MOUNT_UNION;
sbp->f_flags = mstat.f_flags;
sbp->f_bsize = mstat.f_bsize;
sbp->f_iosize = mstat.f_iosize;
@@ -496,18 +465,23 @@ union_statfs(mp, sbp, p)
* kind of sense. none of this makes sense though.
*/
- if (mstat.f_bsize != lbsize) {
+ if (mstat.f_bsize != lbsize)
sbp->f_blocks = sbp->f_blocks * lbsize / mstat.f_bsize;
- sbp->f_bfree = sbp->f_bfree * lbsize / mstat.f_bsize;
- sbp->f_bavail = sbp->f_bavail * lbsize / mstat.f_bsize;
- }
+
+ /*
+ * The "total" fields count total resources in all layers,
+ * the "free" fields count only those resources which are
+ * free in the upper layer (since only the upper layer
+ * is writeable).
+ */
sbp->f_blocks += mstat.f_blocks;
- sbp->f_bfree += mstat.f_bfree;
- sbp->f_bavail += mstat.f_bavail;
+ sbp->f_bfree = mstat.f_bfree;
+ sbp->f_bavail = mstat.f_bavail;
sbp->f_files += mstat.f_files;
- sbp->f_ffree += mstat.f_ffree;
+ sbp->f_ffree = mstat.f_ffree;
if (sbp != &mp->mnt_stat) {
+ sbp->f_type = mp->mnt_vfc->vfc_typenum;
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
@@ -515,51 +489,21 @@ union_statfs(mp, sbp, p)
return (0);
}
-int
-union_sync(mp, waitfor, cred, p)
- struct mount *mp;
- int waitfor;
- struct ucred *cred;
- struct proc *p;
-{
-
- /*
- * XXX - Assumes no data cached at union layer.
- */
- return (0);
-}
-
-int
-union_vget(mp, ino, vpp)
- struct mount *mp;
- ino_t ino;
- struct vnode **vpp;
-{
-
- return (EOPNOTSUPP);
-}
-
-int
-union_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp)
- struct mount *mp;
- struct fid *fidp;
- struct mbuf *nam;
- struct vnode **vpp;
- int *exflagsp;
- struct ucred **credanonp;
-{
-
- return (EOPNOTSUPP);
-}
-
-int
-union_vptofh(vp, fhp)
- struct vnode *vp;
- struct fid *fhp;
-{
-
- return (EOPNOTSUPP);
-}
+/*
+ * XXX - Assumes no data cached at union layer.
+ */
+#define union_sync ((int (*) __P((struct mount *, int, struct ucred *, \
+ struct proc *)))nullop)
+
+#define union_fhtovp ((int (*) __P((struct mount *, struct fid *, \
+ struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp)
+#define union_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
+ struct proc *)))eopnotsupp)
+#define union_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
+ size_t, struct proc *)))eopnotsupp)
+#define union_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
+ eopnotsupp)
+#define union_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp)
struct vfsops union_vfsops = {
union_mount,
diff --git a/sys/miscfs/union/union_vnops.c b/sys/miscfs/union/union_vnops.c
index 5940243..4a66dc0 100644
--- a/sys/miscfs/union/union_vnops.c
+++ b/sys/miscfs/union/union_vnops.c
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 1992, 1993, 1994 The Regents of the University of California.
- * Copyright (c) 1992, 1993, 1994 Jan-Simon Pendry.
- * All rights reserved.
+ * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry.
+ * Copyright (c) 1992, 1993, 1994, 1995
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Jan-Simon Pendry.
@@ -34,7 +34,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)union_vnops.c 8.6 (Berkeley) 2/17/94
+ * @(#)union_vnops.c 8.32 (Berkeley) 6/23/95
* $FreeBSD$
*/
@@ -43,7 +43,7 @@
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/time.h>
-#include <sys/kernel.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <sys/vnode.h>
#include <sys/mount.h>
@@ -51,16 +51,12 @@
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/queue.h>
+#include <sys/lock.h>
#include <miscfs/union/union.h>
-/* FIXUP throws the lock on the uppervp vnode if the union_node is already
- * locked and the uppervp vnode is not. Before, this was thrown regardless
- * of the state of the union_node which resulted in locked vnodes which
- * were never unlocked (since the union would never be unlocked).
- */
-#define FIXUP(un) { \
- if (((un)->un_flags & (UN_LOCKED|UN_ULOCK)) == UN_LOCKED) { \
- union_fixup(un); \
+#define FIXUP(un, p) { \
+ if (((un)->un_flags & UN_ULOCK) == 0) { \
+ union_fixup(un, p); \
} \
}
@@ -70,7 +66,7 @@ extern int union_advlock __P((struct vop_advlock_args *ap));
extern int union_bmap __P((struct vop_bmap_args *ap));
extern int union_close __P((struct vop_close_args *ap));
extern int union_create __P((struct vop_create_args *ap));
-static void union_fixup __P((struct union_node *un));
+static void union_fixup __P((struct union_node *un, struct proc *p));
extern int union_fsync __P((struct vop_fsync_args *ap));
extern int union_getattr __P((struct vop_getattr_args *ap));
extern int union_inactive __P((struct vop_inactive_args *ap));
@@ -79,7 +75,7 @@ extern int union_islocked __P((struct vop_islocked_args *ap));
extern int union_link __P((struct vop_link_args *ap));
extern int union_lock __P((struct vop_lock_args *ap));
extern int union_lookup __P((struct vop_lookup_args *ap));
-static int union_lookup1 __P((struct vnode *udvp, struct vnode *dvp,
+static int union_lookup1 __P((struct vnode *udvp, struct vnode **dvpp,
struct vnode **vpp,
struct componentname *cnp));
extern int union_mkdir __P((struct vop_mkdir_args *ap));
@@ -100,29 +96,34 @@ extern int union_select __P((struct vop_select_args *ap));
extern int union_setattr __P((struct vop_setattr_args *ap));
extern int union_strategy __P((struct vop_strategy_args *ap));
extern int union_symlink __P((struct vop_symlink_args *ap));
-extern int union_unlock __P((struct vop_lock_args *ap));
+extern int union_unlock __P((struct vop_unlock_args *ap));
extern int union_write __P((struct vop_read_args *ap));
static void
-union_fixup(un)
+union_fixup(un, p)
struct union_node *un;
+ struct proc *p;
{
- VOP_LOCK(un->un_uppervp);
+ vn_lock(un->un_uppervp, LK_EXCLUSIVE | LK_RETRY, p);
un->un_flags |= UN_ULOCK;
}
static int
-union_lookup1(udvp, dvp, vpp, cnp)
+union_lookup1(udvp, dvpp, vpp, cnp)
struct vnode *udvp;
- struct vnode *dvp;
+ struct vnode **dvpp;
struct vnode **vpp;
struct componentname *cnp;
{
int error;
+ struct proc *p = cnp->cn_proc;
struct vnode *tdvp;
+ struct vnode *dvp;
struct mount *mp;
+ dvp = *dvpp;
+
/*
* If stepping up the directory tree, check for going
* back across the mount point, in which case do what
@@ -130,21 +131,18 @@ union_lookup1(udvp, dvp, vpp, cnp)
* hierarchy.
*/
if (cnp->cn_flags & ISDOTDOT) {
- for (;;) {
+ while ((dvp != udvp) && (dvp->v_flag & VROOT)) {
/*
* Don't do the NOCROSSMOUNT check
* at this level. By definition,
* union fs deals with namespaces, not
* filesystems.
*/
- if ((dvp->v_flag & VROOT) == 0)
- break;
-
tdvp = dvp;
- dvp = dvp->v_mount->mnt_vnodecovered;
+ *dvpp = dvp = dvp->v_mount->mnt_vnodecovered;
vput(tdvp);
VREF(dvp);
- VOP_LOCK(dvp);
+ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
}
}
@@ -158,7 +156,7 @@ union_lookup1(udvp, dvp, vpp, cnp)
* here to allow it to be unlocked again (phew) in union_lookup.
*/
if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN))
- VOP_LOCK(dvp);
+ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
dvp = tdvp;
@@ -170,13 +168,11 @@ union_lookup1(udvp, dvp, vpp, cnp)
while (dvp != udvp && (dvp->v_type == VDIR) &&
(mp = dvp->v_mountedhere)) {
- if (mp->mnt_flag & MNT_MLOCK) {
- mp->mnt_flag |= MNT_MWAIT;
- (void) tsleep((caddr_t) mp, PVFS, "unlkup", 0);
+ if (vfs_busy(mp, 0, 0, p))
continue;
- }
error = VFS_ROOT(mp, &tdvp);
+ vfs_unbusy(mp, p);
if (error) {
vput(dvp);
return (error);
@@ -206,9 +202,28 @@ union_lookup(ap)
struct vnode *dvp = ap->a_dvp;
struct union_node *dun = VTOUNION(dvp);
struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
int lockparent = cnp->cn_flags & LOCKPARENT;
struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
- struct ucred *saved_cred = 0;
+ struct ucred *saved_cred;
+ int iswhiteout;
+ struct vattr va;
+
+#ifdef notyet
+ if (cnp->cn_namelen == 3 &&
+ cnp->cn_nameptr[2] == '.' &&
+ cnp->cn_nameptr[1] == '.' &&
+ cnp->cn_nameptr[0] == '.') {
+ dvp = *ap->a_vpp = LOWERVP(ap->a_dvp);
+ if (dvp == NULLVP)
+ return (ENOENT);
+ VREF(dvp);
+ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
+ if (!lockparent || !(cnp->cn_flags & ISLASTCN))
+ VOP_UNLOCK(ap->a_dvp, 0, p);
+ return (0);
+ }
+#endif
cnp->cn_flags |= LOCKPARENT;
@@ -216,6 +231,7 @@ union_lookup(ap)
lowerdvp = dun->un_lowervp;
uppervp = NULLVP;
lowervp = NULLVP;
+ iswhiteout = 0;
/*
* do the lookup in the upper level.
@@ -223,9 +239,9 @@ union_lookup(ap)
* then assume that something special is going
* on and just return that vnode.
*/
- if (upperdvp) {
- FIXUP(dun);
- uerror = union_lookup1(um->um_uppervp, upperdvp,
+ if (upperdvp != NULLVP) {
+ FIXUP(dun, p);
+ uerror = union_lookup1(um->um_uppervp, &upperdvp,
&uppervp, cnp);
/*if (uppervp == upperdvp)
dun->un_flags |= UN_KLOCK;*/
@@ -236,6 +252,16 @@ union_lookup(ap)
cnp->cn_flags &= ~LOCKPARENT;
return (uerror);
}
+ if (uerror == ENOENT || uerror == EJUSTRETURN) {
+ if (cnp->cn_flags & ISWHITEOUT) {
+ iswhiteout = 1;
+ } else if (lowerdvp != NULLVP) {
+ lerror = VOP_GETATTR(upperdvp, &va,
+ cnp->cn_cred, cnp->cn_proc);
+ if (lerror == 0 && (va.va_flags & OPAQUE))
+ iswhiteout = 1;
+ }
+ }
} else {
uerror = ENOENT;
}
@@ -247,10 +273,10 @@ union_lookup(ap)
* back from the upper layer and return the lower vnode
* instead.
*/
- if (lowerdvp) {
+ if (lowerdvp != NULLVP && !iswhiteout) {
int nameiop;
- VOP_LOCK(lowerdvp);
+ vn_lock(lowerdvp, LK_EXCLUSIVE | LK_RETRY, p);
/*
* Only do a LOOKUP on the bottom node, since
@@ -262,17 +288,17 @@ union_lookup(ap)
saved_cred = cnp->cn_cred;
cnp->cn_cred = um->um_cred;
}
- lerror = union_lookup1(um->um_lowervp, lowerdvp,
+ lerror = union_lookup1(um->um_lowervp, &lowerdvp,
&lowervp, cnp);
if (um->um_op == UNMNT_BELOW)
cnp->cn_cred = saved_cred;
cnp->cn_nameiop = nameiop;
if (lowervp != lowerdvp)
- VOP_UNLOCK(lowerdvp);
+ VOP_UNLOCK(lowerdvp, 0, p);
if (cnp->cn_consume != 0) {
- if (uppervp) {
+ if (uppervp != NULLVP) {
if (uppervp == upperdvp)
vrele(uppervp);
else
@@ -286,6 +312,14 @@ union_lookup(ap)
}
} else {
lerror = ENOENT;
+ if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) {
+ lowervp = LOWERVP(dun->un_pvp);
+ if (lowervp != NULLVP) {
+ VREF(lowervp);
+ vn_lock(lowervp, LK_EXCLUSIVE | LK_RETRY, p);
+ lerror = 0;
+ }
+ }
}
if (!lockparent)
@@ -326,13 +360,13 @@ union_lookup(ap)
if (uerror != 0 /* && (lerror == 0) */ ) {
if (lowervp->v_type == VDIR) { /* case 2b. */
dun->un_flags &= ~UN_ULOCK;
- VOP_UNLOCK(upperdvp);
+ VOP_UNLOCK(upperdvp, 0, p);
uerror = union_mkshadow(um, upperdvp, cnp, &uppervp);
- VOP_LOCK(upperdvp);
+ vn_lock(upperdvp, LK_EXCLUSIVE | LK_RETRY, p);
dun->un_flags |= UN_ULOCK;
if (uerror) {
- if (lowervp) {
+ if (lowervp != NULLVP) {
vput(lowervp);
lowervp = NULLVP;
}
@@ -341,21 +375,21 @@ union_lookup(ap)
}
}
- if (lowervp)
- VOP_UNLOCK(lowervp);
+ if (lowervp != NULLVP)
+ VOP_UNLOCK(lowervp, 0, p);
error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
- uppervp, lowervp);
+ uppervp, lowervp, 1);
if (error) {
- if (uppervp)
+ if (uppervp != NULLVP)
vput(uppervp);
- if (lowervp)
+ if (lowervp != NULLVP)
vrele(lowervp);
} else {
if (*ap->a_vpp != dvp)
if (!lockparent || !(cnp->cn_flags & ISLASTCN))
- VOP_UNLOCK(dvp);
+ VOP_UNLOCK(dvp, 0, p);
}
return (error);
@@ -372,28 +406,26 @@ union_create(ap)
{
struct union_node *un = VTOUNION(ap->a_dvp);
struct vnode *dvp = un->un_uppervp;
+ struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
- if (dvp) {
+ if (dvp != NULLVP) {
int error;
struct vnode *vp;
+ struct mount *mp;
- FIXUP(un);
+ FIXUP(un, p);
VREF(dvp);
un->un_flags |= UN_KLOCK;
+ mp = ap->a_dvp->v_mount;
vput(ap->a_dvp);
- error = VOP_CREATE(dvp, &vp, ap->a_cnp, ap->a_vap);
+ error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap);
if (error)
return (error);
- error = union_allocvp(
- ap->a_vpp,
- ap->a_dvp->v_mount,
- ap->a_dvp,
- NULLVP,
- ap->a_cnp,
- vp,
- NULLVP);
+ error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, cnp, vp,
+ NULLVP, 1);
if (error)
vput(vp);
return (error);
@@ -404,6 +436,25 @@ union_create(ap)
}
int
+union_whiteout(ap)
+ struct vop_whiteout_args /* {
+ struct vnode *a_dvp;
+ struct componentname *a_cnp;
+ int a_flags;
+ } */ *ap;
+{
+ struct union_node *un = VTOUNION(ap->a_dvp);
+ struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
+
+ if (un->un_uppervp == NULLVP)
+ return (EOPNOTSUPP);
+
+ FIXUP(un, p);
+ return (VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags));
+}
+
+int
union_mknod(ap)
struct vop_mknod_args /* {
struct vnode *a_dvp;
@@ -414,29 +465,27 @@ union_mknod(ap)
{
struct union_node *un = VTOUNION(ap->a_dvp);
struct vnode *dvp = un->un_uppervp;
+ struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
- if (dvp) {
+ if (dvp != NULLVP) {
int error;
struct vnode *vp;
+ struct mount *mp;
- FIXUP(un);
+ FIXUP(un, p);
VREF(dvp);
un->un_flags |= UN_KLOCK;
+ mp = ap->a_dvp->v_mount;
vput(ap->a_dvp);
- error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap);
+ error = VOP_MKNOD(dvp, &vp, cnp, ap->a_vap);
if (error)
return (error);
- if (vp) {
- error = union_allocvp(
- ap->a_vpp,
- ap->a_dvp->v_mount,
- ap->a_dvp,
- NULLVP,
- ap->a_cnp,
- vp,
- NULLVP);
+ if (vp != NULLVP) {
+ error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP,
+ cnp, vp, NULLVP, 1);
if (error)
vput(vp);
}
@@ -476,77 +525,7 @@ union_open(ap)
*/
tvp = un->un_lowervp;
if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) {
- struct vnode *vp;
- int i;
-
- /*
- * Open the named file in the upper layer. Note that
- * the file may have come into existence *since* the
- * lookup was done, since the upper layer may really
- * be a loopback mount of some other filesystem...
- * so open the file with exclusive create and barf if
- * it already exists.
- * XXX - perhaps should re-lookup the node (once more
- * with feeling) and simply open that. Who knows.
- */
- error = union_vn_create(&vp, un, p);
- if (error)
- return (error);
-
- /* at this point, uppervp is locked */
- union_newupper(un, vp);
- un->un_flags |= UN_ULOCK;
-
- /*
- * Now, if the file is being opened with truncation,
- * then the (new) upper vnode is ready to fly,
- * otherwise the data from the lower vnode must be
- * copied to the upper layer first. This only works
- * for regular files (check is made above).
- */
- if ((mode & O_TRUNC) == 0) {
- /*
- * XXX - should not ignore errors
- * from VOP_CLOSE
- */
- VOP_LOCK(tvp);
- error = VOP_OPEN(tvp, FREAD, cred, p);
- if (error == 0) {
- error = union_copyfile(p, cred,
- tvp, un->un_uppervp);
- VOP_UNLOCK(tvp);
- (void) VOP_CLOSE(tvp, FREAD, cred, p);
- } else {
- VOP_UNLOCK(tvp);
- }
-
-#ifdef UNION_DIAGNOSTIC
- if (!error)
- uprintf("union: copied up %s\n",
- un->un_path);
-#endif
- }
-
- un->un_flags &= ~UN_ULOCK;
- VOP_UNLOCK(un->un_uppervp);
- union_vn_close(un->un_uppervp, FWRITE, cred, p);
- VOP_LOCK(un->un_uppervp);
- un->un_flags |= UN_ULOCK;
-
- /*
- * Subsequent IOs will go to the top layer, so
- * call close on the lower vnode and open on the
- * upper vnode to ensure that the filesystem keeps
- * its references counts right. This doesn't do
- * the right thing with (cred) and (FREAD) though.
- * Ignoring error returns is not righ, either.
- */
- for (i = 0; i < un->un_openl; i++) {
- (void) VOP_CLOSE(tvp, FREAD, cred, p);
- (void) VOP_OPEN(un->un_uppervp, FREAD, cred, p);
- }
- un->un_openl = 0;
-
+ error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p);
if (error == 0)
error = VOP_OPEN(un->un_uppervp, mode, cred, p);
return (error);
@@ -556,14 +535,14 @@ union_open(ap)
* Just open the lower vnode
*/
un->un_openl++;
- VOP_LOCK(tvp);
+ vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p);
error = VOP_OPEN(tvp, mode, cred, p);
- VOP_UNLOCK(tvp);
+ VOP_UNLOCK(tvp, 0, p);
return (error);
}
- FIXUP(un);
+ FIXUP(un, p);
error = VOP_OPEN(tvp, mode, cred, p);
@@ -582,9 +561,7 @@ union_close(ap)
struct union_node *un = VTOUNION(ap->a_vp);
struct vnode *vp;
- if (un->un_uppervp) {
- vp = un->un_uppervp;
- } else {
+ if ((vp = un->un_uppervp) == NULLVP) {
#ifdef UNION_DIAGNOSTIC
if (un->un_openl <= 0)
panic("union: un_openl cnt");
@@ -593,7 +570,8 @@ union_close(ap)
vp = un->un_lowervp;
}
- return (VOP_CLOSE(vp, ap->a_fflag, ap->a_cred, ap->a_p));
+ ap->a_vp = vp;
+ return (VCALL(vp, VOFFSET(vop_close), ap));
}
/*
@@ -615,27 +593,29 @@ union_access(ap)
} */ *ap;
{
struct union_node *un = VTOUNION(ap->a_vp);
+ struct proc *p = ap->a_p;
int error = EACCES;
struct vnode *vp;
- vp = un->un_uppervp;
- if (vp) {
- FIXUP(un);
- return (VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p));
+ if ((vp = un->un_uppervp) != NULLVP) {
+ FIXUP(un, p);
+ ap->a_vp = vp;
+ return (VCALL(vp, VOFFSET(vop_access), ap));
}
- vp = un->un_lowervp;
- if (vp) {
- VOP_LOCK(vp);
- error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p);
+ if ((vp = un->un_lowervp) != NULLVP) {
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ ap->a_vp = vp;
+ error = VCALL(vp, VOFFSET(vop_access), ap);
if (error == 0) {
struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount);
- if (um->um_op == UNMNT_BELOW)
- error = VOP_ACCESS(vp, ap->a_mode,
- um->um_cred, ap->a_p);
+ if (um->um_op == UNMNT_BELOW) {
+ ap->a_cred = um->um_cred;
+ error = VCALL(vp, VOFFSET(vop_access), ap);
+ }
}
- VOP_UNLOCK(vp);
+ VOP_UNLOCK(vp, 0, p);
if (error)
return (error);
}
@@ -644,7 +624,8 @@ union_access(ap)
}
/*
- * We handle getattr only to change the fsid.
+ * We handle getattr only to change the fsid and
+ * track object sizes
*/
int
union_getattr(ap)
@@ -658,6 +639,7 @@ union_getattr(ap)
int error;
struct union_node *un = VTOUNION(ap->a_vp);
struct vnode *vp = un->un_uppervp;
+ struct proc *p = ap->a_p;
struct vattr *vap;
struct vattr va;
@@ -675,10 +657,21 @@ union_getattr(ap)
vp = un->un_uppervp;
if (vp != NULLVP) {
- FIXUP(un);
+ /*
+ * It's not clear whether VOP_GETATTR is to be
+ * called with the vnode locked or not. stat() calls
+ * it with (vp) locked, and fstat calls it with
+ * (vp) unlocked.
+ * In the mean time, compensate here by checking
+ * the union_node's lock flag.
+ */
+ if (un->un_flags & UN_LOCKED)
+ FIXUP(un, p);
+
error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
if (error)
return (error);
+ union_newsize(ap->a_vp, vap->va_size, VNOVAL);
}
if (vp == NULLVP) {
@@ -691,17 +684,16 @@ union_getattr(ap)
}
if (vp != NULLVP) {
- VOP_LOCK(vp);
error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
- VOP_UNLOCK(vp);
if (error)
return (error);
+ union_newsize(ap->a_vp, VNOVAL, vap->va_size);
}
if ((vap != ap->a_vap) && (vap->va_type == VDIR))
ap->a_vap->va_nlink += vap->va_nlink;
- vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
+ ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
return (0);
}
@@ -715,6 +707,7 @@ union_setattr(ap)
} */ *ap;
{
struct union_node *un = VTOUNION(ap->a_vp);
+ struct proc *p = ap->a_p;
int error;
/*
@@ -724,21 +717,11 @@ union_setattr(ap)
*/
if ((un->un_uppervp == NULLVP) &&
/* assert(un->un_lowervp != NULLVP) */
- (un->un_lowervp->v_type == VREG) &&
- (ap->a_vap->va_size == 0)) {
- struct vnode *vp;
-
- error = union_vn_create(&vp, un, ap->a_p);
+ (un->un_lowervp->v_type == VREG)) {
+ error = union_copyup(un, (ap->a_vap->va_size != 0),
+ ap->a_cred, ap->a_p);
if (error)
return (error);
-
- /* at this point, uppervp is locked */
- union_newupper(un, vp);
-
- VOP_UNLOCK(vp);
- union_vn_close(un->un_uppervp, FWRITE, ap->a_cred, ap->a_p);
- VOP_LOCK(vp);
- un->un_flags |= UN_ULOCK;
}
/*
@@ -746,9 +729,11 @@ union_setattr(ap)
* otherwise return read-only filesystem error.
*/
if (un->un_uppervp != NULLVP) {
- FIXUP(un);
+ FIXUP(un, p);
error = VOP_SETATTR(un->un_uppervp, ap->a_vap,
ap->a_cred, ap->a_p);
+ if ((error == 0) && (ap->a_vap->va_size != VNOVAL))
+ union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL);
} else {
error = EROFS;
}
@@ -766,16 +751,36 @@ union_read(ap)
} */ *ap;
{
int error;
+ struct proc *p = ap->a_uio->uio_procp;
struct vnode *vp = OTHERVP(ap->a_vp);
int dolock = (vp == LOWERVP(ap->a_vp));
if (dolock)
- VOP_LOCK(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
else
- FIXUP(VTOUNION(ap->a_vp));
+ FIXUP(VTOUNION(ap->a_vp), p);
error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
if (dolock)
- VOP_UNLOCK(vp);
+ VOP_UNLOCK(vp, 0, p);
+
+ /*
+ * XXX
+ * perhaps the size of the underlying object has changed under
+ * our feet. take advantage of the offset information present
+ * in the uio structure.
+ */
+ if (error == 0) {
+ struct union_node *un = VTOUNION(ap->a_vp);
+ off_t cur = ap->a_uio->uio_offset;
+
+ if (vp == un->un_uppervp) {
+ if (cur > un->un_uppersz)
+ union_newsize(ap->a_vp, cur, VNOVAL);
+ } else {
+ if (cur > un->un_lowersz)
+ union_newsize(ap->a_vp, VNOVAL, cur);
+ }
+ }
return (error);
}
@@ -790,21 +795,47 @@ union_write(ap)
} */ *ap;
{
int error;
- struct vnode *vp = OTHERVP(ap->a_vp);
- int dolock = (vp == LOWERVP(ap->a_vp));
+ struct vnode *vp;
+ struct union_node *un = VTOUNION(ap->a_vp);
+ struct proc *p = ap->a_uio->uio_procp;
- if (dolock)
- VOP_LOCK(vp);
- else
- FIXUP(VTOUNION(ap->a_vp));
+ vp = UPPERVP(ap->a_vp);
+ if (vp == NULLVP)
+ panic("union: missing upper layer in write");
+
+ FIXUP(un, p);
error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
- if (dolock)
- VOP_UNLOCK(vp);
+
+ /*
+ * the size of the underlying object may be changed by the
+ * write.
+ */
+ if (error == 0) {
+ off_t cur = ap->a_uio->uio_offset;
+
+ if (cur > un->un_uppersz)
+ union_newsize(ap->a_vp, cur, VNOVAL);
+ }
return (error);
}
int
+union_lease(ap)
+ struct vop_lease_args /* {
+ struct vnode *a_vp;
+ struct proc *a_p;
+ struct ucred *a_cred;
+ int a_flag;
+ } */ *ap;
+{
+ register struct vnode *ovp = OTHERVP(ap->a_vp);
+
+ ap->a_vp = ovp;
+ return (VCALL(ovp, VOFFSET(vop_lease), ap));
+}
+
+int
union_ioctl(ap)
struct vop_ioctl_args /* {
struct vnode *a_vp;
@@ -815,9 +846,10 @@ union_ioctl(ap)
struct proc *a_p;
} */ *ap;
{
+ register struct vnode *ovp = OTHERVP(ap->a_vp);
- return (VOP_IOCTL(OTHERVP(ap->a_vp), ap->a_command, ap->a_data,
- ap->a_fflag, ap->a_cred, ap->a_p));
+ ap->a_vp = ovp;
+ return (VCALL(ovp, VOFFSET(vop_ioctl), ap));
}
int
@@ -830,9 +862,28 @@ union_select(ap)
struct proc *a_p;
} */ *ap;
{
+ register struct vnode *ovp = OTHERVP(ap->a_vp);
- return (VOP_SELECT(OTHERVP(ap->a_vp), ap->a_which, ap->a_fflags,
- ap->a_cred, ap->a_p));
+ ap->a_vp = ovp;
+ return (VCALL(ovp, VOFFSET(vop_select), ap));
+}
+
+int
+union_revoke(ap)
+ struct vop_revoke_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+
+ if (UPPERVP(vp))
+ VOP_REVOKE(UPPERVP(vp), ap->a_flags);
+ if (LOWERVP(vp))
+ VOP_REVOKE(LOWERVP(vp), ap->a_flags);
+ vgone(vp);
+ return (0);
}
int
@@ -844,9 +895,10 @@ union_mmap(ap)
struct proc *a_p;
} */ *ap;
{
+ register struct vnode *ovp = OTHERVP(ap->a_vp);
- return (VOP_MMAP(OTHERVP(ap->a_vp), ap->a_fflags,
- ap->a_cred, ap->a_p));
+ ap->a_vp = ovp;
+ return (VCALL(ovp, VOFFSET(vop_mmap), ap));
}
int
@@ -859,19 +911,19 @@ union_fsync(ap)
} */ *ap;
{
int error = 0;
+ struct proc *p = ap->a_p;
struct vnode *targetvp = OTHERVP(ap->a_vp);
- if (targetvp) {
+ if (targetvp != NULLVP) {
int dolock = (targetvp == LOWERVP(ap->a_vp));
if (dolock)
- VOP_LOCK(targetvp);
+ vn_lock(targetvp, LK_EXCLUSIVE | LK_RETRY, p);
else
- FIXUP(VTOUNION(ap->a_vp));
- error = VOP_FSYNC(targetvp, ap->a_cred,
- ap->a_waitfor, ap->a_p);
+ FIXUP(VTOUNION(ap->a_vp), p);
+ error = VOP_FSYNC(targetvp, ap->a_cred, ap->a_waitfor, p);
if (dolock)
- VOP_UNLOCK(targetvp);
+ VOP_UNLOCK(targetvp, 0, p);
}
return (error);
@@ -886,8 +938,10 @@ union_seek(ap)
struct ucred *a_cred;
} */ *ap;
{
+ register struct vnode *ovp = OTHERVP(ap->a_vp);
- return (VOP_SEEK(OTHERVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred));
+ ap->a_vp = ovp;
+ return (VCALL(ovp, VOFFSET(vop_seek), ap));
}
int
@@ -901,34 +955,37 @@ union_remove(ap)
int error;
struct union_node *dun = VTOUNION(ap->a_dvp);
struct union_node *un = VTOUNION(ap->a_vp);
+ struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
- if (dun->un_uppervp && un->un_uppervp) {
+ if (dun->un_uppervp == NULLVP)
+ panic("union remove: null upper vnode");
+
+ if (un->un_uppervp != NULLVP) {
struct vnode *dvp = dun->un_uppervp;
struct vnode *vp = un->un_uppervp;
- FIXUP(dun);
+ FIXUP(dun, p);
VREF(dvp);
dun->un_flags |= UN_KLOCK;
vput(ap->a_dvp);
- FIXUP(un);
+ FIXUP(un, p);
VREF(vp);
un->un_flags |= UN_KLOCK;
vput(ap->a_vp);
- error = VOP_REMOVE(dvp, vp, ap->a_cnp);
+ if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc))
+ cnp->cn_flags |= DOWHITEOUT;
+ error = VOP_REMOVE(dvp, vp, cnp);
if (!error)
union_removed_upper(un);
-
- /*
- * XXX: should create a whiteout here
- */
} else {
- /*
- * XXX: should create a whiteout here
- */
+ FIXUP(dun, p);
+ error = union_mkwhiteout(
+ MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
+ dun->un_uppervp, ap->a_cnp, un->un_path);
vput(ap->a_dvp);
vput(ap->a_vp);
- error = EROFS;
}
return (error);
@@ -942,34 +999,51 @@ union_link(ap)
struct componentname *a_cnp;
} */ *ap;
{
- int error;
- struct union_node *dun = VTOUNION(ap->a_vp);
- struct union_node *un = VTOUNION(ap->a_tdvp);
-
- if (dun->un_uppervp && un->un_uppervp) {
- struct vnode *dvp = dun->un_uppervp;
- struct vnode *vp = un->un_uppervp;
+ int error = 0;
+ struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
+ struct union_node *un;
+ struct vnode *vp;
+ struct vnode *tdvp;
- FIXUP(dun);
- VREF(dvp);
- dun->un_flags |= UN_KLOCK;
- vput(ap->a_vp);
- FIXUP(un);
- VREF(vp);
- vrele(ap->a_tdvp);
+ un = VTOUNION(ap->a_tdvp);
- error = VOP_LINK(dvp, vp, ap->a_cnp);
+ if (ap->a_tdvp->v_op != ap->a_vp->v_op) {
+ vp = ap->a_vp;
} else {
- /*
- * XXX: need to copy to upper layer
- * and do the link there.
- */
- vput(ap->a_vp);
- vrele(ap->a_tdvp);
+ struct union_node *tun = VTOUNION(ap->a_vp);
+ if (tun->un_uppervp == NULLVP) {
+ vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
+ if (un->un_uppervp == tun->un_dirvp) {
+ un->un_flags &= ~UN_ULOCK;
+ VOP_UNLOCK(un->un_uppervp, 0, p);
+ }
+ error = union_copyup(tun, 1, cnp->cn_cred, p);
+ if (un->un_uppervp == tun->un_dirvp) {
+ vn_lock(un->un_uppervp,
+ LK_EXCLUSIVE | LK_RETRY, p);
+ un->un_flags |= UN_ULOCK;
+ }
+ VOP_UNLOCK(ap->a_vp, 0, p);
+ }
+ vp = tun->un_uppervp;
+ }
+
+ tdvp = un->un_uppervp;
+ if (tdvp == NULLVP)
error = EROFS;
+
+ if (error) {
+ vput(ap->a_tdvp);
+ return (error);
}
- return (error);
+ FIXUP(un, p);
+ VREF(tdvp);
+ un->un_flags |= UN_KLOCK;
+ vput(ap->a_tdvp);
+
+ return (VOP_LINK(vp, tdvp, cnp));
}
int
@@ -993,11 +1067,16 @@ union_rename(ap)
if (fdvp->v_op == union_vnodeop_p) { /* always true */
struct union_node *un = VTOUNION(fdvp);
if (un->un_uppervp == NULLVP) {
- error = EROFS;
+ /*
+ * this should never happen in normal
+ * operation but might if there was
+ * a problem creating the top-level shadow
+ * directory.
+ */
+ error = EXDEV;
goto bad;
}
- FIXUP(un);
fdvp = un->un_uppervp;
VREF(fdvp);
vrele(ap->a_fdvp);
@@ -1006,11 +1085,14 @@ union_rename(ap)
if (fvp->v_op == union_vnodeop_p) { /* always true */
struct union_node *un = VTOUNION(fvp);
if (un->un_uppervp == NULLVP) {
- error = EROFS;
+ /* XXX: should do a copyup */
+ error = EXDEV;
goto bad;
}
- FIXUP(un);
+ if (un->un_lowervp != NULLVP)
+ ap->a_fcnp->cn_flags |= DOWHITEOUT;
+
fvp = un->un_uppervp;
VREF(fvp);
vrele(ap->a_fvp);
@@ -1019,7 +1101,13 @@ union_rename(ap)
if (tdvp->v_op == union_vnodeop_p) {
struct union_node *un = VTOUNION(tdvp);
if (un->un_uppervp == NULLVP) {
- error = EROFS;
+ /*
+ * this should never happen in normal
+ * operation but might if there was
+ * a problem creating the top-level shadow
+ * directory.
+ */
+ error = EXDEV;
goto bad;
}
@@ -1029,16 +1117,14 @@ union_rename(ap)
vput(ap->a_tdvp);
}
- if (tvp && tvp->v_op == union_vnodeop_p) {
+ if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) {
struct union_node *un = VTOUNION(tvp);
- if (un->un_uppervp == NULLVP) {
- error = EROFS;
- goto bad;
- }
tvp = un->un_uppervp;
- VREF(tvp);
- un->un_flags |= UN_KLOCK;
+ if (tvp != NULLVP) {
+ VREF(tvp);
+ un->un_flags |= UN_KLOCK;
+ }
vput(ap->a_tvp);
}
@@ -1048,7 +1134,7 @@ bad:
vrele(fdvp);
vrele(fvp);
vput(tdvp);
- if (tvp)
+ if (tvp != NULLVP)
vput(tvp);
return (error);
@@ -1065,27 +1151,26 @@ union_mkdir(ap)
{
struct union_node *un = VTOUNION(ap->a_dvp);
struct vnode *dvp = un->un_uppervp;
+ struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
- if (dvp) {
+ if (dvp != NULLVP) {
int error;
struct vnode *vp;
- FIXUP(un);
+ FIXUP(un, p);
VREF(dvp);
un->un_flags |= UN_KLOCK;
- vput(ap->a_dvp);
- error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap);
- if (error)
+ VOP_UNLOCK(ap->a_dvp, 0, p);
+ error = VOP_MKDIR(dvp, &vp, cnp, ap->a_vap);
+ if (error) {
+ vrele(ap->a_dvp);
return (error);
+ }
- error = union_allocvp(
- ap->a_vpp,
- ap->a_dvp->v_mount,
- ap->a_dvp,
- NULLVP,
- ap->a_cnp,
- vp,
- NULLVP);
+ error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount, ap->a_dvp,
+ NULLVP, cnp, vp, NULLVP, 1);
+ vrele(ap->a_dvp);
if (error)
vput(vp);
return (error);
@@ -1106,34 +1191,37 @@ union_rmdir(ap)
int error;
struct union_node *dun = VTOUNION(ap->a_dvp);
struct union_node *un = VTOUNION(ap->a_vp);
+ struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
- if (dun->un_uppervp && un->un_uppervp) {
+ if (dun->un_uppervp == NULLVP)
+ panic("union rmdir: null upper vnode");
+
+ if (un->un_uppervp != NULLVP) {
struct vnode *dvp = dun->un_uppervp;
struct vnode *vp = un->un_uppervp;
- FIXUP(dun);
+ FIXUP(dun, p);
VREF(dvp);
dun->un_flags |= UN_KLOCK;
vput(ap->a_dvp);
- FIXUP(un);
+ FIXUP(un, p);
VREF(vp);
un->un_flags |= UN_KLOCK;
vput(ap->a_vp);
+ if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc))
+ cnp->cn_flags |= DOWHITEOUT;
error = VOP_RMDIR(dvp, vp, ap->a_cnp);
if (!error)
union_removed_upper(un);
-
- /*
- * XXX: should create a whiteout here
- */
} else {
- /*
- * XXX: should create a whiteout here
- */
+ FIXUP(dun, p);
+ error = union_mkwhiteout(
+ MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
+ dun->un_uppervp, ap->a_cnp, un->un_path);
vput(ap->a_dvp);
vput(ap->a_vp);
- error = EROFS;
}
return (error);
@@ -1151,17 +1239,18 @@ union_symlink(ap)
{
struct union_node *un = VTOUNION(ap->a_dvp);
struct vnode *dvp = un->un_uppervp;
+ struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
- if (dvp) {
+ if (dvp != NULLVP) {
int error;
struct vnode *vp;
- FIXUP(un);
+ FIXUP(un, p);
VREF(dvp);
un->un_flags |= UN_KLOCK;
vput(ap->a_dvp);
- error = VOP_SYMLINK(dvp, &vp, ap->a_cnp,
- ap->a_vap, ap->a_target);
+ error = VOP_SYMLINK(dvp, &vp, cnp, ap->a_vap, ap->a_target);
*ap->a_vpp = NULLVP;
return (error);
}
@@ -1183,17 +1272,21 @@ union_readdir(ap)
struct vnode *a_vp;
struct uio *a_uio;
struct ucred *a_cred;
+ int *a_eofflag;
+ u_long *a_cookies;
+ int a_ncookies;
} */ *ap;
{
- int error = 0;
struct union_node *un = VTOUNION(ap->a_vp);
+ struct vnode *uvp = un->un_uppervp;
+ struct proc *p = ap->a_uio->uio_procp;
- if (un->un_uppervp) {
- FIXUP(un);
- error = VOP_READDIR(un->un_uppervp, ap->a_uio, ap->a_cred, NULL, NULL, NULL);
- }
+ if (uvp == NULLVP)
+ return (0);
- return (error);
+ FIXUP(un, p);
+ ap->a_vp = uvp;
+ return (VCALL(uvp, VOFFSET(vop_readdir), ap));
}
int
@@ -1205,16 +1298,19 @@ union_readlink(ap)
} */ *ap;
{
int error;
+ struct uio *uio = ap->a_uio;
+ struct proc *p = uio->uio_procp;
struct vnode *vp = OTHERVP(ap->a_vp);
int dolock = (vp == LOWERVP(ap->a_vp));
if (dolock)
- VOP_LOCK(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
else
- FIXUP(VTOUNION(ap->a_vp));
- error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
+ FIXUP(VTOUNION(ap->a_vp), p);
+ ap->a_vp = vp;
+ error = VCALL(vp, VOFFSET(vop_readlink), ap);
if (dolock)
- VOP_UNLOCK(vp);
+ VOP_UNLOCK(vp, 0, p);
return (error);
}
@@ -1227,6 +1323,8 @@ union_abortop(ap)
} */ *ap;
{
int error;
+ struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
struct vnode *vp = OTHERVP(ap->a_dvp);
struct union_node *un = VTOUNION(ap->a_dvp);
int islocked = un->un_flags & UN_LOCKED;
@@ -1234,13 +1332,14 @@ union_abortop(ap)
if (islocked) {
if (dolock)
- VOP_LOCK(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
else
- FIXUP(VTOUNION(ap->a_dvp));
+ FIXUP(VTOUNION(ap->a_dvp), p);
}
- error = VOP_ABORTOP(vp, ap->a_cnp);
+ ap->a_dvp = vp;
+ error = VCALL(vp, VOFFSET(vop_abortop), ap);
if (islocked && dolock)
- VOP_UNLOCK(vp);
+ VOP_UNLOCK(vp, 0, p);
return (error);
}
@@ -1249,8 +1348,13 @@ int
union_inactive(ap)
struct vop_inactive_args /* {
struct vnode *a_vp;
+ struct proc *a_p;
} */ *ap;
{
+ struct vnode *vp = ap->a_vp;
+ struct proc *p = ap->a_p;
+ struct union_node *un = VTOUNION(vp);
+ struct vnode **vpp;
/*
* Do nothing (and _don't_ bypass).
@@ -1265,12 +1369,17 @@ union_inactive(ap)
* That's too much work for now.
*/
-#ifdef UNION_DIAGNOSTIC
- struct union_node *un = VTOUNION(ap->a_vp);
+ if (un->un_dircache != 0) {
+ for (vpp = un->un_dircache; *vpp != NULLVP; vpp++)
+ vrele(*vpp);
+ free(un->un_dircache, M_TEMP);
+ un->un_dircache = 0;
+ }
- if (un->un_flags & UN_LOCKED)
- panic("union: inactivating locked node");
-#endif
+ VOP_UNLOCK(vp, 0, p);
+
+ if ((un->un_flags & UN_CACHED) == 0)
+ vgone(vp);
return (0);
}
@@ -1292,24 +1401,39 @@ union_lock(ap)
struct vop_lock_args *ap;
{
struct vnode *vp = ap->a_vp;
+ struct proc *p = ap->a_p;
+ int flags = ap->a_flags;
struct union_node *un;
+ int error;
-start:
- while (vp->v_flag & VXLOCK) {
- vp->v_flag |= VXWANT;
- (void) tsleep((caddr_t)vp, PINOD, "unnlk1", 0);
- }
+ vop_nolock(ap);
+ /*
+ * Need to do real lockmgr-style locking here.
+ * in the mean time, draining won't work quite right,
+ * which could lead to a few race conditions.
+ * the following test was here, but is not quite right, we
+ * still need to take the lock:
+ if ((flags & LK_TYPE_MASK) == LK_DRAIN)
+ return (0);
+ */
+ flags &= ~LK_INTERLOCK;
+start:
un = VTOUNION(vp);
- if (un->un_uppervp) {
- if ((un->un_flags & UN_ULOCK) == 0) {
+ if (un->un_uppervp != NULLVP) {
+ if (((un->un_flags & UN_ULOCK) == 0) &&
+ (vp->v_usecount != 0)) {
+ error = vn_lock(un->un_uppervp, flags, p);
+ if (error)
+ return (error);
un->un_flags |= UN_ULOCK;
- VOP_LOCK(un->un_uppervp);
}
#ifdef DIAGNOSTIC
- if (un->un_flags & UN_KLOCK)
- panic("union: dangling upper lock");
+ if (un->un_flags & UN_KLOCK) {
+ vprint("union: dangling klock", vp);
+ panic("union: dangling upper lock (%lx)", vp);
+ }
#endif
}
@@ -1320,7 +1444,7 @@ start:
panic("union: locking against myself");
#endif
un->un_flags |= UN_WANT;
- (void) tsleep((caddr_t) &un->un_flags, PINOD, "unnlk2", 0);
+ tsleep((caddr_t)&un->un_flags, PINOD, "unionlk2", 0);
goto start;
}
@@ -1335,11 +1459,27 @@ start:
return (0);
}
+/*
+ * When operations want to vput() a union node yet retain a lock on
+ * the upper vnode (say, to do some further operations like link(),
+ * mkdir(), ...), they set UN_KLOCK on the union node, then call
+ * vput() which calls VOP_UNLOCK() and comes here. union_unlock()
+ * unlocks the union node (leaving the upper vnode alone), clears the
+ * KLOCK flag, and then returns to vput(). The caller then does whatever
+ * is left to do with the upper vnode, and ensures that it gets unlocked.
+ *
+ * If UN_KLOCK isn't set, then the upper vnode is unlocked here.
+ */
int
union_unlock(ap)
- struct vop_lock_args *ap;
+ struct vop_unlock_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ struct proc *a_p;
+ } */ *ap;
{
struct union_node *un = VTOUNION(ap->a_vp);
+ struct proc *p = ap->a_p;
#ifdef DIAGNOSTIC
if ((un->un_flags & UN_LOCKED) == 0)
@@ -1352,7 +1492,7 @@ union_unlock(ap)
un->un_flags &= ~UN_LOCKED;
if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK)
- VOP_UNLOCK(un->un_uppervp);
+ VOP_UNLOCK(un->un_uppervp, 0, p);
un->un_flags &= ~(UN_ULOCK|UN_KLOCK);
@@ -1364,6 +1504,7 @@ union_unlock(ap)
#ifdef DIAGNOSTIC
un->un_pid = 0;
#endif
+ vop_nounlock(ap);
return (0);
}
@@ -1380,16 +1521,18 @@ union_bmap(ap)
} */ *ap;
{
int error;
+ struct proc *p = curproc; /* XXX */
struct vnode *vp = OTHERVP(ap->a_vp);
int dolock = (vp == LOWERVP(ap->a_vp));
if (dolock)
- VOP_LOCK(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
else
- FIXUP(VTOUNION(ap->a_vp));
- error = VOP_BMAP(vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp, ap->a_runb);
+ FIXUP(VTOUNION(ap->a_vp), p);
+ ap->a_vp = vp;
+ error = VCALL(vp, VOFFSET(vop_bmap), ap);
if (dolock)
- VOP_UNLOCK(vp);
+ VOP_UNLOCK(vp, 0, p);
return (error);
}
@@ -1404,6 +1547,11 @@ union_print(ap)
printf("\ttag VT_UNION, vp=%p, uppervp=%p, lowervp=%p\n",
vp, UPPERVP(vp), LOWERVP(vp));
+ if (UPPERVP(vp) != NULLVP)
+ vprint("union: upper", UPPERVP(vp));
+ if (LOWERVP(vp) != NULLVP)
+ vprint("union: lower", LOWERVP(vp));
+
return (0);
}
@@ -1426,16 +1574,18 @@ union_pathconf(ap)
} */ *ap;
{
int error;
+ struct proc *p = curproc; /* XXX */
struct vnode *vp = OTHERVP(ap->a_vp);
int dolock = (vp == LOWERVP(ap->a_vp));
if (dolock)
- VOP_LOCK(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
else
- FIXUP(VTOUNION(ap->a_vp));
- error = VOP_PATHCONF(vp, ap->a_name, ap->a_retval);
+ FIXUP(VTOUNION(ap->a_vp), p);
+ ap->a_vp = vp;
+ error = VCALL(vp, VOFFSET(vop_pathconf), ap);
if (dolock)
- VOP_UNLOCK(vp);
+ VOP_UNLOCK(vp, 0, p);
return (error);
}
@@ -1450,9 +1600,10 @@ union_advlock(ap)
int a_flags;
} */ *ap;
{
+ register struct vnode *ovp = OTHERVP(ap->a_vp);
- return (VOP_ADVLOCK(OTHERVP(ap->a_vp), ap->a_id, ap->a_op,
- ap->a_fl, ap->a_flags));
+ ap->a_vp = ovp;
+ return (VCALL(ovp, VOFFSET(vop_advlock), ap));
}
@@ -1496,6 +1647,7 @@ struct vnodeopv_entry_desc union_vnodeop_entries[] = {
{ &vop_default_desc, (vop_t *)vn_default_error },
{ &vop_lookup_desc, (vop_t *)union_lookup }, /* lookup */
{ &vop_create_desc, (vop_t *)union_create }, /* create */
+ { &vop_whiteout_desc, (vop_t *)union_whiteout }, /* whiteout */
{ &vop_mknod_desc, (vop_t *)union_mknod }, /* mknod */
{ &vop_open_desc, (vop_t *)union_open }, /* open */
{ &vop_close_desc, (vop_t *)union_close }, /* close */
@@ -1504,8 +1656,10 @@ struct vnodeopv_entry_desc union_vnodeop_entries[] = {
{ &vop_setattr_desc, (vop_t *)union_setattr }, /* setattr */
{ &vop_read_desc, (vop_t *)union_read }, /* read */
{ &vop_write_desc, (vop_t *)union_write }, /* write */
+ { &vop_lease_desc, (vop_t *)union_lease }, /* lease */
{ &vop_ioctl_desc, (vop_t *)union_ioctl }, /* ioctl */
{ &vop_select_desc, (vop_t *)union_select }, /* select */
+ { &vop_revoke_desc, (vop_t *)union_revoke }, /* revoke */
{ &vop_mmap_desc, (vop_t *)union_mmap }, /* mmap */
{ &vop_fsync_desc, (vop_t *)union_fsync }, /* fsync */
{ &vop_seek_desc, (vop_t *)union_seek }, /* seek */
OpenPOWER on IntegriCloud