From 10f666af84d48e89e4e2960415c9b616fce4077f Mon Sep 17 00:00:00 2001 From: dyson Date: Mon, 10 Feb 1997 02:22:35 +0000 Subject: This is the kernel Lite/2 commit. There are some requisite userland changes, so don't expect to be able to run the kernel as-is (very well) without the appropriate Lite/2 userland changes. The system boots and can mount UFS filesystems. Untested: ext2fs, msdosfs, NFS Known problems: Incorrect Berkeley ID strings in some files. Mount_std mounts will not work until the getfsent library routine is changed. Reviewed by: various people Submitted by: Jeffery Hsu --- sys/fs/cd9660/TODO | 30 -- sys/fs/cd9660/cd9660_bmap.c | 12 +- sys/fs/cd9660/cd9660_lookup.c | 173 +++++---- sys/fs/cd9660/cd9660_node.c | 462 ++++++++--------------- sys/fs/cd9660/cd9660_node.h | 36 +- sys/fs/cd9660/cd9660_rrip.c | 76 ++-- sys/fs/cd9660/cd9660_rrip.h | 48 ++- sys/fs/cd9660/cd9660_util.c | 107 +----- sys/fs/cd9660/cd9660_vfsops.c | 448 +++++++++++++--------- sys/fs/cd9660/cd9660_vnops.c | 721 ++++++++++++++++++++---------------- sys/fs/cd9660/iso.h | 135 +++---- sys/fs/deadfs/dead_vnops.c | 28 +- sys/fs/fdescfs/fdesc.h | 5 +- sys/fs/fdescfs/fdesc_vfsops.c | 71 +--- sys/fs/fdescfs/fdesc_vnops.c | 162 ++++---- sys/fs/fifofs/fifo.h | 10 +- sys/fs/fifofs/fifo_vnops.c | 177 +++++---- sys/fs/msdosfs/msdosfs_denode.c | 8 +- sys/fs/msdosfs/msdosfs_lookup.c | 29 +- sys/fs/msdosfs/msdosfs_vfsops.c | 6 +- sys/fs/msdosfs/msdosfs_vnops.c | 28 +- sys/fs/msdosfs/msdosfsmount.h | 12 + sys/fs/nullfs/null.h | 5 +- sys/fs/nullfs/null_subr.c | 61 +-- sys/fs/nullfs/null_vfsops.c | 19 +- sys/fs/nullfs/null_vnops.c | 223 ++++++++++- sys/fs/portalfs/portal_vfsops.c | 97 +---- sys/fs/portalfs/portal_vnops.c | 57 ++- sys/fs/procfs/procfs.h | 50 +-- sys/fs/procfs/procfs_ctl.c | 24 +- sys/fs/procfs/procfs_fpregs.c | 3 +- sys/fs/procfs/procfs_map.c | 2 +- sys/fs/procfs/procfs_mem.c | 10 +- sys/fs/procfs/procfs_regs.c | 3 +- sys/fs/procfs/procfs_status.c | 5 +- sys/fs/procfs/procfs_subr.c | 55 +-- sys/fs/procfs/procfs_vfsops.c | 109 +----- sys/fs/procfs/procfs_vnops.c | 466 ++++++++++++++--------- sys/fs/specfs/spec_vnops.c | 91 ++--- sys/fs/umapfs/umap.h | 5 +- sys/fs/umapfs/umap_subr.c | 61 +-- sys/fs/umapfs/umap_vfsops.c | 21 +- sys/fs/umapfs/umap_vnops.c | 49 ++- sys/fs/unionfs/union.h | 22 +- sys/fs/unionfs/union_subr.c | 538 ++++++++++++++++++++++----- sys/fs/unionfs/union_vfsops.c | 238 +++++------- sys/fs/unionfs/union_vnops.c | 798 ++++++++++++++++++++++++---------------- 47 files changed, 3179 insertions(+), 2617 deletions(-) (limited to 'sys/fs') diff --git a/sys/fs/cd9660/TODO b/sys/fs/cd9660/TODO index eb24a23..71859c7 100644 --- a/sys/fs/cd9660/TODO +++ b/sys/fs/cd9660/TODO @@ -25,16 +25,6 @@ There is some preliminary stuff in there that (ab-)uses the mknod system call, but this needs a writable filesystem - 3) should be called cdfs, as there are other ISO file system soon possible - - Not yet. Probably we should make another file system when the ECMA draft - is valid and do it. For doing Rock Ridge Support, I can use almost same - code. So I just use the same file system interface... - - 4) should have file handles implemented for use with NFS, etc - - Yes. we have already this one, and I based it for this release. - 5) should have name translation enabled by mount flag Yes. we can disable the Rock Ridge Extension by follows option; @@ -57,23 +47,3 @@ clean. As far as I know, if you export the cdrom by NFS, the client can access the 8 bit clean (ie. Solaris Japanese with EUC code ) - 9) Access checks in isofs_access - - Not yet. - - 10) Support for generation numbers - - Yes. Default is to list only the last file (the one with the highest - generation number). If you mount with -gen, all files are shown with - their generation numbers. In both cases you can specify the generation - number on opening files (if you happen to know it) or leave it off, - when it will again find the last file. - - 11) Support for extended attributes - - Yes. Since this requires an extra block buffer for the attributes - this must be enabled on mounting with the option -extattr. - ----------- -Last update July 19, '93 by Atsushi Murai. (amurai@spec.co.jp) -Last update August 19, '93 by Wolfgang Solfrank. (ws@tools.de) diff --git a/sys/fs/cd9660/cd9660_bmap.c b/sys/fs/cd9660/cd9660_bmap.c index 6fffe7a..71dfb9e 100644 --- a/sys/fs/cd9660/cd9660_bmap.c +++ b/sys/fs/cd9660/cd9660_bmap.c @@ -67,7 +67,7 @@ cd9660_bmap(ap) { struct iso_node *ip = VTOI(ap->a_vp); daddr_t lblkno = ap->a_bn; - long bsize; + int bshift; /* * Check for underlying vnode requests and ensure that logical @@ -81,8 +81,8 @@ cd9660_bmap(ap) /* * Compute the requested block number */ - bsize = ip->i_mnt->logical_block_size; - *ap->a_bnp = (ip->iso_start + lblkno) * btodb(bsize); + bshift = ip->i_mnt->im_bshift; + *ap->a_bnp = (ip->iso_start + lblkno) << (bshift - DEV_BSHIFT); /* * Determine maximum number of readahead blocks following the @@ -91,11 +91,11 @@ cd9660_bmap(ap) if (ap->a_runp) { int nblk; - nblk = (ip->i_size - (lblkno + 1) * bsize) / bsize; + nblk = (ip->i_size >> bshift) - (lblkno + 1); if (nblk <= 0) *ap->a_runp = 0; - else if (nblk >= MAXBSIZE/bsize) - *ap->a_runp = MAXBSIZE/bsize - 1; + else if (nblk >= (MAXBSIZE >> bshift)) + *ap->a_runp = (MAXBSIZE >> bshift) - 1; else *ap->a_runp = nblk; } diff --git a/sys/fs/cd9660/cd9660_lookup.c b/sys/fs/cd9660/cd9660_lookup.c index 6e85a81..a7e38bb 100644 --- a/sys/fs/cd9660/cd9660_lookup.c +++ b/sys/fs/cd9660/cd9660_lookup.c @@ -108,8 +108,9 @@ cd9660_lookup(ap) int saveoffset = 0; /* offset of last directory entry in dir */ int numdirpasses; /* strategy for directory search */ doff_t endsearch; /* offset to end directory search */ - struct iso_node *pdp; /* saved dp during symlink work */ - struct iso_node *tdp; /* returned by iget */ + struct vnode *pdp; /* saved dp during symlink work */ + struct vnode *tdp; /* returned by cd9660_vget_internal */ + u_long bmask; /* block offset mask */ int lockparent; /* 1 => lockparent flag is set */ int wantparent; /* 1 => wantparent or lockparent flag */ int error; @@ -126,6 +127,7 @@ cd9660_lookup(ap) struct ucred *cred = cnp->cn_cred; int flags = cnp->cn_flags; int nameiop = cnp->cn_nameiop; + struct proc *p = cnp->cn_proc; bp = NULL; *vpp = NULL; @@ -139,13 +141,13 @@ cd9660_lookup(ap) * Check accessiblity of directory. */ if (vdp->v_type != VDIR) - return (ENOTDIR); - if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc))) + return (ENOTDIR); + if (error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) return (error); if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) return (EROFS); - + /* * We now have a segment name to search for, and a directory to search. * @@ -160,29 +162,29 @@ cd9660_lookup(ap) return (error); #ifdef PARANOID if ((vdp->v_flag & VROOT) && (flags & ISDOTDOT)) - panic("ufs_lookup: .. through root"); + panic("cd9660_lookup: .. through root"); #endif /* * Get the next vnode in the path. * See comment below starting `Step through' for * an explaination of the locking protocol. */ - pdp = dp; + pdp = vdp; dp = VTOI(*vpp); vdp = *vpp; vpid = vdp->v_id; - if (pdp == dp) { + if (pdp == vdp) { VREF(vdp); error = 0; } else if (flags & ISDOTDOT) { - ISO_IUNLOCK(pdp); - error = vget(vdp, 1); + VOP_UNLOCK(pdp, 0, p); + error = vget(vdp, LK_EXCLUSIVE, p); if (!error && lockparent && (flags & ISLASTCN)) - ISO_ILOCK(pdp); + error = vn_lock(pdp, LK_EXCLUSIVE, p); } else { - error = vget(vdp, 1); + error = vget(vdp, LK_EXCLUSIVE, p); if (!lockparent || error || !(flags & ISLASTCN)) - ISO_IUNLOCK(pdp); + VOP_UNLOCK(pdp, 0, p); } /* * Check that the capability number did not change @@ -191,13 +193,14 @@ cd9660_lookup(ap) if (!error) { if (vpid == vdp->v_id) return (0); - iso_iput(dp); - if (lockparent && pdp != dp && (flags & ISLASTCN)) - ISO_IUNLOCK(pdp); + vput(vdp); + if (lockparent && pdp != vdp && (flags & ISLASTCN)) + VOP_UNLOCK(pdp, 0, p); } - ISO_ILOCK(pdp); - dp = pdp; - vdp = ITOV(dp); + if (error = vn_lock(pdp, LK_EXCLUSIVE, p)) + return (error); + vdp = pdp; + dp = VTOI(pdp); *vpp = NULL; } @@ -223,6 +226,7 @@ cd9660_lookup(ap) * profiling time and hence has been removed in the interest * of simplicity. */ + bmask = imp->im_bmask; if (nameiop != LOOKUP || dp->i_diroff == 0 || dp->i_diroff > dp->i_size) { entryoffsetinblock = 0; @@ -230,16 +234,14 @@ cd9660_lookup(ap) numdirpasses = 1; } else { dp->i_offset = dp->i_diroff; - entryoffsetinblock = iso_blkoff(imp, dp->i_offset); - if (entryoffsetinblock != 0) { - if ((error = iso_blkatoff(dp, dp->i_offset, &bp))) + if ((entryoffsetinblock = dp->i_offset & bmask) && + (error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp))) return (error); - } numdirpasses = 2; iso_nchstats.ncs_2passes++; } - endsearch = roundup(dp->i_size, imp->logical_block_size); - + endsearch = dp->i_size; + searchloop: while (dp->i_offset < endsearch) { /* @@ -247,10 +249,11 @@ searchloop: * read the next directory block. * Release previous if it exists. */ - if (iso_blkoff(imp, dp->i_offset) == 0) { + if ((dp->i_offset & bmask) == 0) { if (bp != NULL) brelse(bp); - if ((error = iso_blkatoff(dp, dp->i_offset, &bp))) + if (error = + VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)) return (error); entryoffsetinblock = 0; } @@ -258,13 +261,13 @@ searchloop: * Get pointer to next entry. */ ep = (struct iso_directory_record *) - (bp->b_un.b_addr + entryoffsetinblock); - - reclen = isonum_711 (ep->length); + ((char *)bp->b_data + entryoffsetinblock); + + reclen = isonum_711(ep->length); if (reclen == 0) { /* skip to next block, if any */ dp->i_offset = - roundup(dp->i_offset, imp->logical_block_size); + (dp->i_offset & ~bmask) + imp->logical_block_size; continue; } @@ -275,10 +278,7 @@ searchloop: if (entryoffsetinblock + reclen > imp->logical_block_size) /* entries are not allowed to cross boundaries */ break; - - /* - * Check for a name match. - */ + namelen = isonum_711(ep->name_len); isoflags = isonum_711(imp->iso_ftype == ISO_FTYPE_HIGH_SIERRA? &ep->date[6]: ep->flags); @@ -286,7 +286,10 @@ searchloop: if (reclen < ISO_DIRECTORY_RECORD_SIZE + namelen) /* illegal entry, stop */ break; - + + /* + * Check for a name match. + */ switch (imp->iso_ftype) { default: if (!(isoflags & 4) == !assoc) { @@ -297,10 +300,9 @@ searchloop: && ep->name[0] == ((flags & ISDOTDOT) ? 1 : 0)) { /* * Save directory entry's inode number and - * reclen in ndp->ni_ufs area, and release - * directory buffer. + * release directory buffer. */ - isodirino(&dp->i_ino,ep,imp); + dp->i_ino = isodirino(ep, imp); goto found; } if (namelen != 1 @@ -308,8 +310,8 @@ searchloop: goto notfound; } else if (!(res = isofncmp(name,len, ep->name,namelen))) { - if (isoflags & 2) - isodirino(&ino,ep,imp); + if (isonum_711(ep->flags)&2) + ino = isodirino(ep, imp); else ino = dbtob(bp->b_blkno) + entryoffsetinblock; @@ -326,7 +328,7 @@ searchloop: break; case ISO_FTYPE_RRIP: if (isonum_711(ep->flags)&2) - isodirino(&ino,ep,imp); + ino = isodirino(ep, imp); else ino = dbtob(bp->b_blkno) + entryoffsetinblock; dp->i_ino = ino; @@ -344,15 +346,17 @@ searchloop: foundino: dp->i_ino = ino; if (saveoffset != dp->i_offset) { - if (iso_lblkno(imp,dp->i_offset) - != iso_lblkno(imp,saveoffset)) { + if (lblkno(imp, dp->i_offset) != + lblkno(imp, saveoffset)) { if (bp != NULL) brelse(bp); - if ((error = iso_blkatoff(dp, saveoffset, &bp))) + if (error = VOP_BLKATOFF(vdp, + (off_t)saveoffset, NULL, &bp)) return (error); } - ep = (struct iso_directory_record *)(bp->b_un.b_addr - + iso_blkoff(imp,saveoffset)); + entryoffsetinblock = saveoffset & bmask; + ep = (struct iso_directory_record *) + ((char *)bp->b_data + entryoffsetinblock); dp->i_offset = saveoffset; } goto found; @@ -370,6 +374,7 @@ notfound: } if (bp != NULL) brelse(bp); + /* * Insert name into cache (as non-existent) if appropriate. */ @@ -382,9 +387,7 @@ notfound: found: if (numdirpasses == 2) iso_nchstats.ncs_pass2++; - if (bp != NULL) - brelse(bp); - + /* * Found component in pathname. * If the final component of path name, save information @@ -412,31 +415,39 @@ found: * work if the file system has any hard links other than ".." * that point backwards in the directory structure. */ - pdp = dp; + pdp = vdp; /* * If ino is different from dp->i_ino, * it's a relocated directory. */ if (flags & ISDOTDOT) { - ISO_IUNLOCK(pdp); /* race to get the inode */ - if ((error = iso_iget(dp,dp->i_ino, - dp->i_ino != ino, - &tdp,ep))) { - ISO_ILOCK(pdp); + VOP_UNLOCK(pdp, 0, p); /* race to get the inode */ + error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp, + dp->i_ino != ino, ep); + brelse(bp); + if (error) { + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p); return (error); } - if (lockparent && (flags & ISLASTCN)) - ISO_ILOCK(pdp); - *vpp = ITOV(tdp); + if (lockparent && (flags & ISLASTCN) && + (error = vn_lock(pdp, LK_EXCLUSIVE, p))) { + vput(tdp); + return (error); + } + *vpp = tdp; } else if (dp->i_number == dp->i_ino) { + brelse(bp); VREF(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { - if ((error = iso_iget(dp,dp->i_ino,dp->i_ino!=ino,&tdp,ep))) + error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp, + dp->i_ino != ino, ep); + brelse(bp); + if (error) return (error); if (!lockparent || !(flags & ISLASTCN)) - ISO_IUNLOCK(pdp); - *vpp = ITOV(tdp); + VOP_UNLOCK(pdp, 0, p); + *vpp = tdp; } /* @@ -448,29 +459,37 @@ found: } /* - * Return buffer with contents of block "offset" - * from the beginning of directory "ip". If "res" - * is non-zero, fill it in with a pointer to the + * Return buffer with the contents of block "offset" from the beginning of + * directory "ip". If "res" is non-zero, fill it in with a pointer to the * remaining space in the directory. */ int -iso_blkatoff(ip, offset, bpp) - struct iso_node *ip; - doff_t offset; - struct buf **bpp; +cd9660_blkatoff(ap) + struct vop_blkatoff_args /* { + struct vnode *a_vp; + off_t a_offset; + char **a_res; + struct buf **a_bpp; + } */ *ap; { - register struct iso_mnt *imp = ip->i_mnt; - daddr_t lbn = iso_lblkno(imp,offset); - int bsize = iso_blksize(imp,ip,lbn); + struct iso_node *ip; + register struct iso_mnt *imp; struct buf *bp; - int error; + daddr_t lbn; + int bsize, error; - if ((error = bread(ITOV(ip),lbn,bsize,NOCRED,&bp))) { + ip = VTOI(ap->a_vp); + imp = ip->i_mnt; + lbn = lblkno(imp, ap->a_offset); + bsize = blksize(imp, ip, lbn); + + if (error = bread(ap->a_vp, lbn, bsize, NOCRED, &bp)) { brelse(bp); - *bpp = 0; + *ap->a_bpp = NULL; return (error); } - *bpp = bp; - + if (ap->a_res) + *ap->a_res = (char *)bp->b_data + blkoff(imp, ap->a_offset); + *ap->a_bpp = bp; return (0); } diff --git a/sys/fs/cd9660/cd9660_node.c b/sys/fs/cd9660/cd9660_node.c index c3f0911..c726696 100644 --- a/sys/fs/cd9660/cd9660_node.c +++ b/sys/fs/cd9660/cd9660_node.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1982, 1986, 1989, 1994 + * Copyright (c) 1982, 1986, 1989, 1994, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley @@ -52,32 +52,21 @@ #include #include +#include #include -#define INOHSZ 512 -#if ((INOHSZ&(INOHSZ-1)) == 0) -#define INOHASH(dev,ino) (((dev)+((ino)>>12))&(INOHSZ-1)) -#else -#define INOHASH(dev,ino) (((unsigned)((dev)+((ino)>>12)))%INOHSZ) -#endif - -union iso_ihead { - union iso_ihead *ih_head[2]; - struct iso_node *ih_chain[2]; -} iso_ihead[INOHSZ]; - -#ifdef ISODEVMAP -#define DNOHSZ 64 -#if ((DNOHSZ&(DNOHSZ-1)) == 0) -#define DNOHASH(dev,ino) (((dev)+((ino)>>12))&(DNOHSZ-1)) -#else -#define DNOHASH(dev,ino) (((unsigned)((dev)+((ino)>>12)))%DNOHSZ) -#endif - -union iso_dhead { - union iso_dhead *dh_head[2]; - struct iso_dnode *dh_chain[2]; -} iso_dhead[DNOHSZ]; +/* + * Structures associated with iso_node caching. + */ +struct iso_node **isohashtbl; +u_long isohash; +#define INOHASH(device, inum) (((device) + ((inum)>>12)) & isohash) +struct simplelock cd9660_ihash_slock; + +#ifdef ISODEVMAP +struct iso_node **idvhashtbl; +u_long idvhash; +#define DNOHASH(device, inum) (((device) + ((inum)>>12)) & idvhash) #endif static unsigned cd9660_chars2ui __P((unsigned char *begin, int len)); @@ -86,73 +75,68 @@ static unsigned cd9660_chars2ui __P((unsigned char *begin, int len)); * Initialize hash links for inodes and dnodes. */ int -cd9660_init() +cd9660_init(vfsp) + struct vfsconf *vfsp; { - register int i; - register union iso_ihead *ih = iso_ihead; -#ifdef ISODEVMAP - register union iso_dhead *dh = iso_dhead; -#endif - for (i = INOHSZ; --i >= 0; ih++) { - ih->ih_head[0] = ih; - ih->ih_head[1] = ih; - } -#ifdef ISODEVMAP - for (i = DNOHSZ; --i >= 0; dh++) { - dh->dh_head[0] = dh; - dh->dh_head[1] = dh; - } + isohashtbl = hashinit(desiredvnodes, M_ISOFSMNT, &isohash); + simple_lock_init(&cd9660_ihash_slock); +#ifdef ISODEVMAP + idvhashtbl = hashinit(desiredvnodes / 8, M_ISOFSMNT, &idvhash); #endif return (0); } -#ifdef ISODEVMAP +#ifdef ISODEVMAP /* * Enter a new node into the device hash list */ struct iso_dnode * -iso_dmap(dev,ino,create) - dev_t dev; - ino_t ino; +iso_dmap(device, inum, create) + dev_t device; + ino_t inum; int create; { - struct iso_dnode *dp; - union iso_dhead *dh; + register struct iso_dnode **dpp, *dp, *dq; - dh = &iso_dhead[DNOHASH(dev, ino)]; - for (dp = dh->dh_chain[0]; - dp != (struct iso_dnode *)dh; - dp = dp->d_forw) - if (ino == dp->i_number && dev == dp->i_dev) - return dp; + dpp = &idvhashtbl[DNOHASH(device, inum)]; + for (dp = *dpp;; dp = dp->d_next) { + if (dp == NULL) + return (NULL); + if (inum == dp->i_number && device == dp->i_dev) + return (dp); if (!create) - return (struct iso_dnode *)0; + return (NULL); - MALLOC(dp,struct iso_dnode *,sizeof(struct iso_dnode),M_CACHE,M_WAITOK); + MALLOC(dp, struct iso_dnode *, sizeof(struct iso_dnode), M_CACHE, + M_WAITOK); dp->i_dev = dev; dp->i_number = ino; - insque(dp,dh); - return dp; + if (dq = *dpp) + dq->d_prev = dp->d_next; + dp->d_next = dq; + dp->d_prev = dpp; + *dpp = dp; + + return (dp); } void -iso_dunmap(dev) - dev_t dev; +iso_dunmap(device) + dev_t device; { - struct iso_dnode *dp, *dq; - union iso_dhead *dh; - - for (dh = iso_dhead; dh < iso_dhead + DNOHSZ; dh++) { - for (dp = dh->dh_chain[0]; - dp != (struct iso_dnode *)dh; - dp = dq) { - dq = dp->d_forw; - if (dev == dp->i_dev) { - remque(dp); - FREE(dp,M_CACHE); + struct iso_dnode **dpp, *dp, *dq; + + for (dpp = idvhashtbl; dpp <= idvhashtbl + idvhash; dpp++) { + for (dp = *dpp; dp != NULL; dp = dq) + dq = dp->d_next; + if (device == dp->i_dev) { + if (dq) + dq->d_prev = dp->d_prev; + *dp->d_prev = dq; + FREE(dp, M_CACHE); } } } @@ -160,197 +144,74 @@ iso_dunmap(dev) #endif /* - * Look up a ISOFS dinode number to find its incore vnode. - * If it is not in core, read it in from the specified device. - * If it is in core, wait for the lock bit to clear, then - * return the inode locked. Detection and handling of mount - * points must be done by the calling routine. + * Use the device/inum pair to find the incore inode, and return a pointer + * to it. If it is in core, but locked, wait for it. */ -int -iso_iget(xp, ino, relocated, ipp, isodir) - struct iso_node *xp; - ino_t ino; - int relocated; - struct iso_node **ipp; - struct iso_directory_record *isodir; +struct vnode * +cd9660_ihashget(dev, inum) + dev_t dev; + ino_t inum; { - dev_t dev = xp->i_dev; - struct mount *mntp = ITOV(xp)->v_mount; - register struct iso_node *ip, *iq; - register struct vnode *vp; -#ifdef ISODEVMAP - register struct iso_dnode *dp; -#endif - struct vnode *nvp; - struct buf *bp = NULL, *bp2 = NULL; - union iso_ihead *ih; - int error, result; - struct iso_mnt *imp; + struct proc *p = curproc; /* XXX */ + struct iso_node *ip; + struct vnode *vp; - ih = &iso_ihead[INOHASH(dev, ino)]; loop: - for (ip = ih->ih_chain[0]; - ip != (struct iso_node *)ih; - ip = ip->i_forw) { - if (ino != ip->i_number || dev != ip->i_dev) - continue; - if ((ip->i_flag&ILOCKED) != 0) { - ip->i_flag |= IWANT; - (void) tsleep((caddr_t)ip, PINOD, "isoigt", 0); - goto loop; - } - if (vget(ITOV(ip), 1)) - goto loop; - *ipp = ip; - return 0; - } - - /* - * Do the MALLOC before the getnewvnode since doing so afterward - * might cause a bogus v_data pointer to get dereferenced - * elsewhere if MALLOC should block. - */ - MALLOC(ip, struct iso_node *, sizeof(struct iso_node), M_ISOFSNODE, M_WAITOK); - - /* - * Allocate a new vnode/iso_node. - */ - if ((error = getnewvnode(VT_ISOFS, mntp, cd9660_vnodeop_p, &nvp))) { - *ipp = NULL; - FREE(ip, M_ISOFSNODE); - return error; - } - bzero((caddr_t)ip, sizeof(struct iso_node)); - nvp->v_data = ip; - ip->i_vnode = nvp; - ip->i_flag = 0; - ip->i_devvp = 0; - ip->i_diroff = 0; - ip->i_lockf = 0; - - /* - * Put it onto its hash chain and lock it so that other requests for - * this inode will block if they arrive while we are sleeping waiting - * for old data structures to be purged or for the contents of the - * disk portion of this inode to be read. - */ - ip->i_dev = dev; - ip->i_number = ino; - insque(ip, ih); - ISO_ILOCK(ip); - - imp = VFSTOISOFS (mntp); - ip->i_mnt = imp; - ip->i_devvp = imp->im_devvp; - VREF(ip->i_devvp); - - if (relocated) { - /* - * On relocated directories we must - * read the `.' entry out of a dir. - */ - ip->iso_start = ino >> imp->im_bshift; - if ((error = iso_blkatoff(ip,0,&bp))) { - vrele(ip->i_devvp); - remque(ip); - ip->i_forw = ip; - ip->i_back = ip; - iso_iput(ip); - *ipp = 0; - return error; - } - isodir = (struct iso_directory_record *)bp->b_un.b_addr; - } - - ip->iso_extent = isonum_733(isodir->extent); - ip->i_size = isonum_733(isodir->size); - ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent; - - vp = ITOV(ip); - - /* - * Setup time stamp, attribute - */ - vp->v_type = VNON; - switch (imp->iso_ftype) { - default: /* ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA */ - if ((imp->im_flags&ISOFSMNT_EXTATT) - && isonum_711(isodir->ext_attr_length)) - iso_blkatoff(ip,-isonum_711(isodir->ext_attr_length), - &bp2); - cd9660_defattr(isodir,ip,bp2,imp->iso_ftype ); - cd9660_deftstamp(isodir,ip,bp2,imp->iso_ftype ); - break; - case ISO_FTYPE_RRIP: - result = cd9660_rrip_analyze(isodir,ip,imp); - break; - } - if (bp2) - brelse(bp2); - if (bp) - brelse(bp); - - /* - * Initialize the associated vnode - */ - vp->v_type = IFTOVT(ip->inode.iso_mode); - - if ( vp->v_type == VFIFO ) { - vp->v_op = cd9660_fifoop_p; - } else if ( vp->v_type == VCHR || vp->v_type == VBLK ) { - /* - * if device, look at device number table for translation - */ -#ifdef ISODEVMAP - if (dp = iso_dmap(dev,ino,0)) - ip->inode.iso_rdev = dp->d_dev; -#endif - vp->v_op = cd9660_specop_p; - if ((nvp = checkalias(vp, ip->inode.iso_rdev, mntp))) { - /* - * Reinitialize aliased inode. - */ - vp = nvp; - iq = VTOI(vp); - iq->i_vnode = vp; - iq->i_flag = 0; - ISO_ILOCK(iq); - iq->i_dev = dev; - iq->i_number = ino; - iq->i_mnt = ip->i_mnt; - bcopy(&ip->iso_extent,&iq->iso_extent, - (char *)(ip + 1) - (char *)&ip->iso_extent); - insque(iq, ih); - /* - * Discard unneeded vnode - * (This introduces the need of INACTIVE modification) - */ - ip->inode.iso_mode = 0; - iso_iput(ip); - ip = iq; + simple_lock(&cd9660_ihash_slock); + for (ip = isohashtbl[INOHASH(dev, inum)]; ip; ip = ip->i_next) { + if (inum == ip->i_number && dev == ip->i_dev) { + vp = ITOV(ip); + simple_lock(&vp->v_interlock); + simple_unlock(&cd9660_ihash_slock); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) + goto loop; + return (vp); } } + simple_unlock(&cd9660_ihash_slock); + return (NULL); +} - if (ip->iso_extent == imp->root_extent) - vp->v_flag |= VROOT; - +/* + * Insert the inode into the hash table, and return it locked. + */ +void +cd9660_ihashins(ip) + struct iso_node *ip; +{ + struct proc *p = curproc; /* XXX */ + struct iso_node **ipp, *iq; + + simple_lock(&cd9660_ihash_slock); + ipp = &isohashtbl[INOHASH(ip->i_dev, ip->i_number)]; + if (iq = *ipp) + iq->i_prev = &ip->i_next; + ip->i_next = iq; + ip->i_prev = ipp; *ipp = ip; - return 0; + simple_unlock(&cd9660_ihash_slock); + + lockmgr(&ip->i_lock, LK_EXCLUSIVE, (struct simplelock *)0, p); } /* - * Unlock and decrement the reference count of an inode structure. + * Remove the inode from the hash table. */ -int -iso_iput(ip) +void +cd9660_ihashrem(ip) register struct iso_node *ip; { - - if ((ip->i_flag & ILOCKED) == 0) - panic("iso_iput"); - ISO_IUNLOCK(ip); - vrele(ITOV(ip)); - return (0); + register struct iso_node *iq; + + simple_lock(&cd9660_ihash_slock); + if (iq = ip->i_next) + iq->i_prev = ip->i_prev; + *ip->i_prev = iq; +#ifdef DIAGNOSTIC + ip->i_next = NULL; + ip->i_prev = NULL; +#endif + simple_unlock(&cd9660_ihash_slock); } /* @@ -361,9 +222,11 @@ int cd9660_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; register struct iso_node *ip = VTOI(vp); int error = 0; @@ -371,12 +234,13 @@ cd9660_inactive(ap) vprint("cd9660_inactive: pushing active", vp); ip->i_flag = 0; + VOP_UNLOCK(vp, 0, p); /* * If we are done with the inode, reclaim it * so that it can be reused immediately. */ - if (vp->v_usecount == 0 && ip->inode.iso_mode == 0) - vgone(vp); + if (ip->inode.iso_mode == 0) + vrecycle(vp, (struct simplelock *)0, p); return error; } @@ -387,6 +251,7 @@ int cd9660_reclaim(ap) struct vop_reclaim_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { register struct vnode *vp = ap->a_vp; @@ -397,9 +262,7 @@ cd9660_reclaim(ap) /* * Remove the inode from its hash chain. */ - remque(ip); - ip->i_forw = ip; - ip->i_back = ip; + cd9660_ihashrem(ip); /* * Purge old data structures associated with the inode. */ @@ -410,46 +273,6 @@ cd9660_reclaim(ap) } FREE(vp->v_data, M_ISOFSNODE); vp->v_data = NULL; - return 0; -} - -/* - * Lock an inode. If its already locked, set the WANT bit and sleep. - */ -int -iso_ilock(ip) - register struct iso_node *ip; -{ - - while (ip->i_flag & ILOCKED) { - ip->i_flag |= IWANT; - if (ip->i_spare0 == curproc->p_pid) - panic("locking against myself"); - ip->i_spare1 = curproc->p_pid; - (void) tsleep((caddr_t)ip, PINOD, "isoilk", 0); - } - ip->i_spare1 = 0; - ip->i_spare0 = curproc->p_pid; - ip->i_flag |= ILOCKED; - return (0); -} - -/* - * Unlock an inode. If WANT bit is on, wakeup. - */ -int -iso_iunlock(ip) - register struct iso_node *ip; -{ - - if ((ip->i_flag & ILOCKED) == 0) - vprint("iso_iunlock: unlocked inode", ITOV(ip)); - ip->i_spare0 = 0; - ip->i_flag &= ~ILOCKED; - if (ip->i_flag&IWANT) { - ip->i_flag &= ~IWANT; - wakeup((caddr_t)ip); - } return (0); } @@ -457,7 +280,7 @@ iso_iunlock(ip) * File attributes */ void -cd9660_defattr(isodir,inop,bp,ftype) +cd9660_defattr(isodir, inop, bp, ftype) struct iso_directory_record *isodir; struct iso_node *inop; struct buf *bp; @@ -482,14 +305,15 @@ cd9660_defattr(isodir,inop,bp,ftype) inop->inode.iso_links = 1; } if (!bp - && ((imp = inop->i_mnt)->im_flags&ISOFSMNT_EXTATT) + && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT) && (off = isonum_711(isodir->ext_attr_length))) { - iso_blkatoff(inop,-off * imp->logical_block_size,&bp2); + VOP_BLKATOFF(ITOV(inop), (off_t)-(off << imp->im_bshift), NULL, + &bp2); bp = bp2; } if (bp) { - ap = (struct iso_extended_attributes *)bp->b_un.b_addr; - + ap = (struct iso_extended_attributes *)bp->b_data; + if (isonum_711(ap->version) == 1) { if (!(ap->perm[0]&0x40)) inop->inode.iso_mode |= VEXEC >> 6; @@ -533,16 +357,16 @@ cd9660_deftstamp(isodir,inop,bp,ftype) int off; if (!bp - && ((imp = inop->i_mnt)->im_flags&ISOFSMNT_EXTATT) + && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT) && (off = isonum_711(isodir->ext_attr_length))) { - iso_blkatoff(inop,-off * imp->logical_block_size,&bp2); + VOP_BLKATOFF(ITOV(inop), (off_t)-(off << imp->im_bshift), NULL, + &bp2); bp = bp2; } if (bp) { - ap = (struct iso_extended_attributes *)bp->b_un.b_addr; - - if (ftype != ISO_FTYPE_HIGH_SIERRA - && isonum_711(ap->version) == 1) { + ap = (struct iso_extended_attributes *)bp->b_data; + + if (isonum_711(ap->version) == 1) { if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime)) cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime); if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime)) @@ -563,9 +387,9 @@ cd9660_deftstamp(isodir,inop,bp,ftype) int cd9660_tstamp_conv7(pi,pu,ftype) -char *pi; -struct timespec *pu; -enum ISO_FTYPE ftype; + u_char *pi; + struct timespec *pu; + enum ISO_FTYPE ftype; { int crtime, days; int y, m, d, hour, minute, second, tz; @@ -609,13 +433,13 @@ enum ISO_FTYPE ftype; return 1; } -static unsigned +static u_int cd9660_chars2ui(begin,len) - unsigned char *begin; + u_char *begin; int len; { - unsigned rc; - + u_int rc; + for (rc = 0; --len >= 0;) { rc *= 10; rc += *begin++ - '0'; @@ -625,12 +449,12 @@ cd9660_chars2ui(begin,len) int cd9660_tstamp_conv17(pi,pu) - unsigned char *pi; + u_char *pi; struct timespec *pu; { - unsigned char buf[7]; - - /* year:"0001"-"9999" -> -1900 */ + u_char buf[7]; + + /* year:"0001"-"9999" -> -1900 */ buf[0] = cd9660_chars2ui(pi,4) - 1900; /* month: " 1"-"12" -> 1 - 12 */ @@ -654,12 +478,14 @@ cd9660_tstamp_conv17(pi,pu) return cd9660_tstamp_conv7(buf, pu, ISO_FTYPE_DEFAULT); } -void -isodirino(inump,isodir,imp) - ino_t *inump; +ino_t +isodirino(isodir, imp) struct iso_directory_record *isodir; struct iso_mnt *imp; { - *inump = (isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length)) - * imp->logical_block_size; + ino_t ino; + + ino = (isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length)) + << imp->im_bshift; + return (ino); } diff --git a/sys/fs/cd9660/cd9660_node.h b/sys/fs/cd9660/cd9660_node.h index 992f9cb..de538fb 100644 --- a/sys/fs/cd9660/cd9660_node.h +++ b/sys/fs/cd9660/cd9660_node.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)cd9660_node.h 8.2 (Berkeley) 1/23/94 + * @(#)cd9660_node.h 8.6 (Berkeley) 5/14/95 * $FreeBSD$ */ @@ -59,22 +59,20 @@ typedef struct { dev_t iso_rdev; /* Major/Minor number for special */ } ISO_RRIP_INODE; -#ifdef ISODEVMAP +#ifdef ISODEVMAP /* * FOr device# (major,minor) translation table */ struct iso_dnode { - struct iso_dnode *d_chain[2]; /* hash chain, MUST be first */ + struct iso_dnode *d_next, **d_prev; /* hash chain */ dev_t i_dev; /* device where dnode resides */ ino_t i_number; /* the identity of the inode */ dev_t d_dev; /* device # for translation */ }; -#define d_forw d_chain[0] -#define d_back d_chain[1] #endif struct iso_node { - struct iso_node *i_chain[2]; /* hash chain, MUST be first */ + struct iso_node *i_next, **i_prev; /* hash chain */ struct vnode *i_vnode; /* vnode associated with this inode */ struct vnode *i_devvp; /* vnode for block I/O */ u_long i_flag; /* see below */ @@ -87,8 +85,7 @@ struct iso_node { doff_t i_diroff; /* offset in dir, where we found last entry */ doff_t i_offset; /* offset of free space in directory */ ino_t i_ino; /* inode number of found directory */ - long i_spare0; - long i_spare1; + struct lock i_lock; /* node lock */ long iso_extent; /* extent of file */ long i_size; @@ -101,19 +98,11 @@ struct iso_node { #define i_back i_chain[1] /* flags */ -#define ILOCKED 0x0001 /* inode is locked */ -#define IWANT 0x0002 /* some process waiting on lock */ -#define IACC 0x0020 /* inode access time to be updated */ +#define IN_ACCESS 0x0020 /* inode access time to be updated */ #define VTOI(vp) ((struct iso_node *)(vp)->v_data) #define ITOV(ip) ((ip)->i_vnode) -#define ISO_ILOCK(ip) iso_ilock(ip) -#define ISO_IUNLOCK(ip) iso_iunlock(ip) - -extern vop_t **cd9660_fifoop_p; -extern vop_t **cd9660_specop_p; - /* * Prototypes for ISOFS vnode operations */ @@ -121,14 +110,19 @@ int cd9660_lookup __P((struct vop_lookup_args *)); int cd9660_inactive __P((struct vop_inactive_args *)); int cd9660_reclaim __P((struct vop_reclaim_args *)); int cd9660_bmap __P((struct vop_bmap_args *)); +int cd9660_pathconf __P((struct vop_pathconf_args *)); +int cd9660_blkatoff __P((struct vop_blkatoff_args *)); +#define cd9660_revoke vop_revoke + void cd9660_defattr __P((struct iso_directory_record *, struct iso_node *, struct buf *, enum ISO_FTYPE)); void cd9660_deftstamp __P((struct iso_directory_record *, struct iso_node *, struct buf *, enum ISO_FTYPE)); -int cd9660_tstamp_conv7 __P((char *pi, struct timespec *pu, enum ISO_FTYPE)); -int cd9660_tstamp_conv17 __P((unsigned char *pi, struct timespec *pu)); -void isodirino __P((ino_t *inump, struct iso_directory_record *isodir, - struct iso_mnt *imp)); +struct vnode *cd9660_ihashget __P((dev_t, ino_t)); +void cd9660_ihashins __P((struct iso_node *)); +void cd9660_ihashrem __P((struct iso_node *)); +int cd9660_tstamp_conv7 __P((u_char *, struct timespec *, enum ISO_FTYPE)); +int cd9660_tstamp_conv17 __P((u_char *, struct timespec *)); #ifdef ISODEVMAP struct iso_dnode *iso_dmap __P((dev_t, ino_t, int)); void iso_dunmap __P((dev_t)); diff --git a/sys/fs/cd9660/cd9660_rrip.c b/sys/fs/cd9660/cd9660_rrip.c index 44d52eb..521094f 100644 --- a/sys/fs/cd9660/cd9660_rrip.c +++ b/sys/fs/cd9660/cd9660_rrip.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)cd9660_rrip.c 8.2 (Berkeley) 1/23/94 + * @(#)cd9660_rrip.c 8.6 (Berkeley) 12/5/94 * $FreeBSD$ */ @@ -104,10 +104,10 @@ cd9660_rrip_attr(p,ana) ISO_RRIP_ATTR *p; ISO_RRIP_ANALYZE *ana; { - ana->inop->inode.iso_mode = isonum_731(p->mode_l); - ana->inop->inode.iso_uid = (uid_t)isonum_731(p->uid_l); - ana->inop->inode.iso_gid = (gid_t)isonum_731(p->gid_l); - ana->inop->inode.iso_links = isonum_731(p->links_l); + ana->inop->inode.iso_mode = isonum_733(p->mode); + ana->inop->inode.iso_uid = isonum_733(p->uid); + ana->inop->inode.iso_gid = isonum_733(p->gid); + ana->inop->inode.iso_links = isonum_733(p->links); ana->fields &= ~ISO_SUSP_ATTR; return ISO_SUSP_ATTR; } @@ -352,8 +352,8 @@ cd9660_rrip_tstamp(p,ana) ISO_RRIP_TSTAMP *p; ISO_RRIP_ANALYZE *ana; { - unsigned char *ptime; - + u_char *ptime; + ptime = p->time; /* Check a format of time stamp (7bytes/17bytes) */ @@ -367,7 +367,7 @@ cd9660_rrip_tstamp(p,ana) ptime += 7; } else bzero(&ana->inop->inode.iso_mtime,sizeof(struct timespec)); - + if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) { cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_atime, ISO_FTYPE_RRIP); @@ -390,7 +390,7 @@ cd9660_rrip_tstamp(p,ana) ptime += 17; } else bzero(&ana->inop->inode.iso_mtime,sizeof(struct timespec)); - + if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) { cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_atime); ptime += 17; @@ -423,16 +423,15 @@ cd9660_rrip_device(p,ana) ISO_RRIP_DEVICE *p; ISO_RRIP_ANALYZE *ana; { - unsigned high, low; - - high = isonum_733(p->dev_t_high_l); - low = isonum_733(p->dev_t_low_l); - - if ( high == 0 ) { - ana->inop->inode.iso_rdev = makedev( major(low), minor(low) ); - } else { - ana->inop->inode.iso_rdev = makedev( high, minor(low) ); - } + u_int high, low; + + high = isonum_733(p->dev_t_high); + low = isonum_733(p->dev_t_low); + + if (high == 0) + ana->inop->inode.iso_rdev = makedev(major(low), minor(low)); + else + ana->inop->inode.iso_rdev = makedev(high, minor(low)); ana->fields &= ~ISO_SUSP_DEVICE; return ISO_SUSP_DEVICE; } @@ -475,8 +474,6 @@ cd9660_rrip_stop(p,ana) ISO_SUSP_HEADER *p; ISO_RRIP_ANALYZE *ana; { - /* stop analyzing */ - ana->fields = 0; return ISO_SUSP_STOP; } @@ -545,22 +542,30 @@ cd9660_rrip_loop(isodir,ana,table) if (!ana->fields) break; } + if (result&ISO_SUSP_STOP) { + result &= ~ISO_SUSP_STOP; + break; + } + /* plausibility check */ + if (isonum_711(phead->length) < sizeof(*phead)) + break; /* * move to next SUSP * Hopefully this works with newer versions, too */ phead = (ISO_SUSP_HEADER *)((char *)phead + isonum_711(phead->length)); } - - if ( ana->fields && ana->iso_ce_len ) { + + if (ana->fields && ana->iso_ce_len) { if (ana->iso_ce_blk >= ana->imp->volume_space_size || ana->iso_ce_off + ana->iso_ce_len > ana->imp->logical_block_size || bread(ana->imp->im_devvp, - iso_lblktodaddr(ana->imp, ana->iso_ce_blk), - ana->imp->logical_block_size,NOCRED,&bp)) + ana->iso_ce_blk << + (ana->imp->im_bshift - DEV_BSHIFT), + ana->imp->logical_block_size, NOCRED, &bp)) /* what to do now? */ break; - phead = (ISO_SUSP_HEADER *)(bp->b_un.b_addr + ana->iso_ce_off); + phead = (ISO_SUSP_HEADER *)(bp->b_data + ana->iso_ce_off); pend = (ISO_SUSP_HEADER *) ((char *)phead + ana->iso_ce_len); } else break; @@ -569,7 +574,7 @@ cd9660_rrip_loop(isodir,ana,table) brelse(bp); /* * If we don't find the Basic SUSP stuffs, just set default value - * ( attribute/time stamp ) + * (attribute/time stamp) */ for (ptable = table; ptable->func2; ptable++) if (!(ptable->result&result)) @@ -579,6 +584,9 @@ cd9660_rrip_loop(isodir,ana,table) } /* + * Get Attributes. + */ +/* * XXX the casts are bogus but will do for now. */ #define BC (rrt_func_t *) @@ -607,10 +615,8 @@ cd9660_rrip_analyze(isodir,inop,imp) return cd9660_rrip_loop(isodir,&analyze,rrip_table_analyze); } -/* - * Get Alternate Name from 'AL' record - * If either no AL record or 0 length, - * it will be return the translated ISO9660 name, +/* + * Get Alternate Name. */ static RRIP_TABLE rrip_table_getname[] = { { "NM", BC cd9660_rrip_altname, cd9660_rrip_defname, ISO_SUSP_ALTNAME }, @@ -654,10 +660,8 @@ cd9660_rrip_getname(isodir,outbuf,outlen,inump,imp) return cd9660_rrip_loop(isodir,&analyze,tab); } -/* - * Get Symbolic Name from 'SL' record - * - * Note: isodir should contains SL record! +/* + * Get Symbolic Link. */ static RRIP_TABLE rrip_table_getsymname[] = { { "SL", BC cd9660_rrip_slink, 0, ISO_SUSP_SLINK }, @@ -696,7 +700,7 @@ static RRIP_TABLE rrip_table_extref[] = { /* * Check for Rock Ridge Extension and return offset of its fields. - * Note: We require the ER field. + * Note: We insist on the ER field. */ int cd9660_rrip_offset(isodir,imp) diff --git a/sys/fs/cd9660/cd9660_rrip.h b/sys/fs/cd9660/cd9660_rrip.h index e65fb3b..cacee39 100644 --- a/sys/fs/cd9660/cd9660_rrip.h +++ b/sys/fs/cd9660/cd9660_rrip.h @@ -35,36 +35,30 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)cd9660_rrip.h 8.1 (Berkeley) 1/21/94 - * $FreeBSD$ + * @(#)cd9660_rrip.h 8.2 (Berkeley) 12/5/94 + * $Id: cd9660_rrip.h,v 1.3.2000.1 1996/09/30 12:46:48 dfr Exp $ */ - + typedef struct { - char type [ISODCL ( 0, 1)]; - unsigned char length [ISODCL ( 2, 2)]; /* 711 */ - unsigned char version [ISODCL ( 3, 3)]; + char type [ISODCL ( 0, 1)]; + u_char length [ISODCL ( 2, 2)]; /* 711 */ + u_char version [ISODCL ( 3, 3)]; } ISO_SUSP_HEADER; - + typedef struct { ISO_SUSP_HEADER h; - char mode_l [ISODCL ( 4, 7)]; /* 731 */ - char mode_m [ISODCL ( 8, 11)]; /* 732 */ - char links_l [ISODCL ( 12, 15)]; /* 731 */ - char links_m [ISODCL ( 16, 19)]; /* 732 */ - char uid_l [ISODCL ( 20, 23)]; /* 731 */ - char uid_m [ISODCL ( 24, 27)]; /* 732 */ - char gid_l [ISODCL ( 28, 31)]; /* 731 */ - char gid_m [ISODCL ( 32, 35)]; /* 732 */ + char mode [ISODCL ( 4, 11)]; /* 733 */ + char links [ISODCL ( 12, 19)]; /* 733 */ + char uid [ISODCL ( 20, 27)]; /* 733 */ + char gid [ISODCL ( 28, 35)]; /* 733 */ } ISO_RRIP_ATTR; - + typedef struct { ISO_SUSP_HEADER h; - char dev_t_high_l [ISODCL ( 4, 7)]; /* 731 */ - char dev_t_high_m [ISODCL ( 8, 11)]; /* 732 */ - char dev_t_low_l [ISODCL ( 12, 15)]; /* 731 */ - char dev_t_low_m [ISODCL ( 16, 19)]; /* 732 */ + char dev_t_high [ISODCL ( 4, 11)]; /* 733 */ + char dev_t_low [ISODCL ( 12, 19)]; /* 733 */ } ISO_RRIP_DEVICE; - + #define ISO_SUSP_CFLAG_CONTINUE 0x01 #define ISO_SUSP_CFLAG_CURRENT 0x02 #define ISO_SUSP_CFLAG_PARENT 0x04 @@ -73,9 +67,9 @@ typedef struct { #define ISO_SUSP_CFLAG_HOST 0x20 typedef struct { - u_char cflag [ISODCL ( 1, 1)]; - u_char clen [ISODCL ( 2, 2)]; - u_char name [0]; + u_char cflag [ISODCL ( 1, 1)]; + u_char clen [ISODCL ( 2, 2)]; + u_char name [1]; /* XXX */ } ISO_RRIP_SLINK_COMPONENT; #define ISO_RRIP_SLSIZ 2 @@ -116,13 +110,13 @@ typedef struct { typedef struct { ISO_SUSP_HEADER h; - unsigned char flags [ISODCL ( 4, 4)]; - unsigned char time [ISODCL ( 5, 5)]; + u_char flags [ISODCL ( 4, 4)]; + u_char time [ISODCL ( 5, 5)]; } ISO_RRIP_TSTAMP; typedef struct { ISO_SUSP_HEADER h; - unsigned char flags [ISODCL ( 4, 4)]; + u_char flags [ISODCL ( 4, 4)]; } ISO_RRIP_IDFLAG; typedef struct { diff --git a/sys/fs/cd9660/cd9660_util.c b/sys/fs/cd9660/cd9660_util.c index 786d4fd..151d1c3 100644 --- a/sys/fs/cd9660/cd9660_util.c +++ b/sys/fs/cd9660/cd9660_util.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)cd9660_util.c 8.1 (Berkeley) 1/21/94 + * @(#)cd9660_util.c 8.3 (Berkeley) 12/5/94 * $FreeBSD$ */ @@ -58,104 +58,14 @@ #include -#ifdef __notanymore__ -int -isonum_711 (p) -unsigned char *p; -{ - return (*p); -} - -int -isonum_712 (p) -signed char *p; -{ - return (*p); -} - -int -isonum_721 (p) -unsigned char *p; -{ - /* little endian short */ -#if BYTE_ORDER != LITTLE_ENDIAN - printf ("isonum_721 called on non little-endian machine!\n"); -#endif - - return *(short *)p; -} - -int -isonum_722 (p) -unsigned char *p; -{ - /* big endian short */ -#if BYTE_ORDER != BIG_ENDIAN - printf ("isonum_722 called on non big-endian machine!\n"); -#endif - - return *(short *)p; -} - -int -isonum_723 (p) -unsigned char *p; -{ -#if BYTE_ORDER == BIG_ENDIAN - return isonum_722 (p + 2); -#elif BYTE_ORDER == LITTLE_ENDIAN - return isonum_721 (p); -#else - printf ("isonum_723 unsupported byte order!\n"); - return 0; -#endif -} - -int -isonum_731 (p) -unsigned char *p; -{ - /* little endian long */ -#if BYTE_ORDER != LITTLE_ENDIAN - printf ("isonum_731 called on non little-endian machine!\n"); -#endif - - return *(long *)p; -} - -int -isonum_732 (p) -unsigned char *p; -{ - /* big endian long */ -#if BYTE_ORDER != BIG_ENDIAN - printf ("isonum_732 called on non big-endian machine!\n"); -#endif - - return *(long *)p; -} - -int -isonum_733 (p) -unsigned char *p; -{ -#if BYTE_ORDER == BIG_ENDIAN - return isonum_732 (p + 4); -#elif BYTE_ORDER == LITTLE_ENDIAN - return isonum_731 (p); -#else - printf ("isonum_733 unsupported byte order!\n"); - return 0; -#endif -} -#endif /* __notanymore__ */ - /* * translate and compare a filename * Note: Version number plus ';' may be omitted. */ int -isofncmp(unsigned char *fn,int fnlen,unsigned char *isofn,int isolen) +isofncmp(fn, fnlen, isofn, isolen) + u_char *fn, *isofn; + int fnlen, isolen; { int i, j; unsigned char c; @@ -211,9 +121,12 @@ isofncmp(unsigned char *fn,int fnlen,unsigned char *isofn,int isolen) * translate a filename */ void -isofntrans(unsigned char *infn,int infnlen, - unsigned char *outfn,unsigned short *outfnlen, - int original,int assoc) +isofntrans(infn, infnlen, outfn, outfnlen, original, assoc) + u_char *infn, *outfn; + int infnlen; + u_short *outfnlen; + int original; + int assoc; { int fnidx = 0; diff --git a/sys/fs/cd9660/cd9660_vfsops.c b/sys/fs/cd9660/cd9660_vfsops.c index 752a7b4..15eade4 100644 --- a/sys/fs/cd9660/cd9660_vfsops.c +++ b/sys/fs/cd9660/cd9660_vfsops.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)cd9660_vfsops.c 8.3 (Berkeley) 1/31/94 + * @(#)cd9660_vfsops.c 8.18 (Berkeley) 5/22/95 * $FreeBSD$ */ @@ -52,10 +52,12 @@ #include #include #include +#include #include -#include #include +#include +#include static int cd9660_mount __P((struct mount *, @@ -84,17 +86,14 @@ static struct vfsops cd9660_vfsops = { cd9660_vget, cd9660_fhtovp, cd9660_vptofh, - cd9660_init, + cd9660_init }; VFS_SET(cd9660_vfsops, cd9660, MOUNT_CD9660, VFCF_READONLY); /* * Called by vfs_mountroot when iso is going to be mounted as root. - * - * Name is updated by mount(8) after booting. */ -#define ROOTNAME "root_device" static int iso_mountfs __P((struct vnode *devvp, struct mount *mp, struct proc *p, struct iso_args *argp)); @@ -102,55 +101,38 @@ static int iso_mountfs __P((struct vnode *devvp, struct mount *mp, int cd9660_mountroot() { - register struct mount *mp; + struct mount *mp; struct proc *p = curproc; /* XXX */ - struct iso_mnt *imp; - u_int size; - int error; struct iso_args args; - + int error; + /* * Get vnode for rootdev. */ - if (bdevvp(rootdev, &rootvp)) - panic("cd9660_mountroot: can't setup bdevvp for rootdev"); - - mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); - bzero((char *)mp, (u_long)sizeof(struct mount)); - mp->mnt_op = &cd9660_vfsops; - mp->mnt_flag = MNT_RDONLY; - args.flags = ISOFSMNT_ROOT; - if ((error = iso_mountfs(rootvp, mp, p, &args))) { - free(mp, M_MOUNT); + if ((error = bdevvp(swapdev, &swapdev_vp)) || + (error = bdevvp(rootdev, &rootvp))) { + printf("cd9660_mountroot: can't setup bdevvp's"); return (error); } - if ((error = vfs_lock(mp))) { - (void)cd9660_unmount(mp, 0, p); + + if (error = vfs_rootmountalloc("cd9660", "root_device", &mp)) + return (error); + args.flags = ISOFSMNT_ROOT; + if (error = iso_mountfs(rootvp, mp, p, &args)) { + mp->mnt_vfc->vfc_refcount--; + vfs_unbusy(mp, p); free(mp, M_MOUNT); return (error); } + simple_lock(&mountlist_slock); CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); - mp->mnt_flag |= MNT_ROOTFS; - mp->mnt_vnodecovered = NULLVP; - imp = VFSTOISOFS(mp); - bzero(imp->im_fsmnt, sizeof(imp->im_fsmnt)); - imp->im_fsmnt[0] = '/'; - bcopy((caddr_t)imp->im_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, - MNAMELEN); - (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, - &size); - bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); - (void) cd9660_statfs(mp, &mp->mnt_stat, p); - vfs_unlock(mp); + simple_unlock(&mountlist_slock); + (void)cd9660_statfs(mp, &mp->mnt_stat, p); + vfs_unbusy(mp, p); return (0); } /* - * Flag to allow forcible unmounting. - */ -static int iso_doforce = 1; - -/* * VFS Operations. * * mount system call @@ -214,10 +196,8 @@ cd9660_mount(mp, path, data, ndp, p) return error; } imp = VFSTOISOFS(mp); - (void) copyinstr(path, imp->im_fsmnt, sizeof(imp->im_fsmnt)-1, &size); - bzero(imp->im_fsmnt + size, sizeof(imp->im_fsmnt) - size); - bcopy((caddr_t)imp->im_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, - MNAMELEN); + (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); + bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); @@ -277,11 +257,11 @@ iso_mountfs(devvp, mp, p, argp) iso_bsize = ISO_DEFAULT_BLOCK_SIZE; for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) { - if ((error = bread (devvp, btodb(iso_blknum * iso_bsize), - iso_bsize, NOCRED, &bp))) + if (error = bread(devvp, iso_blknum * btodb(iso_bsize), + iso_bsize, NOCRED, &bp)) goto out; - - vdp = (struct iso_volume_descriptor *)bp->b_un.b_addr; + + vdp = (struct iso_volume_descriptor *)bp->b_data; if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) { if (bcmp (vdp->id_sierra, ISO_SIERRA_ID, sizeof vdp->id) != 0) { @@ -347,7 +327,7 @@ iso_mountfs(devvp, mp, p, argp) mp->mnt_data = (qaddr_t)isomp; mp->mnt_stat.f_fsid.val[0] = (long)dev; - mp->mnt_stat.f_fsid.val[1] = MOUNT_CD9660; + mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; mp->mnt_maxsymlinklen = 0; mp->mnt_flag |= MNT_LOCAL; isomp->im_mountp = mp; @@ -358,14 +338,14 @@ iso_mountfs(devvp, mp, p, argp) /* Check the Rock Ridge Extention support */ if (!(argp->flags & ISOFSMNT_NORRIP)) { - if ((error = bread (isomp->im_devvp, - (isomp->root_extent + isonum_711(rootp->ext_attr_length)) - * isomp->logical_block_size / DEV_BSIZE, - isomp->logical_block_size,NOCRED,&bp))) + if (error = bread(isomp->im_devvp, + (isomp->root_extent + isonum_711(rootp->ext_attr_length)) << + (isomp->im_bshift - DEV_BSHIFT), + isomp->logical_block_size, NOCRED, &bp)) goto out; - - rootp = (struct iso_directory_record *)bp->b_un.b_addr; - + + rootp = (struct iso_directory_record *)bp->b_data; + if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) { argp->flags |= ISOFSMNT_NORRIP; } else { @@ -436,12 +416,9 @@ cd9660_unmount(mp, mntflags, p) { register struct iso_mnt *isomp; int error, flags = 0; - - if (mntflags & MNT_FORCE) { - if (!iso_doforce) - return (EINVAL); + + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } #if 0 mntflushbuf(mp, 0); if (mntinvalbuf(mp)) @@ -474,33 +451,17 @@ cd9660_root(mp, vpp) struct mount *mp; struct vnode **vpp; { - register struct iso_node *ip; - struct iso_node tip, *nip; - struct vnode tvp; - int error; - struct iso_mnt *imp = VFSTOISOFS (mp); - struct iso_directory_record *dp; - - tvp.v_mount = mp; - tvp.v_data = &tip; - ip = VTOI(&tvp); - ip->i_vnode = &tvp; - ip->i_dev = imp->im_dev; - ip->i_diroff = 0; - dp = (struct iso_directory_record *)imp->root; - isodirino(&ip->i_number,dp,imp); - + struct iso_mnt *imp = VFSTOISOFS(mp); + struct iso_directory_record *dp = + (struct iso_directory_record *)imp->root; + ino_t ino = isodirino(dp, imp); + /* * With RRIP we must use the `.' entry of the root directory. - * Simply tell iget, that it's a relocated directory. + * Simply tell vget, that it's a relocated directory. */ - error = iso_iget(ip,ip->i_number, - imp->iso_ftype == ISO_FTYPE_RRIP, - &nip,dp); - if (error) - return error; - *vpp = ITOV(nip); - return 0; + return (cd9660_vget_internal(mp, ino, vpp, + imp->iso_ftype == ISO_FTYPE_RRIP, dp)); } /* @@ -541,10 +502,8 @@ cd9660_statfs(mp, sbp, p) sbp->f_files = 0; /* total files */ sbp->f_ffree = 0; /* free file nodes */ if (sbp != &mp->mnt_stat) { - bcopy((caddr_t)mp->mnt_stat.f_mntonname, - (caddr_t)&sbp->f_mntonname[0], MNAMELEN); - bcopy((caddr_t)mp->mnt_stat.f_mntfromname, - (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); + bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); + bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); } /* Use the first spare for flags: */ sbp->f_spare[0] = isomp->im_flags; @@ -563,21 +522,6 @@ cd9660_sync(mp, waitfor, cred, p) } /* - * Flat namespace lookup. - * Currently unsupported. - */ -/* ARGSUSED */ -static int -cd9660_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - - return (EOPNOTSUPP); -} - -/* * File handle to vnode * * Have to be really careful about stale file handles: @@ -604,92 +548,262 @@ cd9660_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) int *exflagsp; struct ucred **credanonp; { - struct vnode tvp; - int error; - int lbn, off; - struct ifid *ifhp; - struct iso_mnt *imp; - struct buf *bp; - struct iso_directory_record *dirp; - struct iso_node tip, *ip, *nip; - struct netcred *np; - - imp = VFSTOISOFS (mp); - ifhp = (struct ifid *)fhp; - + struct ifid *ifhp = (struct ifid *)fhp; + register struct iso_node *ip; + register struct netcred *np; + register struct iso_mnt *imp = VFSTOISOFS(mp); + struct vnode *nvp; + int error; + #ifdef ISOFS_DBG printf("fhtovp: ino %d, start %ld\n", ifhp->ifid_ino, ifhp->ifid_start); #endif - + + /* + * Get the export permission structure for this tuple. + */ np = vfs_export_lookup(mp, &imp->im_export, nam); if (np == NULL) return (EACCES); - lbn = iso_lblkno(imp, ifhp->ifid_ino); - if (lbn >= imp->volume_space_size) { - printf("fhtovp: lbn exceed volume space %d\n", lbn); - return (ESTALE); + if (error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) { + *vpp = NULLVP; + return (error); } - - off = iso_blkoff(imp, ifhp->ifid_ino); - if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) { - printf("fhtovp: crosses block boundary %d\n", - off + ISO_DIRECTORY_RECORD_SIZE); + ip = VTOI(nvp); + if (ip->inode.iso_mode == 0) { + vput(nvp); + *vpp = NULLVP; return (ESTALE); } + *vpp = nvp; + *exflagsp = np->netc_exflags; + *credanonp = &np->netc_anon; + return (0); +} - error = bread(imp->im_devvp, btodb(lbn * imp->logical_block_size), - imp->logical_block_size, NOCRED, &bp); - if (error) { - printf("fhtovp: bread error %d\n",error); - brelse(bp); +int +cd9660_vget(mp, ino, vpp) + struct mount *mp; + ino_t ino; + struct vnode **vpp; +{ + + /* + * XXXX + * It would be nice if we didn't always set the `relocated' flag + * and force the extra read, but I don't want to think about fixing + * that right now. + */ + return (cd9660_vget_internal(mp, ino, vpp, +#if 0 + VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP, +#else + 0, +#endif + (struct iso_directory_record *)0)); +} + +int +cd9660_vget_internal(mp, ino, vpp, relocated, isodir) + struct mount *mp; + ino_t ino; + struct vnode **vpp; + int relocated; + struct iso_directory_record *isodir; +{ + struct iso_mnt *imp; + struct iso_node *ip; + struct buf *bp; + struct vnode *vp, *nvp; + dev_t dev; + int error; + + imp = VFSTOISOFS(mp); + dev = imp->im_dev; + if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP) + return (0); + + /* Allocate a new vnode/iso_node. */ + if (error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, &vp)) { + *vpp = NULLVP; return (error); } + MALLOC(ip, struct iso_node *, sizeof(struct iso_node), M_ISOFSNODE, + M_WAITOK); + bzero((caddr_t)ip, sizeof(struct iso_node)); + lockinit(&ip->i_lock, PINOD, "isonode", 0, 0); + vp->v_data = ip; + ip->i_vnode = vp; + ip->i_dev = dev; + ip->i_number = ino; - dirp = (struct iso_directory_record *)(bp->b_un.b_addr + off); - if (off + isonum_711(dirp->length) > imp->logical_block_size) { - brelse(bp); - printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n", - off+isonum_711(dirp->length), off, - isonum_711(dirp->length)); - return (ESTALE); + /* + * Put it onto its hash chain and lock it so that other requests for + * this inode will block if they arrive while we are sleeping waiting + * for old data structures to be purged or for the contents of the + * disk portion of this inode to be read. + */ + cd9660_ihashins(ip); + + if (isodir == 0) { + int lbn, off; + + lbn = lblkno(imp, ino); + if (lbn >= imp->volume_space_size) { + vput(vp); + printf("fhtovp: lbn exceed volume space %d\n", lbn); + return (ESTALE); + } + + off = blkoff(imp, ino); + if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) { + vput(vp); + printf("fhtovp: crosses block boundary %d\n", + off + ISO_DIRECTORY_RECORD_SIZE); + return (ESTALE); + } + + error = bread(imp->im_devvp, + lbn << (imp->im_bshift - DEV_BSHIFT), + imp->logical_block_size, NOCRED, &bp); + if (error) { + vput(vp); + brelse(bp); + printf("fhtovp: bread error %d\n",error); + return (error); + } + isodir = (struct iso_directory_record *)(bp->b_data + off); + + if (off + isonum_711(isodir->length) > + imp->logical_block_size) { + vput(vp); + if (bp != 0) + brelse(bp); + printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n", + off +isonum_711(isodir->length), off, + isonum_711(isodir->length)); + return (ESTALE); + } + +#if 0 + if (isonum_733(isodir->extent) + + isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) { + if (bp != 0) + brelse(bp); + printf("fhtovp: file start miss %d vs %d\n", + isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length), + ifhp->ifid_start); + return (ESTALE); + } +#endif + } else + bp = 0; + + ip->i_mnt = imp; + ip->i_devvp = imp->im_devvp; + VREF(ip->i_devvp); + + if (relocated) { + /* + * On relocated directories we must + * read the `.' entry out of a dir. + */ + ip->iso_start = ino >> imp->im_bshift; + if (bp != 0) + brelse(bp); + if (error = VOP_BLKATOFF(vp, (off_t)0, NULL, &bp)) { + vput(vp); + return (error); + } + isodir = (struct iso_directory_record *)bp->b_data; } - if (isonum_733(dirp->extent) + isonum_711(dirp->ext_attr_length) != - ifhp->ifid_start) { - brelse(bp); - printf("fhtovp: file start miss %d vs %ld\n", - isonum_733(dirp->extent)+isonum_711(dirp->ext_attr_length), - ifhp->ifid_start); - return (ESTALE); + ip->iso_extent = isonum_733(isodir->extent); + ip->i_size = isonum_733(isodir->size); + ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent; + + /* + * Setup time stamp, attribute + */ + vp->v_type = VNON; + switch (imp->iso_ftype) { + default: /* ISO_FTYPE_9660 */ + { + struct buf *bp2; + int off; + if ((imp->im_flags & ISOFSMNT_EXTATT) + && (off = isonum_711(isodir->ext_attr_length))) + VOP_BLKATOFF(vp, (off_t)-(off << imp->im_bshift), NULL, + &bp2); + else + bp2 = NULL; + cd9660_defattr(isodir, ip, bp2, ISO_FTYPE_9660); + cd9660_deftstamp(isodir, ip, bp2, ISO_FTYPE_9660); + if (bp2) + brelse(bp2); + break; + } + case ISO_FTYPE_RRIP: + cd9660_rrip_analyze(isodir, ip, imp); + break; } - brelse(bp); - ip = &tip; - tvp.v_mount = mp; - tvp.v_data = ip; - ip->i_vnode = &tvp; - ip->i_dev = imp->im_dev; - if ((error = iso_iget(ip, ifhp->ifid_ino, 0, &nip, dirp))) { - *vpp = NULLVP; - printf("fhtovp: failed to get inode\n"); - return (error); + if (bp != 0) + brelse(bp); + + /* + * Initialize the associated vnode + */ + switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) { + case VFIFO: +#ifdef FIFO + vp->v_op = cd9660_fifoop_p; + break; +#else + vput(vp); + return (EOPNOTSUPP); +#endif /* FIFO */ + case VCHR: + case VBLK: + /* + * if device, look at device number table for translation + */ +#ifdef ISODEVMAP + if (dp = iso_dmap(dev, ino, 0)) + ip->inode.iso_rdev = dp->d_dev; +#endif + vp->v_op = cd9660_specop_p; + if (nvp = checkalias(vp, ip->inode.iso_rdev, mp)) { + /* + * Discard unneeded vnode, but save its iso_node. + * Note that the lock is carried over in the iso_node + * to the replacement vnode. + */ + nvp->v_data = vp->v_data; + vp->v_data = NULL; + vp->v_op = spec_vnodeop_p; + vrele(vp); + vgone(vp); + /* + * Reinitialize aliased inode. + */ + vp = nvp; + ip->i_vnode = vp; + } + break; } - ip = nip; + + if (ip->iso_extent == imp->root_extent) + vp->v_flag |= VROOT; + /* * XXX need generation number? */ - if (ip->inode.iso_mode == 0) { - iso_iput(ip); - *vpp = NULLVP; - printf("fhtovp: inode mode == 0\n"); - return (ESTALE); - } - *vpp = ITOV(ip); - *exflagsp = np->netc_exflags; - *credanonp = &np->netc_anon; - return 0; + + *vpp = vp; + return (0); } /* diff --git a/sys/fs/cd9660/cd9660_vnops.c b/sys/fs/cd9660/cd9660_vnops.c index 88440eb..854d6b5 100644 --- a/sys/fs/cd9660/cd9660_vnops.c +++ b/sys/fs/cd9660/cd9660_vnops.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)cd9660_vnops.c 8.3 (Berkeley) 1/23/94 + * @(#)cd9660_vnops.c 8.19 (Berkeley) 5/27/95 * $FreeBSD$ */ @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -81,7 +82,6 @@ static int cd9660_lock __P((struct vop_lock_args *)); static int cd9660_unlock __P((struct vop_unlock_args *)); static int cd9660_strategy __P((struct vop_strategy_args *)); static int cd9660_print __P((struct vop_print_args *)); -static int cd9660_enotsupp __P((void)); static int cd9660_islocked __P((struct vop_islocked_args *)); #if 0 @@ -100,7 +100,7 @@ cd9660_mknod(ndp, vap, cred, p) free(ndp->ni_pnbuf, M_NAMEI); vput(ndp->ni_dvp); vput(ndp->ni_vp); - return EINVAL; + return (EINVAL); #else register struct vnode *vp; struct iso_node *ip; @@ -116,7 +116,7 @@ cd9660_mknod(ndp, vap, cred, p) free(ndp->ni_pnbuf, M_NAMEI); vput(ndp->ni_dvp); vput(ndp->ni_vp); - return EINVAL; + return (EINVAL); } dp = iso_dmap(ip->i_dev,ip->i_number,1); @@ -144,7 +144,7 @@ cd9660_mknod(ndp, vap, cred, p) /* * Setattr call. Only allowed for block and character special devices. */ -static int +int cd9660_setattr(ap) struct vop_setattr_args /* { struct vnodeop_desc *a_desc; @@ -175,7 +175,7 @@ cd9660_setattr(ap) return (0); } } - return (EOPNOTSUPP); + return (0); } /* @@ -229,23 +229,65 @@ cd9660_access(ap) struct proc *a_p; } */ *ap; { + struct vnode *vp = ap->a_vp; + struct iso_node *ip = VTOI(vp); + struct ucred *cred = ap->a_cred; + mode_t mask, mode = ap->a_mode; + gid_t *gp; + int i; + /* - * Disallow write attempts on read-only file systems; - * unless the file is a socket, fifo, or a block or - * character device resident on the file system. + * Disallow write attempts unless the file is a socket, + * fifo, or a block or character device resident on the + * file system. */ - if (ap->a_mode & VWRITE) { - switch (ap->a_vp->v_type) { + if (mode & VWRITE) { + switch (vp->v_type) { case VDIR: case VLNK: case VREG: - if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - break; + return (EROFS); } } - return (0); + /* User id 0 always gets access. */ + if (cred->cr_uid == 0) + return (0); + + mask = 0; + + /* Otherwise, check the owner. */ + if (cred->cr_uid == ip->inode.iso_uid) { + if (mode & VEXEC) + mask |= S_IXUSR; + if (mode & VREAD) + mask |= S_IRUSR; + if (mode & VWRITE) + mask |= S_IWUSR; + return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES); + } + + /* Otherwise, check the groups. */ + for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) + if (ip->inode.iso_gid == *gp) { + if (mode & VEXEC) + mask |= S_IXGRP; + if (mode & VREAD) + mask |= S_IRGRP; + if (mode & VWRITE) + mask |= S_IWGRP; + return ((ip->inode.iso_mode & mask) == mask ? + 0 : EACCES); + } + + /* Otherwise, check everyone else. */ + if (mode & VEXEC) + mask |= S_IXOTH; + if (mode & VREAD) + mask |= S_IROTH; + if (mode & VWRITE) + mask |= S_IWOTH; + return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES); } static int @@ -275,6 +317,29 @@ cd9660_getattr(ap) vap->va_rdev = ip->inode.iso_rdev; vap->va_size = (u_quad_t) ip->i_size; + if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) { + struct vop_readlink_args rdlnk; + struct iovec aiov; + struct uio auio; + char *cp; + + MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK); + aiov.iov_base = cp; + aiov.iov_len = MAXPATHLEN; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_procp = ap->a_p; + auio.uio_resid = MAXPATHLEN; + rdlnk.a_uio = &auio; + rdlnk.a_vp = ap->a_vp; + rdlnk.a_cred = ap->a_cred; + if (cd9660_readlink(&rdlnk) == 0) + vap->va_size = MAXPATHLEN - auio.uio_resid; + FREE(cp, M_TEMP); + } vap->va_flags = 0; vap->va_gen = 1; vap->va_blocksize = ip->i_mnt->logical_block_size; @@ -325,31 +390,31 @@ cd9660_read(ap) return (0); if (uio->uio_offset < 0) return (EINVAL); - ip->i_flag |= IACC; + ip->i_flag |= IN_ACCESS; imp = ip->i_mnt; do { - lbn = iso_lblkno(imp, uio->uio_offset); - on = iso_blkoff(imp, uio->uio_offset); - n = min((unsigned)(imp->logical_block_size - on), + lbn = lblkno(imp, uio->uio_offset); + on = blkoff(imp, uio->uio_offset); + n = min((u_int)(imp->logical_block_size - on), uio->uio_resid); diff = (off_t)ip->i_size - uio->uio_offset; if (diff <= 0) return (0); if (diff < n) n = diff; - size = iso_blksize(imp, ip, lbn); + size = blksize(imp, ip, lbn); rablock = lbn + 1; if (doclusterread) { - if (iso_lblktosize(imp, rablock) <= ip->i_size) - error = cluster_read(vp, ip->i_size, + if (lblktosize(imp, rablock) <= ip->i_size) + error = cluster_read(vp, (off_t)ip->i_size, lbn, size, NOCRED, uio->uio_resid, (ap->a_ioflag >> 16), &bp); else error = bread(vp, lbn, size, NOCRED, &bp); } else { if (vp->v_lastr + 1 == lbn && - iso_lblktosize(imp, rablock) < ip->i_size) { - rasize = iso_blksize(imp, ip, rablock); + lblktosize(imp, rablock) < ip->i_size) { + rasize = blksize(imp, ip, rablock); error = breadn(vp, lbn, size, &rablock, &rasize, 1, NOCRED, &bp); } else @@ -362,7 +427,10 @@ cd9660_read(ap) return (error); } - error = uiomove(bp->b_un.b_addr + on, (int)n, uio); + error = uiomove(bp->b_data + on, (int)n, uio); + if (n + on == imp->logical_block_size || + uio->uio_offset == (off_t)ip->i_size) + bp->b_flags |= B_AGE; brelse(bp); } while (error == 0 && uio->uio_resid > 0 && n != 0); return (error); @@ -373,8 +441,8 @@ static int cd9660_ioctl(ap) struct vop_ioctl_args /* { struct vnode *a_vp; - int a_command; - caddr_t a_data; + u_long a_command; + caddr_t a_data; int a_fflag; struct ucred *a_cred; struct proc *a_p; @@ -452,12 +520,12 @@ struct isoreaddir { off_t curroff; struct uio *uio; off_t uio_off; - u_int *cookiep; + int eofflag; + u_long *cookies; int ncookies; - int eof; }; -static int +int iso_uiodir(idp,dp,off) struct isoreaddir *idp; struct dirent *dp; @@ -469,27 +537,27 @@ iso_uiodir(idp,dp,off) dp->d_reclen = DIRSIZ(dp); if (idp->uio->uio_resid < dp->d_reclen) { - idp->eof = 0; - return -1; + idp->eofflag = 0; + return (-1); } - if (idp->cookiep) { + if (idp->cookies) { if (idp->ncookies <= 0) { - idp->eof = 0; - return -1; + idp->eofflag = 0; + return (-1); } - *idp->cookiep++ = off; + *idp->cookies++ = off; --idp->ncookies; } - if ((error = uiomove((caddr_t)dp,dp->d_reclen,idp->uio))) - return error; + if (error = uiomove((caddr_t) dp,dp->d_reclen,idp->uio)) + return (error); idp->uio_off = off; - return 0; + return (0); } -static int +int iso_shipdir(idp) struct isoreaddir *idp; { @@ -517,13 +585,13 @@ assoc = (cl > 1) && (*cname == ASSOCCHAR); if (sl != cl || bcmp(sname,cname,sl)) { if (idp->assocent.d_namlen) { - if ((error = iso_uiodir(idp,&idp->assocent,idp->assocoff))) - return error; + if (error = iso_uiodir(idp,&idp->assocent,idp->assocoff)) + return (error); idp->assocent.d_namlen = 0; } if (idp->saveent.d_namlen) { - if ((error = iso_uiodir(idp,&idp->saveent,idp->saveoff))) - return error; + if (error = iso_uiodir(idp,&idp->saveent,idp->saveoff)) + return (error); idp->saveent.d_namlen = 0; } } @@ -536,13 +604,11 @@ assoc = (cl > 1) && (*cname == ASSOCCHAR); idp->saveoff = idp->curroff; bcopy(&idp->current,&idp->saveent,idp->current.d_reclen); } - return 0; + return (0); } /* * Vnode op for readdir - * XXX make sure everything still works now that eofflagp and cookiep - * are no longer args. */ static int cd9660_readdir(ap) @@ -550,54 +616,61 @@ cd9660_readdir(ap) struct vnode *a_vp; struct uio *a_uio; struct ucred *a_cred; + int *a_eofflag; + int *a_ncookies; + u_long *a_cookies; } */ *ap; { register struct uio *uio = ap->a_uio; struct isoreaddir *idp; + struct vnode *vdp = ap->a_vp; + struct iso_node *dp; + struct iso_mnt *imp; + struct buf *bp = NULL; + struct iso_directory_record *ep; int entryoffsetinblock; + doff_t endsearch; + u_long bmask; int error = 0; - int endsearch; - struct iso_directory_record *ep; - u_short elen; - int namlen; int reclen; - int isoflags; - struct iso_mnt *imp; - struct iso_node *ip; - struct buf *bp = NULL; - u_short tmplen; + u_short namelen; int ncookies = 0; - u_int *cookies = NULL; + u_long *cookies = NULL; - ip = VTOI(ap->a_vp); - imp = ip->i_mnt; + dp = VTOI(vdp); + imp = dp->i_mnt; + bmask = imp->im_bmask; - MALLOC(idp,struct isoreaddir *,sizeof(*idp),M_TEMP,M_WAITOK); - idp->saveent.d_namlen = 0; - idp->assocent.d_namlen = 0; + MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK); + idp->saveent.d_namlen = idp->assocent.d_namlen = 0; + /* + * XXX + * Is it worth trying to figure out the type? + */ + idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type = + DT_UNKNOWN; idp->uio = uio; - if (ap->a_ncookies != NULL) { + if (ap->a_ncookies == NULL) { + idp->cookies = NULL; + } else { /* * Guess the number of cookies needed. */ ncookies = uio->uio_resid / 16; - MALLOC(cookies, u_int *, ncookies * sizeof(u_int), M_TEMP, M_WAITOK); - idp->cookiep = cookies; + MALLOC(cookies, u_long *, ncookies * sizeof(u_int), M_TEMP, + M_WAITOK); + idp->cookies = cookies; idp->ncookies = ncookies; - } else - idp->cookiep = 0; - idp->eof = 0; + } + idp->eofflag = 1; idp->curroff = uio->uio_offset; - entryoffsetinblock = iso_blkoff(imp, idp->curroff); - if (entryoffsetinblock != 0) { - if ((error = iso_blkatoff(ip, idp->curroff, &bp))) { - FREE(idp,M_TEMP); - return (error); - } + if ((entryoffsetinblock = idp->curroff & bmask) && + (error = VOP_BLKATOFF(vdp, (off_t)idp->curroff, NULL, &bp))) { + FREE(idp, M_TEMP); + return (error); } - - endsearch = ip->i_size; + endsearch = dp->i_size; while (idp->curroff < endsearch) { /* @@ -605,26 +678,25 @@ cd9660_readdir(ap) * read the next directory block. * Release previous if it exists. */ - - if (iso_blkoff(imp, idp->curroff) == 0) { + if ((idp->curroff & bmask) == 0) { if (bp != NULL) brelse(bp); - if ((error = iso_blkatoff(ip, idp->curroff, &bp))) + if (error = + VOP_BLKATOFF(vdp, (off_t)idp->curroff, NULL, &bp)) break; entryoffsetinblock = 0; } /* * Get pointer to next entry. */ - ep = (struct iso_directory_record *) - (bp->b_un.b_addr + entryoffsetinblock); + ((char *)bp->b_data + entryoffsetinblock); - reclen = isonum_711 (ep->length); + reclen = isonum_711(ep->length); if (reclen == 0) { /* skip to next block, if any */ - idp->curroff = roundup (idp->curroff, - imp->logical_block_size); + idp->curroff = + (idp->curroff & ~bmask) + imp->logical_block_size; continue; } @@ -640,35 +712,27 @@ cd9660_readdir(ap) break; } - namlen = isonum_711 (ep->name_len); - if (reclen < ISO_DIRECTORY_RECORD_SIZE + namlen) { + idp->current.d_namlen = isonum_711(ep->name_len); + + if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) { error = EINVAL; /* illegal entry, stop */ break; } - /* XXX: be more intelligent if we can */ - idp->current.d_type = DT_UNKNOWN; - - idp->current.d_namlen = namlen; - isoflags = isonum_711(imp->iso_ftype == ISO_FTYPE_HIGH_SIERRA? - &ep->date[6]: ep->flags); - if (isoflags & 2) - isodirino(&idp->current.d_fileno,ep,imp); + if (isonum_711(ep->flags)&2) + idp->current.d_fileno = isodirino(ep, imp); else idp->current.d_fileno = dbtob(bp->b_blkno) + - idp->curroff; + entryoffsetinblock; idp->curroff += reclen; - /* - * - */ + switch (imp->iso_ftype) { case ISO_FTYPE_RRIP: - cd9660_rrip_getname(ep,idp->current.d_name, - &tmplen, + cd9660_rrip_getname(ep,idp->current.d_name, &namelen, &idp->current.d_fileno,imp); - idp->current.d_namlen = tmplen; + idp->current.d_namlen = (u_char)namelen; if (idp->current.d_namlen) error = iso_uiodir(idp,&idp->current,idp->curroff); break; @@ -685,10 +749,10 @@ cd9660_readdir(ap) break; default: isofntrans(ep->name,idp->current.d_namlen, - idp->current.d_name, &elen, + idp->current.d_name, &namelen, imp->iso_ftype == ISO_FTYPE_9660, - isoflags & 4); - idp->current.d_namlen = (u_char)elen; + isonum_711(ep->flags)&4); + idp->current.d_namlen = (u_char)namelen; if (imp->iso_ftype == ISO_FTYPE_DEFAULT) error = iso_shipdir(idp); else @@ -711,7 +775,7 @@ cd9660_readdir(ap) if (ap->a_ncookies != NULL) { if (error) - FREE(cookies, M_TEMP); + free(cookies, M_TEMP); else { /* * Work out the number of cookies actually used. @@ -725,10 +789,9 @@ cd9660_readdir(ap) brelse (bp); uio->uio_offset = idp->uio_off; - if (ap->a_eofflag) - *ap->a_eofflag = idp->eof; + *ap->a_eofflag = idp->eofflag; - FREE(idp,M_TEMP); + FREE(idp, M_TEMP); return (error); } @@ -754,44 +817,34 @@ cd9660_readlink(ap) ISODIR *dirp; ISOMNT *imp; struct buf *bp; + struct uio *uio; u_short symlen; int error; char *symname; ip = VTOI(ap->a_vp); imp = ip->i_mnt; + uio = ap->a_uio; if (imp->iso_ftype != ISO_FTYPE_RRIP) - return EINVAL; + return (EINVAL); /* * Get parents directory record block that this inode included. */ error = bread(imp->im_devvp, - iso_dblkno(imp, ip->i_number), - imp->logical_block_size, - NOCRED, - &bp); + (ip->i_number >> imp->im_bshift) << + (imp->im_bshift - DEV_BSHIFT), + imp->logical_block_size, NOCRED, &bp); if (error) { brelse(bp); - return EINVAL; + return (EINVAL); } /* * Setup the directory pointer for this inode */ - dirp = (ISODIR *)(bp->b_un.b_addr + (ip->i_number & imp->im_bmask)); -#ifdef DEBUG - printf("lbn=%d,off=%d,bsize=%d,DEV_BSIZE=%d, dirp= %08x, b_addr=%08x, offset=%08x(%08x)\n", - (daddr_t)(ip->i_number >> imp->im_bshift), - ip->i_number & imp->im_bmask, - imp->logical_block_size, - DEV_BSIZE, - dirp, - bp->b_un.b_addr, - ip->i_number, - ip->i_number & imp->im_bmask ); -#endif + dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask)); /* * Just make sure, we have a right one.... @@ -800,22 +853,26 @@ cd9660_readlink(ap) if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length) > (unsigned)imp->logical_block_size) { brelse(bp); - return EINVAL; + return (EINVAL); } /* * Now get a buffer * Abuse a namei buffer for now. */ - MALLOC(symname,char *,MAXPATHLEN,M_NAMEI,M_WAITOK); - + if (uio->uio_segflg == UIO_SYSSPACE) + symname = uio->uio_iov->iov_base; + else + MALLOC(symname, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + /* * Ok, we just gathering a symbolic name in SL record. */ - if (cd9660_rrip_getsymname(dirp,symname,&symlen,imp) == 0) { - FREE(symname,M_NAMEI); + if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) { + if (uio->uio_segflg != UIO_SYSSPACE) + FREE(symname, M_NAMEI); brelse(bp); - return EINVAL; + return (EINVAL); } /* * Don't forget before you leave from home ;-) @@ -825,11 +882,15 @@ cd9660_readlink(ap) /* * return with the symbolic name to caller's. */ - error = uiomove(symname,symlen,ap->a_uio); - - FREE(symname,M_NAMEI); - - return error; + if (uio->uio_segflg != UIO_SYSSPACE) { + error = uiomove(symname, symlen, uio); + FREE(symname, M_NAMEI); + return (error); + } + uio->uio_resid -= symlen; + uio->uio_iov->iov_base += symlen; + uio->uio_iov->iov_len -= symlen; + return (0); } /* @@ -845,7 +906,7 @@ cd9660_abortop(ap) { if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); - return 0; + return (0); } /* @@ -855,12 +916,14 @@ static int cd9660_lock(ap) struct vop_lock_args /* { struct vnode *a_vp; + int a_flags; + struct proc *a_p; } */ *ap; { - register struct iso_node *ip = VTOI(ap->a_vp); + struct vnode *vp = ap->a_vp; - ISO_ILOCK(ip); - return 0; + return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, &vp->v_interlock, + ap->a_p)); } /* @@ -870,29 +933,14 @@ static int cd9660_unlock(ap) struct vop_unlock_args /* { struct vnode *a_vp; + int a_flags; + struct proc *a_p; } */ *ap; { - register struct iso_node *ip = VTOI(ap->a_vp); - - if (!(ip->i_flag & ILOCKED)) - panic("cd9660_unlock NOT LOCKED"); - ISO_IUNLOCK(ip); - return 0; -} - -/* - * Check for a locked inode. - */ -static int -cd9660_islocked(ap) - struct vop_islocked_args /* { - struct vnode *a_vp; - } */ *ap; -{ + struct vnode *vp = ap->a_vp; - if (VTOI(ap->a_vp)->i_flag & ILOCKED) - return 1; - return 0; + return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE, + &vp->v_interlock, ap->a_p)); } /* @@ -943,102 +991,150 @@ cd9660_print(ap) struct vnode *a_vp; } */ *ap; { + printf("tag VT_ISOFS, isofs vnode\n"); - return 0; + return (0); +} + +/* + * Check for a locked inode. + */ +int +cd9660_islocked(ap) + struct vop_islocked_args /* { + struct vnode *a_vp; + } */ *ap; +{ + + return (lockstatus(&VTOI(ap->a_vp)->i_lock)); } /* - * Unsupported operation + * Return POSIX pathconf information applicable to cd9660 filesystems. */ -static int -cd9660_enotsupp() +int +cd9660_pathconf(ap) + struct vop_pathconf_args /* { + struct vnode *a_vp; + int a_name; + register_t *a_retval; + } */ *ap; { - return (EOPNOTSUPP); + switch (ap->a_name) { + case _PC_LINK_MAX: + *ap->a_retval = 1; + return (0); + case _PC_NAME_MAX: + if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP) + *ap->a_retval = NAME_MAX; + else + *ap->a_retval = 37; + return (0); + case _PC_PATH_MAX: + *ap->a_retval = PATH_MAX; + return (0); + case _PC_PIPE_BUF: + *ap->a_retval = PIPE_BUF; + return (0); + case _PC_CHOWN_RESTRICTED: + *ap->a_retval = 1; + return (0); + case _PC_NO_TRUNC: + *ap->a_retval = 1; + return (0); + default: + return (EINVAL); + } + /* NOTREACHED */ } /* * Global vfs data structures for isofs */ #define cd9660_create \ - ((int (*) __P((struct vop_create_args *)))cd9660_enotsupp) -#define cd9660_mknod ((int (*) __P((struct vop_mknod_args *)))cd9660_enotsupp) -#define cd9660_write ((int (*) __P((struct vop_write_args *)))cd9660_enotsupp) + ((int (*) __P((struct vop_create_args *)))eopnotsupp) +#define cd9660_mknod ((int (*) __P((struct vop_mknod_args *)))eopnotsupp) +#define cd9660_write ((int (*) __P((struct vop_write_args *)))eopnotsupp) +#ifdef NFS +#define cd9660_lease_check lease_check +#else +#define cd9660_lease_check ((int (*) __P((struct vop_lease_args *)))nullop) +#endif #define cd9660_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) #define cd9660_remove \ - ((int (*) __P((struct vop_remove_args *)))cd9660_enotsupp) -#define cd9660_link ((int (*) __P((struct vop_link_args *)))cd9660_enotsupp) + ((int (*) __P((struct vop_remove_args *)))eopnotsupp) +#define cd9660_link ((int (*) __P((struct vop_link_args *)))eopnotsupp) #define cd9660_rename \ - ((int (*) __P((struct vop_rename_args *)))cd9660_enotsupp) -#define cd9660_mkdir ((int (*) __P((struct vop_mkdir_args *)))cd9660_enotsupp) -#define cd9660_rmdir ((int (*) __P((struct vop_rmdir_args *)))cd9660_enotsupp) + ((int (*) __P((struct vop_rename_args *)))eopnotsupp) +#define cd9660_mkdir ((int (*) __P((struct vop_mkdir_args *)))eopnotsupp) +#define cd9660_rmdir ((int (*) __P((struct vop_rmdir_args *)))eopnotsupp) #define cd9660_symlink \ - ((int (*) __P((struct vop_symlink_args *)))cd9660_enotsupp) -#define cd9660_pathconf \ - ((int (*) __P((struct vop_pathconf_args *)))cd9660_enotsupp) + ((int (*) __P((struct vop_symlink_args *)))eopnotsupp) #define cd9660_advlock \ - ((int (*) __P((struct vop_advlock_args *)))cd9660_enotsupp) -#define cd9660_blkatoff \ - ((int (*) __P((struct vop_blkatoff_args *)))cd9660_enotsupp) + ((int (*) __P((struct vop_advlock_args *)))eopnotsupp) #define cd9660_valloc ((int(*) __P(( \ struct vnode *pvp, \ int mode, \ struct ucred *cred, \ - struct vnode **vpp))) cd9660_enotsupp) -#define cd9660_vfree ((int (*) __P((struct vop_vfree_args *)))cd9660_enotsupp) + struct vnode **vpp))) eopnotsupp) +#define cd9660_vfree ((int (*) __P((struct vop_vfree_args *)))eopnotsupp) #define cd9660_truncate \ - ((int (*) __P((struct vop_truncate_args *)))cd9660_enotsupp) + ((int (*) __P((struct vop_truncate_args *)))eopnotsupp) #define cd9660_update \ - ((int (*) __P((struct vop_update_args *)))cd9660_enotsupp) + ((int (*) __P((struct vop_update_args *)))eopnotsupp) #define cd9660_bwrite \ - ((int (*) __P((struct vop_bwrite_args *)))cd9660_enotsupp) + ((int (*) __P((struct vop_bwrite_args *)))eopnotsupp) /* - * Global vfs data structures for nfs + * Global vfs data structures for cd9660 */ vop_t **cd9660_vnodeop_p; -static struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = { +struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = { + { &vop_default_desc, (vop_t *)vn_default_error }, - { &vop_lookup_desc, (vop_t *)cd9660_lookup }, /* lookup */ - { &vop_create_desc, (vop_t *)cd9660_create }, /* create */ - { &vop_mknod_desc, (vop_t *)cd9660_mknod }, /* mknod */ - { &vop_open_desc, (vop_t *)cd9660_open }, /* open */ - { &vop_close_desc, (vop_t *)cd9660_close }, /* close */ - { &vop_access_desc, (vop_t *)cd9660_access }, /* access */ - { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */ - { &vop_setattr_desc, (vop_t *)cd9660_setattr }, /* setattr */ - { &vop_read_desc, (vop_t *)cd9660_read }, /* read */ - { &vop_write_desc, (vop_t *)cd9660_write }, /* write */ - { &vop_ioctl_desc, (vop_t *)cd9660_ioctl }, /* ioctl */ - { &vop_select_desc, (vop_t *)cd9660_select }, /* select */ - { &vop_mmap_desc, (vop_t *)cd9660_mmap }, /* mmap */ - { &vop_fsync_desc, (vop_t *)cd9660_fsync }, /* fsync */ - { &vop_seek_desc, (vop_t *)cd9660_seek }, /* seek */ - { &vop_remove_desc, (vop_t *)cd9660_remove }, /* remove */ - { &vop_link_desc, (vop_t *)cd9660_link }, /* link */ - { &vop_rename_desc, (vop_t *)cd9660_rename }, /* rename */ - { &vop_mkdir_desc, (vop_t *)cd9660_mkdir }, /* mkdir */ - { &vop_rmdir_desc, (vop_t *)cd9660_rmdir }, /* rmdir */ - { &vop_symlink_desc, (vop_t *)cd9660_symlink }, /* symlink */ - { &vop_readdir_desc, (vop_t *)cd9660_readdir }, /* readdir */ - { &vop_readlink_desc, (vop_t *)cd9660_readlink }, /* readlink */ - { &vop_abortop_desc, (vop_t *)cd9660_abortop }, /* abortop */ - { &vop_inactive_desc, (vop_t *)cd9660_inactive }, /* inactive */ - { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */ - { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */ - { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */ - { &vop_bmap_desc, (vop_t *)cd9660_bmap }, /* bmap */ - { &vop_strategy_desc, (vop_t *)cd9660_strategy }, /* strategy */ - { &vop_print_desc, (vop_t *)cd9660_print }, /* print */ - { &vop_islocked_desc, (vop_t *)cd9660_islocked }, /* islocked */ - { &vop_pathconf_desc, (vop_t *)cd9660_pathconf }, /* pathconf */ - { &vop_advlock_desc, (vop_t *)cd9660_advlock }, /* advlock */ - { &vop_blkatoff_desc, (vop_t *)cd9660_blkatoff }, /* blkatoff */ - { &vop_valloc_desc, (vop_t *)cd9660_valloc }, /* valloc */ - { &vop_vfree_desc, (vop_t *)cd9660_vfree }, /* vfree */ - { &vop_truncate_desc, (vop_t *)cd9660_truncate }, /* truncate */ - { &vop_update_desc, (vop_t *)cd9660_update }, /* update */ - { &vop_bwrite_desc, (vop_t *)vn_bwrite }, /* bwrite */ + { &vop_lookup_desc, (vop_t *)cd9660_lookup }, /* lookup */ + { &vop_create_desc, (vop_t *)cd9660_create }, /* create */ + { &vop_mknod_desc, (vop_t *)cd9660_mknod }, /* mknod */ + { &vop_open_desc, (vop_t *)cd9660_open }, /* open */ + { &vop_close_desc, (vop_t *)cd9660_close }, /* close */ + { &vop_access_desc, (vop_t *)cd9660_access }, /* access */ + { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */ + { &vop_setattr_desc, (vop_t *)cd9660_setattr }, /* setattr */ + { &vop_read_desc, (vop_t *)cd9660_read }, /* read */ + { &vop_write_desc, (vop_t *)cd9660_write }, /* write */ + { &vop_lease_desc, (vop_t *)cd9660_lease_check },/* lease */ + { &vop_ioctl_desc, (vop_t *)cd9660_ioctl }, /* ioctl */ + { &vop_select_desc, (vop_t *)cd9660_select }, /* select */ + { &vop_revoke_desc, (vop_t *)cd9660_revoke }, /* revoke */ + { &vop_mmap_desc, (vop_t *)cd9660_mmap }, /* mmap */ + { &vop_fsync_desc, (vop_t *)cd9660_fsync }, /* fsync */ + { &vop_seek_desc, (vop_t *)cd9660_seek }, /* seek */ + { &vop_remove_desc, (vop_t *)cd9660_remove }, /* remove */ + { &vop_link_desc, (vop_t *)cd9660_link }, /* link */ + { &vop_rename_desc, (vop_t *)cd9660_rename }, /* rename */ + { &vop_mkdir_desc, (vop_t *)cd9660_mkdir }, /* mkdir */ + { &vop_rmdir_desc, (vop_t *)cd9660_rmdir }, /* rmdir */ + { &vop_symlink_desc, (vop_t *)cd9660_symlink }, /* symlink */ + { &vop_readdir_desc, (vop_t *)cd9660_readdir }, /* readdir */ + { &vop_readlink_desc, (vop_t *)cd9660_readlink },/* readlink */ + { &vop_abortop_desc, (vop_t *)cd9660_abortop }, /* abortop */ + { &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */ + { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */ + { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */ + { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */ + { &vop_bmap_desc, (vop_t *)cd9660_bmap }, /* bmap */ + { &vop_strategy_desc, (vop_t *)cd9660_strategy },/* strategy */ + { &vop_print_desc, (vop_t *)cd9660_print }, /* print */ + { &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */ + { &vop_pathconf_desc, (vop_t *)cd9660_pathconf },/* pathconf */ + { &vop_advlock_desc, (vop_t *)cd9660_advlock }, /* advlock */ + { &vop_blkatoff_desc, (vop_t *)cd9660_blkatoff },/* blkatoff */ + { &vop_valloc_desc, (vop_t *)cd9660_valloc }, /* valloc */ + { &vop_vfree_desc, (vop_t *)cd9660_vfree }, /* vfree */ + { &vop_truncate_desc, (vop_t *)cd9660_truncate },/* truncate */ + { &vop_update_desc, (vop_t *)cd9660_update }, /* update */ + { &vop_bwrite_desc, (vop_t *)vn_bwrite }, { NULL, NULL } }; static struct vnodeopv_desc cd9660_vnodeop_opv_desc = @@ -1049,101 +1145,106 @@ VNODEOP_SET(cd9660_vnodeop_opv_desc); * Special device vnode ops */ vop_t **cd9660_specop_p; -static struct vnodeopv_entry_desc cd9660_specop_entries[] = { +struct vnodeopv_entry_desc cd9660_specop_entries[] = { { &vop_default_desc, (vop_t *)vn_default_error }, - { &vop_lookup_desc, (vop_t *)spec_lookup }, /* lookup */ - { &vop_create_desc, (vop_t *)cd9660_create }, /* create */ - { &vop_mknod_desc, (vop_t *)cd9660_mknod }, /* mknod */ - { &vop_open_desc, (vop_t *)spec_open }, /* open */ - { &vop_close_desc, (vop_t *)spec_close }, /* close */ - { &vop_access_desc, (vop_t *)cd9660_access }, /* access */ - { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */ - { &vop_setattr_desc, (vop_t *)cd9660_setattr }, /* setattr */ - { &vop_read_desc, (vop_t *)spec_read }, /* read */ - { &vop_write_desc, (vop_t *)spec_write }, /* write */ - { &vop_ioctl_desc, (vop_t *)spec_ioctl }, /* ioctl */ - { &vop_select_desc, (vop_t *)spec_select }, /* select */ - { &vop_mmap_desc, (vop_t *)spec_mmap }, /* mmap */ - { &vop_fsync_desc, (vop_t *)spec_fsync }, /* fsync */ - { &vop_seek_desc, (vop_t *)spec_seek }, /* seek */ - { &vop_remove_desc, (vop_t *)cd9660_remove }, /* remove */ - { &vop_link_desc, (vop_t *)cd9660_link }, /* link */ - { &vop_rename_desc, (vop_t *)cd9660_rename }, /* rename */ - { &vop_mkdir_desc, (vop_t *)cd9660_mkdir }, /* mkdir */ - { &vop_rmdir_desc, (vop_t *)cd9660_rmdir }, /* rmdir */ - { &vop_symlink_desc, (vop_t *)cd9660_symlink }, /* symlink */ - { &vop_readdir_desc, (vop_t *)spec_readdir }, /* readdir */ - { &vop_readlink_desc, (vop_t *)spec_readlink }, /* readlink */ - { &vop_abortop_desc, (vop_t *)spec_abortop }, /* abortop */ - { &vop_inactive_desc, (vop_t *)cd9660_inactive }, /* inactive */ - { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */ - { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */ - { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */ - { &vop_bmap_desc, (vop_t *)spec_bmap }, /* bmap */ - { &vop_strategy_desc, (vop_t *)spec_strategy }, /* strategy */ - { &vop_print_desc, (vop_t *)cd9660_print }, /* print */ - { &vop_islocked_desc, (vop_t *)cd9660_islocked }, /* islocked */ - { &vop_pathconf_desc, (vop_t *)spec_pathconf }, /* pathconf */ - { &vop_advlock_desc, (vop_t *)spec_advlock }, /* advlock */ - { &vop_blkatoff_desc, (vop_t *)spec_blkatoff }, /* blkatoff */ - { &vop_valloc_desc, (vop_t *)spec_valloc }, /* valloc */ - { &vop_vfree_desc, (vop_t *)spec_vfree }, /* vfree */ - { &vop_truncate_desc, (vop_t *)spec_truncate }, /* truncate */ - { &vop_update_desc, (vop_t *)cd9660_update }, /* update */ - { &vop_getpages_desc, (vop_t *)spec_getpages}, /* getpages */ - { &vop_bwrite_desc, (vop_t *)vn_bwrite }, /* bwrite */ + { &vop_lookup_desc, (vop_t *)spec_lookup }, /* lookup */ + { &vop_create_desc, (vop_t *)spec_create }, /* create */ + { &vop_mknod_desc, (vop_t *)spec_mknod }, /* mknod */ + { &vop_open_desc, (vop_t *)spec_open }, /* open */ + { &vop_close_desc, (vop_t *)spec_close }, /* close */ + { &vop_access_desc, (vop_t *)cd9660_access }, /* access */ + { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */ + { &vop_setattr_desc, (vop_t *)cd9660_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 */ + { &vop_remove_desc, (vop_t *)spec_remove }, /* remove */ + { &vop_link_desc, (vop_t *)spec_link }, /* link */ + { &vop_rename_desc, (vop_t *)spec_rename }, /* rename */ + { &vop_mkdir_desc, (vop_t *)spec_mkdir }, /* mkdir */ + { &vop_rmdir_desc, (vop_t *)spec_rmdir }, /* rmdir */ + { &vop_symlink_desc, (vop_t *)spec_symlink }, /* symlink */ + { &vop_readdir_desc, (vop_t *)spec_readdir }, /* readdir */ + { &vop_readlink_desc, (vop_t *)spec_readlink }, /* readlink */ + { &vop_abortop_desc, (vop_t *)spec_abortop }, /* abortop */ + { &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */ + { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */ + { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */ + { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */ + { &vop_bmap_desc, (vop_t *)spec_bmap }, /* bmap */ + { &vop_strategy_desc, (vop_t *)spec_strategy }, /* strategy */ + { &vop_print_desc, (vop_t *)cd9660_print }, /* print */ + { &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */ + { &vop_pathconf_desc, (vop_t *)spec_pathconf }, /* pathconf */ + { &vop_advlock_desc, (vop_t *)spec_advlock }, /* advlock */ + { &vop_blkatoff_desc, (vop_t *)spec_blkatoff }, /* blkatoff */ + { &vop_valloc_desc, (vop_t *)spec_valloc }, /* valloc */ + { &vop_vfree_desc, (vop_t *)spec_vfree }, /* vfree */ + { &vop_truncate_desc, (vop_t *)spec_truncate }, /* truncate */ + { &vop_update_desc, (vop_t *)cd9660_update }, /* update */ + { &vop_bwrite_desc, (vop_t *)vn_bwrite }, { NULL, NULL } }; static struct vnodeopv_desc cd9660_specop_opv_desc = { &cd9660_specop_p, cd9660_specop_entries }; VNODEOP_SET(cd9660_specop_opv_desc); +#ifdef FIFO vop_t **cd9660_fifoop_p; -static struct vnodeopv_entry_desc cd9660_fifoop_entries[] = { +struct vnodeopv_entry_desc cd9660_fifoop_entries[] = { { &vop_default_desc, (vop_t *)vn_default_error }, - { &vop_lookup_desc, (vop_t *)fifo_lookup }, /* lookup */ - { &vop_create_desc, (vop_t *)cd9660_create }, /* create */ - { &vop_mknod_desc, (vop_t *)cd9660_mknod }, /* mknod */ - { &vop_open_desc, (vop_t *)fifo_open }, /* open */ - { &vop_close_desc, (vop_t *)fifo_close }, /* close */ - { &vop_access_desc, (vop_t *)cd9660_access }, /* access */ - { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */ - { &vop_setattr_desc, (vop_t *)cd9660_setattr }, /* setattr */ - { &vop_read_desc, (vop_t *)fifo_read }, /* read */ - { &vop_write_desc, (vop_t *)fifo_write }, /* write */ - { &vop_ioctl_desc, (vop_t *)fifo_ioctl }, /* ioctl */ - { &vop_select_desc, (vop_t *)fifo_select }, /* select */ - { &vop_mmap_desc, (vop_t *)fifo_mmap }, /* mmap */ - { &vop_fsync_desc, (vop_t *)fifo_fsync }, /* fsync */ - { &vop_seek_desc, (vop_t *)fifo_seek }, /* seek */ - { &vop_remove_desc, (vop_t *)cd9660_remove }, /* remove */ - { &vop_link_desc, (vop_t *)cd9660_link }, /* link */ - { &vop_rename_desc, (vop_t *)cd9660_rename }, /* rename */ - { &vop_mkdir_desc, (vop_t *)cd9660_mkdir }, /* mkdir */ - { &vop_rmdir_desc, (vop_t *)cd9660_rmdir }, /* rmdir */ - { &vop_symlink_desc, (vop_t *)cd9660_symlink }, /* symlink */ - { &vop_readdir_desc, (vop_t *)fifo_readdir }, /* readdir */ - { &vop_readlink_desc, (vop_t *)fifo_readlink }, /* readlink */ - { &vop_abortop_desc, (vop_t *)fifo_abortop }, /* abortop */ - { &vop_inactive_desc, (vop_t *)cd9660_inactive }, /* inactive */ - { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */ - { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */ - { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */ - { &vop_bmap_desc, (vop_t *)fifo_bmap }, /* bmap */ - { &vop_strategy_desc, (vop_t *)fifo_badop }, /* strategy */ - { &vop_print_desc, (vop_t *)cd9660_print }, /* print */ - { &vop_islocked_desc, (vop_t *)cd9660_islocked }, /* islocked */ - { &vop_pathconf_desc, (vop_t *)fifo_pathconf }, /* pathconf */ - { &vop_advlock_desc, (vop_t *)fifo_advlock }, /* advlock */ - { &vop_blkatoff_desc, (vop_t *)fifo_blkatoff }, /* blkatoff */ - { &vop_valloc_desc, (vop_t *)fifo_valloc }, /* valloc */ - { &vop_vfree_desc, (vop_t *)fifo_vfree }, /* vfree */ - { &vop_truncate_desc, (vop_t *)fifo_truncate }, /* truncate */ - { &vop_update_desc, (vop_t *)cd9660_update }, /* update */ - { &vop_bwrite_desc, (vop_t *)vn_bwrite }, /* bwrite */ + { &vop_lookup_desc, (vop_t *)fifo_lookup }, /* lookup */ + { &vop_create_desc, (vop_t *)fifo_create }, /* create */ + { &vop_mknod_desc, (vop_t *)fifo_mknod }, /* mknod */ + { &vop_open_desc, (vop_t *)fifo_open }, /* open */ + { &vop_close_desc, (vop_t *)fifo_close }, /* close */ + { &vop_access_desc, (vop_t *)cd9660_access }, /* access */ + { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */ + { &vop_setattr_desc, (vop_t *)cd9660_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 */ + { &vop_remove_desc, (vop_t *)fifo_remove }, /* remove */ + { &vop_link_desc, (vop_t *)fifo_link } , /* link */ + { &vop_rename_desc, (vop_t *)fifo_rename }, /* rename */ + { &vop_mkdir_desc, (vop_t *)fifo_mkdir }, /* mkdir */ + { &vop_rmdir_desc, (vop_t *)fifo_rmdir }, /* rmdir */ + { &vop_symlink_desc, (vop_t *)fifo_symlink }, /* symlink */ + { &vop_readdir_desc, (vop_t *)fifo_readdir }, /* readdir */ + { &vop_readlink_desc, (vop_t *)fifo_readlink }, /* readlink */ + { &vop_abortop_desc, (vop_t *)fifo_abortop }, /* abortop */ + { &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */ + { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */ + { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */ + { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */ + { &vop_bmap_desc, (vop_t *)fifo_bmap }, /* bmap */ + { &vop_strategy_desc, (vop_t *)fifo_strategy }, /* strategy */ + { &vop_print_desc, (vop_t *)cd9660_print }, /* print */ + { &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */ + { &vop_pathconf_desc, (vop_t *)fifo_pathconf }, /* pathconf */ + { &vop_advlock_desc, (vop_t *)fifo_advlock }, /* advlock */ + { &vop_blkatoff_desc, (vop_t *)fifo_blkatoff }, /* blkatoff */ + { &vop_valloc_desc, (vop_t *)fifo_valloc }, /* valloc */ + { &vop_vfree_desc, (vop_t *)fifo_vfree }, /* vfree */ + { &vop_truncate_desc, (vop_t *)fifo_truncate }, /* truncate */ + { &vop_update_desc, (vop_t *)cd9660_update }, /* update */ + { &vop_bwrite_desc, (vop_t *)vn_bwrite }, { NULL, NULL } }; static struct vnodeopv_desc cd9660_fifoop_opv_desc = { &cd9660_fifoop_p, cd9660_fifoop_entries }; VNODEOP_SET(cd9660_fifoop_opv_desc); +#endif /* FIFO */ diff --git a/sys/fs/cd9660/iso.h b/sys/fs/cd9660/iso.h index 1656c23..e2a7779 100644 --- a/sys/fs/cd9660/iso.h +++ b/sys/fs/cd9660/iso.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)iso.h 8.2 (Berkeley) 1/23/94 + * @(#)iso.h 8.6 (Berkeley) 5/10/95 * $FreeBSD$ */ @@ -138,37 +138,37 @@ struct iso_sierra_primary_descriptor { struct iso_directory_record { char length [ISODCL (1, 1)]; /* 711 */ char ext_attr_length [ISODCL (2, 2)]; /* 711 */ - unsigned char extent [ISODCL (3, 10)]; /* 733 */ - unsigned char size [ISODCL (11, 18)]; /* 733 */ + u_char extent [ISODCL (3, 10)]; /* 733 */ + u_char size [ISODCL (11, 18)]; /* 733 */ char date [ISODCL (19, 25)]; /* 7 by 711 */ char flags [ISODCL (26, 26)]; char file_unit_size [ISODCL (27, 27)]; /* 711 */ char interleave [ISODCL (28, 28)]; /* 711 */ char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ char name_len [ISODCL (33, 33)]; /* 711 */ - char name [0]; + char name [1]; /* XXX */ }; /* can't take sizeof(iso_directory_record), because of possible alignment of the last entry (34 instead of 33) */ #define ISO_DIRECTORY_RECORD_SIZE 33 struct iso_extended_attributes { - unsigned char owner [ISODCL (1, 4)]; /* 723 */ - unsigned char group [ISODCL (5, 8)]; /* 723 */ - unsigned char perm [ISODCL (9, 10)]; /* 9.5.3 */ + u_char owner [ISODCL (1, 4)]; /* 723 */ + u_char group [ISODCL (5, 8)]; /* 723 */ + u_char perm [ISODCL (9, 10)]; /* 9.5.3 */ char ctime [ISODCL (11, 27)]; /* 8.4.26.1 */ char mtime [ISODCL (28, 44)]; /* 8.4.26.1 */ char xtime [ISODCL (45, 61)]; /* 8.4.26.1 */ char ftime [ISODCL (62, 78)]; /* 8.4.26.1 */ char recfmt [ISODCL (79, 79)]; /* 711 */ char recattr [ISODCL (80, 80)]; /* 711 */ - unsigned char reclen [ISODCL (81, 84)]; /* 723 */ + u_char reclen [ISODCL (81, 84)]; /* 723 */ char system_id [ISODCL (85, 116)]; /* achars */ char system_use [ISODCL (117, 180)]; char version [ISODCL (181, 181)]; /* 711 */ char len_esc [ISODCL (182, 182)]; /* 711 */ char reserved [ISODCL (183, 246)]; - unsigned char len_au [ISODCL (247, 250)]; /* 723 */ + u_char len_au [ISODCL (247, 250)]; /* 723 */ }; /* CD-ROM Format type */ @@ -191,7 +191,6 @@ struct iso_mnt { int im_bmask; int volume_space_size; - char im_fsmnt[50]; struct netexport im_export; char root[ISODCL (157, 190)]; @@ -205,94 +204,102 @@ struct iso_mnt { #define VFSTOISOFS(mp) ((struct iso_mnt *)((mp)->mnt_data)) -#define iso_blkoff(imp, loc) ((loc) & (imp)->im_bmask) -#define iso_lblkno(imp, loc) ((loc) >> (imp)->im_bshift) -#define iso_blksize(imp, ip, lbn) ((imp)->logical_block_size) -#define iso_lblktosize(imp, blk) ((blk) << (imp)->im_bshift) -#define iso_lblktodaddr(imp, lbn) btodb(iso_lblktosize(imp, lbn)) -#define iso_dblkinc(imp, lbn) ((lbn) + iso_lblktodaddr(imp, 1)) -#define iso_dblkno(imp, loc) iso_lblktodaddr(imp, iso_lblkno(imp, loc)) -int cd9660_init __P((void)); - -struct iso_node; -int iso_blkatoff __P((struct iso_node *ip, long offset, struct buf **bpp)); -int iso_iget __P((struct iso_node *xp, ino_t ino, int relocated, - struct iso_node **ipp, struct iso_directory_record *isodir)); -int iso_iput __P((struct iso_node *ip)); -int iso_ilock __P((struct iso_node *ip)); -int iso_iunlock __P((struct iso_node *ip)); -int cd9660_mountroot __P((void)); +#define blkoff(imp, loc) ((loc) & (imp)->im_bmask) +#define lblktosize(imp, blk) ((blk) << (imp)->im_bshift) +#define lblkno(imp, loc) ((loc) >> (imp)->im_bshift) +#define blksize(imp, ip, lbn) ((imp)->logical_block_size) + +int cd9660_vget_internal __P((struct mount *, ino_t, struct vnode **, int, + struct iso_directory_record *)); +int cd9660_init __P((struct vfsconf *)); +#define cd9660_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ + size_t, struct proc *)))eopnotsupp) + +int cd9660_mountroot __P((void)); extern vop_t **cd9660_vnodeop_p; +extern vop_t **cd9660_specop_p; +#ifdef FIFO +extern vop_t **cd9660_fifoop_p; +#endif -static int isonum_711 __P((unsigned char *p)); -static int isonum_712 __P((char *p)); -static int isonum_721 __P((unsigned char *p)); -static int isonum_722 __P((unsigned char *p)); -static int isonum_723 __P((unsigned char *p)); -static int isonum_731 __P((unsigned char *p)); -static int isonum_732 __P((unsigned char *p)); -static int isonum_733 __P((unsigned char *p)); - -static inline int +static __inline int isonum_711 __P((u_char *)); +static __inline int isonum_711(p) - unsigned char *p; + u_char *p; { return *p; } -static inline int +static __inline int isonum_712 __P((char *)); +static __inline int isonum_712(p) char *p; { return *p; } -static inline int -isonum_721(p) - unsigned char *p; +#ifndef UNALIGNED_ACCESS + +static __inline int isonum_723 __P((u_char *)); +static __inline int +isonum_723(p) + u_char *p; { - return *p|((char)p[1] << 8); + return *p|(p[1] << 8); } -static inline int -isonum_722(p) - unsigned char *p; +static __inline int isonum_733 __P((u_char *)); +static __inline int +isonum_733(p) + u_char *p; { - return ((char)*p << 8)|p[1]; + return *p|(p[1] << 8)|(p[2] << 16)|(p[3] << 24); } -static inline int +#else /* UNALIGNED_ACCESS */ + +#if BYTE_ORDER == LITTLE_ENDIAN + +static __inline int isonum_723(p) - unsigned char *p; + u_char *p { - return isonum_721(p); + return *(u_int16t *)p; } -static inline int -isonum_731(p) - unsigned char *p; +static __inline int +isonum_733(p) + u_char *p; { - return *p|(p[1] << 8)|(p[2] << 16)|(p[3] << 24); + return *(u_int32t *)p; } -static inline int -isonum_732(p) - unsigned char *p; +#endif + +#if BYTE_ORDER == BIG_ENDIAN + +static __inline int +isonum_723(p) + u_char *p { - return (*p << 24)|(p[1] << 16)|(p[2] << 8)|p[3]; + return *(u_int16t *)(p + 2); } -static inline int +static __inline int isonum_733(p) - unsigned char *p; + u_char *p; { - return isonum_731(p); + return *(u_int32t *)(p + 4); } -int isofncmp __P((unsigned char *, int, unsigned char *, int)); -void isofntrans __P((unsigned char *, int, unsigned char *, unsigned short *, - int, int)); +#endif + +#endif /* UNALIGNED_ACCESS */ + +int isofncmp __P((u_char *, int, u_char *, int)); +void isofntrans __P((u_char *, int, u_char *, u_short *, int, int)); +ino_t isodirino __P((struct iso_directory_record *, struct iso_mnt *)); /* * Associated files have a leading '='. diff --git a/sys/fs/deadfs/dead_vnops.c b/sys/fs/deadfs/dead_vnops.c index f22425c..6d83c61 100644 --- a/sys/fs/deadfs/dead_vnops.c +++ b/sys/fs/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/fs/fdescfs/fdesc.h b/sys/fs/fdescfs/fdesc.h index d754655..b4eff1f 100644 --- a/sys/fs/fdescfs/fdesc.h +++ b/sys/fs/fdescfs/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/fs/fdescfs/fdesc_vfsops.c b/sys/fs/fdescfs/fdesc_vfsops.c index 5f6703b..135052e 100644 --- a/sys/fs/fdescfs/fdesc_vfsops.c +++ b/sys/fs/fdescfs/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/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c index 1fe511b..795dfd8 100644 --- a/sys/fs/fdescfs/fdesc_vnops.c +++ b/sys/fs/fdescfs/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/fs/fifofs/fifo.h b/sys/fs/fifofs/fifo.h index efeaf85..6562159 100644 --- a/sys/fs/fifofs/fifo.h +++ b/sys/fs/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/fs/fifofs/fifo_vnops.c b/sys/fs/fifofs/fifo_vnops.c index 240354f..8f915ec 100644 --- a/sys/fs/fifofs/fifo_vnops.c +++ b/sys/fs/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 -#include +#include #include #include #include @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -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/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c index de4bf5e..a891ddc 100644 --- a/sys/fs/msdosfs/msdosfs_denode.c +++ b/sys/fs/msdosfs/msdosfs_denode.c @@ -124,7 +124,7 @@ msdosfs_hashget(dev, dirclust, diroff) (void) tsleep((caddr_t)dep, PINOD, "msdhgt", 0); break; } - if (!vget(DETOV(dep), 1)) + if (!vget(DETOV(dep), LK_EXCLUSIVE | LK_INTERLOCK, curproc)) return dep; break; } @@ -259,7 +259,7 @@ deget(pmp, dirclust, diroffset, direntptr, depp) * can't be accessed until we've read it in and have done what we * need to it. */ - VOP_LOCK(nvp); + vn_lock(nvp, LK_EXCLUSIVE | LK_RETRY, curproc); msdosfs_hashins(ldep); /* @@ -716,7 +716,7 @@ msdosfs_inactive(ap) printf("msdosfs_inactive(): dep %p, refcnt %ld, mntflag %x, MNT_RDONLY %x\n", dep, dep->de_refcnt, vp->v_mount->mnt_flag, MNT_RDONLY); #endif - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc); if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { error = detrunc(dep, (u_long) 0, 0, NOCRED, NULL); dep->de_flag |= DE_UPDATE; @@ -726,7 +726,7 @@ msdosfs_inactive(ap) TIMEVAL_TO_TIMESPEC(&time, &ts); deupdat(dep, &ts, 0); } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, curproc); dep->de_flag = 0; /* diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c index 60236b8..6617f9e 100644 --- a/sys/fs/msdosfs/msdosfs_lookup.c +++ b/sys/fs/msdosfs/msdosfs_lookup.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -156,14 +157,14 @@ msdosfs_lookup(ap) VREF(vdp); error = 0; } else if (flags & ISDOTDOT) { - VOP_UNLOCK(pdp); - error = vget(vdp, 1); + VOP_UNLOCK(pdp, 0, curproc); + error = vget(vdp, LK_EXCLUSIVE | LK_INTERLOCK, curproc); if (!error && lockparent && (flags & ISLASTCN)) - error = VOP_LOCK(pdp); + error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, curproc); } else { - error = vget(vdp, 1); + error = vget(vdp, LK_EXCLUSIVE | LK_INTERLOCK, curproc); if (!lockparent || error || !(flags & ISLASTCN)) - VOP_UNLOCK(pdp); + VOP_UNLOCK(pdp, 0, curproc); } if (!error) { @@ -183,9 +184,9 @@ msdosfs_lookup(ap) } vput(vdp); if (lockparent && pdp != vdp && (flags & ISLASTCN)) - VOP_UNLOCK(pdp); + VOP_UNLOCK(pdp, 0, curproc); } - error = VOP_LOCK(pdp); + error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, curproc); if (error) return error; vdp = pdp; @@ -345,7 +346,7 @@ notfound:; /* dp->de_flag |= DE_UPDATE; never update dos directories */ cnp->cn_flags |= SAVENAME; if (!lockparent)/* leave searched dir locked? */ - VOP_UNLOCK(vdp); + VOP_UNLOCK(vdp, 0, curproc); return EJUSTRETURN; } /* @@ -398,7 +399,7 @@ foundroot:; } *vpp = DETOV(tdp); if (!lockparent) - VOP_UNLOCK(vdp); + VOP_UNLOCK(vdp, 0, curproc); if (bp) brelse(bp); return 0; @@ -428,7 +429,7 @@ foundroot:; *vpp = DETOV(tdp); cnp->cn_flags |= SAVENAME; if (!lockparent) - VOP_UNLOCK(vdp); + VOP_UNLOCK(vdp, 0, curproc); if (bp) brelse(bp); return 0; @@ -439,16 +440,16 @@ foundroot:; */ pdp = vdp; if (flags & ISDOTDOT) { - VOP_UNLOCK(pdp); + VOP_UNLOCK(pdp, 0, curproc); error = deget(pmp, cluster, diroff, dep, &tdp); if (error) { - VOP_LOCK(pdp); + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, curproc); if (bp) brelse(bp); return error; } if (lockparent && (flags & ISLASTCN) - && (error = VOP_LOCK(pdp))) { + && (error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, curproc))) { vput(DETOV(tdp)); return error; } @@ -464,7 +465,7 @@ foundroot:; return error; } if (!lockparent || !(flags & ISLASTCN)) - VOP_UNLOCK(pdp); + VOP_UNLOCK(pdp, 0, curproc); *vpp = DETOV(tdp); } if (bp) diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c index 5669c63..d0c8cdb 100644 --- a/sys/fs/msdosfs/msdosfs_vfsops.c +++ b/sys/fs/msdosfs/msdosfs_vfsops.c @@ -130,10 +130,10 @@ msdosfs_mount(mp, path, data, ndp, p) flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; - if (vfs_busy(mp)) + if (vfs_busy(mp, LK_NOWAIT, 0, p)) return EBUSY; error = vflush(mp, NULLVP, flags); - vfs_unbusy(mp); + vfs_unbusy(mp, p); } if (!error && (mp->mnt_flag & MNT_RELOAD)) /* not yet implemented */ @@ -707,7 +707,7 @@ loop: if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 && vp->v_dirtyblkhd.lh_first == NULL) continue; - if (vget(vp, 1)) /* not there anymore? */ + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) /* not there anymore? */ goto loop; error = VOP_FSYNC(vp, cred, waitfor, p); if (error) diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c index bc4e12e..0f4deae 100644 --- a/sys/fs/msdosfs/msdosfs_vnops.c +++ b/sys/fs/msdosfs/msdosfs_vnops.c @@ -1172,17 +1172,17 @@ msdosfs_rename(ap) */ if (newparent == 0) { /* tddep and fddep point to the same denode here */ - VOP_LOCK(ap->a_fvp); /* ap->a_fdvp is already locked */ + vn_lock(ap->a_fvp, LK_EXCLUSIVE | LK_RETRY, curproc); /* ap->a_fdvp is already locked */ error = readep(fddep->de_pmp, fdep->de_dirclust, fdep->de_diroffset, &bp, &ep); if (error) { - VOP_UNLOCK(ap->a_fvp); + VOP_UNLOCK(ap->a_fvp, 0, curproc); goto bad; } bcopy(toname, ep->deName, 11); error = bwrite(bp); if (error) { - VOP_UNLOCK(ap->a_fvp); + VOP_UNLOCK(ap->a_fvp, 0, curproc); goto bad; } bcopy(toname, fdep->de_Name, 11); /* update denode */ @@ -1204,7 +1204,7 @@ msdosfs_rename(ap) * will also insure that the directory entry on disk has a * filesize of zero. */ - VOP_LOCK(ap->a_fvp); + vn_lock(ap->a_fvp, LK_EXCLUSIVE | LK_RETRY, curproc); bcopy(toname, fdep->de_Name, 11); /* update denode */ if (fdep->de_Attributes & ATTR_DIRECTORY) { dirsize = fdep->de_FileSize; @@ -1216,22 +1216,22 @@ msdosfs_rename(ap) } if (error) { /* should put back filename */ - VOP_UNLOCK(ap->a_fvp); + VOP_UNLOCK(ap->a_fvp, 0, curproc); goto bad; } - VOP_LOCK(ap->a_fdvp); + vn_lock(ap->a_fdvp, LK_EXCLUSIVE | LK_RETRY, curproc); error = readep(fddep->de_pmp, fddep->de_fndclust, fddep->de_fndoffset, &bp, &ep); if (error) { - VOP_UNLOCK(ap->a_fvp); - VOP_UNLOCK(ap->a_fdvp); + VOP_UNLOCK(ap->a_fvp, 0, curproc); + VOP_UNLOCK(ap->a_fdvp, 0, curproc); goto bad; } ep->deName[0] = SLOT_DELETED; error = bwrite(bp); if (error) { - VOP_UNLOCK(ap->a_fvp); - VOP_UNLOCK(ap->a_fdvp); + VOP_UNLOCK(ap->a_fvp, 0, curproc); + VOP_UNLOCK(ap->a_fdvp, 0, curproc); goto bad; } if (!sourceisadirectory) { @@ -1239,7 +1239,7 @@ msdosfs_rename(ap) fdep->de_diroffset = tddep->de_fndoffset; reinsert(fdep); } - VOP_UNLOCK(ap->a_fdvp); + VOP_UNLOCK(ap->a_fdvp, 0, curproc); } /* fdep is still locked here */ @@ -1259,19 +1259,19 @@ msdosfs_rename(ap) NOCRED, &bp); if (error) { /* should really panic here, fs is corrupt */ - VOP_UNLOCK(ap->a_fvp); + VOP_UNLOCK(ap->a_fvp, 0, curproc); goto bad; } dotdotp = (struct direntry *) bp->b_data + 1; putushort(dotdotp->deStartCluster, tddep->de_StartCluster); error = bwrite(bp); - VOP_UNLOCK(ap->a_fvp); + VOP_UNLOCK(ap->a_fvp, 0, curproc); if (error) { /* should really panic here, fs is corrupt */ goto bad; } } else - VOP_UNLOCK(ap->a_fvp); + VOP_UNLOCK(ap->a_fvp, 0, curproc); bad: ; vrele(DETOV(fdep)); vrele(DETOV(fddep)); diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h index 7b0a22e..77c6add 100644 --- a/sys/fs/msdosfs/msdosfsmount.h +++ b/sys/fs/msdosfs/msdosfsmount.h @@ -169,3 +169,15 @@ struct msdosfsmount { (((size) + (pmp)->pm_bpcluster - 1) >> (pmp)->pm_cnshift) int msdosfs_init __P((void)); + +/* + * Arguments to mount MSDOS filesystems. + */ +struct msdosfs_args { + char *fspec; /* blocks special holding the fs to mount */ + struct export_args export; /* network export information */ + uid_t uid; /* uid that owns msdosfs files */ + gid_t gid; /* gid that owns msdosfs files */ + mode_t mask; /* mask to be applied for msdosfs perms */ +}; + diff --git a/sys/fs/nullfs/null.h b/sys/fs/nullfs/null.h index beadb42..70a81b2 100644 --- a/sys/fs/nullfs/null.h +++ b/sys/fs/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/fs/nullfs/null_subr.c b/sys/fs/nullfs/null_subr.c index a14a7e4..4418631 100644 --- a/sys/fs/nullfs/null_subr.c +++ b/sys/fs/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 #include +#include #include #include #include @@ -48,11 +49,8 @@ #include #include -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/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c index e2aeeba..339b7c1 100644 --- a/sys/fs/nullfs/null_vfsops.c +++ b/sys/fs/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 #include -#include +#include #include #include #include @@ -55,7 +55,7 @@ #include #include -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/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c index ec279bc..c1af96f 100644 --- a/sys/fs/nullfs/null_vnops.c +++ b/sys/fs/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/fs/portalfs/portal_vfsops.c b/sys/fs/portalfs/portal_vfsops.c index a980f65..74e1542 100644 --- a/sys/fs/portalfs/portal_vfsops.c +++ b/sys/fs/portalfs/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 #include -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/fs/portalfs/portal_vnops.c b/sys/fs/portalfs/portal_vnops.c index 8135a5e..19b439c 100644 --- a/sys/fs/portalfs/portal_vnops.c +++ b/sys/fs/portalfs/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/fs/procfs/procfs.h b/sys/fs/procfs/procfs.h index df01a39..ef0d7eb 100644 --- a/sys/fs/procfs/procfs.h +++ b/sys/fs/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)); /* */ 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/fs/procfs/procfs_ctl.c b/sys/fs/procfs/procfs_ctl.c index 4ddf7a7..68b93dd 100644 --- a/sys/fs/procfs/procfs_ctl.c +++ b/sys/fs/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 #include #include - -#include -#include -#include - +#include #include +#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/fs/procfs/procfs_fpregs.c b/sys/fs/procfs/procfs_fpregs.c index a3cad5f..841cf76 100644 --- a/sys/fs/procfs/procfs_fpregs.c +++ b/sys/fs/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/fs/procfs/procfs_map.c b/sys/fs/procfs/procfs_map.c index 27c44fa..40c40d8 100644 --- a/sys/fs/procfs/procfs_map.c +++ b/sys/fs/procfs/procfs_map.c @@ -59,7 +59,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/sys/fs/procfs/procfs_mem.c b/sys/fs/procfs/procfs_mem.c index 4e8fac6..06364e5 100644 --- a/sys/fs/procfs/procfs_mem.c +++ b/sys/fs/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 #include #include -#include +#include #include #include #include @@ -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/fs/procfs/procfs_regs.c b/sys/fs/procfs/procfs_regs.c index 9282a3a..56ef233 100644 --- a/sys/fs/procfs/procfs_regs.c +++ b/sys/fs/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/fs/procfs/procfs_status.c b/sys/fs/procfs/procfs_status.c index 432918d..76974b5 100644 --- a/sys/fs/procfs/procfs_status.c +++ b/sys/fs/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/fs/procfs/procfs_subr.c b/sys/fs/procfs/procfs_subr.c index d9b3d2f..5ee78f0 100644 --- a/sys/fs/procfs/procfs_subr.c +++ b/sys/fs/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/fs/procfs/procfs_vfsops.c b/sys/fs/procfs/procfs_vfsops.c index 433b391..5387126 100644 --- a/sys/fs/procfs/procfs_vfsops.c +++ b/sys/fs/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 #include /* 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/fs/procfs/procfs_vnops.c b/sys/fs/procfs/procfs_vnops.c index f497563..85be3ea 100644 --- a/sys/fs/procfs/procfs_vnops.c +++ b/sys/fs/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 #include #include -#include #include /* for PAGE_SIZE */ +#include +#include 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/fs/specfs/spec_vnops.c b/sys/fs/specfs/spec_vnops.c index 049f41e..2e8cc04 100644 --- a/sys/fs/specfs/spec_vnops.c +++ b/sys/fs/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/fs/umapfs/umap.h b/sys/fs/umapfs/umap.h index db1efd4..54ae097 100644 --- a/sys/fs/umapfs/umap.h +++ b/sys/fs/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/fs/umapfs/umap_subr.c b/sys/fs/umapfs/umap_subr.c index 8333943..3b3629d 100644 --- a/sys/fs/umapfs/umap_subr.c +++ b/sys/fs/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 #include +#include #include #include #include @@ -48,11 +49,8 @@ #include #include -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/fs/umapfs/umap_vfsops.c b/sys/fs/umapfs/umap_vfsops.c index 517c291..897e2ce 100644 --- a/sys/fs/umapfs/umap_vfsops.c +++ b/sys/fs/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 #include #include +#include #include #include #include @@ -54,7 +55,7 @@ #include #include -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/fs/umapfs/umap_vnops.c b/sys/fs/umapfs/umap_vnops.c index 7c14cda..17064f4 100644 --- a/sys/fs/umapfs/umap_vnops.c +++ b/sys/fs/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/fs/unionfs/union.h b/sys/fs/unionfs/union.h index 9c740d3..c956921 100644 --- a/sys/fs/unionfs/union.h +++ b/sys/fs/unionfs/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/fs/unionfs/union_subr.c b/sys/fs/unionfs/union_subr.c index 6549f7d..63e25e6 100644 --- a/sys/fs/unionfs/union_subr.c +++ b/sys/fs/unionfs/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 #include #include +#include +#include +#include /* for vnode_pager_setsize */ #include #include @@ -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/fs/unionfs/union_vfsops.c b/sys/fs/unionfs/union_vfsops.c index a1a6a0d..0295961 100644 --- a/sys/fs/unionfs/union_vfsops.c +++ b/sys/fs/unionfs/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 #include -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 = ""; + cp = ":"; break; case UNMNT_BELOW: - cp = ""; + cp = ":"; 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/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c index 5940243..4a66dc0 100644 --- a/sys/fs/unionfs/union_vnops.c +++ b/sys/fs/unionfs/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 #include #include -#include +#include #include #include #include @@ -51,16 +51,12 @@ #include #include #include +#include #include -/* 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 */ -- cgit v1.1