diff options
author | dyson <dyson@FreeBSD.org> | 1997-02-10 02:22:35 +0000 |
---|---|---|
committer | dyson <dyson@FreeBSD.org> | 1997-02-10 02:22:35 +0000 |
commit | 10f666af84d48e89e4e2960415c9b616fce4077f (patch) | |
tree | 88a944de263165091f0a18abeedbaaccec532407 /sys | |
parent | 0960d7e91af3428ffba89b42228d82d8afaa0389 (diff) | |
download | FreeBSD-src-10f666af84d48e89e4e2960415c9b616fce4077f.zip FreeBSD-src-10f666af84d48e89e4e2960415c9b616fce4077f.tar.gz |
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 <hsu@freebsd.org>
Diffstat (limited to 'sys')
302 files changed, 13528 insertions, 9858 deletions
diff --git a/sys/amd64/amd64/autoconf.c b/sys/amd64/amd64/autoconf.c index 866b420..6e305d0 100644 --- a/sys/amd64/amd64/autoconf.c +++ b/sys/amd64/amd64/autoconf.c @@ -53,6 +53,7 @@ #include <sys/reboot.h> #include <sys/kernel.h> #include <sys/mount.h> +#include <sys/vnode.h> #include <sys/sysctl.h> #include <machine/bootinfo.h> @@ -88,31 +89,15 @@ static void configure __P((void *)); SYSINIT(configure, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure, NULL) -#ifdef MFS_ROOT -extern struct vfsops mfs_vfsops; -#endif -#ifdef FFS -extern struct vfsops ufs_vfsops; -#endif -#ifdef LFS -extern struct vfsops lfs_vfsops; -#endif -#ifdef NFS -extern int nfs_mountroot __P((void *)); -#endif -#ifdef CD9660 -extern int cd9660_mountroot __P((void *)); -#endif -#ifdef MSDOSFS -extern int msdosfs_mountroot __P((void *)); -#endif - static void configure_finish __P((void)); static void configure_start __P((void)); static int setdumpdev __P((dev_t dev)); static void setroot __P((void)); #ifdef CD9660 + +#include <isofs/cd9660/iso.h> + /* We need to try out all our potential CDROM drives, so we need a table. */ static struct { char *name; @@ -138,7 +123,7 @@ find_cdrom_root(dummy) rootdev = makedev(try_cdrom[k].major,j*8); printf("trying rootdev=0x%lx (%s%d)\n", rootdev, try_cdrom[k].name,j); - i = (*cd9660_mountroot)((void *)NULL); + i = (*cd9660_mountroot)(); if (!i) return i; } return EINVAL; @@ -176,6 +161,11 @@ configure(dummy) enable_intr(); INTREN(IRQ_SLAVE); +#if NCRD > 0 + /* Before isa_configure to avoid ISA drivers finding our cards */ + pccard_configure(); +#endif + #if NEISA > 0 eisa_configure(); #endif @@ -188,11 +178,6 @@ configure(dummy) isa_configure(); #endif -#if NCRD > 0 - /* After everyone else has a chance at grabbing resources */ - pccard_configure(); -#endif - if (setdumpdev(dumpdev) != 0) dumpdev = NODEV; @@ -235,19 +220,26 @@ configure(dummy) } #ifdef CD9660 - if ((boothowto & RB_CDROM) && !mountroot) { + if ((boothowto & RB_CDROM)) { if (bootverbose) printf("Considering CD-ROM root f/s.\n"); - mountroot = find_cdrom_root; + mountrootfsname = "cd9660"; } #endif +#ifdef NFS + if (!mountrootfsname && nfs_diskless_valid) { + if (bootverbose) + printf("Considering NFS root f/s.\n"); + mountrootfsname = "nfs"; + } +#endif /* NFS */ + #ifdef MFS_ROOT - if (!mountroot) { + if (!mountrootfsname) { if (bootverbose) printf("Considering MFS root f/s.\n"); - mountroot = vfs_mountroot; /* XXX goes away*/ - mountrootvfsops = &mfs_vfsops; + mountrootfsname = "mfs"; /* * Ignore the -a flag if this kernel isn't compiled * with a generic root/swap configuration: if we skip @@ -260,21 +252,11 @@ configure(dummy) setroot(); } #endif - -#ifdef NFS - if (!mountroot && nfs_diskless_valid) { - if (bootverbose) - printf("Considering NFS root f/s.\n"); - mountroot = nfs_mountroot; - } -#endif /* NFS */ - #ifdef FFS - if (!mountroot) { + if (!mountrootfsname) { + mountrootfsname = "ufs"; if (bootverbose) printf("Considering FFS root f/s.\n"); - mountroot = vfs_mountroot; /* XXX goes away*/ - mountrootvfsops = &ufs_vfsops; /* * Ignore the -a flag if this kernel isn't compiled * with a generic root/swap configuration: if we skip @@ -288,11 +270,10 @@ configure(dummy) } #endif #ifdef LFS - if (!mountroot) { + if (!mountrootfsname) { if (bootverbose) printf("Considering LFS root f/s.\n"); - mountroot = vfs_mountroot; /* XXX goes away*/ - mountrootvfsops = &lfs_vfsops; + mountrootfsname = "lfs"; /* * Ignore the -a flag if this kernel isn't compiled * with a generic root/swap configuration: if we skip @@ -305,8 +286,7 @@ configure(dummy) setroot(); } #endif - - if (!mountroot) { + if (!mountrootfsname) { panic("Nobody wants to mount my root for me"); } @@ -417,4 +397,4 @@ sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS } SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW, - 0, sizeof dumpdev, sysctl_kern_dumpdev, "T,dev_t", ""); + 0, sizeof dumpdev, sysctl_kern_dumpdev, "I", ""); diff --git a/sys/amd64/amd64/db_trace.c b/sys/amd64/amd64/db_trace.c index 386e093..93078a8 100644 --- a/sys/amd64/amd64/db_trace.c +++ b/sys/amd64/amd64/db_trace.c @@ -34,7 +34,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_prot.h> #include <vm/pmap.h> #include <ddb/ddb.h> diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index 9a2f646e..c993129 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -61,13 +61,15 @@ #include <sys/vmmeter.h> #include <vm/vm.h> #include <vm/vm_param.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <sys/user.h> #include <net/if.h> #include <netinet/in.h> #include <nfs/nfsv2.h> +#include <nfs/rpcv2.h> +#include <nfs/nfs.h> #include <nfs/nfsdiskless.h> extern int main __P((void)); diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 6ebccff..b95b0ff 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -82,7 +82,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_kern.h> #include <vm/vm_object.h> #include <vm/vm_page.h> diff --git a/sys/amd64/amd64/mem.c b/sys/amd64/amd64/mem.c index 28d8058..5275e7d 100644 --- a/sys/amd64/amd64/mem.c +++ b/sys/amd64/amd64/mem.c @@ -68,7 +68,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_prot.h> #include <vm/pmap.h> #include <vm/vm_extern.h> diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 3c47ee4..0159c32 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -85,7 +85,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_kern.h> #include <vm/vm_page.h> #include <vm/vm_map.h> diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c index d1b9807..8506cfc 100644 --- a/sys/amd64/amd64/sys_machdep.c +++ b/sys/amd64/amd64/sys_machdep.c @@ -44,7 +44,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_extern.h> diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index b38e35d..c866f32 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -61,7 +61,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_kern.h> #include <vm/vm_map.h> diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c index d320dac..f6c1606 100644 --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -58,7 +58,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_kern.h> #include <vm/vm_page.h> #include <vm/vm_map.h> diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index 55c8a35..9fe4d40 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -450,7 +450,7 @@ linux_getdents(struct proc *p, struct linux_getdents_args *args, int *retval) buflen = max(DIRBLKSIZ, nbytes + blockoff); buflen = min(buflen, MAXBSIZE); buf = malloc(buflen, M_TEMP, M_WAITOK); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); again: aiov.iov_base = buf; aiov.iov_len = buflen; @@ -530,7 +530,7 @@ again: eof: *retval = nbytes - resid; out: - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, p); free(buf, M_TEMP); return error; } diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 536d797..d0332cf 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -237,7 +237,7 @@ linux_uselib(struct proc *p, struct linux_uselib_args *args, int *retval) /* * Lock no longer needed */ - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, p); locked = 0; /* @@ -392,7 +392,7 @@ cleanup: * Unlock vnode if needed */ if (locked) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, p); /* * Release the kernel mapping. diff --git a/sys/conf/files b/sys/conf/files index f543378..48e61f0 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -52,6 +52,7 @@ kern/kern_exit.c standard kern/kern_fork.c standard kern/kern_ktrace.c standard kern/kern_lkm.c standard +kern/kern_lock.c standard kern/kern_lockf.c standard kern/kern_malloc.c standard kern/kern_mib.c standard @@ -373,7 +374,6 @@ ufs/ufs/ufs_vfsops.c standard ufs/ufs/ufs_vnops.c standard vm/default_pager.c standard vm/device_pager.c standard -vm/kern_lock.c standard vm/swap_pager.c standard vm/vm_fault.c standard vm/vm_glue.c standard diff --git a/sys/ddb/db_watch.c b/sys/ddb/db_watch.c index a8edc24..d42fb97 100644 --- a/sys/ddb/db_watch.c +++ b/sys/ddb/db_watch.c @@ -35,7 +35,7 @@ #include <sys/systm.h> #include <vm/vm.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_prot.h> diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c index 9c095c9..c2d495d 100644 --- a/sys/dev/fdc/fdc.c +++ b/sys/dev/fdc/fdc.c @@ -277,7 +277,7 @@ static d_strategy_t fdstrategy; static struct cdevsw fd_cdevsw; static struct bdevsw fd_bdevsw = { Fdopen, fdclose, fdstrategy, fdioctl, /*2*/ - nodump, nopsize, 0, "fd", &fd_cdevsw, -1 }; + nodump, nopsize, D_DISK, "fd", &fd_cdevsw, -1 }; static struct isa_device *fdcdevs[NFDC]; diff --git a/sys/dev/vn/vn.c b/sys/dev/vn/vn.c index cbff83c..f03b7c1 100644 --- a/sys/dev/vn/vn.c +++ b/sys/dev/vn/vn.c @@ -457,11 +457,11 @@ vnioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) return(error); error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p); if (error) { - VOP_UNLOCK(nd.ni_vp); + VOP_UNLOCK(nd.ni_vp, 0, p); (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p); return(error); } - VOP_UNLOCK(nd.ni_vp); + VOP_UNLOCK(nd.ni_vp, 0, p); vn->sc_vp = nd.ni_vp; vn->sc_size = btodb(vattr.va_size); /* note truncation */ error = vnsetcred(vn, p->p_ucred); 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 <isofs/cd9660/iso.h> #include <isofs/cd9660/cd9660_node.h> +#include <isofs/cd9660/cd9660_mount.h> #include <isofs/cd9660/iso_rrip.h> -#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 <isofs/cd9660/iso.h> -#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 <sys/ioctl.h> #include <sys/errno.h> #include <sys/malloc.h> +#include <sys/stat.h> #include <isofs/cd9660/iso.h> -#include <isofs/cd9660/cd9660_node.h> #include <isofs/cd9660/iso_rrip.h> +#include <isofs/cd9660/cd9660_node.h> +#include <isofs/cd9660/cd9660_mount.h> 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 <mp, client> 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 <miscfs/fifofs/fifo.h> #include <sys/malloc.h> #include <sys/dir.h> +#include <sys/unistd.h> #include <isofs/cd9660/iso.h> #include <isofs/cd9660/cd9660_node.h> @@ -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 <sys/param.h> -#include <sys/kernel.h> +#include <sys/systm.h> #include <sys/proc.h> #include <sys/time.h> #include <sys/namei.h> @@ -44,7 +44,6 @@ #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/stat.h> -#include <sys/systm.h> #include <sys/ioctl.h> #include <sys/file.h> #include <sys/errno.h> @@ -64,8 +63,6 @@ struct fifoinfo { }; static int fifo_ebadf __P((void)); -static int fifo_unlock __P((struct vop_unlock_args *)); -static int fifo_lock __P((struct vop_lock_args *)); static int fifo_print __P((struct vop_print_args *)); vop_t **fifo_vnodeop_p; @@ -81,8 +78,10 @@ static struct vnodeopv_entry_desc fifo_vnodeop_entries[] = { { &vop_setattr_desc, (vop_t *)fifo_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)fifo_read }, /* read */ { &vop_write_desc, (vop_t *)fifo_write }, /* write */ + { &vop_lease_desc, (vop_t *)fifo_lease_check }, /* lease */ { &vop_ioctl_desc, (vop_t *)fifo_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)fifo_select }, /* select */ + { &vop_revoke_desc, (vop_t *)fifo_revoke }, /* revoke */ { &vop_mmap_desc, (vop_t *)fifo_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)fifo_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)fifo_seek }, /* seek */ @@ -149,8 +148,9 @@ fifo_open(ap) struct proc *a_p; } */ *ap; { - register struct vnode *vp = ap->a_vp; - register struct fifoinfo *fip; + struct vnode *vp = ap->a_vp; + struct fifoinfo *fip; + struct proc *p = ap->a_p; struct socket *rso, *wso; int error; static char openstr[] = "fifo"; @@ -158,14 +158,14 @@ fifo_open(ap) if ((fip = vp->v_fifoinfo) == NULL) { MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK); vp->v_fifoinfo = fip; - error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0, ap->a_p); + error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, ap->a_p); if (error) { free(fip, M_VNODE); vp->v_fifoinfo = NULL; return (error); } fip->fi_readsock = rso; - error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0, ap->a_p); + error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, ap->a_p); if (error) { (void)soclose(rso); free(fip, M_VNODE); @@ -185,60 +185,52 @@ fifo_open(ap) wso->so_state |= SS_CANTRCVMORE; rso->so_state |= SS_CANTSENDMORE; } - error = 0; - if ((ap->a_mode & (FREAD|FWRITE)) == (FREAD|FWRITE)) { - if (fip->fi_readers == 0) { + if (ap->a_mode & FREAD) { + fip->fi_readers++; + if (fip->fi_readers == 1) { fip->fi_writesock->so_state &= ~SS_CANTSENDMORE; if (fip->fi_writers > 0) wakeup((caddr_t)&fip->fi_writers); } - if (fip->fi_writers == 0) { + } + if (ap->a_mode & FWRITE) { + fip->fi_writers++; + if (fip->fi_writers == 1) { fip->fi_readsock->so_state &= ~SS_CANTRCVMORE; if (fip->fi_readers > 0) wakeup((caddr_t)&fip->fi_readers); } - fip->fi_readers++; - fip->fi_writers++; } - else if (ap->a_mode & FREAD) { - fip->fi_readers++; - if (fip->fi_readers == 1) { - fip->fi_writesock->so_state &= ~SS_CANTSENDMORE; - if (fip->fi_writers > 0) - wakeup((caddr_t)&fip->fi_writers); + if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) { + while (fip->fi_writers == 0) { + VOP_UNLOCK(vp, 0, p); + error = tsleep((caddr_t)&fip->fi_readers, + PCATCH | PSOCK, openstr, 0); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + if (error) + goto bad; } - if (!(ap->a_mode & O_NONBLOCK)) - while (fip->fi_writers == 0) { - VOP_UNLOCK(vp); - error = tsleep((caddr_t)&fip->fi_readers, - PCATCH | PSOCK, openstr, 0); - VOP_LOCK(vp); - if (error) - break; - } } - else { - fip->fi_writers++; - if (fip->fi_readers == 0 && (ap->a_mode & O_NONBLOCK)) { - error = ENXIO; - } else { - if (fip->fi_writers == 1) { - fip->fi_readsock->so_state &= ~SS_CANTRCVMORE; - if (fip->fi_readers > 0) - wakeup((caddr_t)&fip->fi_readers); + if (ap->a_mode & FWRITE) { + if (ap->a_mode & O_NONBLOCK) { + if (fip->fi_readers == 0) { + error = ENXIO; + goto bad; } + } else { while (fip->fi_readers == 0) { - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); error = tsleep((caddr_t)&fip->fi_writers, PCATCH | PSOCK, openstr, 0); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (error) - break; + goto bad; } } } - if (error) - VOP_CLOSE(vp, ap->a_mode, ap->a_cred, ap->a_p); + return (0); +bad: + VOP_CLOSE(vp, ap->a_mode, ap->a_cred, p); return (error); } @@ -255,8 +247,9 @@ fifo_read(ap) struct ucred *a_cred; } */ *ap; { - register struct uio *uio = ap->a_uio; - register struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock; + struct uio *uio = ap->a_uio; + struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock; + struct proc *p = uio->uio_procp; int error, startresid; #ifdef DIAGNOSTIC @@ -268,10 +261,10 @@ fifo_read(ap) if (ap->a_ioflag & IO_NDELAY) rso->so_state |= SS_NBIO; startresid = uio->uio_resid; - VOP_UNLOCK(ap->a_vp); - error = soreceive(rso, (struct mbuf **)0, uio, - (struct mbuf **)0, (struct mbuf **)0, (int*)0); - VOP_LOCK(ap->a_vp); + VOP_UNLOCK(ap->a_vp, 0, p); + error = soreceive(rso, (struct mbuf **)0, uio, (struct mbuf **)0, + (struct mbuf **)0, (int *)0); + vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p); /* * Clear EOF indication after first such return. */ @@ -296,6 +289,7 @@ fifo_write(ap) } */ *ap; { struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock; + struct proc *p = ap->a_uio->uio_procp; int error; #ifdef DIAGNOSTIC @@ -304,9 +298,9 @@ fifo_write(ap) #endif if (ap->a_ioflag & IO_NDELAY) wso->so_state |= SS_NBIO; - VOP_UNLOCK(ap->a_vp); + VOP_UNLOCK(ap->a_vp, 0, p); error = sosend(wso, (struct mbuf *)0, ap->a_uio, 0, (struct mbuf *)0, 0); - VOP_LOCK(ap->a_vp); + vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p); if (ap->a_ioflag & IO_NDELAY) wso->so_state &= ~SS_NBIO; return (error); @@ -328,14 +322,23 @@ fifo_ioctl(ap) } */ *ap; { struct file filetmp; + int error; if (ap->a_command == FIONBIO) return (0); - if (ap->a_fflag & FREAD) + if (ap->a_fflag & FREAD) { filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock; - else + error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p); + if (error) + return (error); + } + if (ap->a_fflag & FWRITE) { filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock; - return (soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p)); + error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p); + if (error) + return (error); + } + return (0); } /* ARGSUSED */ @@ -350,12 +353,33 @@ fifo_select(ap) } */ *ap; { struct file filetmp; + int ready; - if (ap->a_fflags & FREAD) + if (ap->a_fflags & FREAD) { filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock; - else + ready = soo_select(&filetmp, ap->a_which, ap->a_p); + if (ready) + return (ready); + } + if (ap->a_fflags & FWRITE) { filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock; - return (soo_select(&filetmp, ap->a_which, ap->a_p)); + ready = soo_select(&filetmp, ap->a_which, ap->a_p); + if (ready) + return (ready); + } + return (0); +} + +int +fifo_inactive(ap) + struct vop_inactive_args /* { + struct vnode *a_vp; + struct proc *a_p; + } */ *ap; +{ + + VOP_UNLOCK(ap->a_vp, 0, ap->a_p); + return (0); } /* @@ -385,31 +409,6 @@ fifo_bmap(ap) } /* - * At the moment we do not do any locking. - */ -/* ARGSUSED */ -static int -fifo_lock(ap) - struct vop_lock_args /* { - struct vnode *a_vp; - } */ *ap; -{ - - return (0); -} - -/* ARGSUSED */ -static int -fifo_unlock(ap) - struct vop_unlock_args /* { - struct vnode *a_vp; - } */ *ap; -{ - - return (0); -} - -/* * Device close routine */ /* ARGSUSED */ @@ -426,16 +425,16 @@ fifo_close(ap) register struct fifoinfo *fip = vp->v_fifoinfo; int error1, error2; - if (ap->a_fflag & FWRITE) { - fip->fi_writers--; - if (fip->fi_writers == 0) - socantrcvmore(fip->fi_readsock); - } if (ap->a_fflag & FREAD) { fip->fi_readers--; if (fip->fi_readers == 0) socantsendmore(fip->fi_writesock); } + if (ap->a_fflag & FWRITE) { + fip->fi_writers--; + if (fip->fi_writers == 0) + socantrcvmore(fip->fi_readsock); + } if (vp->v_usecount > 1) return (0); error1 = soclose(fip->fi_readsock); diff --git a/sys/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 <sys/vnode.h> #include <sys/mount.h> #include <sys/systm.h> +#include <sys/proc.h> #include <msdosfs/bpb.h> #include <msdosfs/direntry.h> @@ -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 <sys/param.h> #include <sys/systm.h> +#include <sys/proc.h> #include <sys/time.h> #include <sys/types.h> #include <sys/vnode.h> @@ -48,11 +49,8 @@ #include <sys/malloc.h> #include <miscfs/nullfs/null.h> -extern int nullfs_init __P((void)); - #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ #define NNULLNODECACHE 16 -#define NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1)) /* * Null layer cache: @@ -62,51 +60,32 @@ extern int nullfs_init __P((void)); * alias is removed the lower vnode is vrele'd. */ -/* - * Cache head - */ -struct null_node_cache { - struct null_node *ac_forw; - struct null_node *ac_back; -}; - -static struct null_node_cache null_node_cache[NNULLNODECACHE]; +#define NULL_NHASH(vp) \ + (&null_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & null_node_hash]) +LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl; +u_long null_node_hash; static int null_node_alloc __P((struct mount *mp, struct vnode *lowervp, struct vnode **vpp)); static struct vnode * null_node_find __P((struct mount *mp, struct vnode *lowervp)); -static struct null_node_cache * - null_node_hash __P((struct vnode *lowervp)); /* * Initialise cache headers */ int -nullfs_init() +nullfs_init(vfsp) + struct vfsconf *vfsp; { - struct null_node_cache *ac; + #ifdef NULLFS_DIAGNOSTIC printf("nullfs_init\n"); /* printed during system boot */ #endif - - for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) - ac->ac_forw = ac->ac_back = (struct null_node *) ac; + null_node_hashtbl = hashinit(NNULLNODECACHE, M_CACHE, &null_node_hash); return (0); } /* - * Compute hash list for given lower vnode - */ -static struct null_node_cache * -null_node_hash(lowervp) -struct vnode *lowervp; -{ - - return (&null_node_cache[NULL_NHASH(lowervp)]); -} - -/* * Return a VREF'ed alias for lower vnode if already exists, else 0. */ static struct vnode * @@ -114,7 +93,8 @@ null_node_find(mp, lowervp) struct mount *mp; struct vnode *lowervp; { - struct null_node_cache *hd; + struct proc *p = curproc; /* XXX */ + struct null_node_hashhead *hd; struct null_node *a; struct vnode *vp; @@ -124,9 +104,9 @@ null_node_find(mp, lowervp) * the lower vnode. If found, the increment the null_node * reference count (but NOT the lower vnode's VREF counter). */ - hd = null_node_hash(lowervp); + hd = NULL_NHASH(lowervp); loop: - for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) { + for (a = hd->lh_first; a != 0; a = a->null_hash.le_next) { if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { vp = NULLTOV(a); /* @@ -134,7 +114,7 @@ loop: * stuff, but we don't want to lock * the lower node. */ - if (vget(vp, 0)) { + if (vget(vp, 0, p)) { printf ("null_node_find: vget failed.\n"); goto loop; }; @@ -157,7 +137,7 @@ null_node_alloc(mp, lowervp, vpp) struct vnode *lowervp; struct vnode **vpp; { - struct null_node_cache *hd; + struct null_node_hashhead *hd; struct null_node *xp; struct vnode *othervp, *vp; int error; @@ -194,8 +174,8 @@ null_node_alloc(mp, lowervp, vpp) return 0; }; VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */ - hd = null_node_hash(lowervp); - insque(xp, hd); + hd = NULL_NHASH(lowervp); + LIST_INSERT_HEAD(hd, xp, null_hash); return 0; } @@ -250,9 +230,8 @@ null_node_create(mp, lowervp, newvpp) #ifdef DIAGNOSTIC if (lowervp->v_usecount < 1) { /* Should never happen... */ - vprint ("null_node_create: alias ",aliasvp); - vprint ("null_node_create: lower ",lowervp); - printf ("null_node_create: lower has 0 usecount.\n"); + vprint ("null_node_create: alias ", aliasvp); + vprint ("null_node_create: lower ", lowervp); panic ("null_node_create: lower has 0 usecount."); }; #endif diff --git a/sys/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 <sys/param.h> #include <sys/systm.h> -#include <sys/kernel.h> +#include <sys/proc.h> #include <sys/time.h> #include <sys/types.h> #include <sys/vnode.h> @@ -55,7 +55,7 @@ #include <sys/malloc.h> #include <miscfs/nullfs/null.h> -extern int nullfs_init __P((void)); +extern int nullfs_init __P((struct vfsconf *)); static int nullfs_fhtovp __P((struct mount *mp, struct fid *fidp, struct mbuf *nam, struct vnode **vpp, @@ -146,7 +146,7 @@ nullfs_mount(mp, path, data, ndp, p) /* * Unlock the node (either the lower or the alias) */ - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); /* * Make sure the node alias worked */ @@ -166,7 +166,7 @@ nullfs_mount(mp, path, data, ndp, p) if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) mp->mnt_flag |= MNT_LOCAL; mp->mnt_data = (qaddr_t) xmp; - getnewfsid(mp, MOUNT_LOFS); + vfs_getnewfsid(mp); (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); @@ -212,12 +212,8 @@ nullfs_unmount(mp, mntflags, p) printf("nullfs_unmount(mp = %x)\n", mp); #endif - if (mntflags & MNT_FORCE) { - /* lofs can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } /* * Clear out buffer cache. I don't think we @@ -259,6 +255,7 @@ nullfs_root(mp, vpp) struct mount *mp; struct vnode **vpp; { + struct proc *p = curproc; /* XXX */ struct vnode *vp; #ifdef NULLFS_DIAGNOSTIC @@ -273,7 +270,7 @@ nullfs_root(mp, vpp) */ vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; VREF(vp); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); *vpp = vp; return 0; } diff --git a/sys/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 <sys/un.h> #include <miscfs/portal/portal.h> -static int portal_init __P((void)); static int portal_mount __P((struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct proc *p)); static int portal_start __P((struct mount *mp, int flags, struct proc *p)); static int portal_unmount __P((struct mount *mp, int mntflags, struct proc *p)); static int portal_root __P((struct mount *mp, struct vnode **vpp)); -static int portal_quotactl __P((struct mount *mp, int cmd, uid_t uid, - caddr_t arg, struct proc *p)); static int portal_statfs __P((struct mount *mp, struct statfs *sbp, struct proc *p)); -static int portal_sync __P((struct mount *mp, int waitfor, - struct ucred *cred, struct proc *p)); -static int portal_vget __P((struct mount *mp, ino_t ino, - struct vnode **vpp)); -static int portal_fhtovp __P((struct mount *mp, struct fid *fhp, - struct mbuf *nam, struct vnode **vpp, - int *exflagsp, struct ucred **credanonp)); -static int portal_vptofh __P((struct vnode *vp, struct fid *fhp)); static int -portal_init() +portal_init(vfsp) + struct vfsconf *vfsp; { return (0); @@ -150,7 +140,7 @@ portal_mount(mp, path, data, ndp, p) mp->mnt_flag |= MNT_LOCAL; mp->mnt_data = (qaddr_t) fmp; - getnewfsid(mp, MOUNT_PORTAL); + vfs_getnewfsid(mp); (void)copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); @@ -186,12 +176,8 @@ portal_unmount(mp, mntflags, p) int error, flags = 0; - if (mntflags & MNT_FORCE) { - /* portal can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } /* * Clear out buffer cache. I don't think we @@ -241,39 +227,26 @@ portal_root(mp, vpp) struct mount *mp; struct vnode **vpp; { + struct proc *p = curproc; /* XXX */ struct vnode *vp; - /* * Return locked reference to root. */ vp = VFSTOPORTAL(mp)->pm_root; VREF(vp); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); *vpp = vp; return (0); } static int -portal_quotactl(mp, cmd, uid, arg, p) - struct mount *mp; - int cmd; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - - return (EOPNOTSUPP); -} - -static int portal_statfs(mp, sbp, p) struct mount *mp; struct statfs *sbp; struct proc *p; { - sbp->f_type = MOUNT_PORTAL; sbp->f_flags = 0; sbp->f_bsize = DEV_BSIZE; sbp->f_iosize = DEV_BSIZE; @@ -283,6 +256,7 @@ portal_statfs(mp, sbp, p) sbp->f_files = 1; /* Allow for "." */ sbp->f_ffree = 0; /* See comments above */ if (sbp != &mp->mnt_stat) { + sbp->f_type = mp->mnt_vfc->vfc_typenum; bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); @@ -290,48 +264,17 @@ portal_statfs(mp, sbp, p) return (0); } -static int -portal_sync(mp, waitfor, cred, p) - struct mount *mp; - int waitfor; - struct ucred *cred; - struct proc *p; -{ - - return (0); -} - -static int -portal_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - - return (EOPNOTSUPP); -} - -static int -portal_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) - struct mount *mp; - struct fid *fhp; - struct mbuf *nam; - struct vnode **vpp; - int *exflagsp; - struct ucred **credanonp; -{ - - return (EOPNOTSUPP); -} - -static int -portal_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; -{ - - return (EOPNOTSUPP); -} +#define portal_fhtovp ((int (*) __P((struct mount *, struct fid *, \ + struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp) +#define portal_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \ + struct proc *)))eopnotsupp) +#define portal_sync ((int (*) __P((struct mount *, int, struct ucred *, \ + struct proc *)))nullop) +#define portal_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ + size_t, struct proc *)))eopnotsupp) +#define portal_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \ + eopnotsupp) +#define portal_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp) static struct vfsops portal_vfsops = { portal_mount, diff --git a/sys/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)); /* <machine/reg.h> */ struct reg; struct fpreg; #define PFIND(pid) ((pid) ? pfind(pid) : &proc0) -extern int procfs_freevp __P((struct vnode *)); -extern int procfs_allocvp __P((struct mount *, struct vnode **, long, pfstype)); -extern struct vnode *procfs_findtextvp __P((struct proc *)); -extern int procfs_sstep __P((struct proc *)); -extern void procfs_fix_sstep __P((struct proc *)); -extern int procfs_read_regs __P((struct proc *, struct reg *)); -extern int procfs_write_regs __P((struct proc *, struct reg *)); -extern int procfs_read_fpregs __P((struct proc *, struct fpreg *)); -extern int procfs_write_fpregs __P((struct proc *, struct fpreg *)); -extern int procfs_donote __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_doregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_dofpregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_doctl __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_dostatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_domap __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_dotype __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_freevp __P((struct vnode *)); +int procfs_allocvp __P((struct mount *, struct vnode **, long, pfstype)); +struct vnode *procfs_findtextvp __P((struct proc *)); +int procfs_sstep __P((struct proc *)); +void procfs_fix_sstep __P((struct proc *)); +int procfs_read_regs __P((struct proc *, struct reg *)); +int procfs_write_regs __P((struct proc *, struct reg *)); +int procfs_read_fpregs __P((struct proc *, struct fpreg *)); +int procfs_write_fpregs __P((struct proc *, struct fpreg *)); +int procfs_donote __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_doregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_dofpregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_doctl __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_dostatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_domap __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_dotype __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -/* check to see if the process has the "items" (regs/file) */ +/* functions to check whether or not files should be displayed */ int procfs_validfile __P((struct proc *)); int procfs_validfpregs __P((struct proc *)); int procfs_validregs __P((struct proc *)); diff --git a/sys/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 <sys/resourcevar.h> #include <sys/signal.h> #include <sys/signalvar.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_extern.h> - +#include <sys/ptrace.h> #include <miscfs/procfs/procfs.h> +#ifndef FIX_SSTEP +#define FIX_SSTEP(p) +#endif + /* * True iff process (p) is in trace wait state * relative to process (curp) @@ -67,13 +68,6 @@ (p)->p_pptr == (curp) && \ ((p)->p_flag & P_TRACED)) -#ifdef notdef -#define FIX_SSTEP(p) { \ - procfs_fix_sstep(p); \ - } \ -} -#endif - #define PROCFS_CTL_ATTACH 1 #define PROCFS_CTL_DETACH 2 #define PROCFS_CTL_STEP 3 @@ -220,8 +214,10 @@ procfs_control(curp, p, op) */ case PROCFS_CTL_STEP: PHOLD(p); - procfs_sstep(p); + error = procfs_sstep(p); PRELE(p); + if (error) + return (error); break; /* diff --git a/sys/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 <vm/vm_param.h> #include <vm/vm_prot.h> #include <vm/vm_inherit.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_page.h> diff --git a/sys/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 <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_kern.h> @@ -295,14 +295,11 @@ procfs_domem(curp, p, pfs, uio) struct pfsnode *pfs; struct uio *uio; { - int error; if (uio->uio_resid == 0) return (0); - error = procfs_rwmem(p, uio); - - return (error); + return (procfs_rwmem(p, uio)); } /* @@ -320,5 +317,6 @@ struct vnode * procfs_findtextvp(p) struct proc *p; { + return (p->p_textvp); } diff --git a/sys/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 <miscfs/procfs/procfs.h> #include <vm/vm.h> /* for PAGE_SIZE */ -static int procfs_fhtovp __P((struct mount *mp, struct fid *fhp, - struct mbuf *nam, struct vnode **vpp, - int *exflagsp, struct ucred **credanonp)); -static int procfs_init __P((void)); +static int procfs_init __P((struct vfsconf *vfsp)); static int procfs_mount __P((struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct proc *p)); -static int procfs_quotactl __P((struct mount *mp, int cmds, uid_t uid, - caddr_t arg, struct proc *p)); static int procfs_start __P((struct mount *mp, int flags, struct proc *p)); static int procfs_statfs __P((struct mount *mp, struct statfs *sbp, struct proc *p)); -static int procfs_sync __P((struct mount *mp, int waitfor, - struct ucred *cred, struct proc *p)); static int procfs_unmount __P((struct mount *mp, int mntflags, struct proc *p)); -static int procfs_vget __P((struct mount *mp, ino_t ino, - struct vnode **vpp)); -static int procfs_vptofh __P((struct vnode *vp, struct fid *fhp)); /* * VFS Operations. @@ -101,7 +91,7 @@ procfs_mount(mp, path, data, ndp, p) mp->mnt_flag |= MNT_LOCAL; mp->mnt_data = 0; - getnewfsid(mp, MOUNT_PROCFS); + vfs_getnewfsid(mp); (void) copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname, MNAMELEN, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); @@ -125,12 +115,8 @@ procfs_unmount(mp, mntflags, p) int error; int flags = 0; - if (mntflags & MNT_FORCE) { - /* procfs can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } error = vflush(mp, 0, flags); if (error) @@ -144,24 +130,10 @@ procfs_root(mp, vpp) struct mount *mp; struct vnode **vpp; { - struct pfsnode *pfs; - struct vnode *vp; - int error; - - error = procfs_allocvp(mp, &vp, (pid_t) 0, Proot); - if (error) - return (error); - - vp->v_type = VDIR; - vp->v_flag = VROOT; - pfs = VTOPFS(vp); - *vpp = vp; - return (0); + return (procfs_allocvp(mp, vpp, 0, Proot)); } -/* - */ /* ARGSUSED */ static int procfs_start(mp, flags, p) @@ -182,7 +154,6 @@ procfs_statfs(mp, sbp, p) struct statfs *sbp; struct proc *p; { - sbp->f_type = MOUNT_PROCFS; sbp->f_bsize = PAGE_SIZE; sbp->f_iosize = PAGE_SIZE; sbp->f_blocks = 1; /* avoid divide by zero in some df's */ @@ -192,6 +163,7 @@ procfs_statfs(mp, sbp, p) sbp->f_ffree = maxproc - nprocs; /* approx */ if (sbp != &mp->mnt_stat) { + sbp->f_type = mp->mnt_vfc->vfc_typenum; bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); @@ -200,68 +172,25 @@ procfs_statfs(mp, sbp, p) return (0); } - -static int -procfs_quotactl(mp, cmds, uid, arg, p) - struct mount *mp; - int cmds; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - - return (EOPNOTSUPP); -} - static int -procfs_sync(mp, waitfor, cred, p) - struct mount *mp; - int waitfor; - struct ucred *cred; - struct proc *p; +procfs_init(vfsp) + struct vfsconf *vfsp; { return (0); } -static int -procfs_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - - return (EOPNOTSUPP); -} - -static int -procfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) - struct mount *mp; - struct fid *fhp; - struct mbuf *nam; - struct vnode **vpp; - int *exflagsp; - struct ucred **credanonp; -{ - - return (EINVAL); -} - -static int -procfs_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; -{ - - return EINVAL; -} - -static int -procfs_init() -{ - - return (0); -} +#define procfs_fhtovp ((int (*) __P((struct mount *, struct fid *, \ + struct mbuf *, struct vnode **, int *, struct ucred **)))einval) +#define procfs_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \ + struct proc *)))eopnotsupp) +#define procfs_sync ((int (*) __P((struct mount *, int, struct ucred *, \ + struct proc *)))nullop) +#define procfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ + size_t, struct proc *)))eopnotsupp) +#define procfs_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \ + eopnotsupp) +#define procfs_vptofh ((int (*) __P((struct vnode *, struct fid *)))einval) static struct vfsops procfs_vfsops = { procfs_mount, diff --git a/sys/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 <sys/malloc.h> #include <sys/dirent.h> #include <sys/resourcevar.h> -#include <miscfs/procfs/procfs.h> #include <vm/vm.h> /* for PAGE_SIZE */ +#include <machine/reg.h> +#include <miscfs/procfs/procfs.h> static int procfs_abortop __P((struct vop_abortop_args *)); static int procfs_access __P((struct vop_access_args *)); @@ -78,29 +79,30 @@ static int procfs_setattr __P((struct vop_setattr_args *)); * process-specific sub-directories. It is * used in procfs_lookup and procfs_readdir */ -static struct pfsnames { - u_short d_namlen; - char d_name[PROCFS_NAMELEN]; - pfstype d_pfstype; - int (*d_valid) __P((struct proc *)); -} procent[] = { +struct proc_target { + u_char pt_type; + u_char pt_namlen; + char *pt_name; + pfstype pt_pfstype; + int (*pt_valid) __P((struct proc *p)); +} proc_targets[] = { #define N(s) sizeof(s)-1, s - /* namlen, nam, type validp */ - { N("."), Pproc, NULL }, - { N(".."), Proot, NULL }, - { N("file"), Pfile, procfs_validfile }, - { N("mem"), Pmem, NULL }, - { N("regs"), Pregs, procfs_validregs }, - { N("fpregs"), Pfpregs, procfs_validfpregs }, - { N("ctl"), Pctl, NULL }, - { N("status"), Pstatus, NULL }, - { N("note"), Pnote, NULL }, - { N("notepg"), Pnotepg, NULL }, - { N("map"), Pmap, procfs_validmap }, - { N("etype"), Ptype, procfs_validtype }, + /* name type validp */ + { DT_DIR, N("."), Pproc, NULL }, + { DT_DIR, N(".."), Proot, NULL }, + { DT_REG, N("file"), Pfile, procfs_validfile }, + { DT_REG, N("mem"), Pmem, NULL }, + { DT_REG, N("regs"), Pregs, procfs_validregs }, + { DT_REG, N("fpregs"), Pfpregs, procfs_validfpregs }, + { DT_REG, N("ctl"), Pctl, NULL }, + { DT_REG, N("status"), Pstatus, NULL }, + { DT_REG, N("note"), Pnote, NULL }, + { DT_REG, N("notepg"), Pnotepg, NULL }, + { DT_REG, N("map"), Pmap, procfs_validmap }, + { DT_REG, N("etype"), Ptype, procfs_validtype }, #undef N }; -#define Nprocent (sizeof(procent)/sizeof(procent[0])) +static const int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]); static pid_t atopid __P((const char *, u_int)); @@ -117,7 +119,12 @@ static pid_t atopid __P((const char *, u_int)); */ static int procfs_open(ap) - struct vop_open_args *ap; + struct vop_open_args /* { + struct vnode *a_vp; + int a_mode; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { struct pfsnode *pfs = VTOPFS(ap->a_vp); @@ -126,11 +133,10 @@ procfs_open(ap) if (PFIND(pfs->pfs_pid) == 0) return (ENOENT); /* was ESRCH, jsp */ - if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) || - ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) + if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) || + (pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)) return (EBUSY); - if (ap->a_mode & FWRITE) pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); @@ -152,7 +158,12 @@ procfs_open(ap) */ static int procfs_close(ap) - struct vop_close_args *ap; + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { struct pfsnode *pfs = VTOPFS(ap->a_vp); @@ -174,14 +185,51 @@ procfs_close(ap) */ static int procfs_ioctl(ap) - struct vop_ioctl_args *ap; + struct vop_ioctl_args /* { + struct vnode *a_vp; + int a_command; + caddr_t a_data; + int a_fflag; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { return (ENOTTY); } /* - * _inactive is called when the pfsnode + * do block mapping for pfsnode (vp). + * since we don't use the buffer cache + * for procfs this function should never + * be called. in any case, it's not clear + * what part of the kernel ever makes use + * of this function. for sanity, this is the + * usual no-op bmap, although returning + * (EIO) would be a reasonable alternative. + */ +int +procfs_bmap(ap) + struct vop_bmap_args /* { + struct vnode *a_vp; + daddr_t a_bn; + struct vnode **a_vpp; + daddr_t *a_bnp; + int *a_runp; + } */ *ap; +{ + + if (ap->a_vpp != NULL) + *ap->a_vpp = ap->a_vp; + if (ap->a_bnp != NULL) + *ap->a_bnp = ap->a_bn; + if (ap->a_runp != NULL) + *ap->a_runp = 0; + return (0); +} + +/* + * procfs_inactive is called when the pfsnode * is vrele'd and the reference count goes * to zero. (vp) will be on the vnode free * list, so to get it back vget() must be @@ -194,16 +242,20 @@ procfs_ioctl(ap) * chances are that the process will still be * there and PFIND is not free. * - * (vp) is not locked on entry or exit. + * (vp) is locked on entry, but must be unlocked on exit. */ static int procfs_inactive(ap) - struct vop_inactive_args *ap; + struct vop_inactive_args /* { + struct vnode *a_vp; + } */ *ap; { - struct pfsnode *pfs = VTOPFS(ap->a_vp); + struct vnode *vp = ap->a_vp; + struct pfsnode *pfs = VTOPFS(vp); + VOP_UNLOCK(vp, 0, ap->a_p); if (PFIND(pfs->pfs_pid) == 0) - vgone(ap->a_vp); + vgone(vp); return (0); } @@ -217,12 +269,12 @@ procfs_inactive(ap) */ static int procfs_reclaim(ap) - struct vop_reclaim_args *ap; + struct vop_reclaim_args /* { + struct vnode *a_vp; + } */ *ap; { - int error; - error = procfs_freevp(ap->a_vp); - return (error); + return (procfs_freevp(ap->a_vp)); } /* @@ -269,13 +321,14 @@ procfs_pathconf(ap) */ static int procfs_print(ap) - struct vop_print_args *ap; + struct vop_print_args /* { + struct vnode *a_vp; + } */ *ap; { struct pfsnode *pfs = VTOPFS(ap->a_vp); - printf("tag VT_PROCFS, pid %lu, mode %x, flags %lx\n", - pfs->pfs_pid, - pfs->pfs_mode, pfs->pfs_flags); + printf("tag VT_PROCFS, type %s, pid %d, mode %x, flags %x\n", + pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags); return (0); } @@ -287,7 +340,10 @@ procfs_print(ap) */ static int procfs_abortop(ap) - struct vop_abortop_args *ap; + struct vop_abortop_args /* { + struct vnode *a_dvp; + struct componentname *a_cnp; + } */ *ap; { if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) @@ -316,7 +372,12 @@ procfs_badop() */ static int procfs_getattr(ap) - struct vop_getattr_args *ap; + struct vop_getattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { struct pfsnode *pfs = VTOPFS(ap->a_vp); struct vattr *vap = ap->a_vap; @@ -329,6 +390,7 @@ procfs_getattr(ap) */ switch (pfs->pfs_type) { case Proot: + case Pcurproc: procp = 0; break; @@ -353,6 +415,21 @@ procfs_getattr(ap) vap->va_bytes = vap->va_size = 0; /* + * Make all times be current TOD. + * It would be possible to get the process start + * time from the p_stat structure, but there's + * no "file creation" time stamp anyway, and the + * p_stat structure is not addressible if u. gets + * swapped out for that process. + */ + { + struct timeval tv; + microtime(&tv); + TIMEVAL_TO_TIMESPEC(&tv, &vap->va_ctime); + } + vap->va_atime = vap->va_mtime = vap->va_ctime; + + /* * If the process has exercised some setuid or setgid * privilege, then rip away read/write permission so * that only root can gain access. @@ -376,21 +453,6 @@ procfs_getattr(ap) } /* - * Make all times be current TOD. - * It would be possible to get the process start - * time from the p_stat structure, but there's - * no "file creation" time stamp anyway, and the - * p_stat structure is not addressible if u. gets - * swapped out for that process. - */ - { - struct timeval tv; - microtime(&tv); - TIMEVAL_TO_TIMESPEC(&tv, &vap->va_ctime); - } - vap->va_atime = vap->va_mtime = vap->va_ctime; - - /* * now do the object specific fields * * The size could be set from struct reg, but it's hardly @@ -402,17 +464,30 @@ procfs_getattr(ap) switch (pfs->pfs_type) { case Proot: - vap->va_nlink = nprocs + 3; + /* + * Set nlink to 1 to tell fts(3) we don't actually know. + */ + vap->va_nlink = 1; + vap->va_uid = 0; + vap->va_gid = 0; + vap->va_size = vap->va_bytes = DEV_BSIZE; + break; + + case Pcurproc: { + char buf[16]; /* should be enough */ + vap->va_nlink = 1; vap->va_uid = 0; vap->va_gid = 0; - vap->va_bytes = vap->va_size = DEV_BSIZE; + vap->va_size = vap->va_bytes = + sprintf(buf, "%ld", (long)curproc->p_pid); break; + } case Pproc: - vap->va_nlink = Nprocent; + vap->va_nlink = nproc_targets; vap->va_uid = procp->p_ucred->cr_uid; vap->va_gid = procp->p_ucred->cr_gid; - vap->va_bytes = vap->va_size = DEV_BSIZE; + vap->va_size = vap->va_bytes = DEV_BSIZE; break; case Pfile: @@ -436,7 +511,15 @@ procfs_getattr(ap) case Ptype: case Pmap: case Pregs: + vap->va_bytes = vap->va_size = sizeof(struct reg); + vap->va_nlink = 1; + vap->va_uid = procp->p_ucred->cr_uid; + vap->va_gid = procp->p_ucred->cr_gid; + break; + case Pfpregs: + vap->va_bytes = vap->va_size = sizeof(struct fpreg); + case Pctl: case Pstatus: case Pnote: @@ -455,7 +538,12 @@ procfs_getattr(ap) static int procfs_setattr(ap) - struct vop_setattr_args *ap; + struct vop_setattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { /* * just fake out attribute setting @@ -484,7 +572,12 @@ procfs_setattr(ap) */ static int procfs_access(ap) - struct vop_access_args *ap; + struct vop_access_args /* { + struct vnode *a_vp; + int a_mode; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { struct vattr *vap; struct vattr vattr; @@ -494,8 +587,9 @@ procfs_access(ap) * If you're the super-user, * you always get access. */ - if (ap->a_cred->cr_uid == (uid_t) 0) + if (ap->a_cred->cr_uid == 0) return (0); + vap = &vattr; error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p); if (error) @@ -510,7 +604,7 @@ procfs_access(ap) gid_t *gp; int i; - (ap->a_mode) >>= 3; + ap->a_mode >>= 3; gp = ap->a_cred->cr_groups; for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++) if (vap->va_gid == *gp) @@ -537,18 +631,23 @@ found: */ static int procfs_lookup(ap) - struct vop_lookup_args *ap; + struct vop_lookup_args /* { + struct vnode * a_dvp; + struct vnode ** a_vpp; + struct componentname * a_cnp; + } */ *ap; { struct componentname *cnp = ap->a_cnp; struct vnode **vpp = ap->a_vpp; struct vnode *dvp = ap->a_dvp; char *pname = cnp->cn_nameptr; + struct proc *curp = cnp->cn_proc; int error = 0; + struct proc_target *pt; + struct vnode *fvp; pid_t pid; - struct vnode *nvp; struct pfsnode *pfs; - struct proc *procp; - pfstype pfs_type; + struct proc *p; int i; *vpp = NULL; @@ -559,7 +658,7 @@ procfs_lookup(ap) if (cnp->cn_namelen == 1 && *pname == '.') { *vpp = dvp; VREF(dvp); - /*VOP_LOCK(dvp);*/ + /* vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, curp); */ return (0); } @@ -570,72 +669,52 @@ procfs_lookup(ap) return (EIO); if (CNEQ(cnp, "curproc", 7)) - pid = cnp->cn_proc->p_pid; - else - pid = atopid(pname, cnp->cn_namelen); - if (pid == NO_PID) - return (ENOENT); + return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc)); - procp = PFIND(pid); - if (procp == 0) - return (ENOENT); - - error = procfs_allocvp(dvp->v_mount, &nvp, pid, Pproc); - if (error) - return (error); + pid = atopid(pname, cnp->cn_namelen); + if (pid == NO_PID) + break; - nvp->v_type = VDIR; - pfs = VTOPFS(nvp); + p = PFIND(pid); + if (p == 0) + break; - *vpp = nvp; - return (0); + return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc)); case Pproc: - if (cnp->cn_flags & ISDOTDOT) { - error = procfs_root(dvp->v_mount, vpp); - return (error); - } - - procp = PFIND(pfs->pfs_pid); - if (procp == 0) - return (ENOENT); + if (cnp->cn_flags & ISDOTDOT) + return (procfs_root(dvp->v_mount, vpp)); - for (i = 0; i < Nprocent; i++) { - struct pfsnames *dp = &procent[i]; + p = PFIND(pfs->pfs_pid); + if (p == 0) + break; - if (cnp->cn_namelen == dp->d_namlen && - bcmp(pname, dp->d_name, dp->d_namlen) == 0 && - (dp->d_valid == NULL || (*dp->d_valid)(procp))) { - pfs_type = dp->d_pfstype; + for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) { + if (cnp->cn_namelen == pt->pt_namlen && + bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && + (pt->pt_valid == NULL || (*pt->pt_valid)(p))) goto found; - } } - return (ENOENT); + break; found: - if (pfs_type == Pfile) { - nvp = procfs_findtextvp(procp); - if (nvp) { - VREF(nvp); - VOP_LOCK(nvp); - } else { - error = ENXIO; - } - } else { - error = procfs_allocvp(dvp->v_mount, &nvp, - pfs->pfs_pid, pfs_type); - if (error) - return (error); - - nvp->v_type = VREG; - pfs = VTOPFS(nvp); + if (pt->pt_pfstype == Pfile) { + fvp = procfs_findtextvp(p); + /* We already checked that it exists. */ + VREF(fvp); + vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curp); + *vpp = fvp; + return (0); } - *vpp = nvp; - return (error); + + return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, + pt->pt_pfstype)); default: return (ENOTDIR); } + + return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); } /* @@ -645,6 +724,7 @@ int procfs_validfile(p) struct proc *p; { + return (procfs_findtextvp(p) != NULLVP); } @@ -662,7 +742,14 @@ procfs_validfile(p) */ static int procfs_readdir(ap) - struct vop_readdir_args *ap; + struct vop_readdir_args /* { + struct vnode *a_vp; + struct uio *a_uio; + struct ucred *a_cred; + int *a_eofflag; + u_long *a_cookies; + int a_ncookies; + } */ *ap; { struct uio *uio = ap->a_uio; struct pfsdent d; @@ -672,6 +759,13 @@ procfs_readdir(ap) int count; int i; + /* + * We don't allow exporting procfs mounts, and currently local + * requests do not need cookies. + */ + if (ap->a_ncookies) + panic("procfs_readdir: not hungry"); + pfs = VTOPFS(ap->a_vp); if (uio->uio_resid < UIO_MX) @@ -693,39 +787,28 @@ procfs_readdir(ap) */ case Pproc: { struct proc *p; + struct proc_target *pt; p = PFIND(pfs->pfs_pid); if (p == NULL) break; - while (uio->uio_resid >= UIO_MX) { - struct pfsnames *dt; - - if (i >= Nprocent) - break; - - dt = &procent[i]; - - /* see if we should show this one. */ - if (dt->d_valid && (*dt->d_valid)(p) == 0) { - i++; + for (pt = &proc_targets[i]; + uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) { + if (pt->pt_valid && (*pt->pt_valid)(p) == 0) continue; - } dp->d_reclen = UIO_MX; - dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, dt->d_pfstype); - dp->d_type = DT_REG; - dp->d_namlen = dt->d_namlen; - bcopy(dt->d_name, dp->d_name, sizeof(dt->d_name)-1); - error = uiomove((caddr_t) dp, UIO_MX, uio); - if (error) + dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype); + dp->d_namlen = pt->pt_namlen; + bcopy(pt->pt_name, dp->d_name, pt->pt_namlen + 1); + dp->d_type = pt->pt_type; + + if (error = uiomove((caddr_t)dp, UIO_MX, uio)) break; - count += UIO_MX; - i++; } break; - } /* @@ -738,63 +821,61 @@ procfs_readdir(ap) */ case Proot: { - int pcnt; #ifdef PROCFS_ZOMBIE int doingzomb = 0; #endif + int pcnt = 0; volatile struct proc *p = allproc.lh_first; -#define PROCFS_XFILES 3 /* number of other entries, like "curproc" */ - pcnt = PROCFS_XFILES; - - while (p && uio->uio_resid >= UIO_MX) { + again: + for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) { bzero((char *) dp, UIO_MX); - dp->d_type = DT_DIR; dp->d_reclen = UIO_MX; switch (i) { - case 0: + case 0: /* `.' */ + case 1: /* `..' */ dp->d_fileno = PROCFS_FILENO(0, Proot); - dp->d_namlen = sprintf(dp->d_name, "."); - break; - - case 1: - dp->d_fileno = PROCFS_FILENO(0, Proot); - dp->d_namlen = sprintf(dp->d_name, ".."); + dp->d_namlen = i + 1; + bcopy("..", dp->d_name, dp->d_namlen); + dp->d_name[i + 1] = '\0'; + dp->d_type = DT_DIR; break; case 2: - /* ship out entry for "curproc" */ - dp->d_fileno = PROCFS_FILENO(PID_MAX+1, Pproc); - dp->d_namlen = sprintf(dp->d_name, "curproc"); + dp->d_fileno = PROCFS_FILENO(0, Pcurproc); + dp->d_namlen = 7; + bcopy("curproc", dp->d_name, 8); + dp->d_type = DT_LNK; break; default: - if (pcnt >= i) { - dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); - dp->d_namlen = sprintf(dp->d_name, "%ld", (long) p->p_pid); + while (pcnt < i) { + pcnt++; + p = p->p_list.le_next; + if (!p) + goto done; } - + dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); + dp->d_namlen = sprintf(dp->d_name, "%ld", + (long)p->p_pid); + dp->d_type = DT_REG; p = p->p_list.le_next; - -#ifdef PROCFS_ZOMBIE - if (p == 0 && doingzomb == 0) { - doingzomb = 1; - p = zombproc.lh_first; - } -#endif - - if (pcnt++ < i) - continue; - break; } - error = uiomove((caddr_t) dp, UIO_MX, uio); - if (error) + + if (error = uiomove((caddr_t)dp, UIO_MX, uio)) break; - count += UIO_MX; - i++; } + done: + +#ifdef PROCFS_ZOMBIE + if (p == 0 && doingzomb == 0) { + doingzomb = 1; + p = zombproc.lh_first; + goto again; + } +#endif break; @@ -811,6 +892,25 @@ procfs_readdir(ap) } /* + * readlink reads the link of `curproc' + */ +int +procfs_readlink(ap) + struct vop_readlink_args *ap; +{ + struct uio *uio = ap->a_uio; + char buf[16]; /* should be enough */ + int len; + + if (VTOPFS(ap->a_vp)->pfs_fileno != PROCFS_FILENO(0, Pcurproc)) + return (EINVAL); + + len = sprintf(buf, "%ld", (long)curproc->p_pid); + + return (uiomove((caddr_t)buf, len, ap->a_uio)); +} + +/* * convert decimal ascii to pid_t */ static pid_t @@ -838,6 +938,7 @@ atopid(b, len) #define procfs_write procfs_rw #define procfs_select ((int (*) __P((struct vop_select_args *))) procfs_badop) #define procfs_mmap ((int (*) __P((struct vop_mmap_args *))) procfs_badop) +#define procfs_revoke vop_revoke #define procfs_fsync ((int (*) __P((struct vop_fsync_args *))) procfs_badop) #define procfs_seek ((int (*) __P((struct vop_seek_args *))) procfs_badop) #define procfs_remove ((int (*) __P((struct vop_remove_args *))) procfs_badop) @@ -849,7 +950,6 @@ atopid(b, len) #define procfs_readlink ((int (*) __P((struct vop_readlink_args *))) procfs_badop) #define procfs_lock ((int (*) __P((struct vop_lock_args *))) nullop) #define procfs_unlock ((int (*) __P((struct vop_unlock_args *))) nullop) -#define procfs_bmap ((int (*) __P((struct vop_bmap_args *))) procfs_badop) #define procfs_strategy ((int (*) __P((struct vop_strategy_args *))) procfs_badop) #define procfs_islocked ((int (*) __P((struct vop_islocked_args *))) nullop) #define procfs_advlock ((int (*) __P((struct vop_advlock_args *))) procfs_badop) @@ -859,6 +959,9 @@ atopid(b, len) #define procfs_truncate ((int (*) __P((struct vop_truncate_args *))) procfs_badop) #define procfs_update ((int (*) __P((struct vop_update_args *))) nullop) +/* + * procfs vnode operations. + */ vop_t **procfs_vnodeop_p; static struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { { &vop_default_desc, (vop_t *)vn_default_error }, @@ -875,6 +978,7 @@ static struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { { &vop_ioctl_desc, (vop_t *)procfs_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)procfs_select }, /* select */ { &vop_mmap_desc, (vop_t *)procfs_mmap }, /* mmap */ + { &vop_revoke_desc, (vop_t *)procfs_revoke }, /* revoke */ { &vop_fsync_desc, (vop_t *)procfs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)procfs_seek }, /* seek */ { &vop_remove_desc, (vop_t *)procfs_remove }, /* remove */ diff --git a/sys/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 <sys/param.h> #include <sys/systm.h> +#include <sys/proc.h> #include <sys/time.h> #include <sys/types.h> #include <sys/vnode.h> @@ -48,11 +49,8 @@ #include <sys/malloc.h> #include <miscfs/umapfs/umap.h> -extern int umapfs_init __P((void)); - #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ #define NUMAPNODECACHE 16 -#define UMAP_NHASH(vp) ((((u_long) vp)>>LOG2_SIZEVNODE) & (NUMAPNODECACHE-1)) /* * Null layer cache: @@ -62,52 +60,33 @@ extern int umapfs_init __P((void)); * alias is removed the target vnode is vrele'd. */ -/* - * Cache head - */ -struct umap_node_cache { - struct umap_node *ac_forw; - struct umap_node *ac_back; -}; - -static struct umap_node_cache umap_node_cache[NUMAPNODECACHE]; +#define UMAP_NHASH(vp) \ + (&umap_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & umap_node_hash]) +LIST_HEAD(umap_node_hashhead, umap_node) *umap_node_hashtbl; +u_long umap_node_hash; static u_long umap_findid __P((u_long id, u_long map[][2], int nentries)); static int umap_node_alloc __P((struct mount *mp, struct vnode *lowervp, struct vnode **vpp)); static struct vnode * umap_node_find __P((struct mount *mp, struct vnode *targetvp)); -static struct umap_node_cache * - umap_node_hash __P((struct vnode *targetvp)); /* * Initialise cache headers */ int -umapfs_init() +umapfs_init(vfsp) + struct vfsconf *vfsp; { - struct umap_node_cache *ac; + #ifdef UMAPFS_DIAGNOSTIC printf("umapfs_init\n"); /* printed during system boot */ #endif - - for (ac = umap_node_cache; ac < umap_node_cache + NUMAPNODECACHE; ac++) - ac->ac_forw = ac->ac_back = (struct umap_node *) ac; + umap_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, &umap_node_hash); return (0); } /* - * Compute hash list for given target vnode - */ -static struct umap_node_cache * -umap_node_hash(targetvp) - struct vnode *targetvp; -{ - - return (&umap_node_cache[UMAP_NHASH(targetvp)]); -} - -/* * umap_findid is called by various routines in umap_vnodeops.c to * find a user or group id in a map. */ @@ -163,7 +142,8 @@ umap_node_find(mp, targetvp) struct mount *mp; struct vnode *targetvp; { - struct umap_node_cache *hd; + struct proc *p = curproc; /* XXX */ + struct umap_node_hashhead *hd; struct umap_node *a; struct vnode *vp; @@ -177,10 +157,9 @@ umap_node_find(mp, targetvp) * the target vnode. If found, the increment the umap_node * reference count (but NOT the target vnode's VREF counter). */ - hd = umap_node_hash(targetvp); - - loop: - for (a = hd->ac_forw; a != (struct umap_node *) hd; a = a->umap_forw) { + hd = UMAP_NHASH(targetvp); +loop: + for (a = hd->lh_first; a != 0; a = a->umap_hash.le_next) { if (a->umap_lowervp == targetvp && a->umap_vnode->v_mount == mp) { vp = UMAPTOV(a); @@ -189,7 +168,7 @@ umap_node_find(mp, targetvp) * stuff, but we don't want to lock * the lower node. */ - if (vget(vp, 0)) { + if (vget(vp, 0, p)) { #ifdef UMAPFS_DIAGNOSTIC printf ("umap_node_find: vget failed.\n"); #endif @@ -217,7 +196,7 @@ umap_node_alloc(mp, lowervp, vpp) struct vnode *lowervp; struct vnode **vpp; { - struct umap_node_cache *hd; + struct umap_node_hashhead *hd; struct umap_node *xp; struct vnode *othervp, *vp; int error; @@ -257,8 +236,8 @@ umap_node_alloc(mp, lowervp, vpp) return (0); } VREF(lowervp); /* Extra VREF will be vrele'd in umap_node_create */ - hd = umap_node_hash(lowervp); - insque(xp, hd); + hd = UMAP_NHASH(lowervp); + LIST_INSERT_HEAD(hd, xp, umap_hash); return (0); } diff --git a/sys/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 <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/proc.h> #include <sys/time.h> #include <sys/types.h> #include <sys/vnode.h> @@ -54,7 +55,7 @@ #include <sys/malloc.h> #include <miscfs/umapfs/umap.h> -extern int umapfs_init __P((void)); +extern int umapfs_init __P((struct vfsconf *)); static int umapfs_fhtovp __P((struct mount *mp, struct fid *fidp, struct mbuf *nam, struct vnode **vpp, @@ -187,7 +188,7 @@ umapfs_mount(mp, path, data, ndp, p) /* * Unlock the node (either the lower or the alias) */ - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); /* * Make sure the node alias worked */ @@ -207,7 +208,7 @@ umapfs_mount(mp, path, data, ndp, p) if (UMAPVPTOLOWERVP(umapm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) mp->mnt_flag |= MNT_LOCAL; mp->mnt_data = (qaddr_t) amp; - getnewfsid(mp, MOUNT_LOFS); + vfs_getnewfsid(mp); (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); @@ -253,12 +254,8 @@ umapfs_unmount(mp, mntflags, p) printf("umapfs_unmount(mp = %x)\n", mp); #endif - if (mntflags & MNT_FORCE) { - /* lofs can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } /* * Clear out buffer cache. I don't think we @@ -300,6 +297,7 @@ umapfs_root(mp, vpp) struct mount *mp; struct vnode **vpp; { + struct proc *p = curproc; /* XXX */ struct vnode *vp; #ifdef UMAPFS_DIAGNOSTIC @@ -314,7 +312,7 @@ umapfs_root(mp, vpp) */ vp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp; VREF(vp); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); *vpp = vp; return (0); } @@ -429,4 +427,3 @@ static struct vfsops umap_vfsops = { }; VFS_SET(umap_vfsops, umap, MOUNT_UMAP, VFCF_LOOPBACK); - diff --git a/sys/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 <sys/file.h> #include <sys/filedesc.h> #include <sys/queue.h> +#include <sys/mount.h> +#include <sys/stat.h> +#include <vm/vm.h> /* for vnode_pager_setsize */ #include <miscfs/union/union.h> #include <sys/proc.h> @@ -118,31 +121,38 @@ union_updatevp(un, uppervp, lowervp) { int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp); int nhash = UNION_HASH(uppervp, lowervp); + int docache = (lowervp != NULLVP || uppervp != NULLVP); + int lhash, hhash, uhash; - if (ohash != nhash) { - /* - * Ensure locking is ordered from lower to higher - * to avoid deadlocks. - */ - if (nhash < ohash) { - int t = ohash; - ohash = nhash; - nhash = t; - } + /* + * Ensure locking is ordered from lower to higher + * to avoid deadlocks. + */ + if (nhash < ohash) { + lhash = nhash; + uhash = ohash; + } else { + lhash = ohash; + uhash = nhash; + } - while (union_list_lock(ohash)) + if (lhash != uhash) + while (union_list_lock(lhash)) continue; - while (union_list_lock(nhash)) - continue; + while (union_list_lock(uhash)) + continue; - LIST_REMOVE(un, un_cache); - union_list_unlock(ohash); - } else { - while (union_list_lock(nhash)) - continue; + if (ohash != nhash || !docache) { + if (un->un_flags & UN_CACHED) { + un->un_flags &= ~UN_CACHED; + LIST_REMOVE(un, un_cache); + } } + if (ohash != nhash) + union_list_unlock(ohash); + if (un->un_lowervp != lowervp) { if (un->un_lowervp) { vrele(un->un_lowervp); @@ -156,6 +166,7 @@ union_updatevp(un, uppervp, lowervp) } } un->un_lowervp = lowervp; + un->un_lowersz = VNOVAL; } if (un->un_uppervp != uppervp) { @@ -163,10 +174,13 @@ union_updatevp(un, uppervp, lowervp) vrele(un->un_uppervp); un->un_uppervp = uppervp; + un->un_uppersz = VNOVAL; } - if (ohash != nhash) + if (docache && (ohash != nhash)) { LIST_INSERT_HEAD(&unhead[nhash], un, un_cache); + un->un_flags |= UN_CACHED; + } union_list_unlock(nhash); } @@ -190,6 +204,47 @@ union_newupper(un, uppervp) } /* + * Keep track of size changes in the underlying vnodes. + * If the size changes, then callback to the vm layer + * giving priority to the upper layer size. + */ +void +union_newsize(vp, uppersz, lowersz) + struct vnode *vp; + off_t uppersz, lowersz; +{ + struct union_node *un; + off_t sz; + + /* only interested in regular files */ + if (vp->v_type != VREG) + return; + + un = VTOUNION(vp); + sz = VNOVAL; + + if ((uppersz != VNOVAL) && (un->un_uppersz != uppersz)) { + un->un_uppersz = uppersz; + if (sz == VNOVAL) + sz = un->un_uppersz; + } + + if ((lowersz != VNOVAL) && (un->un_lowersz != lowersz)) { + un->un_lowersz = lowersz; + if (sz == VNOVAL) + sz = un->un_lowersz; + } + + if (sz != VNOVAL) { +#ifdef UNION_DIAGNOSTIC + printf("union: %s size now %ld\n", + uppersz != VNOVAL ? "upper" : "lower", (long) sz); +#endif + vnode_pager_setsize(vp, sz); + } +} + +/* * allocate a union_node/vnode pair. the vnode is * referenced and locked. the new vnode is returned * via (vpp). (mp) is the mountpoint of the union filesystem, @@ -221,19 +276,22 @@ union_newupper(un, uppervp) * the vnode free list. */ int -union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp) +union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp, docache) struct vnode **vpp; struct mount *mp; - struct vnode *undvp; + struct vnode *undvp; /* parent union vnode */ struct vnode *dvp; /* may be null */ struct componentname *cnp; /* may be null */ struct vnode *uppervp; /* may be null */ struct vnode *lowervp; /* may be null */ + int docache; { int error; struct union_node *un = 0; struct vnode *xlowervp = NULLVP; - int hash = 0; + struct union_mount *um = MOUNTTOUNIONMOUNT(mp); + int hash; + int vflag; int try; if (uppervp == NULLVP && lowervp == NULLVP) @@ -244,8 +302,22 @@ union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp) lowervp = NULLVP; } + /* detect the root vnode (and aliases) */ + vflag = 0; + if ((uppervp == um->um_uppervp) && + ((lowervp == NULLVP) || lowervp == um->um_lowervp)) { + if (lowervp == NULLVP) { + lowervp = um->um_lowervp; + if (lowervp != NULLVP) + VREF(lowervp); + } + vflag = VROOT; + } + loop: - for (try = 0; try < 3; try++) { + if (!docache) { + un = 0; + } else for (try = 0; try < 3; try++) { switch (try) { case 0: if (lowervp == NULLVP) @@ -276,7 +348,8 @@ loop: (un->un_uppervp == uppervp || un->un_uppervp == NULLVP) && (UNIONTOV(un)->v_mount == mp)) { - if (vget(UNIONTOV(un), 0)) { + if (vget(UNIONTOV(un), 0, + cnp ? cnp->cn_proc : NULL)) { union_list_unlock(hash); goto loop; } @@ -359,8 +432,7 @@ loop: */ if (lowervp != un->un_lowervp) { union_newlower(un, lowervp); - if (cnp && (lowervp != NULLVP) && - (lowervp->v_type == VREG)) { + if (cnp && (lowervp != NULLVP)) { un->un_hash = cnp->cn_hash; un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); @@ -377,14 +449,16 @@ loop: return (0); } - /* - * otherwise lock the vp list while we call getnewvnode - * since that can block. - */ - hash = UNION_HASH(uppervp, lowervp); + if (docache) { + /* + * otherwise lock the vp list while we call getnewvnode + * since that can block. + */ + hash = UNION_HASH(uppervp, lowervp); - if (union_list_lock(hash)) - goto loop; + if (union_list_lock(hash)) + goto loop; + } error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp); if (error) { @@ -403,6 +477,7 @@ loop: MALLOC((*vpp)->v_data, void *, sizeof(struct union_node), M_TEMP, M_WAITOK); + (*vpp)->v_flag |= vflag; if (uppervp) (*vpp)->v_type = uppervp->v_type; else @@ -410,7 +485,13 @@ loop: un = VTOUNION(*vpp); un->un_vnode = *vpp; un->un_uppervp = uppervp; + un->un_uppersz = VNOVAL; un->un_lowervp = lowervp; + un->un_lowersz = VNOVAL; + un->un_pvp = undvp; + if (undvp != NULLVP) + VREF(undvp); + un->un_dircache = 0; un->un_openl = 0; un->un_flags = UN_LOCKED; if (un->un_uppervp) @@ -421,7 +502,7 @@ loop: else un->un_pid = -1; #endif - if (cnp && (lowervp != NULLVP) && (lowervp->v_type == VREG)) { + if (cnp && (lowervp != NULLVP)) { un->un_hash = cnp->cn_hash; un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); @@ -434,13 +515,17 @@ loop: un->un_dirvp = 0; } - LIST_INSERT_HEAD(&unhead[hash], un, un_cache); + if (docache) { + LIST_INSERT_HEAD(&unhead[hash], un, un_cache); + un->un_flags |= UN_CACHED; + } if (xlowervp) vrele(xlowervp); out: - union_list_unlock(hash); + if (docache) + union_list_unlock(hash); return (error); } @@ -451,13 +536,18 @@ union_freevp(vp) { struct union_node *un = VTOUNION(vp); - LIST_REMOVE(un, un_cache); + if (un->un_flags & UN_CACHED) { + un->un_flags &= ~UN_CACHED; + LIST_REMOVE(un, un_cache); + } - if (un->un_uppervp) + if (un->un_pvp != NULLVP) + vrele(un->un_pvp); + if (un->un_uppervp != NULLVP) vrele(un->un_uppervp); - if (un->un_lowervp) + if (un->un_lowervp != NULLVP) vrele(un->un_lowervp); - if (un->un_dirvp) + if (un->un_dirvp != NULLVP) vrele(un->un_dirvp); if (un->un_path) free(un->un_path, M_TEMP); @@ -474,11 +564,11 @@ union_freevp(vp) * and (tvp) are locked on entry and exit. */ int -union_copyfile(p, cred, fvp, tvp) - struct proc *p; - struct ucred *cred; +union_copyfile(fvp, tvp, cred, p) struct vnode *fvp; struct vnode *tvp; + struct ucred *cred; + struct proc *p; { char *buf; struct uio uio; @@ -497,12 +587,12 @@ union_copyfile(p, cred, fvp, tvp) uio.uio_segflg = UIO_SYSSPACE; uio.uio_offset = 0; - VOP_UNLOCK(fvp); /* XXX */ - LEASE_CHECK(fvp, p, cred, LEASE_READ); - VOP_LOCK(fvp); /* XXX */ - VOP_UNLOCK(tvp); /* XXX */ - LEASE_CHECK(tvp, p, cred, LEASE_WRITE); - VOP_LOCK(tvp); /* XXX */ + VOP_UNLOCK(fvp, 0, p); /* XXX */ + VOP_LEASE(fvp, p, cred, LEASE_READ); + vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ + VOP_UNLOCK(tvp, 0, p); /* XXX */ + VOP_LEASE(tvp, p, cred, LEASE_WRITE); + vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK); @@ -542,6 +632,123 @@ union_copyfile(p, cred, fvp, tvp) } /* + * (un) is assumed to be locked on entry and remains + * locked on exit. + */ +int +union_copyup(un, docopy, cred, p) + struct union_node *un; + int docopy; + struct ucred *cred; + struct proc *p; +{ + int error; + struct vnode *lvp, *uvp; + + error = union_vn_create(&uvp, un, p); + if (error) + return (error); + + /* at this point, uppervp is locked */ + union_newupper(un, uvp); + un->un_flags |= UN_ULOCK; + + lvp = un->un_lowervp; + + if (docopy) { + /* + * XX - should not ignore errors + * from VOP_CLOSE + */ + vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, p); + error = VOP_OPEN(lvp, FREAD, cred, p); + if (error == 0) { + error = union_copyfile(lvp, uvp, cred, p); + VOP_UNLOCK(lvp, 0, p); + (void) VOP_CLOSE(lvp, FREAD, cred, p); + } +#ifdef UNION_DIAGNOSTIC + if (error == 0) + uprintf("union: copied up %s\n", un->un_path); +#endif + + } + un->un_flags &= ~UN_ULOCK; + VOP_UNLOCK(uvp, 0, p); + union_vn_close(uvp, FWRITE, cred, p); + vn_lock(uvp, LK_EXCLUSIVE | LK_RETRY, p); + un->un_flags |= UN_ULOCK; + + /* + * Subsequent IOs will go to the top layer, so + * call close on the lower vnode and open on the + * upper vnode to ensure that the filesystem keeps + * its references counts right. This doesn't do + * the right thing with (cred) and (FREAD) though. + * Ignoring error returns is not right, either. + */ + if (error == 0) { + int i; + + for (i = 0; i < un->un_openl; i++) { + (void) VOP_CLOSE(lvp, FREAD, cred, p); + (void) VOP_OPEN(uvp, FREAD, cred, p); + } + un->un_openl = 0; + } + + return (error); + +} + +static int +union_relookup(um, dvp, vpp, cnp, cn, path, pathlen) + struct union_mount *um; + struct vnode *dvp; + struct vnode **vpp; + struct componentname *cnp; + struct componentname *cn; + char *path; + int pathlen; +{ + int error; + + /* + * A new componentname structure must be faked up because + * there is no way to know where the upper level cnp came + * from or what it is being used for. This must duplicate + * some of the work done by NDINIT, some of the work done + * by namei, some of the work done by lookup and some of + * the work done by VOP_LOOKUP when given a CREATE flag. + * Conclusion: Horrible. + * + * The pathname buffer will be FREEed by VOP_MKDIR. + */ + cn->cn_namelen = pathlen; + cn->cn_pnbuf = malloc(cn->cn_namelen+1, M_NAMEI, M_WAITOK); + bcopy(path, cn->cn_pnbuf, cn->cn_namelen); + cn->cn_pnbuf[cn->cn_namelen] = '\0'; + + cn->cn_nameiop = CREATE; + cn->cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN); + cn->cn_proc = cnp->cn_proc; + if (um->um_op == UNMNT_ABOVE) + cn->cn_cred = cnp->cn_cred; + else + cn->cn_cred = um->um_cred; + cn->cn_nameptr = cn->cn_pnbuf; + cn->cn_hash = cnp->cn_hash; + cn->cn_consume = cnp->cn_consume; + + VREF(dvp); + error = relookup(dvp, vpp, cn); + if (!error) + vrele(dvp); + + return (error); +} + +/* * Create a shadow directory in the upper layer. * The new vnode is returned locked. * @@ -565,6 +772,19 @@ union_mkshadow(um, dvp, cnp, vpp) struct proc *p = cnp->cn_proc; struct componentname cn; + error = union_relookup(um, dvp, vpp, cnp, &cn, + cnp->cn_nameptr, cnp->cn_namelen); + if (error) + return (error); + + if (*vpp) { + VOP_ABORTOP(dvp, &cn); + VOP_UNLOCK(dvp, 0, p); + vrele(*vpp); + *vpp = NULLVP; + return (EEXIST); + } + /* * policy: when creating the shadow directory in the * upper layer, create it owned by the user who did @@ -573,55 +793,62 @@ union_mkshadow(um, dvp, cnp, vpp) * mkdir syscall). (jsp, kb) */ - /* - * A new componentname structure must be faked up because - * there is no way to know where the upper level cnp came - * from or what it is being used for. This must duplicate - * some of the work done by NDINIT, some of the work done - * by namei, some of the work done by lookup and some of - * the work done by VOP_LOOKUP when given a CREATE flag. - * Conclusion: Horrible. - * - * The pathname buffer will be FREEed by VOP_MKDIR. - */ - cn.cn_pnbuf = malloc(cnp->cn_namelen+1, M_NAMEI, M_WAITOK); - bcopy(cnp->cn_nameptr, cn.cn_pnbuf, cnp->cn_namelen); - cn.cn_pnbuf[cnp->cn_namelen] = '\0'; + VATTR_NULL(&va); + va.va_type = VDIR; + va.va_mode = um->um_cmode; - cn.cn_nameiop = CREATE; - cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN); - cn.cn_proc = cnp->cn_proc; - if (um->um_op == UNMNT_ABOVE) - cn.cn_cred = cnp->cn_cred; - else - cn.cn_cred = um->um_cred; - cn.cn_nameptr = cn.cn_pnbuf; - cn.cn_namelen = cnp->cn_namelen; - cn.cn_hash = cnp->cn_hash; - cn.cn_consume = cnp->cn_consume; + /* VOP_LEASE: dvp is locked */ + VOP_LEASE(dvp, p, cn.cn_cred, LEASE_WRITE); - VREF(dvp); - error = relookup(dvp, vpp, &cn); - if (error) + error = VOP_MKDIR(dvp, vpp, &cn, &va); + return (error); +} + +/* + * Create a whiteout entry in the upper layer. + * + * (um) points to the union mount structure for access to the + * the mounting process's credentials. + * (dvp) is the directory in which to create the whiteout. + * it is locked on entry and exit. + * (cnp) is the componentname to be created. + */ +int +union_mkwhiteout(um, dvp, cnp, path) + struct union_mount *um; + struct vnode *dvp; + struct componentname *cnp; + char *path; +{ + int error; + struct vattr va; + struct proc *p = cnp->cn_proc; + struct vnode *wvp; + struct componentname cn; + + VOP_UNLOCK(dvp, 0, p); + error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path)); + if (error) { + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); return (error); - vrele(dvp); + } - if (*vpp) { + if (wvp) { VOP_ABORTOP(dvp, &cn); - VOP_UNLOCK(dvp); - vrele(*vpp); - *vpp = NULLVP; + vrele(dvp); + vrele(wvp); return (EEXIST); } - VATTR_NULL(&va); - va.va_type = VDIR; - va.va_mode = um->um_cmode; + /* VOP_LEASE: dvp is locked */ + VOP_LEASE(dvp, p, p->p_ucred, LEASE_WRITE); + + error = VOP_WHITEOUT(dvp, &cn, CREATE); + if (error) + VOP_ABORTOP(dvp, &cn); - /* LEASE_CHECK: dvp is locked */ - LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE); + vrele(dvp); - error = VOP_MKDIR(dvp, vpp, &cn, &va); return (error); } @@ -699,9 +926,8 @@ union_vn_create(vpp, un, p) VATTR_NULL(vap); vap->va_type = VREG; vap->va_mode = cmode; - LEASE_CHECK(un->un_dirvp, p, cred, LEASE_WRITE); - error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap); - if (error) + VOP_LEASE(un->un_dirvp, p, cred, LEASE_WRITE); + if (error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap)) return (error); error = VOP_OPEN(vp, fmode, cred, p); @@ -722,6 +948,7 @@ union_vn_close(vp, fmode, cred, p) struct ucred *cred; struct proc *p; { + if (fmode & FWRITE) --vp->v_writecount; return (VOP_CLOSE(vp, fmode, cred, p)); @@ -731,24 +958,137 @@ void union_removed_upper(un) struct union_node *un; { + struct proc *p = curproc; /* XXX */ + + union_newupper(un, NULLVP); + if (un->un_flags & UN_CACHED) { + un->un_flags &= ~UN_CACHED; + LIST_REMOVE(un, un_cache); + } + if (un->un_flags & UN_ULOCK) { un->un_flags &= ~UN_ULOCK; - VOP_UNLOCK(un->un_uppervp); + VOP_UNLOCK(un->un_uppervp, 0, p); } - - union_newupper(un, NULLVP); } +#if 0 struct vnode * union_lowervp(vp) struct vnode *vp; { struct union_node *un = VTOUNION(vp); - if (un->un_lowervp && (vp->v_type == un->un_lowervp->v_type)) { - if (vget(un->un_lowervp, 0)) - return (NULLVP); + if ((un->un_lowervp != NULLVP) && + (vp->v_type == un->un_lowervp->v_type)) { + if (vget(un->un_lowervp, 0) == 0) + return (un->un_lowervp); } - return (un->un_lowervp); + return (NULLVP); +} +#endif + +/* + * determine whether a whiteout is needed + * during a remove/rmdir operation. + */ +int +union_dowhiteout(un, cred, p) + struct union_node *un; + struct ucred *cred; + struct proc *p; +{ + struct vattr va; + + if (un->un_lowervp != NULLVP) + return (1); + + if (VOP_GETATTR(un->un_uppervp, &va, cred, p) == 0 && + (va.va_flags & OPAQUE)) + return (1); + + return (0); +} + +static void +union_dircache_r(vp, vppp, cntp) + struct vnode *vp; + struct vnode ***vppp; + int *cntp; +{ + struct union_node *un; + + if (vp->v_op != union_vnodeop_p) { + if (vppp) { + VREF(vp); + *(*vppp)++ = vp; + if (--(*cntp) == 0) + panic("union: dircache table too small"); + } else { + (*cntp)++; + } + + return; + } + + un = VTOUNION(vp); + if (un->un_uppervp != NULLVP) + union_dircache_r(un->un_uppervp, vppp, cntp); + if (un->un_lowervp != NULLVP) + union_dircache_r(un->un_lowervp, vppp, cntp); +} + +struct vnode * +union_dircache(vp, p) + struct vnode *vp; + struct proc *p; +{ + int cnt; + struct vnode *nvp; + struct vnode **vpp; + struct vnode **dircache; + struct union_node *un; + int error; + + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + dircache = VTOUNION(vp)->un_dircache; + + nvp = NULLVP; + + if (dircache == 0) { + cnt = 0; + union_dircache_r(vp, 0, &cnt); + cnt++; + dircache = (struct vnode **) + malloc(cnt * sizeof(struct vnode *), + M_TEMP, M_WAITOK); + vpp = dircache; + union_dircache_r(vp, &vpp, &cnt); + *vpp = NULLVP; + vpp = dircache + 1; + } else { + vpp = dircache; + do { + if (*vpp++ == VTOUNION(vp)->un_uppervp) + break; + } while (*vpp != NULLVP); + } + + if (*vpp == NULLVP) + goto out; + + vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, p); + VREF(*vpp); + error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, 0, *vpp, NULLVP, 0); + if (error) + goto out; + + VTOUNION(vp)->un_dircache = 0; + un = VTOUNION(nvp); + un->un_dircache = dircache; + +out: + VOP_UNLOCK(vp, 0, p); + return (nvp); } diff --git a/sys/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 <sys/queue.h> #include <miscfs/union/union.h> -extern int union_init __P((void)); +extern int union_init __P((struct vfsconf *)); extern int union_fhtovp __P((struct mount *mp, struct fid *fidp, struct mbuf *nam, struct vnode **vpp, @@ -92,7 +92,7 @@ union_mount(mp, path, data, ndp, p) struct union_args args; struct vnode *lowerrootvp = NULLVP; struct vnode *upperrootvp = NULLVP; - struct union_mount *um; + struct union_mount *um = 0; struct ucred *cred = 0; struct ucred *scred; struct vattr va; @@ -118,34 +118,6 @@ union_mount(mp, path, data, ndp, p) } /* - * Take a copy of the process's credentials. This isn't - * quite right since the euid will always be zero and we - * want to get the "real" users credentials. So fix up - * the uid field after taking the copy. - */ - cred = crdup(p->p_ucred); - cred->cr_uid = p->p_cred->p_ruid; - - /* - * Ensure the *real* user has write permission on the - * mounted-on directory. This allows the mount_union - * command to be made setuid root so allowing anyone - * to do union mounts onto any directory on which they - * have write permission and which they also own. - */ - error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p); - if (error) - goto bad; - if ((va.va_uid != cred->cr_uid) && - (cred->cr_uid != 0)) { - error = EACCES; - goto bad; - } - error = VOP_ACCESS(mp->mnt_vnodecovered, VWRITE, cred, p); - if (error) - goto bad; - - /* * Get argument */ error = copyin(data, (caddr_t)&args, sizeof(struct union_args)); @@ -156,18 +128,10 @@ union_mount(mp, path, data, ndp, p) VREF(lowerrootvp); /* - * Find upper node. Use the real process credentials, - * not the effective ones since this will have come - * through a setuid process (mount_union). All this - * messing around with permissions is entirely bogus - * and should be removed by allowing any user straight - * past the mount system call. + * Find upper node. */ - scred = p->p_ucred; - p->p_ucred = cred; NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT, UIO_USERSPACE, args.target, p); - p->p_ucred = scred; error = namei(ndp); if (error) @@ -218,7 +182,18 @@ union_mount(mp, path, data, ndp, p) goto bad; } - um->um_cred = cred; + /* + * Unless the mount is readonly, ensure that the top layer + * supports whiteout operations + */ + if ((mp->mnt_flag & MNT_RDONLY) == 0) { + error = VOP_WHITEOUT(um->um_uppervp, (struct componentname *) 0, LOOKUP); + if (error) + goto bad; + } + + um->um_cred = p->p_ucred; + crhold(um->um_cred); um->um_cmode = UN_DIRMODE &~ p->p_fd->fd_cmask; /* @@ -246,24 +221,18 @@ union_mount(mp, path, data, ndp, p) */ mp->mnt_flag |= (um->um_uppervp->v_mount->mnt_flag & MNT_RDONLY); - /* - * This is a user mount. Privilege check for unmount - * will be done in union_unmount. - */ - mp->mnt_flag |= MNT_USER; - mp->mnt_data = (qaddr_t) um; - getnewfsid(mp, MOUNT_UNION); + vfs_getnewfsid(mp); (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); switch (um->um_op) { case UNMNT_ABOVE: - cp = "<above>"; + cp = "<above>:"; break; case UNMNT_BELOW: - cp = "<below>"; + cp = "<below>:"; break; case UNMNT_REPLACE: cp = ""; @@ -287,6 +256,8 @@ union_mount(mp, path, data, ndp, p) return (0); bad: + if (um) + free(um, M_UFSMNT); if (cred) crfree(cred); if (upperrootvp) @@ -323,40 +294,55 @@ union_unmount(mp, mntflags, p) struct union_mount *um = MOUNTTOUNIONMOUNT(mp); struct vnode *um_rootvp; int error; + int freeing; int flags = 0; #ifdef UNION_DIAGNOSTIC printf("union_unmount(mp = %x)\n", mp); #endif - /* only the mounter, or superuser can unmount */ - if ((p->p_cred->p_ruid != um->um_cred->cr_uid) && - (error = suser(p->p_ucred, &p->p_acflag))) + if (mntflags & MNT_FORCE) + flags |= FORCECLOSE; + + if (error = union_root(mp, &um_rootvp)) return (error); - if (mntflags & MNT_FORCE) { - /* union can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); - flags |= FORCECLOSE; + /* + * Keep flushing vnodes from the mount list. + * This is needed because of the un_pvp held + * reference to the parent vnode. + * If more vnodes have been freed on a given pass, + * the try again. The loop will iterate at most + * (d) times, where (d) is the maximum tree depth + * in the filesystem. + */ + for (freeing = 0; vflush(mp, um_rootvp, flags) != 0;) { + struct vnode *vp; + int n; + + /* count #vnodes held on mount list */ + for (n = 0, vp = mp->mnt_vnodelist.lh_first; + vp != NULLVP; + vp = vp->v_mntvnodes.le_next) + n++; + + /* if this is unchanged then stop */ + if (n == freeing) + break; + + /* otherwise try once more time */ + freeing = n; } - error = union_root(mp, &um_rootvp); - if (error) - return (error); + /* At this point the root vnode should have a single reference */ if (um_rootvp->v_usecount > 1) { vput(um_rootvp); return (EBUSY); } - error = vflush(mp, um_rootvp, flags); - if (error) { - vput(um_rootvp); - return (error); - } #ifdef UNION_DIAGNOSTIC - vprint("alias root of lower", um_rootvp); -#endif + vprint("union root", um_rootvp); +#endif /* * Discard references to upper and lower target vnodes. */ @@ -385,16 +371,11 @@ union_root(mp, vpp) struct mount *mp; struct vnode **vpp; { + struct proc *p = curproc; /* XXX */ struct union_mount *um = MOUNTTOUNIONMOUNT(mp); int error; int loselock; -#ifdef UNION_DIAGNOSTIC - printf("union_root(mp = %x, lvp = %x, uvp = %x)\n", mp, - um->um_lowervp, - um->um_uppervp); -#endif - /* * Return locked reference to root. */ @@ -403,7 +384,7 @@ union_root(mp, vpp) VOP_ISLOCKED(um->um_uppervp)) { loselock = 1; } else { - VOP_LOCK(um->um_uppervp); + vn_lock(um->um_uppervp, LK_EXCLUSIVE | LK_RETRY, p); loselock = 0; } if (um->um_lowervp) @@ -413,16 +394,17 @@ union_root(mp, vpp) (struct vnode *) 0, (struct componentname *) 0, um->um_uppervp, - um->um_lowervp); + um->um_lowervp, + 1); if (error) { - if (!loselock) - VOP_UNLOCK(um->um_uppervp); - vrele(um->um_uppervp); + if (loselock) + vrele(um->um_uppervp); + else + vput(um->um_uppervp); if (um->um_lowervp) vrele(um->um_lowervp); } else { - (*vpp)->v_flag |= VROOT; if (loselock) VTOUNION(*vpp)->un_flags &= ~UN_ULOCK; } @@ -431,18 +413,6 @@ union_root(mp, vpp) } int -union_quotactl(mp, cmd, uid, arg, p) - struct mount *mp; - int cmd; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - - return (EOPNOTSUPP); -} - -int union_statfs(mp, sbp, p) struct mount *mp; struct statfs *sbp; @@ -485,7 +455,6 @@ union_statfs(mp, sbp, p) if (error) return (error); - sbp->f_type = MOUNT_UNION; sbp->f_flags = mstat.f_flags; sbp->f_bsize = mstat.f_bsize; sbp->f_iosize = mstat.f_iosize; @@ -496,18 +465,23 @@ union_statfs(mp, sbp, p) * kind of sense. none of this makes sense though. */ - if (mstat.f_bsize != lbsize) { + if (mstat.f_bsize != lbsize) sbp->f_blocks = sbp->f_blocks * lbsize / mstat.f_bsize; - sbp->f_bfree = sbp->f_bfree * lbsize / mstat.f_bsize; - sbp->f_bavail = sbp->f_bavail * lbsize / mstat.f_bsize; - } + + /* + * The "total" fields count total resources in all layers, + * the "free" fields count only those resources which are + * free in the upper layer (since only the upper layer + * is writeable). + */ sbp->f_blocks += mstat.f_blocks; - sbp->f_bfree += mstat.f_bfree; - sbp->f_bavail += mstat.f_bavail; + sbp->f_bfree = mstat.f_bfree; + sbp->f_bavail = mstat.f_bavail; sbp->f_files += mstat.f_files; - sbp->f_ffree += mstat.f_ffree; + sbp->f_ffree = mstat.f_ffree; if (sbp != &mp->mnt_stat) { + sbp->f_type = mp->mnt_vfc->vfc_typenum; bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); @@ -515,51 +489,21 @@ union_statfs(mp, sbp, p) return (0); } -int -union_sync(mp, waitfor, cred, p) - struct mount *mp; - int waitfor; - struct ucred *cred; - struct proc *p; -{ - - /* - * XXX - Assumes no data cached at union layer. - */ - return (0); -} - -int -union_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - - return (EOPNOTSUPP); -} - -int -union_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp) - struct mount *mp; - struct fid *fidp; - struct mbuf *nam; - struct vnode **vpp; - int *exflagsp; - struct ucred **credanonp; -{ - - return (EOPNOTSUPP); -} - -int -union_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; -{ - - return (EOPNOTSUPP); -} +/* + * XXX - Assumes no data cached at union layer. + */ +#define union_sync ((int (*) __P((struct mount *, int, struct ucred *, \ + struct proc *)))nullop) + +#define union_fhtovp ((int (*) __P((struct mount *, struct fid *, \ + struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp) +#define union_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \ + struct proc *)))eopnotsupp) +#define union_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ + size_t, struct proc *)))eopnotsupp) +#define union_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \ + eopnotsupp) +#define union_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp) struct vfsops union_vfsops = { union_mount, diff --git a/sys/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 <sys/proc.h> #include <sys/file.h> #include <sys/time.h> -#include <sys/kernel.h> +#include <sys/stat.h> #include <sys/types.h> #include <sys/vnode.h> #include <sys/mount.h> @@ -51,16 +51,12 @@ #include <sys/malloc.h> #include <sys/buf.h> #include <sys/queue.h> +#include <sys/lock.h> #include <miscfs/union/union.h> -/* FIXUP throws the lock on the uppervp vnode if the union_node is already - * locked and the uppervp vnode is not. Before, this was thrown regardless - * of the state of the union_node which resulted in locked vnodes which - * were never unlocked (since the union would never be unlocked). - */ -#define FIXUP(un) { \ - if (((un)->un_flags & (UN_LOCKED|UN_ULOCK)) == UN_LOCKED) { \ - union_fixup(un); \ +#define FIXUP(un, p) { \ + if (((un)->un_flags & UN_ULOCK) == 0) { \ + union_fixup(un, p); \ } \ } @@ -70,7 +66,7 @@ extern int union_advlock __P((struct vop_advlock_args *ap)); extern int union_bmap __P((struct vop_bmap_args *ap)); extern int union_close __P((struct vop_close_args *ap)); extern int union_create __P((struct vop_create_args *ap)); -static void union_fixup __P((struct union_node *un)); +static void union_fixup __P((struct union_node *un, struct proc *p)); extern int union_fsync __P((struct vop_fsync_args *ap)); extern int union_getattr __P((struct vop_getattr_args *ap)); extern int union_inactive __P((struct vop_inactive_args *ap)); @@ -79,7 +75,7 @@ extern int union_islocked __P((struct vop_islocked_args *ap)); extern int union_link __P((struct vop_link_args *ap)); extern int union_lock __P((struct vop_lock_args *ap)); extern int union_lookup __P((struct vop_lookup_args *ap)); -static int union_lookup1 __P((struct vnode *udvp, struct vnode *dvp, +static int union_lookup1 __P((struct vnode *udvp, struct vnode **dvpp, struct vnode **vpp, struct componentname *cnp)); extern int union_mkdir __P((struct vop_mkdir_args *ap)); @@ -100,29 +96,34 @@ extern int union_select __P((struct vop_select_args *ap)); extern int union_setattr __P((struct vop_setattr_args *ap)); extern int union_strategy __P((struct vop_strategy_args *ap)); extern int union_symlink __P((struct vop_symlink_args *ap)); -extern int union_unlock __P((struct vop_lock_args *ap)); +extern int union_unlock __P((struct vop_unlock_args *ap)); extern int union_write __P((struct vop_read_args *ap)); static void -union_fixup(un) +union_fixup(un, p) struct union_node *un; + struct proc *p; { - VOP_LOCK(un->un_uppervp); + vn_lock(un->un_uppervp, LK_EXCLUSIVE | LK_RETRY, p); un->un_flags |= UN_ULOCK; } static int -union_lookup1(udvp, dvp, vpp, cnp) +union_lookup1(udvp, dvpp, vpp, cnp) struct vnode *udvp; - struct vnode *dvp; + struct vnode **dvpp; struct vnode **vpp; struct componentname *cnp; { int error; + struct proc *p = cnp->cn_proc; struct vnode *tdvp; + struct vnode *dvp; struct mount *mp; + dvp = *dvpp; + /* * If stepping up the directory tree, check for going * back across the mount point, in which case do what @@ -130,21 +131,18 @@ union_lookup1(udvp, dvp, vpp, cnp) * hierarchy. */ if (cnp->cn_flags & ISDOTDOT) { - for (;;) { + while ((dvp != udvp) && (dvp->v_flag & VROOT)) { /* * Don't do the NOCROSSMOUNT check * at this level. By definition, * union fs deals with namespaces, not * filesystems. */ - if ((dvp->v_flag & VROOT) == 0) - break; - tdvp = dvp; - dvp = dvp->v_mount->mnt_vnodecovered; + *dvpp = dvp = dvp->v_mount->mnt_vnodecovered; vput(tdvp); VREF(dvp); - VOP_LOCK(dvp); + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); } } @@ -158,7 +156,7 @@ union_lookup1(udvp, dvp, vpp, cnp) * here to allow it to be unlocked again (phew) in union_lookup. */ if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN)) - VOP_LOCK(dvp); + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); dvp = tdvp; @@ -170,13 +168,11 @@ union_lookup1(udvp, dvp, vpp, cnp) while (dvp != udvp && (dvp->v_type == VDIR) && (mp = dvp->v_mountedhere)) { - if (mp->mnt_flag & MNT_MLOCK) { - mp->mnt_flag |= MNT_MWAIT; - (void) tsleep((caddr_t) mp, PVFS, "unlkup", 0); + if (vfs_busy(mp, 0, 0, p)) continue; - } error = VFS_ROOT(mp, &tdvp); + vfs_unbusy(mp, p); if (error) { vput(dvp); return (error); @@ -206,9 +202,28 @@ union_lookup(ap) struct vnode *dvp = ap->a_dvp; struct union_node *dun = VTOUNION(dvp); struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; int lockparent = cnp->cn_flags & LOCKPARENT; struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount); - struct ucred *saved_cred = 0; + struct ucred *saved_cred; + int iswhiteout; + struct vattr va; + +#ifdef notyet + if (cnp->cn_namelen == 3 && + cnp->cn_nameptr[2] == '.' && + cnp->cn_nameptr[1] == '.' && + cnp->cn_nameptr[0] == '.') { + dvp = *ap->a_vpp = LOWERVP(ap->a_dvp); + if (dvp == NULLVP) + return (ENOENT); + VREF(dvp); + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); + if (!lockparent || !(cnp->cn_flags & ISLASTCN)) + VOP_UNLOCK(ap->a_dvp, 0, p); + return (0); + } +#endif cnp->cn_flags |= LOCKPARENT; @@ -216,6 +231,7 @@ union_lookup(ap) lowerdvp = dun->un_lowervp; uppervp = NULLVP; lowervp = NULLVP; + iswhiteout = 0; /* * do the lookup in the upper level. @@ -223,9 +239,9 @@ union_lookup(ap) * then assume that something special is going * on and just return that vnode. */ - if (upperdvp) { - FIXUP(dun); - uerror = union_lookup1(um->um_uppervp, upperdvp, + if (upperdvp != NULLVP) { + FIXUP(dun, p); + uerror = union_lookup1(um->um_uppervp, &upperdvp, &uppervp, cnp); /*if (uppervp == upperdvp) dun->un_flags |= UN_KLOCK;*/ @@ -236,6 +252,16 @@ union_lookup(ap) cnp->cn_flags &= ~LOCKPARENT; return (uerror); } + if (uerror == ENOENT || uerror == EJUSTRETURN) { + if (cnp->cn_flags & ISWHITEOUT) { + iswhiteout = 1; + } else if (lowerdvp != NULLVP) { + lerror = VOP_GETATTR(upperdvp, &va, + cnp->cn_cred, cnp->cn_proc); + if (lerror == 0 && (va.va_flags & OPAQUE)) + iswhiteout = 1; + } + } } else { uerror = ENOENT; } @@ -247,10 +273,10 @@ union_lookup(ap) * back from the upper layer and return the lower vnode * instead. */ - if (lowerdvp) { + if (lowerdvp != NULLVP && !iswhiteout) { int nameiop; - VOP_LOCK(lowerdvp); + vn_lock(lowerdvp, LK_EXCLUSIVE | LK_RETRY, p); /* * Only do a LOOKUP on the bottom node, since @@ -262,17 +288,17 @@ union_lookup(ap) saved_cred = cnp->cn_cred; cnp->cn_cred = um->um_cred; } - lerror = union_lookup1(um->um_lowervp, lowerdvp, + lerror = union_lookup1(um->um_lowervp, &lowerdvp, &lowervp, cnp); if (um->um_op == UNMNT_BELOW) cnp->cn_cred = saved_cred; cnp->cn_nameiop = nameiop; if (lowervp != lowerdvp) - VOP_UNLOCK(lowerdvp); + VOP_UNLOCK(lowerdvp, 0, p); if (cnp->cn_consume != 0) { - if (uppervp) { + if (uppervp != NULLVP) { if (uppervp == upperdvp) vrele(uppervp); else @@ -286,6 +312,14 @@ union_lookup(ap) } } else { lerror = ENOENT; + if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) { + lowervp = LOWERVP(dun->un_pvp); + if (lowervp != NULLVP) { + VREF(lowervp); + vn_lock(lowervp, LK_EXCLUSIVE | LK_RETRY, p); + lerror = 0; + } + } } if (!lockparent) @@ -326,13 +360,13 @@ union_lookup(ap) if (uerror != 0 /* && (lerror == 0) */ ) { if (lowervp->v_type == VDIR) { /* case 2b. */ dun->un_flags &= ~UN_ULOCK; - VOP_UNLOCK(upperdvp); + VOP_UNLOCK(upperdvp, 0, p); uerror = union_mkshadow(um, upperdvp, cnp, &uppervp); - VOP_LOCK(upperdvp); + vn_lock(upperdvp, LK_EXCLUSIVE | LK_RETRY, p); dun->un_flags |= UN_ULOCK; if (uerror) { - if (lowervp) { + if (lowervp != NULLVP) { vput(lowervp); lowervp = NULLVP; } @@ -341,21 +375,21 @@ union_lookup(ap) } } - if (lowervp) - VOP_UNLOCK(lowervp); + if (lowervp != NULLVP) + VOP_UNLOCK(lowervp, 0, p); error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp, - uppervp, lowervp); + uppervp, lowervp, 1); if (error) { - if (uppervp) + if (uppervp != NULLVP) vput(uppervp); - if (lowervp) + if (lowervp != NULLVP) vrele(lowervp); } else { if (*ap->a_vpp != dvp) if (!lockparent || !(cnp->cn_flags & ISLASTCN)) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); } return (error); @@ -372,28 +406,26 @@ union_create(ap) { struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; - if (dvp) { + if (dvp != NULLVP) { int error; struct vnode *vp; + struct mount *mp; - FIXUP(un); + FIXUP(un, p); VREF(dvp); un->un_flags |= UN_KLOCK; + mp = ap->a_dvp->v_mount; vput(ap->a_dvp); - error = VOP_CREATE(dvp, &vp, ap->a_cnp, ap->a_vap); + error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap); if (error) return (error); - error = union_allocvp( - ap->a_vpp, - ap->a_dvp->v_mount, - ap->a_dvp, - NULLVP, - ap->a_cnp, - vp, - NULLVP); + error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, cnp, vp, + NULLVP, 1); if (error) vput(vp); return (error); @@ -404,6 +436,25 @@ union_create(ap) } int +union_whiteout(ap) + struct vop_whiteout_args /* { + struct vnode *a_dvp; + struct componentname *a_cnp; + int a_flags; + } */ *ap; +{ + struct union_node *un = VTOUNION(ap->a_dvp); + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; + + if (un->un_uppervp == NULLVP) + return (EOPNOTSUPP); + + FIXUP(un, p); + return (VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags)); +} + +int union_mknod(ap) struct vop_mknod_args /* { struct vnode *a_dvp; @@ -414,29 +465,27 @@ union_mknod(ap) { struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; - if (dvp) { + if (dvp != NULLVP) { int error; struct vnode *vp; + struct mount *mp; - FIXUP(un); + FIXUP(un, p); VREF(dvp); un->un_flags |= UN_KLOCK; + mp = ap->a_dvp->v_mount; vput(ap->a_dvp); - error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap); + error = VOP_MKNOD(dvp, &vp, cnp, ap->a_vap); if (error) return (error); - if (vp) { - error = union_allocvp( - ap->a_vpp, - ap->a_dvp->v_mount, - ap->a_dvp, - NULLVP, - ap->a_cnp, - vp, - NULLVP); + if (vp != NULLVP) { + error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, + cnp, vp, NULLVP, 1); if (error) vput(vp); } @@ -476,77 +525,7 @@ union_open(ap) */ tvp = un->un_lowervp; if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) { - struct vnode *vp; - int i; - - /* - * Open the named file in the upper layer. Note that - * the file may have come into existence *since* the - * lookup was done, since the upper layer may really - * be a loopback mount of some other filesystem... - * so open the file with exclusive create and barf if - * it already exists. - * XXX - perhaps should re-lookup the node (once more - * with feeling) and simply open that. Who knows. - */ - error = union_vn_create(&vp, un, p); - if (error) - return (error); - - /* at this point, uppervp is locked */ - union_newupper(un, vp); - un->un_flags |= UN_ULOCK; - - /* - * Now, if the file is being opened with truncation, - * then the (new) upper vnode is ready to fly, - * otherwise the data from the lower vnode must be - * copied to the upper layer first. This only works - * for regular files (check is made above). - */ - if ((mode & O_TRUNC) == 0) { - /* - * XXX - should not ignore errors - * from VOP_CLOSE - */ - VOP_LOCK(tvp); - error = VOP_OPEN(tvp, FREAD, cred, p); - if (error == 0) { - error = union_copyfile(p, cred, - tvp, un->un_uppervp); - VOP_UNLOCK(tvp); - (void) VOP_CLOSE(tvp, FREAD, cred, p); - } else { - VOP_UNLOCK(tvp); - } - -#ifdef UNION_DIAGNOSTIC - if (!error) - uprintf("union: copied up %s\n", - un->un_path); -#endif - } - - un->un_flags &= ~UN_ULOCK; - VOP_UNLOCK(un->un_uppervp); - union_vn_close(un->un_uppervp, FWRITE, cred, p); - VOP_LOCK(un->un_uppervp); - un->un_flags |= UN_ULOCK; - - /* - * Subsequent IOs will go to the top layer, so - * call close on the lower vnode and open on the - * upper vnode to ensure that the filesystem keeps - * its references counts right. This doesn't do - * the right thing with (cred) and (FREAD) though. - * Ignoring error returns is not righ, either. - */ - for (i = 0; i < un->un_openl; i++) { - (void) VOP_CLOSE(tvp, FREAD, cred, p); - (void) VOP_OPEN(un->un_uppervp, FREAD, cred, p); - } - un->un_openl = 0; - + error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p); if (error == 0) error = VOP_OPEN(un->un_uppervp, mode, cred, p); return (error); @@ -556,14 +535,14 @@ union_open(ap) * Just open the lower vnode */ un->un_openl++; - VOP_LOCK(tvp); + vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_OPEN(tvp, mode, cred, p); - VOP_UNLOCK(tvp); + VOP_UNLOCK(tvp, 0, p); return (error); } - FIXUP(un); + FIXUP(un, p); error = VOP_OPEN(tvp, mode, cred, p); @@ -582,9 +561,7 @@ union_close(ap) struct union_node *un = VTOUNION(ap->a_vp); struct vnode *vp; - if (un->un_uppervp) { - vp = un->un_uppervp; - } else { + if ((vp = un->un_uppervp) == NULLVP) { #ifdef UNION_DIAGNOSTIC if (un->un_openl <= 0) panic("union: un_openl cnt"); @@ -593,7 +570,8 @@ union_close(ap) vp = un->un_lowervp; } - return (VOP_CLOSE(vp, ap->a_fflag, ap->a_cred, ap->a_p)); + ap->a_vp = vp; + return (VCALL(vp, VOFFSET(vop_close), ap)); } /* @@ -615,27 +593,29 @@ union_access(ap) } */ *ap; { struct union_node *un = VTOUNION(ap->a_vp); + struct proc *p = ap->a_p; int error = EACCES; struct vnode *vp; - vp = un->un_uppervp; - if (vp) { - FIXUP(un); - return (VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p)); + if ((vp = un->un_uppervp) != NULLVP) { + FIXUP(un, p); + ap->a_vp = vp; + return (VCALL(vp, VOFFSET(vop_access), ap)); } - vp = un->un_lowervp; - if (vp) { - VOP_LOCK(vp); - error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p); + if ((vp = un->un_lowervp) != NULLVP) { + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + ap->a_vp = vp; + error = VCALL(vp, VOFFSET(vop_access), ap); if (error == 0) { struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount); - if (um->um_op == UNMNT_BELOW) - error = VOP_ACCESS(vp, ap->a_mode, - um->um_cred, ap->a_p); + if (um->um_op == UNMNT_BELOW) { + ap->a_cred = um->um_cred; + error = VCALL(vp, VOFFSET(vop_access), ap); + } } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); if (error) return (error); } @@ -644,7 +624,8 @@ union_access(ap) } /* - * We handle getattr only to change the fsid. + * We handle getattr only to change the fsid and + * track object sizes */ int union_getattr(ap) @@ -658,6 +639,7 @@ union_getattr(ap) int error; struct union_node *un = VTOUNION(ap->a_vp); struct vnode *vp = un->un_uppervp; + struct proc *p = ap->a_p; struct vattr *vap; struct vattr va; @@ -675,10 +657,21 @@ union_getattr(ap) vp = un->un_uppervp; if (vp != NULLVP) { - FIXUP(un); + /* + * It's not clear whether VOP_GETATTR is to be + * called with the vnode locked or not. stat() calls + * it with (vp) locked, and fstat calls it with + * (vp) unlocked. + * In the mean time, compensate here by checking + * the union_node's lock flag. + */ + if (un->un_flags & UN_LOCKED) + FIXUP(un, p); + error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); if (error) return (error); + union_newsize(ap->a_vp, vap->va_size, VNOVAL); } if (vp == NULLVP) { @@ -691,17 +684,16 @@ union_getattr(ap) } if (vp != NULLVP) { - VOP_LOCK(vp); error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); - VOP_UNLOCK(vp); if (error) return (error); + union_newsize(ap->a_vp, VNOVAL, vap->va_size); } if ((vap != ap->a_vap) && (vap->va_type == VDIR)) ap->a_vap->va_nlink += vap->va_nlink; - vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; + ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; return (0); } @@ -715,6 +707,7 @@ union_setattr(ap) } */ *ap; { struct union_node *un = VTOUNION(ap->a_vp); + struct proc *p = ap->a_p; int error; /* @@ -724,21 +717,11 @@ union_setattr(ap) */ if ((un->un_uppervp == NULLVP) && /* assert(un->un_lowervp != NULLVP) */ - (un->un_lowervp->v_type == VREG) && - (ap->a_vap->va_size == 0)) { - struct vnode *vp; - - error = union_vn_create(&vp, un, ap->a_p); + (un->un_lowervp->v_type == VREG)) { + error = union_copyup(un, (ap->a_vap->va_size != 0), + ap->a_cred, ap->a_p); if (error) return (error); - - /* at this point, uppervp is locked */ - union_newupper(un, vp); - - VOP_UNLOCK(vp); - union_vn_close(un->un_uppervp, FWRITE, ap->a_cred, ap->a_p); - VOP_LOCK(vp); - un->un_flags |= UN_ULOCK; } /* @@ -746,9 +729,11 @@ union_setattr(ap) * otherwise return read-only filesystem error. */ if (un->un_uppervp != NULLVP) { - FIXUP(un); + FIXUP(un, p); error = VOP_SETATTR(un->un_uppervp, ap->a_vap, ap->a_cred, ap->a_p); + if ((error == 0) && (ap->a_vap->va_size != VNOVAL)) + union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL); } else { error = EROFS; } @@ -766,16 +751,36 @@ union_read(ap) } */ *ap; { int error; + struct proc *p = ap->a_uio->uio_procp; struct vnode *vp = OTHERVP(ap->a_vp); int dolock = (vp == LOWERVP(ap->a_vp)); if (dolock) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp)); + FIXUP(VTOUNION(ap->a_vp), p); error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); if (dolock) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); + + /* + * XXX + * perhaps the size of the underlying object has changed under + * our feet. take advantage of the offset information present + * in the uio structure. + */ + if (error == 0) { + struct union_node *un = VTOUNION(ap->a_vp); + off_t cur = ap->a_uio->uio_offset; + + if (vp == un->un_uppervp) { + if (cur > un->un_uppersz) + union_newsize(ap->a_vp, cur, VNOVAL); + } else { + if (cur > un->un_lowersz) + union_newsize(ap->a_vp, VNOVAL, cur); + } + } return (error); } @@ -790,21 +795,47 @@ union_write(ap) } */ *ap; { int error; - struct vnode *vp = OTHERVP(ap->a_vp); - int dolock = (vp == LOWERVP(ap->a_vp)); + struct vnode *vp; + struct union_node *un = VTOUNION(ap->a_vp); + struct proc *p = ap->a_uio->uio_procp; - if (dolock) - VOP_LOCK(vp); - else - FIXUP(VTOUNION(ap->a_vp)); + vp = UPPERVP(ap->a_vp); + if (vp == NULLVP) + panic("union: missing upper layer in write"); + + FIXUP(un, p); error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); - if (dolock) - VOP_UNLOCK(vp); + + /* + * the size of the underlying object may be changed by the + * write. + */ + if (error == 0) { + off_t cur = ap->a_uio->uio_offset; + + if (cur > un->un_uppersz) + union_newsize(ap->a_vp, cur, VNOVAL); + } return (error); } int +union_lease(ap) + struct vop_lease_args /* { + struct vnode *a_vp; + struct proc *a_p; + struct ucred *a_cred; + int a_flag; + } */ *ap; +{ + register struct vnode *ovp = OTHERVP(ap->a_vp); + + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_lease), ap)); +} + +int union_ioctl(ap) struct vop_ioctl_args /* { struct vnode *a_vp; @@ -815,9 +846,10 @@ union_ioctl(ap) struct proc *a_p; } */ *ap; { + register struct vnode *ovp = OTHERVP(ap->a_vp); - return (VOP_IOCTL(OTHERVP(ap->a_vp), ap->a_command, ap->a_data, - ap->a_fflag, ap->a_cred, ap->a_p)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_ioctl), ap)); } int @@ -830,9 +862,28 @@ union_select(ap) struct proc *a_p; } */ *ap; { + register struct vnode *ovp = OTHERVP(ap->a_vp); - return (VOP_SELECT(OTHERVP(ap->a_vp), ap->a_which, ap->a_fflags, - ap->a_cred, ap->a_p)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_select), ap)); +} + +int +union_revoke(ap) + struct vop_revoke_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + if (UPPERVP(vp)) + VOP_REVOKE(UPPERVP(vp), ap->a_flags); + if (LOWERVP(vp)) + VOP_REVOKE(LOWERVP(vp), ap->a_flags); + vgone(vp); + return (0); } int @@ -844,9 +895,10 @@ union_mmap(ap) struct proc *a_p; } */ *ap; { + register struct vnode *ovp = OTHERVP(ap->a_vp); - return (VOP_MMAP(OTHERVP(ap->a_vp), ap->a_fflags, - ap->a_cred, ap->a_p)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_mmap), ap)); } int @@ -859,19 +911,19 @@ union_fsync(ap) } */ *ap; { int error = 0; + struct proc *p = ap->a_p; struct vnode *targetvp = OTHERVP(ap->a_vp); - if (targetvp) { + if (targetvp != NULLVP) { int dolock = (targetvp == LOWERVP(ap->a_vp)); if (dolock) - VOP_LOCK(targetvp); + vn_lock(targetvp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp)); - error = VOP_FSYNC(targetvp, ap->a_cred, - ap->a_waitfor, ap->a_p); + FIXUP(VTOUNION(ap->a_vp), p); + error = VOP_FSYNC(targetvp, ap->a_cred, ap->a_waitfor, p); if (dolock) - VOP_UNLOCK(targetvp); + VOP_UNLOCK(targetvp, 0, p); } return (error); @@ -886,8 +938,10 @@ union_seek(ap) struct ucred *a_cred; } */ *ap; { + register struct vnode *ovp = OTHERVP(ap->a_vp); - return (VOP_SEEK(OTHERVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_seek), ap)); } int @@ -901,34 +955,37 @@ union_remove(ap) int error; struct union_node *dun = VTOUNION(ap->a_dvp); struct union_node *un = VTOUNION(ap->a_vp); + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; - if (dun->un_uppervp && un->un_uppervp) { + if (dun->un_uppervp == NULLVP) + panic("union remove: null upper vnode"); + + if (un->un_uppervp != NULLVP) { struct vnode *dvp = dun->un_uppervp; struct vnode *vp = un->un_uppervp; - FIXUP(dun); + FIXUP(dun, p); VREF(dvp); dun->un_flags |= UN_KLOCK; vput(ap->a_dvp); - FIXUP(un); + FIXUP(un, p); VREF(vp); un->un_flags |= UN_KLOCK; vput(ap->a_vp); - error = VOP_REMOVE(dvp, vp, ap->a_cnp); + if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc)) + cnp->cn_flags |= DOWHITEOUT; + error = VOP_REMOVE(dvp, vp, cnp); if (!error) union_removed_upper(un); - - /* - * XXX: should create a whiteout here - */ } else { - /* - * XXX: should create a whiteout here - */ + FIXUP(dun, p); + error = union_mkwhiteout( + MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount), + dun->un_uppervp, ap->a_cnp, un->un_path); vput(ap->a_dvp); vput(ap->a_vp); - error = EROFS; } return (error); @@ -942,34 +999,51 @@ union_link(ap) struct componentname *a_cnp; } */ *ap; { - int error; - struct union_node *dun = VTOUNION(ap->a_vp); - struct union_node *un = VTOUNION(ap->a_tdvp); - - if (dun->un_uppervp && un->un_uppervp) { - struct vnode *dvp = dun->un_uppervp; - struct vnode *vp = un->un_uppervp; + int error = 0; + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; + struct union_node *un; + struct vnode *vp; + struct vnode *tdvp; - FIXUP(dun); - VREF(dvp); - dun->un_flags |= UN_KLOCK; - vput(ap->a_vp); - FIXUP(un); - VREF(vp); - vrele(ap->a_tdvp); + un = VTOUNION(ap->a_tdvp); - error = VOP_LINK(dvp, vp, ap->a_cnp); + if (ap->a_tdvp->v_op != ap->a_vp->v_op) { + vp = ap->a_vp; } else { - /* - * XXX: need to copy to upper layer - * and do the link there. - */ - vput(ap->a_vp); - vrele(ap->a_tdvp); + struct union_node *tun = VTOUNION(ap->a_vp); + if (tun->un_uppervp == NULLVP) { + vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p); + if (un->un_uppervp == tun->un_dirvp) { + un->un_flags &= ~UN_ULOCK; + VOP_UNLOCK(un->un_uppervp, 0, p); + } + error = union_copyup(tun, 1, cnp->cn_cred, p); + if (un->un_uppervp == tun->un_dirvp) { + vn_lock(un->un_uppervp, + LK_EXCLUSIVE | LK_RETRY, p); + un->un_flags |= UN_ULOCK; + } + VOP_UNLOCK(ap->a_vp, 0, p); + } + vp = tun->un_uppervp; + } + + tdvp = un->un_uppervp; + if (tdvp == NULLVP) error = EROFS; + + if (error) { + vput(ap->a_tdvp); + return (error); } - return (error); + FIXUP(un, p); + VREF(tdvp); + un->un_flags |= UN_KLOCK; + vput(ap->a_tdvp); + + return (VOP_LINK(vp, tdvp, cnp)); } int @@ -993,11 +1067,16 @@ union_rename(ap) if (fdvp->v_op == union_vnodeop_p) { /* always true */ struct union_node *un = VTOUNION(fdvp); if (un->un_uppervp == NULLVP) { - error = EROFS; + /* + * this should never happen in normal + * operation but might if there was + * a problem creating the top-level shadow + * directory. + */ + error = EXDEV; goto bad; } - FIXUP(un); fdvp = un->un_uppervp; VREF(fdvp); vrele(ap->a_fdvp); @@ -1006,11 +1085,14 @@ union_rename(ap) if (fvp->v_op == union_vnodeop_p) { /* always true */ struct union_node *un = VTOUNION(fvp); if (un->un_uppervp == NULLVP) { - error = EROFS; + /* XXX: should do a copyup */ + error = EXDEV; goto bad; } - FIXUP(un); + if (un->un_lowervp != NULLVP) + ap->a_fcnp->cn_flags |= DOWHITEOUT; + fvp = un->un_uppervp; VREF(fvp); vrele(ap->a_fvp); @@ -1019,7 +1101,13 @@ union_rename(ap) if (tdvp->v_op == union_vnodeop_p) { struct union_node *un = VTOUNION(tdvp); if (un->un_uppervp == NULLVP) { - error = EROFS; + /* + * this should never happen in normal + * operation but might if there was + * a problem creating the top-level shadow + * directory. + */ + error = EXDEV; goto bad; } @@ -1029,16 +1117,14 @@ union_rename(ap) vput(ap->a_tdvp); } - if (tvp && tvp->v_op == union_vnodeop_p) { + if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) { struct union_node *un = VTOUNION(tvp); - if (un->un_uppervp == NULLVP) { - error = EROFS; - goto bad; - } tvp = un->un_uppervp; - VREF(tvp); - un->un_flags |= UN_KLOCK; + if (tvp != NULLVP) { + VREF(tvp); + un->un_flags |= UN_KLOCK; + } vput(ap->a_tvp); } @@ -1048,7 +1134,7 @@ bad: vrele(fdvp); vrele(fvp); vput(tdvp); - if (tvp) + if (tvp != NULLVP) vput(tvp); return (error); @@ -1065,27 +1151,26 @@ union_mkdir(ap) { struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; - if (dvp) { + if (dvp != NULLVP) { int error; struct vnode *vp; - FIXUP(un); + FIXUP(un, p); VREF(dvp); un->un_flags |= UN_KLOCK; - vput(ap->a_dvp); - error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap); - if (error) + VOP_UNLOCK(ap->a_dvp, 0, p); + error = VOP_MKDIR(dvp, &vp, cnp, ap->a_vap); + if (error) { + vrele(ap->a_dvp); return (error); + } - error = union_allocvp( - ap->a_vpp, - ap->a_dvp->v_mount, - ap->a_dvp, - NULLVP, - ap->a_cnp, - vp, - NULLVP); + error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount, ap->a_dvp, + NULLVP, cnp, vp, NULLVP, 1); + vrele(ap->a_dvp); if (error) vput(vp); return (error); @@ -1106,34 +1191,37 @@ union_rmdir(ap) int error; struct union_node *dun = VTOUNION(ap->a_dvp); struct union_node *un = VTOUNION(ap->a_vp); + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; - if (dun->un_uppervp && un->un_uppervp) { + if (dun->un_uppervp == NULLVP) + panic("union rmdir: null upper vnode"); + + if (un->un_uppervp != NULLVP) { struct vnode *dvp = dun->un_uppervp; struct vnode *vp = un->un_uppervp; - FIXUP(dun); + FIXUP(dun, p); VREF(dvp); dun->un_flags |= UN_KLOCK; vput(ap->a_dvp); - FIXUP(un); + FIXUP(un, p); VREF(vp); un->un_flags |= UN_KLOCK; vput(ap->a_vp); + if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc)) + cnp->cn_flags |= DOWHITEOUT; error = VOP_RMDIR(dvp, vp, ap->a_cnp); if (!error) union_removed_upper(un); - - /* - * XXX: should create a whiteout here - */ } else { - /* - * XXX: should create a whiteout here - */ + FIXUP(dun, p); + error = union_mkwhiteout( + MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount), + dun->un_uppervp, ap->a_cnp, un->un_path); vput(ap->a_dvp); vput(ap->a_vp); - error = EROFS; } return (error); @@ -1151,17 +1239,18 @@ union_symlink(ap) { struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; - if (dvp) { + if (dvp != NULLVP) { int error; struct vnode *vp; - FIXUP(un); + FIXUP(un, p); VREF(dvp); un->un_flags |= UN_KLOCK; vput(ap->a_dvp); - error = VOP_SYMLINK(dvp, &vp, ap->a_cnp, - ap->a_vap, ap->a_target); + error = VOP_SYMLINK(dvp, &vp, cnp, ap->a_vap, ap->a_target); *ap->a_vpp = NULLVP; return (error); } @@ -1183,17 +1272,21 @@ union_readdir(ap) struct vnode *a_vp; struct uio *a_uio; struct ucred *a_cred; + int *a_eofflag; + u_long *a_cookies; + int a_ncookies; } */ *ap; { - int error = 0; struct union_node *un = VTOUNION(ap->a_vp); + struct vnode *uvp = un->un_uppervp; + struct proc *p = ap->a_uio->uio_procp; - if (un->un_uppervp) { - FIXUP(un); - error = VOP_READDIR(un->un_uppervp, ap->a_uio, ap->a_cred, NULL, NULL, NULL); - } + if (uvp == NULLVP) + return (0); - return (error); + FIXUP(un, p); + ap->a_vp = uvp; + return (VCALL(uvp, VOFFSET(vop_readdir), ap)); } int @@ -1205,16 +1298,19 @@ union_readlink(ap) } */ *ap; { int error; + struct uio *uio = ap->a_uio; + struct proc *p = uio->uio_procp; struct vnode *vp = OTHERVP(ap->a_vp); int dolock = (vp == LOWERVP(ap->a_vp)); if (dolock) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp)); - error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); + FIXUP(VTOUNION(ap->a_vp), p); + ap->a_vp = vp; + error = VCALL(vp, VOFFSET(vop_readlink), ap); if (dolock) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1227,6 +1323,8 @@ union_abortop(ap) } */ *ap; { int error; + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; struct vnode *vp = OTHERVP(ap->a_dvp); struct union_node *un = VTOUNION(ap->a_dvp); int islocked = un->un_flags & UN_LOCKED; @@ -1234,13 +1332,14 @@ union_abortop(ap) if (islocked) { if (dolock) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_dvp)); + FIXUP(VTOUNION(ap->a_dvp), p); } - error = VOP_ABORTOP(vp, ap->a_cnp); + ap->a_dvp = vp; + error = VCALL(vp, VOFFSET(vop_abortop), ap); if (islocked && dolock) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1249,8 +1348,13 @@ int union_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { + struct vnode *vp = ap->a_vp; + struct proc *p = ap->a_p; + struct union_node *un = VTOUNION(vp); + struct vnode **vpp; /* * Do nothing (and _don't_ bypass). @@ -1265,12 +1369,17 @@ union_inactive(ap) * That's too much work for now. */ -#ifdef UNION_DIAGNOSTIC - struct union_node *un = VTOUNION(ap->a_vp); + if (un->un_dircache != 0) { + for (vpp = un->un_dircache; *vpp != NULLVP; vpp++) + vrele(*vpp); + free(un->un_dircache, M_TEMP); + un->un_dircache = 0; + } - if (un->un_flags & UN_LOCKED) - panic("union: inactivating locked node"); -#endif + VOP_UNLOCK(vp, 0, p); + + if ((un->un_flags & UN_CACHED) == 0) + vgone(vp); return (0); } @@ -1292,24 +1401,39 @@ union_lock(ap) struct vop_lock_args *ap; { struct vnode *vp = ap->a_vp; + struct proc *p = ap->a_p; + int flags = ap->a_flags; struct union_node *un; + int error; -start: - while (vp->v_flag & VXLOCK) { - vp->v_flag |= VXWANT; - (void) tsleep((caddr_t)vp, PINOD, "unnlk1", 0); - } + vop_nolock(ap); + /* + * Need to do real lockmgr-style locking here. + * in the mean time, draining won't work quite right, + * which could lead to a few race conditions. + * the following test was here, but is not quite right, we + * still need to take the lock: + if ((flags & LK_TYPE_MASK) == LK_DRAIN) + return (0); + */ + flags &= ~LK_INTERLOCK; +start: un = VTOUNION(vp); - if (un->un_uppervp) { - if ((un->un_flags & UN_ULOCK) == 0) { + if (un->un_uppervp != NULLVP) { + if (((un->un_flags & UN_ULOCK) == 0) && + (vp->v_usecount != 0)) { + error = vn_lock(un->un_uppervp, flags, p); + if (error) + return (error); un->un_flags |= UN_ULOCK; - VOP_LOCK(un->un_uppervp); } #ifdef DIAGNOSTIC - if (un->un_flags & UN_KLOCK) - panic("union: dangling upper lock"); + if (un->un_flags & UN_KLOCK) { + vprint("union: dangling klock", vp); + panic("union: dangling upper lock (%lx)", vp); + } #endif } @@ -1320,7 +1444,7 @@ start: panic("union: locking against myself"); #endif un->un_flags |= UN_WANT; - (void) tsleep((caddr_t) &un->un_flags, PINOD, "unnlk2", 0); + tsleep((caddr_t)&un->un_flags, PINOD, "unionlk2", 0); goto start; } @@ -1335,11 +1459,27 @@ start: return (0); } +/* + * When operations want to vput() a union node yet retain a lock on + * the upper vnode (say, to do some further operations like link(), + * mkdir(), ...), they set UN_KLOCK on the union node, then call + * vput() which calls VOP_UNLOCK() and comes here. union_unlock() + * unlocks the union node (leaving the upper vnode alone), clears the + * KLOCK flag, and then returns to vput(). The caller then does whatever + * is left to do with the upper vnode, and ensures that it gets unlocked. + * + * If UN_KLOCK isn't set, then the upper vnode is unlocked here. + */ int union_unlock(ap) - struct vop_lock_args *ap; + struct vop_unlock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; { struct union_node *un = VTOUNION(ap->a_vp); + struct proc *p = ap->a_p; #ifdef DIAGNOSTIC if ((un->un_flags & UN_LOCKED) == 0) @@ -1352,7 +1492,7 @@ union_unlock(ap) un->un_flags &= ~UN_LOCKED; if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK) - VOP_UNLOCK(un->un_uppervp); + VOP_UNLOCK(un->un_uppervp, 0, p); un->un_flags &= ~(UN_ULOCK|UN_KLOCK); @@ -1364,6 +1504,7 @@ union_unlock(ap) #ifdef DIAGNOSTIC un->un_pid = 0; #endif + vop_nounlock(ap); return (0); } @@ -1380,16 +1521,18 @@ union_bmap(ap) } */ *ap; { int error; + struct proc *p = curproc; /* XXX */ struct vnode *vp = OTHERVP(ap->a_vp); int dolock = (vp == LOWERVP(ap->a_vp)); if (dolock) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp)); - error = VOP_BMAP(vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp, ap->a_runb); + FIXUP(VTOUNION(ap->a_vp), p); + ap->a_vp = vp; + error = VCALL(vp, VOFFSET(vop_bmap), ap); if (dolock) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1404,6 +1547,11 @@ union_print(ap) printf("\ttag VT_UNION, vp=%p, uppervp=%p, lowervp=%p\n", vp, UPPERVP(vp), LOWERVP(vp)); + if (UPPERVP(vp) != NULLVP) + vprint("union: upper", UPPERVP(vp)); + if (LOWERVP(vp) != NULLVP) + vprint("union: lower", LOWERVP(vp)); + return (0); } @@ -1426,16 +1574,18 @@ union_pathconf(ap) } */ *ap; { int error; + struct proc *p = curproc; /* XXX */ struct vnode *vp = OTHERVP(ap->a_vp); int dolock = (vp == LOWERVP(ap->a_vp)); if (dolock) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp)); - error = VOP_PATHCONF(vp, ap->a_name, ap->a_retval); + FIXUP(VTOUNION(ap->a_vp), p); + ap->a_vp = vp; + error = VCALL(vp, VOFFSET(vop_pathconf), ap); if (dolock) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1450,9 +1600,10 @@ union_advlock(ap) int a_flags; } */ *ap; { + register struct vnode *ovp = OTHERVP(ap->a_vp); - return (VOP_ADVLOCK(OTHERVP(ap->a_vp), ap->a_id, ap->a_op, - ap->a_fl, ap->a_flags)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_advlock), ap)); } @@ -1496,6 +1647,7 @@ struct vnodeopv_entry_desc union_vnodeop_entries[] = { { &vop_default_desc, (vop_t *)vn_default_error }, { &vop_lookup_desc, (vop_t *)union_lookup }, /* lookup */ { &vop_create_desc, (vop_t *)union_create }, /* create */ + { &vop_whiteout_desc, (vop_t *)union_whiteout }, /* whiteout */ { &vop_mknod_desc, (vop_t *)union_mknod }, /* mknod */ { &vop_open_desc, (vop_t *)union_open }, /* open */ { &vop_close_desc, (vop_t *)union_close }, /* close */ @@ -1504,8 +1656,10 @@ struct vnodeopv_entry_desc union_vnodeop_entries[] = { { &vop_setattr_desc, (vop_t *)union_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)union_read }, /* read */ { &vop_write_desc, (vop_t *)union_write }, /* write */ + { &vop_lease_desc, (vop_t *)union_lease }, /* lease */ { &vop_ioctl_desc, (vop_t *)union_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)union_select }, /* select */ + { &vop_revoke_desc, (vop_t *)union_revoke }, /* revoke */ { &vop_mmap_desc, (vop_t *)union_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)union_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)union_seek }, /* seek */ diff --git a/sys/gnu/ext2fs/ext2_bmap.c b/sys/gnu/ext2fs/ext2_bmap.c index e17b5b7..aef2b83 100644 --- a/sys/gnu/ext2fs/ext2_bmap.c +++ b/sys/gnu/ext2fs/ext2_bmap.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ufs_bmap.c 8.6 (Berkeley) 1/21/94 + * @(#)ufs_bmap.c 8.7 (Berkeley) 3/21/95 * $FreeBSD$ */ @@ -63,9 +63,9 @@ int ufs_bmap(ap) struct vop_bmap_args /* { struct vnode *a_vp; - daddr_t a_bn; + ufs_daddr_t a_bn; struct vnode **a_vpp; - daddr_t *a_bnp; + ufs_daddr_t *a_bnp; int *a_runp; int *a_runb; } */ *ap; @@ -100,8 +100,8 @@ ufs_bmap(ap) int ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb) struct vnode *vp; - register daddr_t bn; - daddr_t *bnp; + ufs_daddr_t bn; + ufs_daddr_t *bnp; struct indir *ap; int *nump; int *runp; @@ -113,7 +113,7 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb) struct mount *mp; struct vnode *devvp; struct indir a[NIADDR+1], *xap; - daddr_t daddr; + ufs_daddr_t daddr; long metalbn; int error, maxrun = 0, num; @@ -209,12 +209,13 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb) } } - daddr = ((daddr_t *)bp->b_data)[xap->in_off]; + daddr = ((ufs_daddr_t *)bp->b_data)[xap->in_off]; if (num == 1 && daddr && runp) { for (bn = xap->in_off + 1; bn < MNINDIR(ump) && *runp < maxrun && - is_sequential(ump, ((daddr_t *)bp->b_data)[bn - 1], - ((daddr_t *)bp->b_data)[bn]); + is_sequential(ump, + ((ufs_daddr_t *)bp->b_data)[bn - 1], + ((ufs_daddr_t *)bp->b_data)[bn]); ++bn, ++*runp); bn = xap->in_off; if (runb && bn) { @@ -245,7 +246,7 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb) int ufs_getlbns(vp, bn, ap, nump) struct vnode *vp; - register daddr_t bn; + ufs_daddr_t bn; struct indir *ap; int *nump; { diff --git a/sys/gnu/ext2fs/ext2_extern.h b/sys/gnu/ext2fs/ext2_extern.h index f07b7b7..de6cd08f 100644 --- a/sys/gnu/ext2fs/ext2_extern.h +++ b/sys/gnu/ext2fs/ext2_extern.h @@ -56,7 +56,7 @@ int ext2_blkatoff __P((struct vop_blkatoff_args *)); void ext2_blkfree __P((struct inode *, daddr_t, long)); daddr_t ext2_blkpref __P((struct inode *, daddr_t, int, daddr_t *, daddr_t)); int ext2_bmap __P((struct vop_bmap_args *)); -int ext2_init __P((void)); +int ext2_init __P((struct vfsconf *)); int ext2_reallocblks __P((struct vop_reallocblks_args *)); int ext2_reclaim __P((struct vop_reclaim_args *)); void ext2_setblock __P((struct ext2_sb_info *, u_char *, daddr_t)); diff --git a/sys/gnu/ext2fs/ext2_ihash.c b/sys/gnu/ext2fs/ext2_ihash.c index a51af00..ea83308 100644 --- a/sys/gnu/ext2fs/ext2_ihash.c +++ b/sys/gnu/ext2fs/ext2_ihash.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1982, 1986, 1989, 1991, 1993 + * Copyright (c) 1982, 1986, 1989, 1991, 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. * - * @(#)ufs_ihash.c 8.4 (Berkeley) 12/30/93 + * @(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95 * $FreeBSD$ */ @@ -47,9 +47,10 @@ /* * Structures associated with inode cacheing. */ -struct inode **ihashtbl; +LIST_HEAD(ihashhead, inode) *ihashtbl; u_long ihash; /* size of hash table - 1 */ -#define INOHASH(device, inum) (((device) + (inum)) & ihash) +#define INOHASH(device, inum) (&ihashtbl[((device) + (inum)) & ihash]) +struct simplelock ufs_ihash_slock; /* * Initialize inode hash table. @@ -59,6 +60,7 @@ ufs_ihashinit() { ihashtbl = hashinit(desiredvnodes, M_UFSMNT, &ihash); + simple_lock_init(&ufs_ihash_slock); } /* @@ -66,19 +68,21 @@ ufs_ihashinit() * to it. If it is in core, return it, even if it is locked. */ struct vnode * -ufs_ihashlookup(device, inum) - dev_t device; +ufs_ihashlookup(dev, inum) + dev_t dev; ino_t inum; { - register struct inode *ip; + struct inode *ip; - for (ip = ihashtbl[INOHASH(device, inum)];; ip = ip->i_next) { - if (ip == NULL) - return (NULL); - if (inum == ip->i_number && device == ip->i_dev) - return (ITOV(ip)); - } - /* NOTREACHED */ + simple_lock(&ufs_ihash_slock); + for (ip = INOHASH(dev, inum)->lh_first; ip; ip = ip->i_hash.le_next) + if (inum == ip->i_number && dev == ip->i_dev) + break; + simple_unlock(&ufs_ihash_slock); + + if (ip) + return (ITOV(ip)); + return (NULLVP); } /* @@ -86,36 +90,28 @@ ufs_ihashlookup(device, inum) * to it. If it is in core, but locked, wait for it. */ struct vnode * -ufs_ihashget(device, inum) - dev_t device; +ufs_ihashget(dev, inum) + dev_t dev; ino_t inum; { - register struct inode *ip; + struct proc *p = curproc; /* XXX */ + struct inode *ip; struct vnode *vp; - for (;;) - for (ip = ihashtbl[INOHASH(device, inum)];; ip = ip->i_next) { - if (ip == NULL) - return (NULL); - if (inum == ip->i_number && device == ip->i_dev) { - if (ip->i_flag & IN_LOCKED) { - if( curproc->p_pid != ip->i_lockholder) { - ip->i_flag |= IN_WANTED; - (void) tsleep(ip, PINOD, "uihget", 0); - break; - } else if (ip->i_flag & IN_RECURSE) { - ip->i_lockcount++; - } else { - panic("ufs_ihashget: recursive lock not expected -- pid %d\n", ip->i_lockholder); - } - } - vp = ITOV(ip); - if (!vget(vp, 1)) - return (vp); - break; - } +loop: + simple_lock(&ufs_ihash_slock); + for (ip = INOHASH(dev, inum)->lh_first; ip; ip = ip->i_hash.le_next) { + if (inum == ip->i_number && dev == ip->i_dev) { + vp = ITOV(ip); + simple_lock(&vp->v_interlock); + simple_unlock(&ufs_ihash_slock); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) + goto loop; + return (vp); } - /* NOTREACHED */ + } + simple_unlock(&ufs_ihash_slock); + return (NULL); } /* @@ -125,26 +121,16 @@ void ufs_ihashins(ip) struct inode *ip; { - struct inode **ipp, *iq; + struct proc *p = curproc; /* XXX */ + struct ihashhead *ipp; - ipp = &ihashtbl[INOHASH(ip->i_dev, ip->i_number)]; - iq = *ipp; - if (iq) - iq->i_prev = &ip->i_next; - ip->i_next = iq; - ip->i_prev = ipp; - *ipp = ip; - if ((ip->i_flag & IN_LOCKED) && - ((ip->i_flag & IN_RECURSE) == 0 || - (!curproc || (curproc && (ip->i_lockholder != curproc->p_pid))))) - panic("ufs_ihashins: already locked"); - if (curproc) { - ip->i_lockcount += 1; - ip->i_lockholder = curproc->p_pid; - } else { - ip->i_lockholder = -1; - } - ip->i_flag |= IN_LOCKED; + /* lock the inode, then put it on the appropriate hash list */ + lockmgr(&ip->i_lock, LK_EXCLUSIVE, (struct simplelock *)0, p); + + simple_lock(&ufs_ihash_slock); + ipp = INOHASH(ip->i_dev, ip->i_number); + LIST_INSERT_HEAD(ipp, ip, i_hash); + simple_unlock(&ufs_ihash_slock); } /* @@ -152,16 +138,13 @@ ufs_ihashins(ip) */ void ufs_ihashrem(ip) - register struct inode *ip; + struct inode *ip; { - register struct inode *iq; - - iq = ip->i_next; - if (iq) - iq->i_prev = ip->i_prev; - *ip->i_prev = iq; + simple_lock(&ufs_ihash_slock); + LIST_REMOVE(ip, i_hash); #ifdef DIAGNOSTIC - ip->i_next = NULL; - ip->i_prev = NULL; + ip->i_hash.le_next = NULL; + ip->i_hash.le_prev = NULL; #endif + simple_unlock(&ufs_ihash_slock); } diff --git a/sys/gnu/ext2fs/ext2_inode.c b/sys/gnu/ext2fs/ext2_inode.c index d3b7038..788f5eb 100644 --- a/sys/gnu/ext2fs/ext2_inode.c +++ b/sys/gnu/ext2fs/ext2_inode.c @@ -77,9 +77,9 @@ static int ext2_indirtrunc __P((struct inode *, daddr_t, daddr_t, daddr_t, int, long *)); int -ext2_init() +ext2_init(struct vfsconf *vfsp) { - return (ufs_init()); + return (ufs_init(vfsp)); } /* @@ -118,16 +118,16 @@ ext2_update(ap) (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) return (0); if (ip->i_flag & IN_ACCESS) - ip->i_atime.tv_sec = ap->a_access->tv_sec; + ip->i_atime = ap->a_access->tv_sec; if (ip->i_flag & IN_UPDATE) { - ip->i_mtime.tv_sec = ap->a_modify->tv_sec; + ip->i_mtime = ap->a_modify->tv_sec; ip->i_modrev++; } if (ip->i_flag & IN_CHANGE) { #if !defined(__FreeBSD__) get_time(&time); #endif - ip->i_ctime.tv_sec = time.tv_sec; + ip->i_ctime = time.tv_sec; } ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); fs = ip->i_e2fs; diff --git a/sys/gnu/ext2fs/ext2_inode_cnv.c b/sys/gnu/ext2fs/ext2_inode_cnv.c index fbc743b..a39e7b9 100644 --- a/sys/gnu/ext2fs/ext2_inode_cnv.c +++ b/sys/gnu/ext2fs/ext2_inode_cnv.c @@ -66,17 +66,17 @@ ext2_print_dinode( di ) di->di_uid, di->di_gid, di->di_size); printf( "Links: %3d Blockcount: %d\n", di->di_nlink, di->di_blocks); - printf( "ctime: 0x%x", di->di_ctime.tv_sec); + printf( "ctime: 0x%x", di->di_ctime); #if !defined(__FreeBSD__) - print_time(" -- %s\n", di->di_ctime.tv_sec); + print_time(" -- %s\n", di->di_ctime); #endif - printf( "atime: 0x%x", di->di_atime.tv_sec); + printf( "atime: 0x%x", di->di_atime); #if !defined(__FreeBSD__) - print_time(" -- %s\n", di->di_atime.tv_sec); + print_time(" -- %s\n", di->di_atime); #endif - printf( "mtime: 0x%x", di->di_mtime.tv_sec); + printf( "mtime: 0x%x", di->di_mtime); #if !defined(__FreeBSD__) - print_time(" -- %s\n", di->di_mtime.tv_sec); + print_time(" -- %s\n", di->di_mtime); #endif printf( "BLOCKS: "); for(i=0; i < (di->di_blocks <= 24 ? ((di->di_blocks+1)/2): 12); i++) @@ -110,9 +110,9 @@ ext2_ei2di(ei, di) */ di->di_mode = ei->i_links_count ? ei->i_mode : 0; di->di_size = ei->i_size; - di->di_atime.tv_sec = ei->i_atime; - di->di_mtime.tv_sec = ei->i_mtime; - di->di_ctime.tv_sec = ei->i_ctime; + di->di_atime = ei->i_atime; + di->di_mtime = ei->i_mtime; + di->di_ctime = ei->i_ctime; di->di_flags = 0; di->di_flags |= (ei->i_flags & EXT2_APPEND_FL) ? APPEND : 0; di->di_flags |= (ei->i_flags & EXT2_IMMUTABLE_FL) ? IMMUTABLE : 0; @@ -143,11 +143,11 @@ ext2_di2ei(di, ei) Godmar thinks: if dtime is nonzero, ext2 says this inode has been deleted, this would correspond to a zero link count */ - ei->i_dtime = ei->i_links_count ? 0 : di->di_mtime.tv_sec; + ei->i_dtime = ei->i_links_count ? 0 : di->di_mtime; ei->i_size = di->di_size; - ei->i_atime = di->di_atime.tv_sec; - ei->i_mtime = di->di_mtime.tv_sec; - ei->i_ctime = di->di_ctime.tv_sec; + ei->i_atime = di->di_atime; + ei->i_mtime = di->di_mtime; + ei->i_ctime = di->di_ctime; ei->i_flags = di->di_flags; ei->i_flags = 0; ei->i_flags |= (di->di_flags & APPEND) ? EXT2_APPEND_FL: 0; diff --git a/sys/gnu/ext2fs/ext2_lookup.c b/sys/gnu/ext2fs/ext2_lookup.c index baeaa52..eabd40e 100644 --- a/sys/gnu/ext2fs/ext2_lookup.c +++ b/sys/gnu/ext2fs/ext2_lookup.c @@ -274,6 +274,7 @@ ext2_lookup(ap) struct ucred *cred = cnp->cn_cred; int flags = cnp->cn_flags; int nameiop = cnp->cn_nameiop; + struct proc *p = cnp->cn_proc; int DIRBLKSIZ = VTOI(ap->a_dvp)->i_e2fs->s_blocksize; @@ -318,14 +319,14 @@ ext2_lookup(ap) VREF(vdp); error = 0; } else if (flags & ISDOTDOT) { - VOP_UNLOCK(pdp); - error = vget(vdp, 1); + VOP_UNLOCK(pdp, 0, p); + error = vget(vdp, LK_EXCLUSIVE, p); if (!error && lockparent && (flags & ISLASTCN)) - error = VOP_LOCK(pdp); + error = vn_lock(pdp, LK_EXCLUSIVE, p); } else { - error = vget(vdp, 1); + error = vget(vdp, LK_EXCLUSIVE, p); if (!lockparent || error || !(flags & ISLASTCN)) - VOP_UNLOCK(pdp); + VOP_UNLOCK(pdp, 0, p); } /* * Check that the capability number did not change @@ -336,9 +337,9 @@ ext2_lookup(ap) return (0); vput(vdp); if (lockparent && pdp != vdp && (flags & ISLASTCN)) - VOP_UNLOCK(pdp); + VOP_UNLOCK(pdp, 0, p); } - if (error = VOP_LOCK(pdp)) + if (error = vn_lock(pdp, LK_EXCLUSIVE, p)) return (error); vdp = pdp; dp = VTOI(pdp); @@ -548,7 +549,7 @@ searchloop: */ cnp->cn_flags |= SAVENAME; if (!lockparent) - VOP_UNLOCK(vdp); + VOP_UNLOCK(vdp, 0, p); return (EJUSTRETURN); } /* @@ -625,7 +626,7 @@ found: } *vpp = tdp; if (!lockparent) - VOP_UNLOCK(vdp); + VOP_UNLOCK(vdp, 0, p); return (0); } @@ -650,7 +651,7 @@ found: *vpp = tdp; cnp->cn_flags |= SAVENAME; if (!lockparent) - VOP_UNLOCK(vdp); + VOP_UNLOCK(vdp, 0, p); return (0); } @@ -675,13 +676,13 @@ found: */ pdp = vdp; if (flags & ISDOTDOT) { - VOP_UNLOCK(pdp); /* race to get the inode */ + VOP_UNLOCK(pdp, 0, p); /* race to get the inode */ if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) { - VOP_LOCK(pdp); + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p); return (error); } if (lockparent && (flags & ISLASTCN) && - (error = VOP_LOCK(pdp))) { + (error = vn_lock(pdp, LK_EXCLUSIVE, p))) { vput(tdp); return (error); } @@ -693,7 +694,7 @@ found: if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) return (error); if (!lockparent || !(flags & ISLASTCN)) - VOP_UNLOCK(pdp); + VOP_UNLOCK(pdp, 0, p); *vpp = tdp; } diff --git a/sys/gnu/ext2fs/ext2_mount.h b/sys/gnu/ext2fs/ext2_mount.h index d7b7b28..87041a6 100644 --- a/sys/gnu/ext2fs/ext2_mount.h +++ b/sys/gnu/ext2fs/ext2_mount.h @@ -30,13 +30,34 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ufsmount.h 8.2 (Berkeley) 1/12/94 + * @(#)ufsmount.h 8.6 (Berkeley) 3/30/95 * $FreeBSD$ */ #ifndef _UFS_UFS_UFSMOUNT_H_ #define _UFS_UFS_UFSMOUNT_H_ +/* + * Arguments to mount UFS-based filesystems + */ +struct ufs_args { + char *fspec; /* block special device to mount */ + struct export_args export; /* network export information */ +}; + +#ifdef MFS +/* + * Arguments to mount MFS + */ +struct mfs_args { + char *fspec; /* name to export for statfs */ + struct export_args export; /* if exported MFSes are supported */ + caddr_t base; /* base of file system in memory */ + u_long size; /* size of file system */ +}; +#endif /* MFS */ + +#ifdef KERNEL struct buf; struct inode; struct nameidata; @@ -51,6 +72,7 @@ struct ufsmount { struct mount *um_mountp; /* filesystem vfs structure */ dev_t um_dev; /* device mounted */ struct vnode *um_devvp; /* block device mounted vnode */ + union { /* pointer to superblock */ struct lfs *lfs; /* LFS */ struct fs *fs; /* FFS */ @@ -60,6 +82,7 @@ struct ufsmount { #define um_lfs ufsmount_u.lfs #define um_e2fs ufsmount_u.e2fs #define um_e2fsb ufsmount_u.e2fs->s_es + struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */ struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */ u_long um_nindir; /* indirect ptrs per block */ @@ -69,7 +92,9 @@ struct ufsmount { time_t um_itime[MAXQUOTAS]; /* inode quota time limit */ char um_qflags[MAXQUOTAS]; /* quota specific flags */ struct netexport um_export; /* export information */ + int64_t um_savedmaxfilesize; /* XXX - limit maxfilesize */ }; + /* * Flags describing the state of quotas. */ @@ -83,8 +108,9 @@ struct ufsmount { * Macros to access file system parameters in the ufsmount structure. * Used by ufs_bmap. */ -#define blkptrtodb(ump, b) ((b) << (ump)->um_bptrtodb) -#define is_sequential(ump, a, b) ((b) == (a) + ump->um_seqinc) -#define MNINDIR(ump) ((ump)->um_nindir) +#define MNINDIR(ump) ((ump)->um_nindir) +#define blkptrtodb(ump, b) ((b) << (ump)->um_bptrtodb) +#define is_sequential(ump, a, b) ((b) == (a) + ump->um_seqinc) +#endif /* KERNEL */ #endif diff --git a/sys/gnu/ext2fs/ext2_vfsops.c b/sys/gnu/ext2fs/ext2_vfsops.c index d7c3e03..f01c059 100644 --- a/sys/gnu/ext2fs/ext2_vfsops.c +++ b/sys/gnu/ext2fs/ext2_vfsops.c @@ -221,10 +221,10 @@ ext2_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 = ext2_flushfiles(mp, flags, p); - vfs_unbusy(mp); + vfs_unbusy(mp, p); } if (!error && (mp->mnt_flag & MNT_RELOAD)) error = ext2_reload(mp, ndp->ni_cnd.cn_cred, p); @@ -515,7 +515,7 @@ loop: /* * Step 5: invalidate all cached file data. */ - if (vget(vp, 1)) + if (vget(vp, LK_EXCLUSIVE, p)) goto loop; if (vinvalbuf(vp, 0, cred, p, 0, 0)) panic("ext2_reload: dirty2"); @@ -727,17 +727,12 @@ ext2_flushfiles(mp, flags, p) int flags; struct proc *p; { -#if !defined(__FreeBSD__) - extern int doforce; -#endif register struct ufsmount *ump; int error; #if QUOTA int i; #endif - if (!doforce) - flags &= ~FORCECLOSE; ump = VFSTOUFS(mp); #if QUOTA if (mp->mnt_flag & MNT_QUOTA) { @@ -872,7 +867,7 @@ loop: (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && vp->v_dirtyblkhd.lh_first == NULL) continue; - if (vget(vp, 1)) + if (vget(vp, LK_EXCLUSIVE, p)) goto loop; if (error = VOP_FSYNC(vp, cred, waitfor, p)) allerror = error; diff --git a/sys/gnu/ext2fs/fs.h b/sys/gnu/ext2fs/fs.h index 28071d4..03f137c 100644 --- a/sys/gnu/ext2fs/fs.h +++ b/sys/gnu/ext2fs/fs.h @@ -152,6 +152,6 @@ extern u_char *fragtbl[]; * I think I'll try a VOP_LOCK/VOP_UNLOCK on the device vnode */ #define DEVVP(inode) (VFSTOUFS(ITOV(inode)->v_mount)->um_devvp) -#define lock_super(devvp) VOP_LOCK(devvp) -#define unlock_super(devvp) VOP_UNLOCK(devvp) +#define lock_super(devvp) vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, curproc) +#define unlock_super(devvp) VOP_UNLOCK(devvp, 0, curproc) diff --git a/sys/gnu/ext2fs/inode.h b/sys/gnu/ext2fs/inode.h index dc19d34..438471f 100644 --- a/sys/gnu/ext2fs/inode.h +++ b/sys/gnu/ext2fs/inode.h @@ -35,42 +35,33 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)inode.h 8.4 (Berkeley) 1/21/94 + * @(#)inode.h 8.9 (Berkeley) 5/14/95 * $FreeBSD$ */ #ifndef _UFS_UFS_INODE_H_ #define _UFS_UFS_INODE_H_ +#include <ufs/ufs/dir.h> #include <ufs/ufs/dinode.h> /* - * Theoretically, directories can be more than 2Gb in length, however, in - * practice this seems unlikely. So, we define the type doff_t as a long - * to keep down the cost of doing lookup on a 32-bit machine. If you are - * porting to a 64-bit architecture, you should make doff_t the same as off_t. - */ -#define doff_t long - -/* - * The inode is used to describe each active (or recently active) - * file in the UFS filesystem. It is composed of two types of - * information. The first part is the information that is needed - * only while the file is active (such as the identity of the file - * and linkage to speed its lookup). The second part is the - * permanent meta-data associated with the file which is read - * in from the permanent dinode from long term storage when the - * file becomes active, and is put back when the file is no longer - * being used. + * The inode is used to describe each active (or recently active) file in the + * UFS filesystem. It is composed of two types of information. The first part + * is the information that is needed only while the file is active (such as + * the identity of the file and linkage to speed its lookup). The second part + * is the permanent meta-data associated with the file which is read in + * from the permanent dinode from long term storage when the file becomes + * active, and is put back when the file is no longer being used. */ struct inode { - struct inode *i_next; /* Hash chain forward. */ - struct inode **i_prev; /* Hash chain back. */ - struct vnode *i_vnode; /* Vnode associated with this inode. */ - struct vnode *i_devvp; /* Vnode for block I/O. */ - u_long i_flag; /* I* flags. */ - dev_t i_dev; /* Device associated with the inode. */ - ino_t i_number; /* The identity of the inode. */ + LIST_ENTRY(inode) i_hash;/* Hash chain. */ + struct vnode *i_vnode;/* Vnode associated with this inode. */ + struct vnode *i_devvp;/* Vnode for block I/O. */ + u_int32_t i_flag; /* flags, see below */ + dev_t i_dev; /* Device associated with the inode. */ + ino_t i_number; /* The identity of the inode. */ + union { /* Associated filesystem. */ struct fs *fs; /* FFS */ struct lfs *lfs; /* LFS */ @@ -79,22 +70,21 @@ struct inode { #define i_fs inode_u.fs #define i_lfs inode_u.lfs #define i_e2fs inode_u.e2fs - struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ - u_quad_t i_modrev; /* Revision level for lease. */ - struct lockf *i_lockf; /* Head of byte-level lock list. */ - pid_t i_lockholder; /* DEBUG: holder of inode lock. */ - pid_t i_lockwaiter; /* DEBUG: latest blocked for inode lock. */ + struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ + u_quad_t i_modrev; /* Revision level for NFS lease. */ + struct lockf *i_lockf;/* Head of byte-level lock list. */ + struct lock i_lock; /* Inode lock. */ /* * Side effects; used during directory lookup. */ - long i_count; /* Size of free slot in directory. */ - doff_t i_endoff; /* End of useful stuff in directory. */ - 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. */ - u_long i_reclen; /* Size of found directory entry. */ - int i_lockcount; /* Process lock count (recursion) */ - long i_spare[10]; /* Spares to round up to 128 bytes. */ + int32_t i_count; /* Size of free slot in directory. */ + doff_t i_endoff; /* End of useful stuff in directory. */ + 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. */ + u_int32_t i_reclen; /* Size of found directory entry. */ + int i_lockcount; /* Process lock count (recursion) */ + int i_spare[10]; /* XXX spare storage (for ext2fs) */ /* * The on-disk dinode itself. */ @@ -102,8 +92,10 @@ struct inode { }; #define i_atime i_din.di_atime +#define i_atimensec i_din.di_atimensec #define i_blocks i_din.di_blocks #define i_ctime i_din.di_ctime +#define i_ctimensec i_din.di_ctimensec #define i_db i_din.di_db #define i_flags i_din.di_flags #define i_gen i_din.di_gen @@ -111,6 +103,7 @@ struct inode { #define i_ib i_din.di_ib #define i_mode i_din.di_mode #define i_mtime i_din.di_mtime +#define i_mtimensec i_din.di_mtimensec #define i_nlink i_din.di_nlink #define i_rdev i_din.di_rdev #define i_shortlink i_din.di_shortlink @@ -120,15 +113,12 @@ struct inode { /* These flags are kept in i_flag. */ #define IN_ACCESS 0x0001 /* Access time update request. */ #define IN_CHANGE 0x0002 /* Inode change time update request. */ -#define IN_EXLOCK 0x0004 /* File has exclusive lock. */ -#define IN_LOCKED 0x0008 /* Inode lock. */ -#define IN_LWAIT 0x0010 /* Process waiting on file lock. */ -#define IN_MODIFIED 0x0020 /* Inode has been modified. */ -#define IN_RENAME 0x0040 /* Inode is being renamed. */ -#define IN_SHLOCK 0x0080 /* File has shared lock. */ -#define IN_UPDATE 0x0100 /* Modification time update request. */ -#define IN_WANTED 0x0200 /* Inode is wanted by a process. */ -#define IN_RECURSE 0x0400 /* Recursion expected */ +#define IN_UPDATE 0x0004 /* Modification time update request. */ +#define IN_MODIFIED 0x0008 /* Inode has been modified. */ +#define IN_RENAME 0x0010 /* Inode is being renamed. */ +#define IN_SHLOCK 0x0020 /* File has shared lock. */ +#define IN_EXLOCK 0x0040 /* File has exclusive lock. */ +#define IN_RECURSE 0x0080 /* Recursion expected */ #ifdef KERNEL /* @@ -136,7 +126,7 @@ struct inode { * ufs_getlbns and used by truncate and bmap code. */ struct indir { - daddr_t in_lbn; /* Logical block number. */ + ufs_daddr_t in_lbn; /* Logical block number. */ int in_off; /* Offset in buffer. */ int in_exists; /* Flag if the block exists. */ }; @@ -155,25 +145,25 @@ struct indir { if ((ip)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) { \ (ip)->i_flag |= IN_MODIFIED; \ if ((ip)->i_flag & IN_ACCESS) \ - (ip)->i_atime.tv_sec \ + (ip)->i_atime \ = ((t1) == &time ? tv_sec : (t1)->tv_sec); \ if ((ip)->i_flag & IN_UPDATE) { \ - (ip)->i_mtime.tv_sec \ + (ip)->i_mtime \ = ((t2) == &time ? tv_sec : (t2)->tv_sec); \ (ip)->i_modrev++; \ } \ if ((ip)->i_flag & IN_CHANGE) \ - (ip)->i_ctime.tv_sec = tv_sec; \ + (ip)->i_ctime = tv_sec; \ (ip)->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); \ } \ } /* This overlays the fid structure (see mount.h). */ struct ufid { - u_short ufid_len; /* Length of structure. */ - u_short ufid_pad; /* Force long alignment. */ - ino_t ufid_ino; /* File number (ino). */ - long ufid_gen; /* Generation number. */ + u_int16_t ufid_len; /* Length of structure. */ + u_int16_t ufid_pad; /* Force 32-bit alignment. */ + ino_t ufid_ino; /* File number (ino). */ + int32_t ufid_gen; /* Generation number. */ }; #endif /* KERNEL */ diff --git a/sys/gnu/fs/ext2fs/ext2_bmap.c b/sys/gnu/fs/ext2fs/ext2_bmap.c index e17b5b7..aef2b83 100644 --- a/sys/gnu/fs/ext2fs/ext2_bmap.c +++ b/sys/gnu/fs/ext2fs/ext2_bmap.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ufs_bmap.c 8.6 (Berkeley) 1/21/94 + * @(#)ufs_bmap.c 8.7 (Berkeley) 3/21/95 * $FreeBSD$ */ @@ -63,9 +63,9 @@ int ufs_bmap(ap) struct vop_bmap_args /* { struct vnode *a_vp; - daddr_t a_bn; + ufs_daddr_t a_bn; struct vnode **a_vpp; - daddr_t *a_bnp; + ufs_daddr_t *a_bnp; int *a_runp; int *a_runb; } */ *ap; @@ -100,8 +100,8 @@ ufs_bmap(ap) int ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb) struct vnode *vp; - register daddr_t bn; - daddr_t *bnp; + ufs_daddr_t bn; + ufs_daddr_t *bnp; struct indir *ap; int *nump; int *runp; @@ -113,7 +113,7 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb) struct mount *mp; struct vnode *devvp; struct indir a[NIADDR+1], *xap; - daddr_t daddr; + ufs_daddr_t daddr; long metalbn; int error, maxrun = 0, num; @@ -209,12 +209,13 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb) } } - daddr = ((daddr_t *)bp->b_data)[xap->in_off]; + daddr = ((ufs_daddr_t *)bp->b_data)[xap->in_off]; if (num == 1 && daddr && runp) { for (bn = xap->in_off + 1; bn < MNINDIR(ump) && *runp < maxrun && - is_sequential(ump, ((daddr_t *)bp->b_data)[bn - 1], - ((daddr_t *)bp->b_data)[bn]); + is_sequential(ump, + ((ufs_daddr_t *)bp->b_data)[bn - 1], + ((ufs_daddr_t *)bp->b_data)[bn]); ++bn, ++*runp); bn = xap->in_off; if (runb && bn) { @@ -245,7 +246,7 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb) int ufs_getlbns(vp, bn, ap, nump) struct vnode *vp; - register daddr_t bn; + ufs_daddr_t bn; struct indir *ap; int *nump; { diff --git a/sys/gnu/fs/ext2fs/ext2_extern.h b/sys/gnu/fs/ext2fs/ext2_extern.h index f07b7b7..de6cd08f 100644 --- a/sys/gnu/fs/ext2fs/ext2_extern.h +++ b/sys/gnu/fs/ext2fs/ext2_extern.h @@ -56,7 +56,7 @@ int ext2_blkatoff __P((struct vop_blkatoff_args *)); void ext2_blkfree __P((struct inode *, daddr_t, long)); daddr_t ext2_blkpref __P((struct inode *, daddr_t, int, daddr_t *, daddr_t)); int ext2_bmap __P((struct vop_bmap_args *)); -int ext2_init __P((void)); +int ext2_init __P((struct vfsconf *)); int ext2_reallocblks __P((struct vop_reallocblks_args *)); int ext2_reclaim __P((struct vop_reclaim_args *)); void ext2_setblock __P((struct ext2_sb_info *, u_char *, daddr_t)); diff --git a/sys/gnu/fs/ext2fs/ext2_inode.c b/sys/gnu/fs/ext2fs/ext2_inode.c index d3b7038..788f5eb 100644 --- a/sys/gnu/fs/ext2fs/ext2_inode.c +++ b/sys/gnu/fs/ext2fs/ext2_inode.c @@ -77,9 +77,9 @@ static int ext2_indirtrunc __P((struct inode *, daddr_t, daddr_t, daddr_t, int, long *)); int -ext2_init() +ext2_init(struct vfsconf *vfsp) { - return (ufs_init()); + return (ufs_init(vfsp)); } /* @@ -118,16 +118,16 @@ ext2_update(ap) (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) return (0); if (ip->i_flag & IN_ACCESS) - ip->i_atime.tv_sec = ap->a_access->tv_sec; + ip->i_atime = ap->a_access->tv_sec; if (ip->i_flag & IN_UPDATE) { - ip->i_mtime.tv_sec = ap->a_modify->tv_sec; + ip->i_mtime = ap->a_modify->tv_sec; ip->i_modrev++; } if (ip->i_flag & IN_CHANGE) { #if !defined(__FreeBSD__) get_time(&time); #endif - ip->i_ctime.tv_sec = time.tv_sec; + ip->i_ctime = time.tv_sec; } ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); fs = ip->i_e2fs; diff --git a/sys/gnu/fs/ext2fs/ext2_inode_cnv.c b/sys/gnu/fs/ext2fs/ext2_inode_cnv.c index fbc743b..a39e7b9 100644 --- a/sys/gnu/fs/ext2fs/ext2_inode_cnv.c +++ b/sys/gnu/fs/ext2fs/ext2_inode_cnv.c @@ -66,17 +66,17 @@ ext2_print_dinode( di ) di->di_uid, di->di_gid, di->di_size); printf( "Links: %3d Blockcount: %d\n", di->di_nlink, di->di_blocks); - printf( "ctime: 0x%x", di->di_ctime.tv_sec); + printf( "ctime: 0x%x", di->di_ctime); #if !defined(__FreeBSD__) - print_time(" -- %s\n", di->di_ctime.tv_sec); + print_time(" -- %s\n", di->di_ctime); #endif - printf( "atime: 0x%x", di->di_atime.tv_sec); + printf( "atime: 0x%x", di->di_atime); #if !defined(__FreeBSD__) - print_time(" -- %s\n", di->di_atime.tv_sec); + print_time(" -- %s\n", di->di_atime); #endif - printf( "mtime: 0x%x", di->di_mtime.tv_sec); + printf( "mtime: 0x%x", di->di_mtime); #if !defined(__FreeBSD__) - print_time(" -- %s\n", di->di_mtime.tv_sec); + print_time(" -- %s\n", di->di_mtime); #endif printf( "BLOCKS: "); for(i=0; i < (di->di_blocks <= 24 ? ((di->di_blocks+1)/2): 12); i++) @@ -110,9 +110,9 @@ ext2_ei2di(ei, di) */ di->di_mode = ei->i_links_count ? ei->i_mode : 0; di->di_size = ei->i_size; - di->di_atime.tv_sec = ei->i_atime; - di->di_mtime.tv_sec = ei->i_mtime; - di->di_ctime.tv_sec = ei->i_ctime; + di->di_atime = ei->i_atime; + di->di_mtime = ei->i_mtime; + di->di_ctime = ei->i_ctime; di->di_flags = 0; di->di_flags |= (ei->i_flags & EXT2_APPEND_FL) ? APPEND : 0; di->di_flags |= (ei->i_flags & EXT2_IMMUTABLE_FL) ? IMMUTABLE : 0; @@ -143,11 +143,11 @@ ext2_di2ei(di, ei) Godmar thinks: if dtime is nonzero, ext2 says this inode has been deleted, this would correspond to a zero link count */ - ei->i_dtime = ei->i_links_count ? 0 : di->di_mtime.tv_sec; + ei->i_dtime = ei->i_links_count ? 0 : di->di_mtime; ei->i_size = di->di_size; - ei->i_atime = di->di_atime.tv_sec; - ei->i_mtime = di->di_mtime.tv_sec; - ei->i_ctime = di->di_ctime.tv_sec; + ei->i_atime = di->di_atime; + ei->i_mtime = di->di_mtime; + ei->i_ctime = di->di_ctime; ei->i_flags = di->di_flags; ei->i_flags = 0; ei->i_flags |= (di->di_flags & APPEND) ? EXT2_APPEND_FL: 0; diff --git a/sys/gnu/fs/ext2fs/ext2_lookup.c b/sys/gnu/fs/ext2fs/ext2_lookup.c index baeaa52..eabd40e 100644 --- a/sys/gnu/fs/ext2fs/ext2_lookup.c +++ b/sys/gnu/fs/ext2fs/ext2_lookup.c @@ -274,6 +274,7 @@ ext2_lookup(ap) struct ucred *cred = cnp->cn_cred; int flags = cnp->cn_flags; int nameiop = cnp->cn_nameiop; + struct proc *p = cnp->cn_proc; int DIRBLKSIZ = VTOI(ap->a_dvp)->i_e2fs->s_blocksize; @@ -318,14 +319,14 @@ ext2_lookup(ap) VREF(vdp); error = 0; } else if (flags & ISDOTDOT) { - VOP_UNLOCK(pdp); - error = vget(vdp, 1); + VOP_UNLOCK(pdp, 0, p); + error = vget(vdp, LK_EXCLUSIVE, p); if (!error && lockparent && (flags & ISLASTCN)) - error = VOP_LOCK(pdp); + error = vn_lock(pdp, LK_EXCLUSIVE, p); } else { - error = vget(vdp, 1); + error = vget(vdp, LK_EXCLUSIVE, p); if (!lockparent || error || !(flags & ISLASTCN)) - VOP_UNLOCK(pdp); + VOP_UNLOCK(pdp, 0, p); } /* * Check that the capability number did not change @@ -336,9 +337,9 @@ ext2_lookup(ap) return (0); vput(vdp); if (lockparent && pdp != vdp && (flags & ISLASTCN)) - VOP_UNLOCK(pdp); + VOP_UNLOCK(pdp, 0, p); } - if (error = VOP_LOCK(pdp)) + if (error = vn_lock(pdp, LK_EXCLUSIVE, p)) return (error); vdp = pdp; dp = VTOI(pdp); @@ -548,7 +549,7 @@ searchloop: */ cnp->cn_flags |= SAVENAME; if (!lockparent) - VOP_UNLOCK(vdp); + VOP_UNLOCK(vdp, 0, p); return (EJUSTRETURN); } /* @@ -625,7 +626,7 @@ found: } *vpp = tdp; if (!lockparent) - VOP_UNLOCK(vdp); + VOP_UNLOCK(vdp, 0, p); return (0); } @@ -650,7 +651,7 @@ found: *vpp = tdp; cnp->cn_flags |= SAVENAME; if (!lockparent) - VOP_UNLOCK(vdp); + VOP_UNLOCK(vdp, 0, p); return (0); } @@ -675,13 +676,13 @@ found: */ pdp = vdp; if (flags & ISDOTDOT) { - VOP_UNLOCK(pdp); /* race to get the inode */ + VOP_UNLOCK(pdp, 0, p); /* race to get the inode */ if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) { - VOP_LOCK(pdp); + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p); return (error); } if (lockparent && (flags & ISLASTCN) && - (error = VOP_LOCK(pdp))) { + (error = vn_lock(pdp, LK_EXCLUSIVE, p))) { vput(tdp); return (error); } @@ -693,7 +694,7 @@ found: if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) return (error); if (!lockparent || !(flags & ISLASTCN)) - VOP_UNLOCK(pdp); + VOP_UNLOCK(pdp, 0, p); *vpp = tdp; } diff --git a/sys/gnu/fs/ext2fs/ext2_mount.h b/sys/gnu/fs/ext2fs/ext2_mount.h index d7b7b28..87041a6 100644 --- a/sys/gnu/fs/ext2fs/ext2_mount.h +++ b/sys/gnu/fs/ext2fs/ext2_mount.h @@ -30,13 +30,34 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ufsmount.h 8.2 (Berkeley) 1/12/94 + * @(#)ufsmount.h 8.6 (Berkeley) 3/30/95 * $FreeBSD$ */ #ifndef _UFS_UFS_UFSMOUNT_H_ #define _UFS_UFS_UFSMOUNT_H_ +/* + * Arguments to mount UFS-based filesystems + */ +struct ufs_args { + char *fspec; /* block special device to mount */ + struct export_args export; /* network export information */ +}; + +#ifdef MFS +/* + * Arguments to mount MFS + */ +struct mfs_args { + char *fspec; /* name to export for statfs */ + struct export_args export; /* if exported MFSes are supported */ + caddr_t base; /* base of file system in memory */ + u_long size; /* size of file system */ +}; +#endif /* MFS */ + +#ifdef KERNEL struct buf; struct inode; struct nameidata; @@ -51,6 +72,7 @@ struct ufsmount { struct mount *um_mountp; /* filesystem vfs structure */ dev_t um_dev; /* device mounted */ struct vnode *um_devvp; /* block device mounted vnode */ + union { /* pointer to superblock */ struct lfs *lfs; /* LFS */ struct fs *fs; /* FFS */ @@ -60,6 +82,7 @@ struct ufsmount { #define um_lfs ufsmount_u.lfs #define um_e2fs ufsmount_u.e2fs #define um_e2fsb ufsmount_u.e2fs->s_es + struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */ struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */ u_long um_nindir; /* indirect ptrs per block */ @@ -69,7 +92,9 @@ struct ufsmount { time_t um_itime[MAXQUOTAS]; /* inode quota time limit */ char um_qflags[MAXQUOTAS]; /* quota specific flags */ struct netexport um_export; /* export information */ + int64_t um_savedmaxfilesize; /* XXX - limit maxfilesize */ }; + /* * Flags describing the state of quotas. */ @@ -83,8 +108,9 @@ struct ufsmount { * Macros to access file system parameters in the ufsmount structure. * Used by ufs_bmap. */ -#define blkptrtodb(ump, b) ((b) << (ump)->um_bptrtodb) -#define is_sequential(ump, a, b) ((b) == (a) + ump->um_seqinc) -#define MNINDIR(ump) ((ump)->um_nindir) +#define MNINDIR(ump) ((ump)->um_nindir) +#define blkptrtodb(ump, b) ((b) << (ump)->um_bptrtodb) +#define is_sequential(ump, a, b) ((b) == (a) + ump->um_seqinc) +#endif /* KERNEL */ #endif diff --git a/sys/gnu/fs/ext2fs/ext2_vfsops.c b/sys/gnu/fs/ext2fs/ext2_vfsops.c index d7c3e03..f01c059 100644 --- a/sys/gnu/fs/ext2fs/ext2_vfsops.c +++ b/sys/gnu/fs/ext2fs/ext2_vfsops.c @@ -221,10 +221,10 @@ ext2_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 = ext2_flushfiles(mp, flags, p); - vfs_unbusy(mp); + vfs_unbusy(mp, p); } if (!error && (mp->mnt_flag & MNT_RELOAD)) error = ext2_reload(mp, ndp->ni_cnd.cn_cred, p); @@ -515,7 +515,7 @@ loop: /* * Step 5: invalidate all cached file data. */ - if (vget(vp, 1)) + if (vget(vp, LK_EXCLUSIVE, p)) goto loop; if (vinvalbuf(vp, 0, cred, p, 0, 0)) panic("ext2_reload: dirty2"); @@ -727,17 +727,12 @@ ext2_flushfiles(mp, flags, p) int flags; struct proc *p; { -#if !defined(__FreeBSD__) - extern int doforce; -#endif register struct ufsmount *ump; int error; #if QUOTA int i; #endif - if (!doforce) - flags &= ~FORCECLOSE; ump = VFSTOUFS(mp); #if QUOTA if (mp->mnt_flag & MNT_QUOTA) { @@ -872,7 +867,7 @@ loop: (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && vp->v_dirtyblkhd.lh_first == NULL) continue; - if (vget(vp, 1)) + if (vget(vp, LK_EXCLUSIVE, p)) goto loop; if (error = VOP_FSYNC(vp, cred, waitfor, p)) allerror = error; diff --git a/sys/gnu/fs/ext2fs/fs.h b/sys/gnu/fs/ext2fs/fs.h index 28071d4..03f137c 100644 --- a/sys/gnu/fs/ext2fs/fs.h +++ b/sys/gnu/fs/ext2fs/fs.h @@ -152,6 +152,6 @@ extern u_char *fragtbl[]; * I think I'll try a VOP_LOCK/VOP_UNLOCK on the device vnode */ #define DEVVP(inode) (VFSTOUFS(ITOV(inode)->v_mount)->um_devvp) -#define lock_super(devvp) VOP_LOCK(devvp) -#define unlock_super(devvp) VOP_UNLOCK(devvp) +#define lock_super(devvp) vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, curproc) +#define unlock_super(devvp) VOP_UNLOCK(devvp, 0, curproc) diff --git a/sys/gnu/fs/ext2fs/inode.h b/sys/gnu/fs/ext2fs/inode.h index dc19d34..438471f 100644 --- a/sys/gnu/fs/ext2fs/inode.h +++ b/sys/gnu/fs/ext2fs/inode.h @@ -35,42 +35,33 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)inode.h 8.4 (Berkeley) 1/21/94 + * @(#)inode.h 8.9 (Berkeley) 5/14/95 * $FreeBSD$ */ #ifndef _UFS_UFS_INODE_H_ #define _UFS_UFS_INODE_H_ +#include <ufs/ufs/dir.h> #include <ufs/ufs/dinode.h> /* - * Theoretically, directories can be more than 2Gb in length, however, in - * practice this seems unlikely. So, we define the type doff_t as a long - * to keep down the cost of doing lookup on a 32-bit machine. If you are - * porting to a 64-bit architecture, you should make doff_t the same as off_t. - */ -#define doff_t long - -/* - * The inode is used to describe each active (or recently active) - * file in the UFS filesystem. It is composed of two types of - * information. The first part is the information that is needed - * only while the file is active (such as the identity of the file - * and linkage to speed its lookup). The second part is the - * permanent meta-data associated with the file which is read - * in from the permanent dinode from long term storage when the - * file becomes active, and is put back when the file is no longer - * being used. + * The inode is used to describe each active (or recently active) file in the + * UFS filesystem. It is composed of two types of information. The first part + * is the information that is needed only while the file is active (such as + * the identity of the file and linkage to speed its lookup). The second part + * is the permanent meta-data associated with the file which is read in + * from the permanent dinode from long term storage when the file becomes + * active, and is put back when the file is no longer being used. */ struct inode { - struct inode *i_next; /* Hash chain forward. */ - struct inode **i_prev; /* Hash chain back. */ - struct vnode *i_vnode; /* Vnode associated with this inode. */ - struct vnode *i_devvp; /* Vnode for block I/O. */ - u_long i_flag; /* I* flags. */ - dev_t i_dev; /* Device associated with the inode. */ - ino_t i_number; /* The identity of the inode. */ + LIST_ENTRY(inode) i_hash;/* Hash chain. */ + struct vnode *i_vnode;/* Vnode associated with this inode. */ + struct vnode *i_devvp;/* Vnode for block I/O. */ + u_int32_t i_flag; /* flags, see below */ + dev_t i_dev; /* Device associated with the inode. */ + ino_t i_number; /* The identity of the inode. */ + union { /* Associated filesystem. */ struct fs *fs; /* FFS */ struct lfs *lfs; /* LFS */ @@ -79,22 +70,21 @@ struct inode { #define i_fs inode_u.fs #define i_lfs inode_u.lfs #define i_e2fs inode_u.e2fs - struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ - u_quad_t i_modrev; /* Revision level for lease. */ - struct lockf *i_lockf; /* Head of byte-level lock list. */ - pid_t i_lockholder; /* DEBUG: holder of inode lock. */ - pid_t i_lockwaiter; /* DEBUG: latest blocked for inode lock. */ + struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ + u_quad_t i_modrev; /* Revision level for NFS lease. */ + struct lockf *i_lockf;/* Head of byte-level lock list. */ + struct lock i_lock; /* Inode lock. */ /* * Side effects; used during directory lookup. */ - long i_count; /* Size of free slot in directory. */ - doff_t i_endoff; /* End of useful stuff in directory. */ - 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. */ - u_long i_reclen; /* Size of found directory entry. */ - int i_lockcount; /* Process lock count (recursion) */ - long i_spare[10]; /* Spares to round up to 128 bytes. */ + int32_t i_count; /* Size of free slot in directory. */ + doff_t i_endoff; /* End of useful stuff in directory. */ + 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. */ + u_int32_t i_reclen; /* Size of found directory entry. */ + int i_lockcount; /* Process lock count (recursion) */ + int i_spare[10]; /* XXX spare storage (for ext2fs) */ /* * The on-disk dinode itself. */ @@ -102,8 +92,10 @@ struct inode { }; #define i_atime i_din.di_atime +#define i_atimensec i_din.di_atimensec #define i_blocks i_din.di_blocks #define i_ctime i_din.di_ctime +#define i_ctimensec i_din.di_ctimensec #define i_db i_din.di_db #define i_flags i_din.di_flags #define i_gen i_din.di_gen @@ -111,6 +103,7 @@ struct inode { #define i_ib i_din.di_ib #define i_mode i_din.di_mode #define i_mtime i_din.di_mtime +#define i_mtimensec i_din.di_mtimensec #define i_nlink i_din.di_nlink #define i_rdev i_din.di_rdev #define i_shortlink i_din.di_shortlink @@ -120,15 +113,12 @@ struct inode { /* These flags are kept in i_flag. */ #define IN_ACCESS 0x0001 /* Access time update request. */ #define IN_CHANGE 0x0002 /* Inode change time update request. */ -#define IN_EXLOCK 0x0004 /* File has exclusive lock. */ -#define IN_LOCKED 0x0008 /* Inode lock. */ -#define IN_LWAIT 0x0010 /* Process waiting on file lock. */ -#define IN_MODIFIED 0x0020 /* Inode has been modified. */ -#define IN_RENAME 0x0040 /* Inode is being renamed. */ -#define IN_SHLOCK 0x0080 /* File has shared lock. */ -#define IN_UPDATE 0x0100 /* Modification time update request. */ -#define IN_WANTED 0x0200 /* Inode is wanted by a process. */ -#define IN_RECURSE 0x0400 /* Recursion expected */ +#define IN_UPDATE 0x0004 /* Modification time update request. */ +#define IN_MODIFIED 0x0008 /* Inode has been modified. */ +#define IN_RENAME 0x0010 /* Inode is being renamed. */ +#define IN_SHLOCK 0x0020 /* File has shared lock. */ +#define IN_EXLOCK 0x0040 /* File has exclusive lock. */ +#define IN_RECURSE 0x0080 /* Recursion expected */ #ifdef KERNEL /* @@ -136,7 +126,7 @@ struct inode { * ufs_getlbns and used by truncate and bmap code. */ struct indir { - daddr_t in_lbn; /* Logical block number. */ + ufs_daddr_t in_lbn; /* Logical block number. */ int in_off; /* Offset in buffer. */ int in_exists; /* Flag if the block exists. */ }; @@ -155,25 +145,25 @@ struct indir { if ((ip)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) { \ (ip)->i_flag |= IN_MODIFIED; \ if ((ip)->i_flag & IN_ACCESS) \ - (ip)->i_atime.tv_sec \ + (ip)->i_atime \ = ((t1) == &time ? tv_sec : (t1)->tv_sec); \ if ((ip)->i_flag & IN_UPDATE) { \ - (ip)->i_mtime.tv_sec \ + (ip)->i_mtime \ = ((t2) == &time ? tv_sec : (t2)->tv_sec); \ (ip)->i_modrev++; \ } \ if ((ip)->i_flag & IN_CHANGE) \ - (ip)->i_ctime.tv_sec = tv_sec; \ + (ip)->i_ctime = tv_sec; \ (ip)->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); \ } \ } /* This overlays the fid structure (see mount.h). */ struct ufid { - u_short ufid_len; /* Length of structure. */ - u_short ufid_pad; /* Force long alignment. */ - ino_t ufid_ino; /* File number (ino). */ - long ufid_gen; /* Generation number. */ + u_int16_t ufid_len; /* Length of structure. */ + u_int16_t ufid_pad; /* Force 32-bit alignment. */ + ino_t ufid_ino; /* File number (ino). */ + int32_t ufid_gen; /* Generation number. */ }; #endif /* KERNEL */ diff --git a/sys/i386/i386/autoconf.c b/sys/i386/i386/autoconf.c index 866b420..6e305d0 100644 --- a/sys/i386/i386/autoconf.c +++ b/sys/i386/i386/autoconf.c @@ -53,6 +53,7 @@ #include <sys/reboot.h> #include <sys/kernel.h> #include <sys/mount.h> +#include <sys/vnode.h> #include <sys/sysctl.h> #include <machine/bootinfo.h> @@ -88,31 +89,15 @@ static void configure __P((void *)); SYSINIT(configure, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure, NULL) -#ifdef MFS_ROOT -extern struct vfsops mfs_vfsops; -#endif -#ifdef FFS -extern struct vfsops ufs_vfsops; -#endif -#ifdef LFS -extern struct vfsops lfs_vfsops; -#endif -#ifdef NFS -extern int nfs_mountroot __P((void *)); -#endif -#ifdef CD9660 -extern int cd9660_mountroot __P((void *)); -#endif -#ifdef MSDOSFS -extern int msdosfs_mountroot __P((void *)); -#endif - static void configure_finish __P((void)); static void configure_start __P((void)); static int setdumpdev __P((dev_t dev)); static void setroot __P((void)); #ifdef CD9660 + +#include <isofs/cd9660/iso.h> + /* We need to try out all our potential CDROM drives, so we need a table. */ static struct { char *name; @@ -138,7 +123,7 @@ find_cdrom_root(dummy) rootdev = makedev(try_cdrom[k].major,j*8); printf("trying rootdev=0x%lx (%s%d)\n", rootdev, try_cdrom[k].name,j); - i = (*cd9660_mountroot)((void *)NULL); + i = (*cd9660_mountroot)(); if (!i) return i; } return EINVAL; @@ -176,6 +161,11 @@ configure(dummy) enable_intr(); INTREN(IRQ_SLAVE); +#if NCRD > 0 + /* Before isa_configure to avoid ISA drivers finding our cards */ + pccard_configure(); +#endif + #if NEISA > 0 eisa_configure(); #endif @@ -188,11 +178,6 @@ configure(dummy) isa_configure(); #endif -#if NCRD > 0 - /* After everyone else has a chance at grabbing resources */ - pccard_configure(); -#endif - if (setdumpdev(dumpdev) != 0) dumpdev = NODEV; @@ -235,19 +220,26 @@ configure(dummy) } #ifdef CD9660 - if ((boothowto & RB_CDROM) && !mountroot) { + if ((boothowto & RB_CDROM)) { if (bootverbose) printf("Considering CD-ROM root f/s.\n"); - mountroot = find_cdrom_root; + mountrootfsname = "cd9660"; } #endif +#ifdef NFS + if (!mountrootfsname && nfs_diskless_valid) { + if (bootverbose) + printf("Considering NFS root f/s.\n"); + mountrootfsname = "nfs"; + } +#endif /* NFS */ + #ifdef MFS_ROOT - if (!mountroot) { + if (!mountrootfsname) { if (bootverbose) printf("Considering MFS root f/s.\n"); - mountroot = vfs_mountroot; /* XXX goes away*/ - mountrootvfsops = &mfs_vfsops; + mountrootfsname = "mfs"; /* * Ignore the -a flag if this kernel isn't compiled * with a generic root/swap configuration: if we skip @@ -260,21 +252,11 @@ configure(dummy) setroot(); } #endif - -#ifdef NFS - if (!mountroot && nfs_diskless_valid) { - if (bootverbose) - printf("Considering NFS root f/s.\n"); - mountroot = nfs_mountroot; - } -#endif /* NFS */ - #ifdef FFS - if (!mountroot) { + if (!mountrootfsname) { + mountrootfsname = "ufs"; if (bootverbose) printf("Considering FFS root f/s.\n"); - mountroot = vfs_mountroot; /* XXX goes away*/ - mountrootvfsops = &ufs_vfsops; /* * Ignore the -a flag if this kernel isn't compiled * with a generic root/swap configuration: if we skip @@ -288,11 +270,10 @@ configure(dummy) } #endif #ifdef LFS - if (!mountroot) { + if (!mountrootfsname) { if (bootverbose) printf("Considering LFS root f/s.\n"); - mountroot = vfs_mountroot; /* XXX goes away*/ - mountrootvfsops = &lfs_vfsops; + mountrootfsname = "lfs"; /* * Ignore the -a flag if this kernel isn't compiled * with a generic root/swap configuration: if we skip @@ -305,8 +286,7 @@ configure(dummy) setroot(); } #endif - - if (!mountroot) { + if (!mountrootfsname) { panic("Nobody wants to mount my root for me"); } @@ -417,4 +397,4 @@ sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS } SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW, - 0, sizeof dumpdev, sysctl_kern_dumpdev, "T,dev_t", ""); + 0, sizeof dumpdev, sysctl_kern_dumpdev, "I", ""); diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c index 386e093..93078a8 100644 --- a/sys/i386/i386/db_trace.c +++ b/sys/i386/i386/db_trace.c @@ -34,7 +34,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_prot.h> #include <vm/pmap.h> #include <ddb/ddb.h> diff --git a/sys/i386/i386/genassym.c b/sys/i386/i386/genassym.c index 9a2f646e..c993129 100644 --- a/sys/i386/i386/genassym.c +++ b/sys/i386/i386/genassym.c @@ -61,13 +61,15 @@ #include <sys/vmmeter.h> #include <vm/vm.h> #include <vm/vm_param.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <sys/user.h> #include <net/if.h> #include <netinet/in.h> #include <nfs/nfsv2.h> +#include <nfs/rpcv2.h> +#include <nfs/nfs.h> #include <nfs/nfsdiskless.h> extern int main __P((void)); diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index 6ebccff..b95b0ff 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -82,7 +82,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_kern.h> #include <vm/vm_object.h> #include <vm/vm_page.h> diff --git a/sys/i386/i386/math_emulate.c b/sys/i386/i386/math_emulate.c index 8bfa140..7a773a8 100644 --- a/sys/i386/i386/math_emulate.c +++ b/sys/i386/i386/math_emulate.c @@ -56,7 +56,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <sys/user.h> diff --git a/sys/i386/i386/mem.c b/sys/i386/i386/mem.c index 28d8058..5275e7d 100644 --- a/sys/i386/i386/mem.c +++ b/sys/i386/i386/mem.c @@ -68,7 +68,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_prot.h> #include <vm/pmap.h> #include <vm/vm_extern.h> diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index 3c47ee4..0159c32 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -85,7 +85,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_kern.h> #include <vm/vm_page.h> #include <vm/vm_map.h> diff --git a/sys/i386/i386/procfs_machdep.c b/sys/i386/i386/procfs_machdep.c index 9e1dbff..78eb796 100644 --- a/sys/i386/i386/procfs_machdep.c +++ b/sys/i386/i386/procfs_machdep.c @@ -80,7 +80,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c index d1b9807..8506cfc 100644 --- a/sys/i386/i386/sys_machdep.c +++ b/sys/i386/i386/sys_machdep.c @@ -44,7 +44,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_extern.h> diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index b38e35d..c866f32 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -61,7 +61,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_kern.h> #include <vm/vm_map.h> diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c index d320dac..f6c1606 100644 --- a/sys/i386/i386/vm_machdep.c +++ b/sys/i386/i386/vm_machdep.c @@ -58,7 +58,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_kern.h> #include <vm/vm_page.h> #include <vm/vm_map.h> diff --git a/sys/i386/ibcs2/ibcs2_misc.c b/sys/i386/ibcs2/ibcs2_misc.c index 693182f..7b7c172 100644 --- a/sys/i386/ibcs2/ibcs2_misc.c +++ b/sys/i386/ibcs2/ibcs2_misc.c @@ -354,7 +354,7 @@ ibcs2_getdents(p, uap, retval) buflen = max(DIRBLKSIZ, SCARG(uap, nbytes) + blockoff); buflen = min(buflen, MAXBSIZE); buf = malloc(buflen, M_TEMP, M_WAITOK); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); again: aiov.iov_base = buf; aiov.iov_len = buflen; @@ -420,7 +420,7 @@ again: eof: *retval = SCARG(uap, nbytes) - resid; out: - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, p); free(buf, M_TEMP); return (error); } @@ -465,7 +465,7 @@ ibcs2_read(p, uap, retval) buflen = max(DIRBLKSIZ, SCARG(uap, nbytes) + blockoff); buflen = min(buflen, MAXBSIZE); buf = malloc(buflen, M_TEMP, M_WAITOK); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); again: aiov.iov_base = buf; aiov.iov_len = buflen; @@ -535,7 +535,7 @@ again: eof: *retval = SCARG(uap, nbytes) - resid; out: - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, p); free(buf, M_TEMP); return (error); } diff --git a/sys/i386/ibcs2/imgact_coff.c b/sys/i386/ibcs2/imgact_coff.c index d140406..bd1adc3 100644 --- a/sys/i386/ibcs2/imgact_coff.c +++ b/sys/i386/ibcs2/imgact_coff.c @@ -214,7 +214,7 @@ coff_load_file(struct proc *p, char *name) * Lose the lock on the vnode. It's no longer needed, and must not * exist for the pagefault paging to work below. */ - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, p); if (error = vm_mmap(kernel_map, (vm_offset_t *) &ptr, diff --git a/sys/i386/include/param.h b/sys/i386/include/param.h index b560351..01d8615 100644 --- a/sys/i386/include/param.h +++ b/sys/i386/include/param.h @@ -45,6 +45,7 @@ */ #define MACHINE "i386" +#define NCPUS 1 #define MID_MACHINE MID_I386 /* @@ -125,4 +126,63 @@ #define i386_btop(x) ((unsigned)(x) >> PAGE_SHIFT) #define i386_ptob(x) ((unsigned)(x) << PAGE_SHIFT) +#ifndef _SIMPLELOCK_H_ +#define _SIMPLELOCK_H_ +/* + * A simple spin lock. + * + * This structure only sets one bit of data, but is sized based on the + * minimum word size that can be operated on by the hardware test-and-set + * instruction. It is only needed for multiprocessors, as uniprocessors + * will always run to completion or a sleep. It is an error to hold one + * of these locks while a process is sleeping. + */ +struct simplelock { + int lock_data; +}; + +#if !defined(SIMPLELOCK_DEBUG) && NCPUS > 1 +/* + * The simple-lock routines are the primitives out of which the lock + * package is built. The machine-dependent code must implement an + * atomic test_and_set operation that indivisibly sets the simple lock + * to non-zero and returns its old value. It also assumes that the + * setting of the lock to zero below is indivisible. Simple locks may + * only be used for exclusive locks. + */ +static __inline void +simple_lock_init(lkp) + struct simplelock *lkp; +{ + + lkp->lock_data = 0; +} + +static __inline void +simple_lock(lkp) + __volatile struct simplelock *lkp; +{ + + while (test_and_set(&lkp->lock_data)) + continue; +} + +static __inline int +simple_lock_try(lkp) + __volatile struct simplelock *lkp; +{ + + return (!test_and_set(&lkp->lock_data)) +} + +static __inline void +simple_unlock(lkp) + __volatile struct simplelock *lkp; +{ + + lkp->lock_data = 0; +} +#endif /* NCPUS > 1 */ +#endif /* !_SIMPLELOCK_H_ */ + #endif /* !_MACHINE_PARAM_H_ */ diff --git a/sys/i386/include/types.h b/sys/i386/include/types.h index 040501f..3eee8a7 100644 --- a/sys/i386/include/types.h +++ b/sys/i386/include/types.h @@ -67,4 +67,6 @@ typedef unsigned long long u_int64_t; typedef int32_t register_t; +typedef int32_t ufs_daddr_t; + #endif /* !_MACHINE_TYPES_H_ */ diff --git a/sys/i386/isa/fd.c b/sys/i386/isa/fd.c index 9c095c9..c2d495d 100644 --- a/sys/i386/isa/fd.c +++ b/sys/i386/isa/fd.c @@ -277,7 +277,7 @@ static d_strategy_t fdstrategy; static struct cdevsw fd_cdevsw; static struct bdevsw fd_bdevsw = { Fdopen, fdclose, fdstrategy, fdioctl, /*2*/ - nodump, nopsize, 0, "fd", &fd_cdevsw, -1 }; + nodump, nopsize, D_DISK, "fd", &fd_cdevsw, -1 }; static struct isa_device *fdcdevs[NFDC]; diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c index 7ec5989..6e5823a 100644 --- a/sys/i386/isa/wd.c +++ b/sys/i386/isa/wd.c @@ -236,7 +236,7 @@ static d_psize_t wdsize; static struct cdevsw wd_cdevsw; static struct bdevsw wd_bdevsw = { wdopen, wdclose, wdstrategy, wdioctl, /*0*/ - wddump, wdsize, 0, "wd", &wd_cdevsw, -1 }; + wddump, wdsize, D_DISK, "wd", &wd_cdevsw, -1 }; /* * Probe for controller. diff --git a/sys/i386/linux/linux_file.c b/sys/i386/linux/linux_file.c index 55c8a35..9fe4d40 100644 --- a/sys/i386/linux/linux_file.c +++ b/sys/i386/linux/linux_file.c @@ -450,7 +450,7 @@ linux_getdents(struct proc *p, struct linux_getdents_args *args, int *retval) buflen = max(DIRBLKSIZ, nbytes + blockoff); buflen = min(buflen, MAXBSIZE); buf = malloc(buflen, M_TEMP, M_WAITOK); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); again: aiov.iov_base = buf; aiov.iov_len = buflen; @@ -530,7 +530,7 @@ again: eof: *retval = nbytes - resid; out: - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, p); free(buf, M_TEMP); return error; } diff --git a/sys/i386/linux/linux_misc.c b/sys/i386/linux/linux_misc.c index 536d797..d0332cf 100644 --- a/sys/i386/linux/linux_misc.c +++ b/sys/i386/linux/linux_misc.c @@ -237,7 +237,7 @@ linux_uselib(struct proc *p, struct linux_uselib_args *args, int *retval) /* * Lock no longer needed */ - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, p); locked = 0; /* @@ -392,7 +392,7 @@ cleanup: * Unlock vnode if needed */ if (locked) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, p); /* * Release the kernel mapping. diff --git a/sys/isa/fd.c b/sys/isa/fd.c index 9c095c9..c2d495d 100644 --- a/sys/isa/fd.c +++ b/sys/isa/fd.c @@ -277,7 +277,7 @@ static d_strategy_t fdstrategy; static struct cdevsw fd_cdevsw; static struct bdevsw fd_bdevsw = { Fdopen, fdclose, fdstrategy, fdioctl, /*2*/ - nodump, nopsize, 0, "fd", &fd_cdevsw, -1 }; + nodump, nopsize, D_DISK, "fd", &fd_cdevsw, -1 }; static struct isa_device *fdcdevs[NFDC]; diff --git a/sys/isofs/cd9660/TODO b/sys/isofs/cd9660/TODO index eb24a23..71859c7 100644 --- a/sys/isofs/cd9660/TODO +++ b/sys/isofs/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/isofs/cd9660/cd9660_bmap.c b/sys/isofs/cd9660/cd9660_bmap.c index 6fffe7a..71dfb9e 100644 --- a/sys/isofs/cd9660/cd9660_bmap.c +++ b/sys/isofs/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/isofs/cd9660/cd9660_lookup.c b/sys/isofs/cd9660/cd9660_lookup.c index 6e85a81..a7e38bb 100644 --- a/sys/isofs/cd9660/cd9660_lookup.c +++ b/sys/isofs/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/isofs/cd9660/cd9660_node.c b/sys/isofs/cd9660/cd9660_node.c index c3f0911..c726696 100644 --- a/sys/isofs/cd9660/cd9660_node.c +++ b/sys/isofs/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 <isofs/cd9660/iso.h> #include <isofs/cd9660/cd9660_node.h> +#include <isofs/cd9660/cd9660_mount.h> #include <isofs/cd9660/iso_rrip.h> -#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/isofs/cd9660/cd9660_node.h b/sys/isofs/cd9660/cd9660_node.h index 992f9cb..de538fb 100644 --- a/sys/isofs/cd9660/cd9660_node.h +++ b/sys/isofs/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/isofs/cd9660/cd9660_rrip.c b/sys/isofs/cd9660/cd9660_rrip.c index 44d52eb..521094f 100644 --- a/sys/isofs/cd9660/cd9660_rrip.c +++ b/sys/isofs/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/isofs/cd9660/cd9660_rrip.h b/sys/isofs/cd9660/cd9660_rrip.h index e65fb3b..cacee39 100644 --- a/sys/isofs/cd9660/cd9660_rrip.h +++ b/sys/isofs/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/isofs/cd9660/cd9660_util.c b/sys/isofs/cd9660/cd9660_util.c index 786d4fd..151d1c3 100644 --- a/sys/isofs/cd9660/cd9660_util.c +++ b/sys/isofs/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 <isofs/cd9660/iso.h> -#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/isofs/cd9660/cd9660_vfsops.c b/sys/isofs/cd9660/cd9660_vfsops.c index 752a7b4..15eade4 100644 --- a/sys/isofs/cd9660/cd9660_vfsops.c +++ b/sys/isofs/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 <sys/ioctl.h> #include <sys/errno.h> #include <sys/malloc.h> +#include <sys/stat.h> #include <isofs/cd9660/iso.h> -#include <isofs/cd9660/cd9660_node.h> #include <isofs/cd9660/iso_rrip.h> +#include <isofs/cd9660/cd9660_node.h> +#include <isofs/cd9660/cd9660_mount.h> 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 <mp, client> 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/isofs/cd9660/cd9660_vnops.c b/sys/isofs/cd9660/cd9660_vnops.c index 88440eb..854d6b5 100644 --- a/sys/isofs/cd9660/cd9660_vnops.c +++ b/sys/isofs/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 <miscfs/fifofs/fifo.h> #include <sys/malloc.h> #include <sys/dir.h> +#include <sys/unistd.h> #include <isofs/cd9660/iso.h> #include <isofs/cd9660/cd9660_node.h> @@ -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/isofs/cd9660/iso.h b/sys/isofs/cd9660/iso.h index 1656c23..e2a7779 100644 --- a/sys/isofs/cd9660/iso.h +++ b/sys/isofs/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/kern/imgact_aout.c b/sys/kern/imgact_aout.c index 71311eb..0730253 100644 --- a/sys/kern/imgact_aout.c +++ b/sys/kern/imgact_aout.c @@ -43,7 +43,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_extern.h> diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index edc4c45..47caf98 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -55,7 +55,7 @@ #include <vm/vm_kern.h> #include <vm/vm_param.h> #include <vm/pmap.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_map.h> #include <vm/vm_prot.h> #include <vm/vm_extern.h> @@ -358,7 +358,7 @@ elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) /* * No longer need this, and it prevents demand paging. */ - VOP_UNLOCK(nd.ni_vp); + VOP_UNLOCK(nd.ni_vp, 0, p); if (error) goto fail; diff --git a/sys/kern/imgact_gzip.c b/sys/kern/imgact_gzip.c index 3156a86..9186749 100644 --- a/sys/kern/imgact_gzip.c +++ b/sys/kern/imgact_gzip.c @@ -39,7 +39,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_kern.h> diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 24c8ffb..589a4c5 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -66,7 +66,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <sys/user.h> @@ -468,16 +468,16 @@ sched_setup(dummy) SYSINIT(sched_setup, SI_SUB_KICK_SCHEDULER, SI_ORDER_FIRST, sched_setup, NULL) /* ARGSUSED*/ -static void xxx_vfs_mountroot __P((void *dummy)); +static void xxx_vfs_mountroot __P((void *fsnamep)); static void -xxx_vfs_mountroot(dummy) - void *dummy; +xxx_vfs_mountroot(fsnamep) + void *fsnamep; { /* Mount the root file system. */ - if ((*mountroot)(mountrootvfsops)) + if (vfs_mountrootfs(*((char **) fsnamep))) panic("cannot mount root"); } -SYSINIT(mountroot, SI_SUB_ROOT, SI_ORDER_FIRST, xxx_vfs_mountroot, NULL) +SYSINIT(mountroot, SI_SUB_ROOT, SI_ORDER_FIRST, xxx_vfs_mountroot, &mountrootfsname) /* ARGSUSED*/ static void xxx_vfs_root_fdtab __P((void *dummy)); @@ -492,7 +492,7 @@ xxx_vfs_root_fdtab(dummy) panic("cannot find root vnode"); fdp->fd_fd.fd_cdir = rootvnode; VREF(fdp->fd_fd.fd_cdir); - VOP_UNLOCK(rootvnode); + VOP_UNLOCK(rootvnode, 0, &proc0); fdp->fd_fd.fd_rdir = NULL; } SYSINIT(retrofit, SI_SUB_ROOT_FDTAB, SI_ORDER_FIRST, xxx_vfs_root_fdtab, NULL) diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 9f41c00..dc5978d 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -238,7 +238,7 @@ struct sysent sysent[] = { { 2, (sy_call_t *)mlock }, /* 203 = mlock */ { 2, (sy_call_t *)munlock }, /* 204 = munlock */ { 2, (sy_call_t *)utrace }, /* 205 = utrace */ - { 0, (sy_call_t *)nosys }, /* 206 = nosys */ + { 1, (sy_call_t *)undelete }, /* 206 = undelete */ { 0, (sy_call_t *)nosys }, /* 207 = nosys */ { 0, (sy_call_t *)nosys }, /* 208 = nosys */ { 0, (sy_call_t *)nosys }, /* 209 = nosys */ diff --git a/sys/kern/kern_acct.c b/sys/kern/kern_acct.c index 2704347..59d0d35 100644 --- a/sys/kern/kern_acct.c +++ b/sys/kern/kern_acct.c @@ -49,6 +49,7 @@ #include <sys/file.h> #include <sys/syslog.h> #include <sys/kernel.h> +#include <sys/sysent.h> #include <sys/sysctl.h> #include <sys/namei.h> #include <sys/errno.h> @@ -101,18 +102,15 @@ SYSCTL_INT(_kern, OID_AUTO, acct_chkfreq, CTLFLAG_RW, * Accounting system call. Written based on the specification and * previous implementation done by Mark Tinguely. */ -#ifndef _SYS_SYSPROTO_H_ -struct acct_args { - char *path; -}; - -#endif int -acct(p, uap, retval) - struct proc *p; - struct acct_args *uap; - int *retval; +acct(a1, uap, a3) + struct proc *a1; + struct acct_args /* { + syscallarg(char *) path; + } */ *uap; + int *a3; { + struct proc *p = curproc; /* XXX */ struct nameidata nd; int error; @@ -125,12 +123,13 @@ acct(p, uap, retval) * If accounting is to be started to a file, open that file for * writing and make sure it's a 'normal'. */ - if (uap->path != NULL) { - NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, p); + if (SCARG(uap, path) != NULL) { + NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), + p); error = vn_open(&nd, FWRITE, 0); if (error) return (error); - VOP_UNLOCK(nd.ni_vp); + VOP_UNLOCK(nd.ni_vp, 0, p); if (nd.ni_vp->v_type != VREG) { vn_close(nd.ni_vp, FWRITE, p->p_ucred, p); return (EACCES); @@ -147,7 +146,7 @@ acct(p, uap, retval) p->p_ucred, p); acctp = savacctp = NULLVP; } - if (uap->path == NULL) + if (SCARG(uap, path) == NULL) return (error); /* @@ -228,7 +227,7 @@ acct_process(p) /* * Now, just write the accounting information to the file. */ - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); return (vn_rdwr(UIO_WRITE, vp, (caddr_t)&acct, sizeof (acct), (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, p->p_ucred, (int *)0, p)); @@ -298,7 +297,9 @@ acctwatch(a) savacctp = NULLVP; log(LOG_NOTICE, "Accounting resumed\n"); } - } else if (acctp != NULLVP) { + } else { + if (acctp == NULLVP) + return; if (acctp->v_type == VBAD) { (void) vn_close(acctp, FWRITE, NOCRED, NULL); acctp = NULLVP; @@ -310,7 +311,6 @@ acctwatch(a) acctp = NULLVP; log(LOG_NOTICE, "Accounting suspended\n"); } - } else - return; + } timeout(acctwatch, NULL, acctchkfreq * hz); } diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index 6b958df..938e3df 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -70,7 +70,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <sys/sysctl.h> diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c index 62deb52..c6a9e14 100644 --- a/sys/kern/kern_conf.c +++ b/sys/kern/kern_conf.c @@ -192,6 +192,14 @@ void bdevsw_add_generic(int bdev, int cdev, struct bdevsw *bdevsw) { dev_t dev; + /* + * XXX hack alert. + */ + if (isdisk(makedev(bdev, 0), VBLK) && bdevsw->d_flags != D_DISK) { + printf("bdevsw_add_generic: adding D_DISK flag for device %d\n", + bdev); + bdevsw->d_flags = D_DISK; + } cdevsw_make(bdevsw); dev = makedev(cdev, 0); cdevsw_add(&dev, bdevsw->d_cdev, NULL); diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 1a27a34..2d4247c 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -51,7 +51,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_kern.h> @@ -162,7 +162,7 @@ interpret: * Lose the lock on the vnode. It's no longer needed, and must not * exist for the pagefault paging to work below. */ - VOP_UNLOCK(imgp->vp); + VOP_UNLOCK(imgp->vp, 0, p); if (error) goto exec_fail_dealloc; diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 82c1f8b..f65419f 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -1,4 +1,4 @@ -/*- +/* * Copyright (c) 1982, 1986, 1989, 1991, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. @@ -73,7 +73,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_kern.h> @@ -208,7 +208,7 @@ exit1(p, rv) * if we blocked. */ if (sp->s_ttyvp) - vgoneall(sp->s_ttyvp); + VOP_REVOKE(sp->s_ttyvp, REVOKEALL); } if (sp->s_ttyvp) vrele(sp->s_ttyvp); diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 572cb60..0de5272 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -56,7 +56,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_extern.h> diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index e9f4792..3ed8013 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -271,7 +271,7 @@ ktrace(curp, uap, retval) return (error); } vp = nd.ni_vp; - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, curp); if (vp->v_type != VREG) { (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp); curp->p_traceflag &= ~KTRFAC_ACTIVE; @@ -478,9 +478,9 @@ ktrwrite(vp, kth) aiov[1].iov_len = kth->ktr_len; auio.uio_resid += kth->ktr_len; } - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); if (!error) return; /* diff --git a/sys/kern/kern_lkm.c b/sys/kern/kern_lkm.c index c2dad16..33c5ef3 100644 --- a/sys/kern/kern_lkm.c +++ b/sys/kern/kern_lkm.c @@ -604,8 +604,11 @@ _lkm_vfs(lkmtp, cmd) { struct lkm_vfs *args = lkmtp->private.lkm_vfs; struct vfsconf *vfc = args->lkm_vfsconf; + struct vfsconf *vfsp, *lastvfsp, *prev_vfsp, *new_vfc; int i; int err = 0; + char fstypename[MFSNAMELEN]; + int neednamesearch = 1; switch(cmd) { case LKM_E_LOAD: @@ -613,26 +616,51 @@ _lkm_vfs(lkmtp, cmd) if (lkmexists(lkmtp)) return(EEXIST); - for(i = 0; i < MOUNT_MAXTYPE; i++) { - if(!strcmp(vfc->vfc_name, vfsconf[i]->vfc_name)) { - return EEXIST; - } - } - - i = args->lkm_offset = vfc->vfc_index; - if (i < 0) { - for (i = MOUNT_MAXTYPE - 1; i >= 0; i--) { - if(vfsconf[i] == &void_vfsconf) + /* check to see if filesystem already exists */ + vfsp = NULL; +#ifdef COMPAT_43 /* see vfs_syscalls.c:mount() */ + if (vfc->vfc_typenum < maxvfsconf) { + neednamesearch = 0; + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) + if (vfsp->vfc_typenum == vfc->vfc_typenum) break; + if (vfsp != NULL) { + neednamesearch = 1; + strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); + } + } else +#endif /* COMPAT_43 */ + if (neednamesearch) { + strncpy(fstypename, vfc->vfc_name, MFSNAMELEN); + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) { + if (!strcmp(vfsp->vfc_name, fstypename)) { + return EEXIST; + } } } + + i = args->lkm_offset = vfc->vfc_typenum; if (i < 0) { - return EINVAL; + i = maxvfsconf; } - args->lkm_offset = vfc->vfc_index = i; + args->lkm_offset = vfc->vfc_typenum = i; + + if (maxvfsconf <= vfsp->vfc_typenum) + maxvfsconf = vfsp->vfc_typenum + 1; + + /* find vfsconf tail */ + for (lastvfsp = vfsconf; lastvfsp->vfc_next; + lastvfsp = lastvfsp->vfc_next) ; - vfsconf[i] = vfc; - vfssw[i] = vfc->vfc_vfsops; + /* make copy */ +/* possible race condition if vfsconf changes while we wait XXX JH */ + MALLOC(new_vfc, struct vfsconf *, sizeof(struct vfsconf), + M_VFSCONF, M_WAITOK); + *new_vfc = *vfc; + vfc = new_vfc; + + lastvfsp->vfc_next = vfc; + vfc->vfc_next = NULL; /* like in vfs_op_init */ for(i = 0; args->lkm_vnodeops->ls_items[i]; i++) { @@ -645,7 +673,7 @@ _lkm_vfs(lkmtp, cmd) /* * Call init function for this VFS... */ - (*(vfssw[vfc->vfc_index]->vfs_init))(); + (*(vfsp->vfc_vfsops->vfs_init))(vfsp); /* done! */ break; @@ -654,13 +682,23 @@ _lkm_vfs(lkmtp, cmd) /* current slot... */ i = args->lkm_offset; - if (vfsconf[i]->vfc_refcount) { + prev_vfsp = NULL; + for (vfsp = vfsconf; vfsp; + prev_vfsp = vfsp, vfsp = vfsp->vfc_next) { + if (vfsp->vfc_typenum == vfc->vfc_typenum) + break; + } + if (vfsp == NULL) { + return EINVAL; + } + + if (vfsp->vfc_refcount) { return EBUSY; } - /* replace current slot contents with old contents */ - vfssw[i] = (struct vfsops *)0; - vfsconf[i] = &void_vfsconf; + FREE(vfsp, M_VFSCONF); + + prev_vfsp->vfc_next = vfsp->vfc_next; break; diff --git a/sys/kern/kern_lockf.c b/sys/kern/kern_lockf.c index aea3976..3491e63 100644 --- a/sys/kern/kern_lockf.c +++ b/sys/kern/kern_lockf.c @@ -52,16 +52,18 @@ * This variable controls the maximum number of processes that will * be checked in doing deadlock detection. */ -int maxlockdepth = MAXDEPTH; +static int maxlockdepth = MAXDEPTH; #ifdef LOCKF_DEBUG +#include <vm/vm.h> +#include <sys/sysctl.h> int lockf_debug = 0; +SYSCTL_INT(_debug, 4, lockf_debug, CTLFLAG_RW, &lockf_debug, 0, ""); #endif #define NOLOCKF (struct lockf *)0 #define SELF 0x1 #define OTHERS 0x2 -static void lf_addblock __P((struct lockf *, struct lockf *)); static int lf_clearlock __P((struct lockf *)); static int lf_findoverlap __P((struct lockf *, struct lockf *, int, struct lockf ***, struct lockf **)); @@ -138,10 +140,11 @@ lf_advlock(ap, head, size) lock->lf_start = start; lock->lf_end = end; lock->lf_id = ap->a_id; - lock->lf_head = head; +/* lock->lf_inode = ip; */ /* XXX JH */ lock->lf_type = fl->l_type; + lock->lf_head = head; lock->lf_next = (struct lockf *)0; - lock->lf_block = (struct lockf *)0; + TAILQ_INIT(&lock->lf_blkhd); lock->lf_flags = ap->a_flags; /* * Do the requested operation. @@ -252,7 +255,7 @@ lf_setlock(lock) * Remember who blocked us (for deadlock detection). */ lock->lf_next = block; - lf_addblock(block, lock); + TAILQ_INSERT_TAIL(&block->lf_blkhd, lock, lf_block); #ifdef LOCKF_DEBUG if (lockf_debug & 1) { lf_print("lf_setlock: blocking on", block); @@ -260,19 +263,19 @@ lf_setlock(lock) } #endif /* LOCKF_DEBUG */ if ((error = tsleep((caddr_t)lock, priority, lockstr, 0))) { - /* - * Delete ourselves from the waiting to lock list. - */ - for (block = lock->lf_next; - block != NOLOCKF; - block = block->lf_block) { - if (block->lf_block != lock) - continue; - block->lf_block = block->lf_block->lf_block; - break; - } - free(lock, M_LOCKF); - return (error); + /* + * We may have been awakened by a signal (in + * which case we must remove ourselves from the + * blocked list) and/or by another process + * releasing a lock (in which case we have already + * been removed from the blocked list and our + * lf_next field set to NOLOCKF). + */ + if (lock->lf_next) + TAILQ_REMOVE(&lock->lf_next->lf_blkhd, lock, + lf_block); + free(lock, M_LOCKF); + return (error); } } /* @@ -347,9 +350,12 @@ lf_setlock(lock) overlap->lf_type == F_WRLCK) { lf_wakelock(overlap); } else { - ltmp = lock->lf_block; - lock->lf_block = overlap->lf_block; - lf_addblock(lock, ltmp); + while (ltmp = overlap->lf_blkhd.tqh_first) { + TAILQ_REMOVE(&overlap->lf_blkhd, ltmp, + lf_block); + TAILQ_INSERT_TAIL(&lock->lf_blkhd, + ltmp, lf_block); + } } /* * Add the new lock if necessary and delete the overlap. @@ -645,34 +651,6 @@ lf_findoverlap(lf, lock, type, prev, overlap) } /* - * Add a lock to the end of the blocked list. - */ -static void -lf_addblock(blocklist, lock) - struct lockf *blocklist; - struct lockf *lock; -{ - register struct lockf *lf; - - if (lock == NOLOCKF) - return; -#ifdef LOCKF_DEBUG - if (lockf_debug & 2) { - lf_print("addblock: adding", lock); - lf_print("to blocked list of", blocklist); - } -#endif /* LOCKF_DEBUG */ - if ((lf = blocklist->lf_block) == NOLOCKF) { - blocklist->lf_block = lock; - return; - } - while (lf->lf_block != NOLOCKF) - lf = lf->lf_block; - lf->lf_block = lock; - return; -} - -/* * Split a lock and a contained region into * two or three locks as necessary. */ @@ -710,7 +688,7 @@ lf_split(lock1, lock2) MALLOC(splitlock, struct lockf *, sizeof *splitlock, M_LOCKF, M_WAITOK); bcopy((caddr_t)lock1, (caddr_t)splitlock, sizeof *splitlock); splitlock->lf_start = lock2->lf_end + 1; - splitlock->lf_block = NOLOCKF; + TAILQ_INIT(&splitlock->lf_blkhd); lock1->lf_end = lock2->lf_start - 1; /* * OK, now link it in @@ -727,28 +705,23 @@ static void lf_wakelock(listhead) struct lockf *listhead; { - register struct lockf *blocklist, *wakelock; - - blocklist = listhead->lf_block; - listhead->lf_block = NOLOCKF; - while (blocklist != NOLOCKF) { - wakelock = blocklist; - blocklist = blocklist->lf_block; - wakelock->lf_block = NOLOCKF; + register struct lockf *wakelock; + + while (wakelock = listhead->lf_blkhd.tqh_first) { + TAILQ_REMOVE(&listhead->lf_blkhd, wakelock, lf_block); wakelock->lf_next = NOLOCKF; #ifdef LOCKF_DEBUG if (lockf_debug & 2) lf_print("lf_wakelock: awakening", wakelock); #endif /* LOCKF_DEBUG */ - wakeup((caddr_t)wakelock); - } + wakeup((caddr_t)wakelock); + } } #ifdef LOCKF_DEBUG /* * Print out a lock. */ -void lf_print(tag, lock) char *tag; register struct lockf *lock; @@ -767,18 +740,17 @@ lf_print(tag, lock) lock->lf_type == F_WRLCK ? "exclusive" : lock->lf_type == F_UNLCK ? "unlock" : "unknown", lock->lf_start, lock->lf_end); - if (lock->lf_block) - printf(" block 0x%x\n", lock->lf_block); + if (lock->lf_blkhd.tqh_first) + printf(" block 0x%x\n", lock->lf_blkhd.tqh_first); else printf("\n"); } -void lf_printlist(tag, lock) char *tag; struct lockf *lock; { - register struct lockf *lf; + register struct lockf *lf, *blk; printf("%s: Lock list for ino %d on dev <%d, %d>:\n", tag, lock->lf_inode->i_number, @@ -795,10 +767,23 @@ lf_printlist(tag, lock) lf->lf_type == F_WRLCK ? "exclusive" : lf->lf_type == F_UNLCK ? "unlock" : "unknown", lf->lf_start, lf->lf_end); - if (lf->lf_block) - printf(" block 0x%x\n", lf->lf_block); - else - printf("\n"); + for (blk = lf->lf_blkhd.tqh_first; blk; + blk = blk->lf_block.tqe_next) { + printf("\n\t\tlock request 0x%lx for ", blk); + if (blk->lf_flags & F_POSIX) + printf("proc %d", + ((struct proc *)(blk->lf_id))->p_pid); + else + printf("id 0x%x", blk->lf_id); + printf(", %s, start %d, end %d", + blk->lf_type == F_RDLCK ? "shared" : + blk->lf_type == F_WRLCK ? "exclusive" : + blk->lf_type == F_UNLCK ? "unlock" : + "unknown", blk->lf_start, blk->lf_end); + if (blk->lf_blkhd.tqh_first) + panic("lf_printlist: bad list"); + } + printf("\n"); } } #endif /* LOCKF_DEBUG */ diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 2b162be..37d99e4 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -53,7 +53,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <sys/user.h> diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index 70d1551..d9381a6 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -53,7 +53,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 0b82597..0f6c9e5 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -67,7 +67,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <sys/user.h> /* for coredump */ @@ -660,7 +660,7 @@ gsignal(pgid, signum) } /* - * Send a signal to a process group. If checktty is 1, + * Send a signal to a process group. If checktty is 1, * limit to members which have a controlling terminal. */ void @@ -1255,7 +1255,7 @@ coredump(p) } VATTR_NULL(&vattr); vattr.va_size = 0; - LEASE_CHECK(vp, p, cred, LEASE_WRITE); + VOP_LEASE(vp, p, cred, LEASE_WRITE); VOP_SETATTR(vp, &vattr, cred, p); p->p_acflag |= ACORE; bcopy(p, &p->p_addr->u_kproc.kp_proc, sizeof(struct proc)); @@ -1272,7 +1272,7 @@ coredump(p) (off_t)ctob(UPAGES) + ctob(vm->vm_dsize), UIO_USERSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p); out: - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); error1 = vn_close(vp, FWRITE, cred, p); if (error == 0) error = error1; diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index d591c96..43f9e5d 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -529,9 +529,10 @@ mi_switch() register long s, u; struct timeval tv; -#ifdef DEBUG - if (p->p_simple_locks) - panic("sleep: holding simple lock"); +#ifdef SIMPLELOCK_DEBUG + if (p->p_simple_locks) { + printf("sleep: holding simple lock"); + } #endif /* * Compute the amount of time during which the current diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index 6b958df..938e3df 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -70,7 +70,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <sys/sysctl.h> diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 82b03d5..baa8789 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -139,7 +139,9 @@ settimeofday(p, uap, retval) for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) if (timerisset(&p->p_realtimer.it_value)) timevaladd(&p->p_realtimer.it_value, &delta); - LEASE_UPDATETIME(delta.tv_sec); +# ifdef NFS + lease_updatetime(delta.tv_sec); +# endif splx(s); resettodr(); } diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c index 6b958df..938e3df 100644 --- a/sys/kern/kern_timeout.c +++ b/sys/kern/kern_timeout.c @@ -70,7 +70,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <sys/sysctl.h> diff --git a/sys/kern/subr_diskslice.c b/sys/kern/subr_diskslice.c index c88ffe7..303e33b 100644 --- a/sys/kern/subr_diskslice.c +++ b/sys/kern/subr_diskslice.c @@ -63,6 +63,7 @@ #include <sys/systm.h> #include <sys/vnode.h> +#include <ufs/ufs/dinode.h> #include <ufs/ffs/fs.h> #define TRACE(str) do { if (ds_debug) printf str; } while (0) diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index b38e35d..c866f32 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -61,7 +61,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_kern.h> #include <vm/vm_map.h> diff --git a/sys/kern/subr_xxx.c b/sys/kern/subr_xxx.c index 78e4013..fcb951f 100644 --- a/sys/kern/subr_xxx.c +++ b/sys/kern/subr_xxx.c @@ -52,6 +52,17 @@ eopnotsupp() } /* + * Return error for an inval operation + * on a specific object or file type. + */ +int +einval() +{ + + return (EINVAL); +} + +/* * Generic null operation, always returns success. */ int diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index 9ad0a61..6d9a566 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -73,7 +73,7 @@ #include <vm/vm.h> #include <vm/vm_prot.h> #include <vm/vm_param.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_object.h> #include <vm/vm_kern.h> #include <vm/vm_extern.h> diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index b64f1e6..72e95e7 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -45,7 +45,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_object.h> diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index e0c707d..2afd2b4 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -227,7 +227,7 @@ char *syscallnames[] = { "mlock", /* 203 = mlock */ "munlock", /* 204 = munlock */ "utrace", /* 205 = utrace */ - "#206", /* 206 = nosys */ + "undelete", /* 206 = undelete */ "#207", /* 207 = nosys */ "#208", /* 208 = nosys */ "#209", /* 209 = nosys */ diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 896f846..cacaf42 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -60,7 +60,7 @@ int flags); } 19 COMPAT POSIX { long lseek(int fd, long offset, int whence); } 20 STD POSIX { pid_t getpid(void); } -21 STD BSD { int mount(int type, char *path, int flags, \ +21 STD BSD { int mount(char *type, char *path, int flags, \ caddr_t data); } ; XXX 4.4lite2 uses `char *type' but we're not ready for that. ; XXX `path' should have type `const char *' but we're not ready for that. @@ -111,7 +111,7 @@ 57 STD POSIX { int symlink(char *path, char *link); } 58 STD POSIX { int readlink(char *path, char *buf, int count); } 59 STD POSIX { int execve(char *fname, char **argv, char **envv); } -60 STD POSIX { int umask(int newmask); } umask umask_args mode_t +60 STD POSIX { int umask(int newmask); } umask umask_args int 61 STD BSD { int chroot(char *path); } 62 COMPAT POSIX { int fstat(int fd, struct ostat *sb); } 63 COMPAT BSD { int getkerninfo(int op, char *where, int *size, \ @@ -328,7 +328,7 @@ 203 STD BSD { int mlock(caddr_t addr, size_t len); } 204 STD BSD { int munlock(caddr_t addr, size_t len); } 205 STD BSD { int utrace(caddr_t addr, size_t len); } -206 UNIMPL NOHIDE nosys +206 STD BSD { int undelete(char *path); } 207 UNIMPL NOHIDE nosys 208 UNIMPL NOHIDE nosys 209 UNIMPL NOHIDE nosys diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c index f02a785..b777250 100644 --- a/sys/kern/sysv_shm.c +++ b/sys/kern/sysv_shm.c @@ -48,7 +48,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_object.h> #include <vm/vm_map.h> diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 47707db..06ce568 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -94,7 +94,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> diff --git a/sys/kern/tty_tty.c b/sys/kern/tty_tty.c index 770b66e..b6e3fda 100644 --- a/sys/kern/tty_tty.c +++ b/sys/kern/tty_tty.c @@ -78,7 +78,7 @@ cttyopen(dev, flag, mode, p) if (ttyvp == NULL) return (ENXIO); - VOP_LOCK(ttyvp); + vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, p); #ifdef PARANOID /* * Since group is tty and mode is 620 on most terminal lines @@ -93,7 +93,7 @@ cttyopen(dev, flag, mode, p) if (!error) #endif /* PARANOID */ error = VOP_OPEN(ttyvp, flag, NOCRED, p); - VOP_UNLOCK(ttyvp); + VOP_UNLOCK(ttyvp, 0, p); return (error); } @@ -104,14 +104,15 @@ cttyread(dev, uio, flag) struct uio *uio; int flag; { - register struct vnode *ttyvp = cttyvp(uio->uio_procp); + struct proc *p = uio->uio_procp; + register struct vnode *ttyvp = cttyvp(p); int error; if (ttyvp == NULL) return (EIO); - VOP_LOCK(ttyvp); + vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_READ(ttyvp, uio, flag, NOCRED); - VOP_UNLOCK(ttyvp); + VOP_UNLOCK(ttyvp, 0, p); return (error); } @@ -122,14 +123,15 @@ cttywrite(dev, uio, flag) struct uio *uio; int flag; { - register struct vnode *ttyvp = cttyvp(uio->uio_procp); + struct proc *p = uio->uio_procp; + struct vnode *ttyvp = cttyvp(uio->uio_procp); int error; if (ttyvp == NULL) return (EIO); - VOP_LOCK(ttyvp); + vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_WRITE(ttyvp, uio, flag, NOCRED); - VOP_UNLOCK(ttyvp); + VOP_UNLOCK(ttyvp, 0, p); return (error); } @@ -195,5 +197,3 @@ ctty_drvinit(void *unused) } SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL) - - diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 2017de9..bfbb3c6 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -436,7 +436,7 @@ unp_bind(unp, nam, p) struct nameidata nd; NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE, - soun->sun_path, p); + soun->sun_path, p); if (unp->unp_vnode != NULL) return (EINVAL); if (nam->m_len == MLEN) { @@ -461,15 +461,14 @@ unp_bind(unp, nam, p) VATTR_NULL(&vattr); vattr.va_type = VSOCK; vattr.va_mode = ACCESSPERMS; - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); - if (error) + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)) return (error); vp = nd.ni_vp; vp->v_socket = unp->unp_socket; unp->unp_vnode = vp; unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (0); } @@ -888,7 +887,7 @@ unp_gc() for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) sorflush((struct socket *)(*fpp)->f_data); for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) - closef(*fpp,(struct proc*) NULL); + closef(*fpp, (struct proc *) NULL); free((caddr_t)extra_ref, M_FILE); unp_gcing = 0; } @@ -897,6 +896,7 @@ void unp_dispose(m) struct mbuf *m; { + if (m) unp_scan(m, unp_discard); } @@ -904,7 +904,7 @@ unp_dispose(m) static void unp_scan(m0, op) register struct mbuf *m0; - void (*op)(struct file *); + void (*op) __P((struct file *)); { register struct mbuf *m; register struct file **rp; diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index bee702d..718c4a3 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -1,8 +1,9 @@ /* - * Copyright (c) 1989, 1993 + * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. - * Copyright (c) 1995 - * Poul-Henning Kamp. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Poul-Henning Kamp of the FreeBSD Project. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -58,9 +59,8 @@ * obtained from (vp, name) where vp refers to the directory * containing name. * - * If it is a "negative" entry, (that we know a name to >not< exist) - * we point out entry at our own "nchENOENT", to avoid too much special - * casing in the inner loops of lookup. + * If it is a "negative" entry, (i.e. for a name that is known NOT to + * exist) the vnode pointer will be NULL. * * For simplicity (and economy of storage), names longer than * a maximum length of NCHNAMLEN are not cached; they occur @@ -74,15 +74,15 @@ /* * Structures associated with name cacheing. */ +#define NCHHASH(dvp, cnp) \ + (&nchashtbl[((dvp)->v_id + (cnp)->cn_hash) & nchash]) static LIST_HEAD(nchashhead, namecache) *nchashtbl; /* Hash Table */ -static TAILQ_HEAD(, namecache) nclruhead; /* LRU chain */ -static u_long nchash; /* size of hash table */ -struct nchstats nchstats; /* cache effectiveness statistics */ -static struct vnode nchENOENT; /* our own "novnode" */ -static int doingcache = 1; /* 1 => enable the cache */ +static u_long nchash; /* size of hash table - 1 */ +static int doingcache = 1; /* 1 => enable the cache */ SYSCTL_INT(_debug, OID_AUTO, vfscache, CTLFLAG_RW, &doingcache, 0, ""); -static u_long numcache; -u_long numvnodes; +static u_long numcache; /* number of cache entries allocated */ +static TAILQ_HEAD(, namecache) nclruhead; /* LRU chain */ +struct nchstats nchstats; /* cache effectiveness statistics */ #ifdef NCH_STATISTICS u_long nchnbr; @@ -93,32 +93,42 @@ u_long nchnbr; #define NCHHIT(ncp) #endif +/* + * Delete an entry from its hash list and move it to the front + * of the LRU list for immediate reuse. + */ #define PURGE(ncp) { \ LIST_REMOVE(ncp, nc_hash); \ ncp->nc_hash.le_prev = 0; \ TAILQ_REMOVE(&nclruhead, ncp, nc_lru); \ - TAILQ_INSERT_HEAD(&nclruhead, ncp, nc_lru); } + TAILQ_INSERT_HEAD(&nclruhead, ncp, nc_lru); \ +} +/* + * Move an entry that has been used to the tail of the LRU list + * so that it will be preserved for future use. + */ #define TOUCH(ncp) { \ - if (ncp->nc_lru.tqe_next == 0) { } else { \ + if (ncp->nc_lru.tqe_next != 0) { \ TAILQ_REMOVE(&nclruhead, ncp, nc_lru); \ TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru); \ - NCHNBR(ncp); } } + NCHNBR(ncp); \ + } \ +} /* - * Lookup an entry in the cache + * Lookup an entry in the cache * - * We don't do this if the segment name is long, simply so the cache + * We don't do this if the segment name is long, simply so the cache * can avoid holding long names (which would either waste space, or * add greatly to the complexity). * * Lookup is called with dvp pointing to the directory to search, - * cnp pointing to the name of the entry being sought. - * If the lookup succeeds, the vnode is returned in *vpp, and a status - * of -1 is returned. - * If the lookup determines that the name does not exist (negative cacheing), - * a status of ENOENT is returned. - * If the lookup fails, a status of zero is returned. + * cnp pointing to the name of the entry being sought. If the lookup + * succeeds, the vnode is returned in *vpp, and a status of -1 is + * returned. If the lookup determines that the name does not exist + * (negative cacheing), a status of ENOENT is returned. If the lookup + * fails, a status of zero is returned. */ int @@ -127,7 +137,7 @@ cache_lookup(dvp, vpp, cnp) struct vnode **vpp; struct componentname *cnp; { - register struct namecache *ncp,*nnp; + register struct namecache *ncp, *nnp; register struct nchashhead *ncpp; if (!doingcache) { @@ -141,12 +151,12 @@ cache_lookup(dvp, vpp, cnp) return (0); } - ncpp = &nchashtbl[(dvp->v_id + cnp->cn_hash) % nchash]; + ncpp = NCHHASH(dvp, cnp); for (ncp = ncpp->lh_first; ncp != 0; ncp = nnp) { nnp = ncp->nc_hash.le_next; /* If one of the vp's went stale, don't bother anymore. */ if ((ncp->nc_dvpid != ncp->nc_dvp->v_id) || - (ncp->nc_vpid != ncp->nc_vp->v_id)) { + (ncp->nc_vp && ncp->nc_vpid != ncp->nc_vp->v_id)) { nchstats.ncs_falsehits++; PURGE(ncp); continue; @@ -155,12 +165,15 @@ cache_lookup(dvp, vpp, cnp) if (ncp->nc_dvp == dvp && ncp->nc_nlen == cnp->cn_namelen && !bcmp(ncp->nc_name, cnp->cn_nameptr, (u_int)ncp->nc_nlen)) - goto found; /* Fanatism considered bad. */ + break; + } + + /* We failed to find an entry */ + if (ncp == 0) { + nchstats.ncs_miss++; + return (0); } - nchstats.ncs_miss++; - return (0); - found: NCHHIT(ncp); /* We don't want to have an entry, so dump it */ @@ -168,10 +181,10 @@ cache_lookup(dvp, vpp, cnp) nchstats.ncs_badhits++; PURGE(ncp); return (0); - } + } /* We found a "positive" match, return the vnode */ - if (ncp->nc_vp != &nchENOENT) { + if (ncp->nc_vp) { nchstats.ncs_goodhits++; TOUCH(ncp); *vpp = ncp->nc_vp; @@ -187,16 +200,19 @@ cache_lookup(dvp, vpp, cnp) return (0); } - /* The name does not exists */ + /* + * We found a "negative" match, ENOENT notifies client of this match. + * The nc_vpid field records whether this is a whiteout. + */ nchstats.ncs_neghits++; TOUCH(ncp); + cnp->cn_flags |= ncp->nc_vpid; return (ENOENT); } /* * Add an entry to the cache. */ - void cache_enter(dvp, vp, cnp) struct vnode *dvp; @@ -209,12 +225,21 @@ cache_enter(dvp, vp, cnp) if (!doingcache) return; +#ifdef DIAGNOSTIC if (cnp->cn_namelen > NCHNAMLEN) { printf("cache_enter: name too long"); return; } +#endif - if (numcache < numvnodes) { + /* + * We allocate a new entry if we are less than the maximum + * allowed and the one at the front of the LRU list is in use. + * Otherwise we use the one at the front of the LRU list. + */ + if (numcache < desiredvnodes && + ((ncp = nclruhead.tqh_first) == NULL || + ncp->nc_hash.le_prev != 0)) { /* Add one more entry */ ncp = (struct namecache *) malloc((u_long)sizeof *ncp, M_CACHE, M_WAITOK); @@ -231,52 +256,51 @@ cache_enter(dvp, vp, cnp) /* give up */ return; } - - /* If vp is NULL this is a "negative" cache entry */ - if (!vp) - vp = &nchENOENT; - - /* fill in cache info */ + /* + * Fill in cache info, if vp is NULL this is a "negative" cache entry. + * For negative entries, we have to record whether it is a whiteout. + * the whiteout flag is stored in the nc_vpid field which is + * otherwise unused. + */ ncp->nc_vp = vp; - if (vp->v_usage < MAXVNODEUSE) - ++vp->v_usage; - ncp->nc_vpid = vp->v_id; + if (vp) { + ncp->nc_vpid = vp->v_id; + if (vp->v_usage < MAXVNODEUSE) + ++vp->v_usage; + } else + ncp->nc_vpid = cnp->cn_flags & ISWHITEOUT; ncp->nc_dvp = dvp; ncp->nc_dvpid = dvp->v_id; ncp->nc_nlen = cnp->cn_namelen; bcopy(cnp->cn_nameptr, ncp->nc_name, (unsigned)ncp->nc_nlen); TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru); - ncpp = &nchashtbl[(dvp->v_id + cnp->cn_hash) % nchash]; + ncpp = NCHHASH(dvp, cnp); LIST_INSERT_HEAD(ncpp, ncp, nc_hash); } /* * Name cache initialization, from vfs_init() when we are booting */ - void nchinit() { - TAILQ_INIT(&nclruhead); nchashtbl = phashinit(desiredvnodes, M_CACHE, &nchash); - cache_purge(&nchENOENT); /* Initialize v_id */ } /* - * Invalidate all entries to a particular vnode. - * - * We actually just increment the v_id, that will do it. The stale entries - * will be purged by lookup as they get found. - * If the v_id wraps around, we need to ditch the entire cache, to avoid - * confusion. - * No valid vnode will ever have (v_id == 0). + * Invalidate all entries to particular vnode. + * + * We actually just increment the v_id, that will do it. The stale entries + * will be purged by lookup as they get found. If the v_id wraps around, we + * need to ditch the entire cache, to avoid confusion. No valid vnode will + * ever have (v_id == 0). */ - void cache_purge(vp) struct vnode *vp; { + struct namecache *ncp; struct nchashhead *ncpp; static u_long nextvnodeid; @@ -284,10 +308,9 @@ cache_purge(vp) if (nextvnodeid != 0) return; for (ncpp = &nchashtbl[nchash - 1]; ncpp >= nchashtbl; ncpp--) { - while(ncpp->lh_first) - PURGE(ncpp->lh_first); + while (ncp = ncpp->lh_first) + PURGE(ncp); } - nchENOENT.v_id = ++nextvnodeid; vp->v_id = ++nextvnodeid; } @@ -296,29 +319,22 @@ cache_purge(vp) * * Since we need to check it anyway, we will flush all the invalid * entries at the same time. - * - * If we purge anything, we scan the hash-bucket again. There is only - * a handful of entries, so it cheap and simple. */ - void cache_purgevfs(mp) struct mount *mp; { struct nchashhead *ncpp; - struct namecache *ncp; + struct namecache *ncp, *nnp; /* Scan hash tables for applicable entries */ for (ncpp = &nchashtbl[nchash - 1]; ncpp >= nchashtbl; ncpp--) { - ncp = ncpp->lh_first; - while(ncp) { + for (ncp = ncpp->lh_first; ncp != 0; ncp = nnp) { + nnp = ncp->nc_hash.le_next; if (ncp->nc_dvpid != ncp->nc_dvp->v_id || - ncp->nc_vpid != ncp->nc_vp->v_id || + (ncp->nc_vp && ncp->nc_vpid != ncp->nc_vp->v_id) || ncp->nc_dvp->v_mount == mp) { PURGE(ncp); - ncp = ncpp->lh_first; - } else { - ncp = ncp->nc_hash.le_next; } } } diff --git a/sys/kern/vfs_conf.c b/sys/kern/vfs_conf.c index fb8061b..5a84570 100644 --- a/sys/kern/vfs_conf.c +++ b/sys/kern/vfs_conf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1993 + * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. * Copyright (c) 1995 Artisoft, Inc. All Rights Reserved. * @@ -61,26 +61,33 @@ /* * GLOBALS */ -int (*mountroot) __P((void *)); + +/* + * These define the root filesystem, device, and root filesystem type. + */ +struct mount *rootfs; struct vnode *rootvnode; -struct vfsops *mountrootvfsops; +char *mountrootfsname; +/* + * vfs_init() will set maxvfsconf + * to the highest defined type number. + */ +int maxvfsconf; +struct vfsconf *vfsconf; /* * Common root mount code shared by all filesystems */ -#define ROOTDIR "/" #define ROOTNAME "root_device" - - /* - * vfs_mountroot + * vfs_mountrootfs * * Common entry point for root mounts * * PARAMETERS: - * data pointer to the vfs_ops for the FS type mounting + * fsname name of the filesystem * * RETURNS: 0 Success * !0 error number (errno.h) @@ -97,67 +104,44 @@ struct vfsops *mountrootvfsops; * fixing the other file systems, not this code! */ int -vfs_mountroot(data) - void *data; +vfs_mountrootfs(fsname) + char *fsname; { struct mount *mp; - u_int size; int err = 0; struct proc *p = curproc; /* XXX */ - struct vfsops *mnt_op = (struct vfsops *)data; /* * New root mount structure */ - mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); - bzero((char *)mp, (u_long)sizeof(struct mount)); - mp->mnt_op = mnt_op; - mp->mnt_flag = MNT_ROOTFS; - mp->mnt_vnodecovered = NULLVP; - - /* - * Lock mount point - */ - if( ( err = vfs_lock(mp)) != 0) - goto error_1; - - /* Save "last mounted on" info for mount point (NULL pad)*/ - copystr( ROOTDIR, /* mount point*/ - mp->mnt_stat.f_mntonname, /* save area*/ - MNAMELEN - 1, /* max size*/ - &size); /* real size*/ - bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size); - - /* Save "mounted from" info for mount point (NULL pad)*/ - copystr( ROOTNAME, /* device name*/ - mp->mnt_stat.f_mntfromname, /* save area*/ - MNAMELEN - 1, /* max size*/ - &size); /* real size*/ - bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); + err = vfs_rootmountalloc(fsname, ROOTNAME, &mp); + if (err) + return (err); + mp->mnt_flag |= MNT_ROOTFS; /* * Attempt the mount */ - err = VFS_MOUNT( mp, NULL, NULL, NULL, p); - if( err) + err = VFS_MOUNT(mp, NULL, NULL, NULL, p); + if (err) goto error_2; + simple_lock(&mountlist_slock); /* Add fs to list of mounted file systems*/ - CIRCLEQ_INSERT_TAIL( &mountlist, mp, mnt_list); + CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); + simple_unlock(&mountlist_slock); - /* Unlock mount point*/ - vfs_unlock(mp); + vfs_unbusy(mp, p); /* root mount, update system time from FS specific data*/ - inittodr( mp->mnt_time); + inittodr(mp->mnt_time); goto success; error_2: /* mount error*/ - /* unlock before failing*/ - vfs_unlock( mp); + vfs_unbusy(mp, p); error_1: /* lock error*/ diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c index 43f8669..0dea7bd 100644 --- a/sys/kern/vfs_export.c +++ b/sys/kern/vfs_export.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)vfs_subr.c 8.13 (Berkeley) 4/18/94 + * @(#)vfs_subr.c 8.31 (Berkeley) 5/26/95 * $FreeBSD$ */ @@ -75,7 +75,9 @@ #ifdef DDB extern void printlockedvnodes __P((void)); #endif -extern void vclean __P((struct vnode *vp, int flags)); +static void vclean __P((struct vnode *vp, int flags, struct proc *p)); +extern void vgonel __P((struct vnode *vp, struct proc *p)); +unsigned long numvnodes; extern void vfs_unmountroot __P((struct mount *rootfs)); enum vtype iftovt_tab[16] = { @@ -91,15 +93,19 @@ int vttoif_tab[9] = { * Insq/Remq for the vnode usage lists. */ #define bufinsvn(bp, dp) LIST_INSERT_HEAD(dp, bp, b_vnbufs) -#define bufremvn(bp) { \ - LIST_REMOVE(bp, b_vnbufs); \ - (bp)->b_vnbufs.le_next = NOLIST; \ +#define bufremvn(bp) { \ + LIST_REMOVE(bp, b_vnbufs); \ + (bp)->b_vnbufs.le_next = NOLIST; \ } - TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */ static u_long freevnodes = 0; struct mntlist mountlist; /* mounted filesystem list */ +struct simplelock mountlist_slock; +static struct simplelock mntid_slock; +struct simplelock mntvnode_slock; +struct simplelock vnode_free_list_slock; +static struct simplelock spechash_slock; int desiredvnodes; SYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RW, &desiredvnodes, 0, ""); @@ -117,164 +123,153 @@ vntblinit() { desiredvnodes = maxproc + vm_object_cache_max; + simple_lock_init(&mntvnode_slock); + simple_lock_init(&mntid_slock); + simple_lock_init(&spechash_slock); TAILQ_INIT(&vnode_free_list); + simple_lock_init(&vnode_free_list_slock); CIRCLEQ_INIT(&mountlist); } /* - * Lock a filesystem. - * Used to prevent access to it while mounting and unmounting. + * Mark a mount point as busy. Used to synchronize access and to delay + * unmounting. Interlock is not released on failure. */ int -vfs_lock(mp) - register struct mount *mp; +vfs_busy(mp, flags, interlkp, p) + struct mount *mp; + int flags; + struct simplelock *interlkp; + struct proc *p; { + int lkflags; - while (mp->mnt_flag & MNT_MLOCK) { + if (mp->mnt_flag & MNT_UNMOUNT) { + if (flags & LK_NOWAIT) + return (ENOENT); mp->mnt_flag |= MNT_MWAIT; - (void) tsleep((caddr_t) mp, PVFS, "vfslck", 0); + if (interlkp) { + simple_unlock(interlkp); + } + /* + * Since all busy locks are shared except the exclusive + * lock granted when unmounting, the only place that a + * wakeup needs to be done is at the release of the + * exclusive lock at the end of dounmount. + */ + tsleep((caddr_t)mp, PVFS, "vfs_busy", 0); + if (interlkp) { + simple_lock(interlkp); + } + return (ENOENT); } - mp->mnt_flag |= MNT_MLOCK; + lkflags = LK_SHARED; + if (interlkp) + lkflags |= LK_INTERLOCK; + if (lockmgr(&mp->mnt_lock, lkflags, interlkp, p)) + panic("vfs_busy: unexpected lock failure"); return (0); } /* - * Unlock a locked filesystem. - * Panic if filesystem is not locked. + * Free a busy filesystem. */ void -vfs_unlock(mp) - register struct mount *mp; +vfs_unbusy(mp, p) + struct mount *mp; + struct proc *p; { - if ((mp->mnt_flag & MNT_MLOCK) == 0) - panic("vfs_unlock: not locked"); - mp->mnt_flag &= ~MNT_MLOCK; - if (mp->mnt_flag & MNT_MWAIT) { - mp->mnt_flag &= ~MNT_MWAIT; - wakeup((caddr_t) mp); - } + lockmgr(&mp->mnt_lock, LK_RELEASE, NULL, p); } /* - * Mark a mount point as busy. - * Used to synchronize access and to delay unmounting. + * Lookup a filesystem type, and if found allocate and initialize + * a mount structure for it. + * + * Devname is usually updated by mount(8) after booting. */ int -vfs_busy(mp) - register struct mount *mp; +vfs_rootmountalloc(fstypename, devname, mpp) + char *fstypename; + char *devname; + struct mount **mpp; { + struct proc *p = curproc; /* XXX */ + struct vfsconf *vfsp; + struct mount *mp; - while (mp->mnt_flag & MNT_MPBUSY) { - mp->mnt_flag |= MNT_MPWANT; - (void) tsleep((caddr_t) &mp->mnt_flag, PVFS, "vfsbsy", 0); - } - if (mp->mnt_flag & MNT_UNMOUNT) - return (1); - mp->mnt_flag |= MNT_MPBUSY; + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) + if (!strcmp(vfsp->vfc_name, fstypename)) + break; + if (vfsp == NULL) + return (ENODEV); + mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); + bzero((char *)mp, (u_long)sizeof(struct mount)); + lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); + (void)vfs_busy(mp, LK_NOWAIT, 0, p); + LIST_INIT(&mp->mnt_vnodelist); + mp->mnt_vfc = vfsp; + mp->mnt_op = vfsp->vfc_vfsops; + mp->mnt_flag = MNT_RDONLY; + mp->mnt_vnodecovered = NULLVP; + vfsp->vfc_refcount++; + mp->mnt_stat.f_type = vfsp->vfc_typenum; + mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; + strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); + mp->mnt_stat.f_mntonname[0] = '/'; + mp->mnt_stat.f_mntonname[1] = 0; + (void) copystr(devname, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 0); + *mpp = mp; return (0); } /* - * Free a busy filesystem. - * Panic if filesystem is not busy. - */ -void -vfs_unbusy(mp) - register struct mount *mp; -{ - - if ((mp->mnt_flag & MNT_MPBUSY) == 0) - panic("vfs_unbusy: not busy"); - mp->mnt_flag &= ~MNT_MPBUSY; - if (mp->mnt_flag & MNT_MPWANT) { - mp->mnt_flag &= ~MNT_MPWANT; - wakeup((caddr_t) &mp->mnt_flag); - } -} - -void -vfs_unmountroot(struct mount *rootfs) -{ - struct mount *mp = rootfs; - int error; - - if (vfs_busy(mp)) { - printf("failed to unmount root\n"); - return; - } - mp->mnt_flag |= MNT_UNMOUNT; - if ((error = vfs_lock(mp))) { - printf("lock of root filesystem failed (%d)\n", error); - return; - } - vnode_pager_umount(mp); /* release cached vnodes */ - cache_purgevfs(mp); /* remove cache entries for this file sys */ - - if ((error = VFS_SYNC(mp, MNT_WAIT, initproc->p_ucred, initproc))) - printf("sync of root filesystem failed (%d)\n", error); - - if ((error = VFS_UNMOUNT(mp, MNT_FORCE, initproc))) { - printf("unmount of root filesystem failed ("); - if (error == EBUSY) - printf("BUSY)\n"); - else - printf("%d)\n", error); - } - mp->mnt_flag &= ~MNT_UNMOUNT; - vfs_unbusy(mp); -} - -/* - * Unmount all filesystems. Should only be called by halt(). + * Find an appropriate filesystem to use for the root. If a filesystem + * has not been preselected, walk through the list of known filesystems + * trying those that have mountroot routines, and try them until one + * works or we have tried them all. */ -void -vfs_unmountall() +#ifdef notdef /* XXX JH */ +int +lite2_vfs_mountroot(void) { - struct mount *mp, *nmp, *rootfs = NULL; + struct vfsconf *vfsp; + extern int (*lite2_mountroot)(void); int error; - /* unmount all but rootfs */ - for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) { - nmp = mp->mnt_list.cqe_prev; - - if (mp->mnt_flag & MNT_ROOTFS) { - rootfs = mp; + if (lite2_mountroot != NULL) + return ((*lite2_mountroot)()); + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) { + if (vfsp->vfc_mountroot == NULL) continue; - } - error = dounmount(mp, MNT_FORCE, initproc); - if (error) { - printf("unmount of %s failed (", mp->mnt_stat.f_mntonname); - if (error == EBUSY) - printf("BUSY)\n"); - else - printf("%d)\n", error); - } - } - - /* and finally... */ - if (rootfs) { - vfs_unmountroot(rootfs); - } else { - printf("no root filesystem\n"); + if ((error = (*vfsp->vfc_mountroot)()) == 0) + return (0); + printf("%s_mountroot failed: %d\n", vfsp->vfc_name, error); } + return (ENODEV); } +#endif /* * Lookup a mount point by filesystem identifier. */ struct mount * -getvfs(fsid) +vfs_getvfs(fsid) fsid_t *fsid; { register struct mount *mp; + simple_lock(&mountlist_slock); for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = mp->mnt_list.cqe_next) { if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && - mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) + mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { + simple_unlock(&mountlist_slock); return (mp); + } } + simple_unlock(&mountlist_slock); return ((struct mount *) 0); } @@ -282,14 +277,16 @@ getvfs(fsid) * Get a new unique fsid */ void -getnewfsid(mp, mtype) +vfs_getnewfsid(mp) struct mount *mp; - int mtype; { static u_short xxxfs_mntid; fsid_t tfsid; + int mtype; + simple_lock(&mntid_slock); + mtype = mp->mnt_vfc->vfc_typenum; mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + mtype, 0); mp->mnt_stat.f_fsid.val[1] = mtype; if (xxxfs_mntid == 0) @@ -297,12 +294,13 @@ getnewfsid(mp, mtype) tfsid.val[0] = makedev(nblkdev + mtype, xxxfs_mntid); tfsid.val[1] = mtype; if (mountlist.cqh_first != (void *)&mountlist) { - while (getvfs(&tfsid)) { + while (vfs_getvfs(&tfsid)) { tfsid.val[0]++; xxxfs_mntid++; } } mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; + simple_unlock(&mntid_slock); } /* @@ -326,6 +324,35 @@ vattr_null(vap) vap->va_vaflags = 0; } +void +vfs_unmountroot(struct mount *rootfs) +{ + struct proc *p = curproc; /* XXX */ + struct mount *mp = rootfs; + int error; + + if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { + printf("failed to unmount root\n"); + return; + } + mp->mnt_flag |= MNT_UNMOUNT; + vnode_pager_umount(mp); /* release cached vnodes */ + cache_purgevfs(mp); /* remove cache entries for this file sys */ + + if ((error = VFS_SYNC(mp, MNT_WAIT, initproc->p_ucred, initproc))) + printf("sync of root filesystem failed (%d)\n", error); + + if ((error = VFS_UNMOUNT(mp, MNT_FORCE, initproc))) { + printf("unmount of root filesystem failed ("); + if (error == EBUSY) + printf("BUSY)\n"); + else + printf("%d)\n", error); + } + mp->mnt_flag &= ~MNT_UNMOUNT; + vfs_unbusy(mp, p); +} + /* * Routines having to do with the management of the vnode table. */ @@ -341,10 +368,11 @@ getnewvnode(tag, mp, vops, vpp) vop_t **vops; struct vnode **vpp; { - register struct vnode *vp; + struct proc *p = curproc; /* XXX */ + struct vnode *vp; + simple_lock(&vnode_free_list_slock); retry: - vp = vnode_free_list.tqh_first; /* * we allocate a new vnode if * 1. we don't have any free @@ -357,12 +385,31 @@ retry: */ if (freevnodes < (numvnodes >> 2) || numvnodes < desiredvnodes || - vp == NULL) { + vnode_free_list.tqh_first == NULL) { + simple_unlock(&vnode_free_list_slock); vp = (struct vnode *) malloc((u_long) sizeof *vp, M_VNODE, M_WAITOK); bzero((char *) vp, sizeof *vp); numvnodes++; } else { + for (vp = vnode_free_list.tqh_first; + vp != NULLVP; vp = vp->v_freelist.tqe_next) { + if (simple_lock_try(&vp->v_interlock)) + break; + } + /* + * Unless this is a bad time of the month, at most + * the first NCPUS items on the free list are + * locked, so this is close enough to being empty. + */ + if (vp == NULLVP) { + simple_unlock(&vnode_free_list_slock); + tablefull("vnode"); + *vpp = 0; + return (ENFILE); + } + if (vp->v_usecount) + panic("free vnode isn't"); TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); if (vp->v_usage > 0) { --vp->v_usage; @@ -370,14 +417,16 @@ retry: goto retry; } freevnodes--; - if (vp->v_usecount) - panic("free vnode isn't"); /* see comment on why 0xdeadb is set at end of vgone (below) */ vp->v_freelist.tqe_prev = (struct vnode **) 0xdeadb; + simple_unlock(&vnode_free_list_slock); vp->v_lease = NULL; if (vp->v_type != VBAD) - vgone(vp); + vgonel(vp, p); + else { + simple_unlock(&vp->v_interlock); + } #ifdef DIAGNOSTIC { @@ -421,6 +470,7 @@ insmntque(vp, mp) register struct mount *mp; { + simple_lock(&mntvnode_slock); /* * Delete from old mount point vnode list, if on one. */ @@ -429,9 +479,12 @@ insmntque(vp, mp) /* * Insert into list of vnodes for the new mount point, if available. */ - if ((vp->v_mount = mp) == NULL) + if ((vp->v_mount = mp) == NULL) { + simple_unlock(&mntvnode_slock); return; + } LIST_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes); + simple_unlock(&mntvnode_slock); } /* @@ -723,7 +776,8 @@ checkalias(nvp, nvp_rdev, mp) dev_t nvp_rdev; struct mount *mp; { - register struct vnode *vp; + struct proc *p = curproc; /* XXX */ + struct vnode *vp; struct vnode **vpp; if (nvp->v_type != VBLK && nvp->v_type != VCHR) @@ -731,18 +785,24 @@ checkalias(nvp, nvp_rdev, mp) vpp = &speclisth[SPECHASH(nvp_rdev)]; loop: + simple_lock(&spechash_slock); for (vp = *vpp; vp; vp = vp->v_specnext) { if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) continue; /* * Alias, but not in use, so flush it out. */ + simple_lock(&vp->v_interlock); if (vp->v_usecount == 0) { - vgone(vp); + simple_unlock(&spechash_slock); + vgonel(vp, p); goto loop; } - if (vget(vp, 1)) + simple_unlock(&spechash_slock); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) { goto loop; + } + simple_lock(&spechash_slock); break; } @@ -753,16 +813,19 @@ loop: nvp->v_hashchain = vpp; nvp->v_specnext = *vpp; nvp->v_specflags = 0; + simple_unlock(&spechash_slock); *vpp = nvp; - if (vp != NULL) { + if (vp != NULLVP) { nvp->v_flag |= VALIASED; vp->v_flag |= VALIASED; vput(vp); } return (NULLVP); } - VOP_UNLOCK(vp); - vclean(vp, 0); + simple_unlock(&spechash_slock); + VOP_UNLOCK(vp, 0, p); + simple_lock(&vp->v_interlock); + vclean(vp, 0, p); vp->v_op = nvp->v_op; vp->v_tag = nvp->v_tag; nvp->v_type = VNON; @@ -779,47 +842,162 @@ loop: * been changed to a new file system type). */ int -vget(vp, lockflag) +vget(vp, flags, p) register struct vnode *vp; - int lockflag; + int flags; + struct proc *p; { + int error; /* - * If the vnode is in the process of being cleaned out for another - * use, we wait for the cleaning to finish and then return failure. - * Cleaning is determined either by checking that the VXLOCK flag is - * set, or that the use count is zero with the back pointer set to - * show that it has been removed from the free list by getnewvnode. - * The VXLOCK flag may not have been set yet because vclean is blocked - * in the VOP_LOCK call waiting for the VOP_INACTIVE to complete. + * If the vnode is in the process of being cleaned out for + * another use, we wait for the cleaning to finish and then + * return failure. Cleaning is determined by checking that + * the VXLOCK flag is set. */ - if ((vp->v_flag & VXLOCK) || - (vp->v_usecount == 0 && - vp->v_freelist.tqe_prev == (struct vnode **) 0xdeadb)) { + if ((flags & LK_INTERLOCK) == 0) { + simple_lock(&vp->v_interlock); + } + if (vp->v_flag & VXLOCK) { vp->v_flag |= VXWANT; - (void) tsleep((caddr_t) vp, PINOD, "vget", 0); - return (1); + simple_unlock(&vp->v_interlock); + tsleep((caddr_t)vp, PINOD, "vget", 0); + return (ENOENT); } if (vp->v_usecount == 0) { + simple_lock(&vnode_free_list_slock); TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); + simple_unlock(&vnode_free_list_slock); freevnodes--; } vp->v_usecount++; - /* * Create the VM object, if needed */ if ((vp->v_type == VREG) && ((vp->v_object == NULL) || (vp->v_object->flags & OBJ_VFS_REF) == 0)) { + /* + * XXX vfs_object_create probably needs the interlock. + */ + simple_unlock(&vp->v_interlock); vfs_object_create(vp, curproc, curproc->p_ucred, 0); + simple_lock(&vp->v_interlock); + } + if (flags & LK_TYPE_MASK) { + if (error = vn_lock(vp, flags | LK_INTERLOCK, p)) + vrele(vp); + return (error); } - if (lockflag) - VOP_LOCK(vp); + simple_unlock(&vp->v_interlock); + return (0); +} + +/* + * Stubs to use when there is no locking to be done on the underlying object. + * A minimal shared lock is necessary to ensure that the underlying object + * is not revoked while an operation is in progress. So, an active shared + * count is maintained in an auxillary vnode lock structure. + */ +int +vop_nolock(ap) + struct vop_lock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; +{ +#ifdef notyet + /* + * This code cannot be used until all the non-locking filesystems + * (notably NFS) are converted to properly lock and release nodes. + * 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. Note that the inactive + * and lookup operations also change their lock state, but this + * cannot be avoided, so these two operations will always need + * to be handled in intermediate layers. + */ + struct vnode *vp = ap->a_vp; + int vnflags, flags = ap->a_flags; + if (vp->v_vnlock == NULL) { + if ((flags & LK_TYPE_MASK) == LK_DRAIN) + return (0); + MALLOC(vp->v_vnlock, struct lock *, sizeof(struct lock), + M_VNODE, M_WAITOK); + lockinit(vp->v_vnlock, PVFS, "vnlock", 0, 0); + } + switch (flags & LK_TYPE_MASK) { + case LK_DRAIN: + vnflags = LK_DRAIN; + break; + case LK_EXCLUSIVE: + case LK_SHARED: + vnflags = LK_SHARED; + break; + case LK_UPGRADE: + case LK_EXCLUPGRADE: + case LK_DOWNGRADE: + return (0); + case LK_RELEASE: + default: + panic("vop_nolock: bad operation %d", flags & LK_TYPE_MASK); + } + if (flags & LK_INTERLOCK) + vnflags |= LK_INTERLOCK; + return(lockmgr(vp->v_vnlock, vnflags, &vp->v_interlock, ap->a_p)); +#else /* for now */ + /* + * Since we are not using the lock manager, we must clear + * the interlock here. + */ + if (ap->a_flags & LK_INTERLOCK) { + simple_unlock(&ap->a_vp->v_interlock); + } return (0); +#endif +} + +/* + * Decrement the active use count. + */ +int +vop_nounlock(ap) + struct vop_unlock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + if (vp->v_vnlock == NULL) + return (0); + return (lockmgr(vp->v_vnlock, LK_RELEASE, NULL, ap->a_p)); +} + +/* + * Return whether or not the node is in use. + */ +int +vop_noislocked(ap) + struct vop_islocked_args /* { + struct vnode *a_vp; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + if (vp->v_vnlock == NULL) + return (0); + return (lockstatus(vp->v_vnlock)); } +/* #ifdef DIAGNOSTIC */ /* * Vnode reference, just increment the count */ @@ -827,6 +1005,7 @@ void vref(vp) struct vnode *vp; { + simple_lock(&vp->v_interlock); if (vp->v_usecount <= 0) panic("vref used where vget required"); @@ -840,8 +1019,11 @@ vref(vp) * the object is created. This is necessary to * keep the system from re-entrantly doing it * multiple times. + * XXX vfs_object_create probably needs the interlock? */ + simple_unlock(&vp->v_interlock); vfs_object_create(vp, curproc, curproc->p_ucred, 0); + simple_lock(&vp->v_interlock); } } @@ -850,9 +1032,9 @@ vref(vp) */ void vput(vp) - register struct vnode *vp; + struct vnode *vp; { - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, curproc); vrele(vp); } @@ -862,33 +1044,38 @@ vput(vp) */ void vrele(vp) - register struct vnode *vp; + struct vnode *vp; { + struct proc *p = curproc; /* XXX */ #ifdef DIAGNOSTIC if (vp == NULL) panic("vrele: null vp"); #endif - + simple_lock(&vp->v_interlock); vp->v_usecount--; if ((vp->v_usecount == 1) && vp->v_object && (vp->v_object->flags & OBJ_VFS_REF)) { vp->v_object->flags &= ~OBJ_VFS_REF; + simple_unlock(&vp->v_interlock); vm_object_deallocate(vp->v_object); return; } - if (vp->v_usecount > 0) + if (vp->v_usecount > 0) { + simple_unlock(&vp->v_interlock); return; + } if (vp->v_usecount < 0) { #ifdef DIAGNOSTIC vprint("vrele: negative ref count", vp); #endif - panic("vrele: negative reference cnt"); + panic("vrele: negative ref cnt"); } + simple_lock(&vnode_free_list_slock); if (vp->v_flag & VAGE) { if(vp->v_tag != VT_TFS) TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); @@ -898,9 +1085,12 @@ vrele(vp) if(vp->v_tag != VT_TFS) TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist); } + simple_unlock(&vnode_free_list_slock); + freevnodes++; - VOP_INACTIVE(vp); + if (vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK, p) == 0) + VOP_INACTIVE(vp, p); } #ifdef DIAGNOSTIC @@ -912,7 +1102,9 @@ vhold(vp) register struct vnode *vp; { + simple_lock(&vp->v_interlock); vp->v_holdcnt++; + simple_unlock(&vp->v_interlock); } /* @@ -923,9 +1115,11 @@ holdrele(vp) register struct vnode *vp; { + simple_lock(&vp->v_interlock); if (vp->v_holdcnt <= 0) panic("holdrele: holdcnt"); vp->v_holdcnt--; + simple_unlock(&vp->v_interlock); } #endif /* DIAGNOSTIC */ @@ -948,11 +1142,11 @@ vflush(mp, skipvp, flags) struct vnode *skipvp; int flags; { - register struct vnode *vp, *nvp; + struct proc *p = curproc; /* XXX */ + struct vnode *vp, *nvp; int busy = 0; - if ((mp->mnt_flag & MNT_MPBUSY) == 0) - panic("vflush: not busy"); + simple_lock(&mntvnode_slock); loop: for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { /* @@ -967,24 +1161,34 @@ loop: */ if (vp == skipvp) continue; + + simple_lock(&vp->v_interlock); /* * Skip over a vnodes marked VSYSTEM. */ - if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) + if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) { + simple_unlock(&vp->v_interlock); continue; + } /* * If WRITECLOSE is set, only flush out regular file vnodes * open for writing. */ if ((flags & WRITECLOSE) && - (vp->v_writecount == 0 || vp->v_type != VREG)) + (vp->v_writecount == 0 || vp->v_type != VREG)) { + simple_unlock(&vp->v_interlock); continue; + } if (vp->v_object && (vp->v_object->flags & OBJ_VFS_REF)) { + simple_unlock(&vp->v_interlock); + simple_unlock(&mntvnode_slock); vm_object_reference(vp->v_object); pager_cache(vp->v_object, FALSE); vp->v_object->flags &= ~OBJ_VFS_REF; vm_object_deallocate(vp->v_object); + simple_lock(&mntvnode_slock); + simple_lock(&vp->v_interlock); } /* @@ -992,7 +1196,9 @@ loop: * vnode data structures and we are done. */ if (vp->v_usecount == 0) { - vgone(vp); + simple_unlock(&mntvnode_slock); + vgonel(vp, p); + simple_lock(&mntvnode_slock); continue; } @@ -1002,21 +1208,25 @@ loop: * all other files, just kill them. */ if (flags & FORCECLOSE) { + simple_unlock(&mntvnode_slock); if (vp->v_type != VBLK && vp->v_type != VCHR) { - vgone(vp); + vgonel(vp, p); } else { - vclean(vp, 0); + vclean(vp, 0, p); vp->v_op = spec_vnodeop_p; insmntque(vp, (struct mount *) 0); } + simple_lock(&mntvnode_slock); continue; } #ifdef DIAGNOSTIC if (busyprt) vprint("vflush: busy vnode", vp); #endif + simple_unlock(&vp->v_interlock); busy++; } + simple_unlock(&mntvnode_slock); if (busy) return (EBUSY); return (0); @@ -1025,8 +1235,8 @@ loop: /* * Disassociate the underlying file system from a vnode. */ -void -vclean(struct vnode *vp, int flags) +static void +vclean(struct vnode *vp, int flags, struct proc *p) { int active; @@ -1036,15 +1246,7 @@ vclean(struct vnode *vp, int flags) * generate a race against ourselves to recycle it. */ if ((active = vp->v_usecount)) - VREF(vp); - /* - * Even if the count is zero, the VOP_INACTIVE routine may still have - * the object locked while it cleans it out. The VOP_LOCK ensures that - * the VOP_INACTIVE routine is done with its work. For active vnodes, - * it ensures that no other activity can occur while the underlying - * object is being cleaned out. - */ - VOP_LOCK(vp); + vp->v_usecount++; /* * Prevent the vnode from being recycled or brought into use while we * clean it out. @@ -1053,31 +1255,48 @@ vclean(struct vnode *vp, int flags) panic("vclean: deadlock"); vp->v_flag |= VXLOCK; /* - * Clean out any buffers associated with the vnode. + * Even if the count is zero, the VOP_INACTIVE routine may still + * have the object locked while it cleans it out. The VOP_LOCK + * ensures that the VOP_INACTIVE routine is done with its work. + * For active vnodes, it ensures that no other activity can + * occur while the underlying object is being cleaned out. */ - if (flags & DOCLOSE) - vinvalbuf(vp, V_SAVE, NOCRED, NULL, 0, 0); + VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, p); /* - * Any other processes trying to obtain this lock must first wait for - * VXLOCK to clear, then call the new lock operation. + * Clean out any buffers associated with the vnode. */ - VOP_UNLOCK(vp); + if (flags & DOCLOSE) + vinvalbuf(vp, V_SAVE, NOCRED, p, 0, 0); /* - * If purging an active vnode, it must be closed and deactivated - * before being reclaimed. + * If purging an active vnode, it must be closed and + * deactivated before being reclaimed. Note that the + * VOP_INACTIVE will unlock the vnode. */ if (active) { if (flags & DOCLOSE) - VOP_CLOSE(vp, FNONBLOCK, NOCRED, NULL); - VOP_INACTIVE(vp); + VOP_CLOSE(vp, IO_NDELAY, NOCRED, p); + VOP_INACTIVE(vp, p); + } else { + /* + * Any other processes trying to obtain this lock must first + * wait for VXLOCK to clear, then call the new lock operation. + */ + VOP_UNLOCK(vp, 0, p); } /* * Reclaim the vnode. */ - if (VOP_RECLAIM(vp)) + if (VOP_RECLAIM(vp, p)) panic("vclean: cannot reclaim"); if (active) vrele(vp); + cache_purge(vp); + if (vp->v_vnlock) { + if ((vp->v_vnlock->lk_flags & LK_DRAINED) == 0) + vprint("vclean: lock not drained", vp); + FREE(vp->v_vnlock, M_VNODE); + vp->v_vnlock = NULL; + } /* * Done with purge, notify sleepers of the grim news. @@ -1092,46 +1311,91 @@ vclean(struct vnode *vp, int flags) } /* - * Eliminate all activity associated with the requested vnode + * Eliminate all activity associated with the requested vnode * and with all vnodes aliased to the requested vnode. */ -void -vgoneall(vp) - register struct vnode *vp; +int +vop_revoke(ap) + struct vop_revoke_args /* { + struct vnode *a_vp; + int a_flags; + } */ *ap; { - register struct vnode *vq; + struct vnode *vp, *vq; + struct proc *p = curproc; /* XXX */ + +#ifdef DIAGNOSTIC + if ((ap->a_flags & REVOKEALL) == 0) + panic("vop_revoke"); +#endif + + vp = ap->a_vp; + simple_lock(&vp->v_interlock); if (vp->v_flag & VALIASED) { /* - * If a vgone (or vclean) is already in progress, wait until - * it is done and return. + * If a vgone (or vclean) is already in progress, + * wait until it is done and return. */ if (vp->v_flag & VXLOCK) { vp->v_flag |= VXWANT; - (void) tsleep((caddr_t) vp, PINOD, "vgall", 0); - return; + simple_unlock(&vp->v_interlock); + tsleep((caddr_t)vp, PINOD, "vop_revokeall", 0); + return (0); } /* - * Ensure that vp will not be vgone'd while we are eliminating - * its aliases. + * Ensure that vp will not be vgone'd while we + * are eliminating its aliases. */ vp->v_flag |= VXLOCK; + simple_unlock(&vp->v_interlock); while (vp->v_flag & VALIASED) { + simple_lock(&spechash_slock); for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type || vp == vq) continue; + simple_unlock(&spechash_slock); vgone(vq); break; } + if (vq == NULLVP) { + simple_unlock(&spechash_slock); + } } /* - * Remove the lock so that vgone below will really eliminate - * the vnode after which time vgone will awaken any sleepers. + * Remove the lock so that vgone below will + * really eliminate the vnode after which time + * vgone will awaken any sleepers. */ + simple_lock(&vp->v_interlock); vp->v_flag &= ~VXLOCK; } - vgone(vp); + vgonel(vp, p); + return (0); +} + +/* + * Recycle an unused vnode to the front of the free list. + * Release the passed interlock if the vnode will be recycled. + */ +int +vrecycle(vp, inter_lkp, p) + struct vnode *vp; + struct simplelock *inter_lkp; + struct proc *p; +{ + + simple_lock(&vp->v_interlock); + if (vp->v_usecount == 0) { + if (inter_lkp) { + simple_unlock(inter_lkp); + } + vgonel(vp, p); + return (1); + } + simple_unlock(&vp->v_interlock); + return (0); } /* @@ -1142,16 +1406,31 @@ void vgone(vp) register struct vnode *vp; { - register struct vnode *vq; + struct proc *p = curproc; /* XXX */ + + simple_lock(&vp->v_interlock); + vgonel(vp, p); +} + +/* + * vgone, with the vp interlock held. + */ +void +vgonel(vp, p) + struct vnode *vp; + struct proc *p; +{ + struct vnode *vq; struct vnode *vx; /* - * If a vgone (or vclean) is already in progress, wait until it is - * done and return. + * If a vgone (or vclean) is already in progress, + * wait until it is done and return. */ if (vp->v_flag & VXLOCK) { vp->v_flag |= VXWANT; - (void) tsleep((caddr_t) vp, PINOD, "vgone", 0); + simple_unlock(&vp->v_interlock); + tsleep((caddr_t)vp, PINOD, "vgone", 0); return; } @@ -1162,18 +1441,18 @@ vgone(vp) /* * Clean out the filesystem specific data. */ - vclean(vp, DOCLOSE); + vclean(vp, DOCLOSE, p); /* * Delete from old mount point vnode list, if on one. */ - if (vp->v_mount != NULL) { - LIST_REMOVE(vp, v_mntvnodes); - vp->v_mount = NULL; - } + if (vp->v_mount != NULL) + insmntque(vp, (struct mount *)0); /* - * If special device, remove it from special device alias list. + * If special device, remove it from special device alias list + * if it is on one. */ - if (vp->v_type == VBLK || vp->v_type == VCHR) { + if ((vp->v_type == VBLK || vp->v_type == VCHR) && vp->v_specinfo != 0) { + simple_lock(&spechash_slock); if (*vp->v_hashchain == vp) { *vp->v_hashchain = vp->v_specnext; } else { @@ -1202,28 +1481,34 @@ vgone(vp) vx->v_flag &= ~VALIASED; vp->v_flag &= ~VALIASED; } + simple_unlock(&spechash_slock); FREE(vp->v_specinfo, M_VNODE); vp->v_specinfo = NULL; } + /* - * If it is on the freelist and not already at the head, move it to - * the head of the list. The test of the back pointer and the - * reference count of zero is because it will be removed from the free - * list by getnewvnode, but will not have its reference count - * incremented until after calling vgone. If the reference count were - * incremented first, vgone would (incorrectly) try to close the - * previous instance of the underlying object. So, the back pointer is - * explicitly set to `0xdeadb' in getnewvnode after removing it from - * the freelist to ensure that we do not try to move it here. + * If it is on the freelist and not already at the head, + * move it to the head of the list. The test of the back + * pointer and the reference count of zero is because + * it will be removed from the free list by getnewvnode, + * but will not have its reference count incremented until + * after calling vgone. If the reference count were + * incremented first, vgone would (incorrectly) try to + * close the previous instance of the underlying object. + * So, the back pointer is explicitly set to `0xdeadb' in + * getnewvnode after removing it from the freelist to ensure + * that we do not try to move it here. */ - if (vp->v_usecount == 0 && - vp->v_freelist.tqe_prev != (struct vnode **) 0xdeadb && - vnode_free_list.tqh_first != vp) { - if(vp->v_tag != VT_TFS) { + if (vp->v_usecount == 0) { + simple_lock(&vnode_free_list_slock); + if ((vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb) && + vnode_free_list.tqh_first != vp) { TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); } + simple_unlock(&vnode_free_list_slock); } + vp->v_type = VBAD; } @@ -1254,7 +1539,7 @@ int vcount(vp) register struct vnode *vp; { - register struct vnode *vq, *vnext; + struct vnode *vq, *vnext; int count; loop: @@ -1354,6 +1639,7 @@ int kinfo_vgetfailed; static int sysctl_vnode SYSCTL_HANDLER_ARGS { + struct proc *p = curproc; /* XXX */ register struct mount *mp, *nmp; struct vnode *vp; int error; @@ -1368,7 +1654,7 @@ sysctl_vnode SYSCTL_HANDLER_ARGS for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { nmp = mp->mnt_list.cqe_next; - if (vfs_busy(mp)) + if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) continue; again: for (vp = mp->mnt_vnodelist.lh_first; @@ -1386,11 +1672,11 @@ again: } if ((error = SYSCTL_OUT(req, &vp, VPTRSZ)) || (error = SYSCTL_OUT(req, vp, VNODESZ))) { - vfs_unbusy(mp); + vfs_unbusy(mp, p); return (error); } } - vfs_unbusy(mp); + vfs_unbusy(mp, p); } return (0); @@ -1404,22 +1690,63 @@ SYSCTL_PROC(_kern, KERN_VNODE, vnode, CTLTYPE_OPAQUE|CTLFLAG_RD, */ int vfs_mountedon(vp) - register struct vnode *vp; + struct vnode *vp; { - register struct vnode *vq; + struct vnode *vq; + int error = 0; if (vp->v_specflags & SI_MOUNTEDON) return (EBUSY); if (vp->v_flag & VALIASED) { + simple_lock(&spechash_slock); for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) continue; - if (vq->v_specflags & SI_MOUNTEDON) - return (EBUSY); + if (vq->v_specflags & SI_MOUNTEDON) { + error = EBUSY; + break; + } } + simple_unlock(&spechash_slock); + } + return (error); +} + +/* + * Unmount all filesystems. The list is traversed in reverse order + * of mounting to avoid dependencies. Should only be called by halt(). + */ +void +vfs_unmountall() +{ + struct mount *mp, *nmp, *rootfs = NULL; + int error; + + /* unmount all but rootfs */ + for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) { + nmp = mp->mnt_list.cqe_prev; + + if (mp->mnt_flag & MNT_ROOTFS) { + rootfs = mp; + continue; + } + error = dounmount(mp, MNT_FORCE, initproc); + if (error) { + printf("unmount of %s failed (", mp->mnt_stat.f_mntonname); + if (error == EBUSY) + printf("BUSY)\n"); + else + printf("%d)\n", error); + } + } + + /* and finally... */ + if (rootfs) { + vfs_unmountroot(rootfs); + } else { + printf("no root filesystem\n"); } - return (0); } /* @@ -1565,8 +1892,8 @@ vfs_export_lookup(mp, nep, nam) rnh = nep->ne_rtable[saddr->sa_family]; if (rnh != NULL) { np = (struct netcred *) - (*rnh->rnh_matchaddr) ((caddr_t) saddr, - rnh); + (*rnh->rnh_matchaddr)((caddr_t)saddr, + rnh); if (np && np->netc_rnodes->rn_flags & RNF_ROOT) np = NULL; } @@ -1580,7 +1907,6 @@ vfs_export_lookup(mp, nep, nam) return (np); } - /* * perform msync on all vnodes under a mount point * the mount point must be locked. @@ -1639,10 +1965,10 @@ retry: } else { if (object->flags & OBJ_DEAD) { if (waslocked) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); tsleep(object, PVM, "vodead", 0); if (waslocked) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); goto retry; } if ((object->flags & OBJ_VFS_REF) == 0) { diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index 22e16d84..83b6dec 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -50,6 +50,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/sysent.h> #include <sys/sysproto.h> #include <sys/namei.h> #include <sys/filedesc.h> @@ -64,9 +65,11 @@ #include <sys/malloc.h> #include <sys/dirent.h> +/* see if this is needed XXX JH #ifdef UNION #include <miscfs/union/union.h> #endif +*/ #include <vm/vm.h> #include <vm/vm_param.h> @@ -74,7 +77,8 @@ #include <vm/vm_extern.h> #include <sys/sysctl.h> -static int change_dir __P((struct nameidata *ndp, struct proc *p)); +static int change_dir __P((struct nameidata *ndp, struct proc *p)); +static void checkdirs __P((struct vnode *olddp)); /* * Virtual File System System Calls @@ -85,7 +89,7 @@ static int change_dir __P((struct nameidata *ndp, struct proc *p)); */ #ifndef _SYS_SYSPROTO_H_ struct mount_args { - int type; + char *type; char *path; int flags; caddr_t data; @@ -95,29 +99,32 @@ struct mount_args { int mount(p, uap, retval) struct proc *p; - register struct mount_args *uap; - int *retval; + register struct mount_args /* { + syscallarg(char *) type; + syscallarg(char *) path; + syscallarg(int) flags; + syscallarg(caddr_t) data; + } */ *uap; + register_t *retval; { - register struct vnode *vp; - register struct mount *mp; + struct vnode *vp; + struct mount *mp; + struct vfsconf *vfsp; int error, flag = 0; + struct vattr va; + u_long fstypenum; struct nameidata nd; + char fstypename[MFSNAMELEN]; /* - * Must be super user - */ - error = suser(p->p_ucred, &p->p_acflag); - if (error) - return (error); - /* * Get vnode to be covered */ - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - if (uap->flags & MNT_UPDATE) { + if (SCARG(uap, flags) & MNT_UPDATE) { if ((vp->v_flag & VROOT) == 0) { vput(vp); return (EINVAL); @@ -128,68 +135,135 @@ mount(p, uap, retval) * We only allow the filesystem to be reloaded if it * is currently mounted read-only. */ - if ((uap->flags & MNT_RELOAD) && + if ((SCARG(uap, flags) & MNT_RELOAD) && ((mp->mnt_flag & MNT_RDONLY) == 0)) { vput(vp); return (EOPNOTSUPP); /* Needs translation */ } mp->mnt_flag |= - uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); - VOP_UNLOCK(vp); + SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); + /* + * Only root, or the user that did the original mount is + * permitted to update it. + */ + if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && + (error = suser(p->p_ucred, &p->p_acflag))) { + vput(vp); + return (error); + } + /* + * Do not allow NFS export by non-root users. Silently + * enforce MNT_NOSUID and MNT_NODEV for non-root users. + */ + if (p->p_ucred->cr_uid != 0) { + if (SCARG(uap, flags) & MNT_EXPORTED) { + vput(vp); + return (EPERM); + } + SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; + } + if (vfs_busy(mp, LK_NOWAIT, 0, p)) { + vput(vp); + return (EBUSY); + } + VOP_UNLOCK(vp, 0, p); goto update; } - error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0); - if (error) + /* + * If the user is not root, ensure that they own the directory + * onto which we are attempting to mount. + */ + if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || + (va.va_uid != p->p_ucred->cr_uid && + (error = suser(p->p_ucred, &p->p_acflag)))) { + vput(vp); + return (error); + } + /* + * Do not allow NFS export by non-root users. Silently + * enforce MNT_NOSUID and MNT_NODEV for non-root users. + */ + if (p->p_ucred->cr_uid != 0) { + if (SCARG(uap, flags) & MNT_EXPORTED) { + vput(vp); + return (EPERM); + } + SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; + } + if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) return (error); if (vp->v_type != VDIR) { vput(vp); return (ENOTDIR); } - if ((u_long)uap->type > MOUNT_MAXTYPE || vfssw[uap->type] == NULL) { - vput(vp); - return (ENODEV); - } - +#ifdef COMPAT_43 /* - * Allocate and initialize the file system. + * Historically filesystem types were identified by number. If we + * get an integer for the filesystem type instead of a string, we + * check to see if it matches one of the historic filesystem types. */ - mp = (struct mount *)malloc((u_long)sizeof(struct mount), - M_MOUNT, M_WAITOK); - bzero((char *)mp, (u_long)sizeof(struct mount)); - mp->mnt_op = vfssw[uap->type]; - mp->mnt_vfc = vfsconf[uap->type]; - error = vfs_lock(mp); - if (error) { - free((caddr_t)mp, M_MOUNT); + fstypenum = (u_long)SCARG(uap, type); + if (fstypenum < maxvfsconf) { + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) + if (vfsp->vfc_typenum == fstypenum) + break; + if (vfsp == NULL) { + vput(vp); + return (ENODEV); + } + strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); + } else +#endif /* COMPAT_43 */ + if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) { vput(vp); return (error); } + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) + if (!strcmp(vfsp->vfc_name, fstypename)) + break; + if (vfsp == NULL) { + vput(vp); + return (ENODEV); + } if (vp->v_mountedhere != NULL) { - vfs_unlock(mp); - free((caddr_t)mp, M_MOUNT); vput(vp); return (EBUSY); } + + /* + * Allocate and initialize the filesystem. + */ + mp = (struct mount *)malloc((u_long)sizeof(struct mount), + M_MOUNT, M_WAITOK); + bzero((char *)mp, (u_long)sizeof(struct mount)); + lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); + (void)vfs_busy(mp, LK_NOWAIT, 0, p); + mp->mnt_op = vfsp->vfc_vfsops; + mp->mnt_vfc = vfsp; + vfsp->vfc_refcount++; + mp->mnt_stat.f_type = vfsp->vfc_typenum; + mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; + strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); vp->v_mountedhere = mp; mp->mnt_vnodecovered = vp; - vfsconf[uap->type]->vfc_refcount++; - + mp->mnt_stat.f_owner = p->p_ucred->cr_uid; update: /* * Set the mount level flags. */ - if (uap->flags & MNT_RDONLY) + if (SCARG(uap, flags) & MNT_RDONLY) mp->mnt_flag |= MNT_RDONLY; else if (mp->mnt_flag & MNT_RDONLY) mp->mnt_flag |= MNT_WANTRDWR; mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME); - mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | - MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE | MNT_NOATIME); + mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | + MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE | + MNT_NOATIME); /* * Mount the filesystem. */ - error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p); + error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); if (mp->mnt_flag & MNT_UPDATE) { vrele(vp); if (mp->mnt_flag & MNT_WANTRDWR) @@ -198,6 +272,7 @@ update: (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); if (error) mp->mnt_flag = flag; + vfs_unbusy(mp, p); return (error); } /* @@ -205,23 +280,63 @@ update: */ cache_purge(vp); if (!error) { + simple_lock(&mountlist_slock); CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); - VOP_UNLOCK(vp); - vfs_unlock(mp); - error = VFS_START(mp, 0, p); - if (error) + simple_unlock(&mountlist_slock); + checkdirs(vp); + VOP_UNLOCK(vp, 0, p); + vfs_unbusy(mp, p); + if (error = VFS_START(mp, 0, p)) vrele(vp); } else { mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; - vfs_unlock(mp); + mp->mnt_vfc->vfc_refcount--; + vfs_unbusy(mp, p); free((caddr_t)mp, M_MOUNT); vput(vp); - vfsconf[uap->type]->vfc_refcount--; } return (error); } /* + * Scan all active processes to see if any of them have a current + * or root directory onto which the new filesystem has just been + * mounted. If so, replace them with the new mount point. + */ +static void +checkdirs(olddp) + struct vnode *olddp; +{ + struct filedesc *fdp; + struct vnode *newdp; + struct proc *p; + + if (olddp->v_usecount == 1) + return; + if (VFS_ROOT(olddp->v_mountedhere, &newdp)) + panic("mount: lost mount"); + for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { + fdp = p->p_fd; + if (fdp->fd_cdir == olddp) { + vrele(fdp->fd_cdir); + VREF(newdp); + fdp->fd_cdir = newdp; + } + if (fdp->fd_rdir == olddp) { + vrele(fdp->fd_rdir); + VREF(newdp); + fdp->fd_rdir = newdp; + } + } + if (rootvnode == olddp) { + vrele(rootvnode); + VREF(newdp); + rootvnode = newdp; + } + vput(newdp); +} + +/* * Unmount a file system. * * Note: unmount takes a path to the vnode mounted on as argument, @@ -237,47 +352,51 @@ struct unmount_args { int unmount(p, uap, retval) struct proc *p; - register struct unmount_args *uap; - int *retval; + register struct unmount_args /* { + syscallarg(char *) path; + syscallarg(int) flags; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct mount *mp; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; + mp = vp->v_mount; /* - * Unless this is a user mount, then must - * have suser privilege. + * Only root, or the user that did the original mount is + * permitted to unmount this filesystem. */ - if (((vp->v_mount->mnt_flag & MNT_USER) == 0) && + if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && (error = suser(p->p_ucred, &p->p_acflag))) { vput(vp); return (error); } /* - * Must be the root of the filesystem + * Don't allow unmounting the root file system. */ - if ((vp->v_flag & VROOT) == 0) { + if (mp->mnt_flag & MNT_ROOTFS) { vput(vp); return (EINVAL); } - mp = vp->v_mount; - vput(vp); /* - * Don't allow unmount of the root filesystem + * Must be the root of the filesystem */ - if (mp->mnt_flag & MNT_ROOTFS) + if ((vp->v_flag & VROOT) == 0) { + vput(vp); return (EINVAL); - - return (dounmount(mp, uap->flags, p)); + } + vput(vp); + return (dounmount(mp, SCARG(uap, flags), p)); } /* @@ -292,74 +411,86 @@ dounmount(mp, flags, p) struct vnode *coveredvp; int error; - coveredvp = mp->mnt_vnodecovered; - if (vfs_busy(mp)) - return (EBUSY); + simple_lock(&mountlist_slock); mp->mnt_flag |= MNT_UNMOUNT; - error = vfs_lock(mp); - if (error) - return (error); - + lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p); mp->mnt_flag &=~ MNT_ASYNC; vfs_msync(mp, MNT_NOWAIT); vnode_pager_umount(mp); /* release cached vnodes */ cache_purgevfs(mp); /* remove cache entries for this file sys */ - if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || + if (((mp->mnt_flag & MNT_RDONLY) || + (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) || (flags & MNT_FORCE)) error = VFS_UNMOUNT(mp, flags, p); - mp->mnt_flag &= ~MNT_UNMOUNT; - vfs_unbusy(mp); + simple_lock(&mountlist_slock); if (error) { - vfs_unlock(mp); - } else { + mp->mnt_flag &= ~MNT_UNMOUNT; + lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE, + &mountlist_slock, p); + return (error); + } + CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); + if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) { + coveredvp->v_mountedhere = (struct mount *)0; vrele(coveredvp); - CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); - mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; - vfs_unlock(mp); - mp->mnt_vfc->vfc_refcount--; - if (mp->mnt_vnodelist.lh_first != NULL) - panic("unmount: dangling vnode"); - free((caddr_t)mp, M_MOUNT); } - return (error); + mp->mnt_vfc->vfc_refcount--; + if (mp->mnt_vnodelist.lh_first != NULL) + panic("unmount: dangling vnode"); + lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p); + if (mp->mnt_flag & MNT_MWAIT) + wakeup((caddr_t)mp); + free((caddr_t)mp, M_MOUNT); + return (0); } /* * Sync each mounted filesystem. */ - #ifndef _SYS_SYSPROTO_H_ struct sync_args { int dummy; }; #endif +#ifdef DEBUG +int syncprt = 0; +SYSCTL_INT(_debug, 0, syncprt, CTLFLAG_RW, &syncprt, 0, ""); +#endif + /* ARGSUSED */ int sync(p, uap, retval) struct proc *p; struct sync_args *uap; - int *retval; + register_t *retval; { - register struct mount *mp; + register struct mount *mp, *nmp; int asyncflag; - for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = mp->mnt_list.cqe_next) { - /* - * The lock check below is to avoid races with mount - * and unmount. - */ - if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && - !vfs_busy(mp)) { + simple_lock(&mountlist_slock); + for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { + if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { + nmp = mp->mnt_list.cqe_next; + continue; + } + if ((mp->mnt_flag & MNT_RDONLY) == 0) { asyncflag = mp->mnt_flag & MNT_ASYNC; mp->mnt_flag &= ~MNT_ASYNC; vfs_msync(mp, MNT_NOWAIT); VFS_SYNC(mp, MNT_NOWAIT, p != NULL ? p->p_ucred : NOCRED, p); if (asyncflag) mp->mnt_flag |= MNT_ASYNC; - vfs_unbusy(mp); } + simple_lock(&mountlist_slock); + nmp = mp->mnt_list.cqe_next; + vfs_unbusy(mp, p); } + simple_unlock(&mountlist_slock); +#ifdef DIAGNOSTIC + if (syncprt) + vfs_bufstats(); +#endif /* DIAGNOSTIC */ return (0); } @@ -378,20 +509,25 @@ struct quotactl_args { int quotactl(p, uap, retval) struct proc *p; - register struct quotactl_args *uap; - int *retval; + register struct quotactl_args /* { + syscallarg(char *) path; + syscallarg(int) cmd; + syscallarg(int) uid; + syscallarg(caddr_t) arg; + } */ *uap; + register_t *retval; { register struct mount *mp; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); mp = nd.ni_vp->v_mount; vrele(nd.ni_vp); - return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); + return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), + SCARG(uap, arg), p)); } /* @@ -407,17 +543,19 @@ struct statfs_args { int statfs(p, uap, retval) struct proc *p; - register struct statfs_args *uap; - int *retval; + register struct statfs_args /* { + syscallarg(char *) path; + syscallarg(struct statfs *) buf; + } */ *uap; + register_t *retval; { register struct mount *mp; register struct statfs *sp; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); mp = nd.ni_vp->v_mount; sp = &mp->mnt_stat; @@ -426,7 +564,7 @@ statfs(p, uap, retval) if (error) return (error); sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); + return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); } /* @@ -442,16 +580,18 @@ struct fstatfs_args { int fstatfs(p, uap, retval) struct proc *p; - register struct fstatfs_args *uap; - int *retval; + register struct fstatfs_args /* { + syscallarg(int) fd; + syscallarg(struct statfs *) buf; + } */ *uap; + register_t *retval; { struct file *fp; struct mount *mp; register struct statfs *sp; int error; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); mp = ((struct vnode *)fp->f_data)->v_mount; sp = &mp->mnt_stat; @@ -459,7 +599,7 @@ fstatfs(p, uap, retval) if (error) return (error); sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); + return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); } /* @@ -475,48 +615,55 @@ struct getfsstat_args { int getfsstat(p, uap, retval) struct proc *p; - register struct getfsstat_args *uap; - int *retval; + register struct getfsstat_args /* { + syscallarg(struct statfs *) buf; + syscallarg(long) bufsize; + syscallarg(int) flags; + } */ *uap; + register_t *retval; { register struct mount *mp, *nmp; register struct statfs *sp; caddr_t sfsp; long count, maxcount, error; - maxcount = uap->bufsize / sizeof(struct statfs); - sfsp = (caddr_t)uap->buf; + maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); + sfsp = (caddr_t)SCARG(uap, buf); count = 0; + simple_lock(&mountlist_slock); for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { - if (vfs_busy(mp)) { + if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { nmp = mp->mnt_list.cqe_next; continue; } - if (sfsp && count < maxcount && - ((mp->mnt_flag & MNT_MLOCK) == 0)) { + if (sfsp && count < maxcount) { sp = &mp->mnt_stat; /* * If MNT_NOWAIT is specified, do not refresh the * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. */ - if (((uap->flags & MNT_NOWAIT) == 0 || - (uap->flags & MNT_WAIT)) && + if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 || + (SCARG(uap, flags) & MNT_WAIT)) && (error = VFS_STATFS(mp, sp, p))) { + simple_lock(&mountlist_slock); nmp = mp->mnt_list.cqe_next; - vfs_unbusy(mp); + vfs_unbusy(mp, p); continue; } sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; error = copyout((caddr_t)sp, sfsp, sizeof(*sp)); if (error) { - vfs_unbusy(mp); + vfs_unbusy(mp, p); return (error); } sfsp += sizeof(*sp); } count++; + simple_lock(&mountlist_slock); nmp = mp->mnt_list.cqe_next; - vfs_unbusy(mp); + vfs_unbusy(mp, p); } + simple_unlock(&mountlist_slock); if (sfsp && count > maxcount) *retval = maxcount; else @@ -536,27 +683,41 @@ struct fchdir_args { int fchdir(p, uap, retval) struct proc *p; - struct fchdir_args *uap; - int *retval; + struct fchdir_args /* { + syscallarg(int) fd; + } */ *uap; + register_t *retval; { register struct filedesc *fdp = p->p_fd; - register struct vnode *vp; + struct vnode *vp, *tdp; + struct mount *mp; struct file *fp; int error; - error = getvnode(fdp, uap->fd, &fp); - if (error) + if (error = getvnode(fdp, SCARG(uap, fd), &fp)) return (error); vp = (struct vnode *)fp->f_data; - VOP_LOCK(vp); + VREF(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (vp->v_type != VDIR) error = ENOTDIR; else error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); - VOP_UNLOCK(vp); - if (error) + while (!error && (mp = vp->v_mountedhere) != NULL) { + if (vfs_busy(mp, 0, 0, p)) + continue; + error = VFS_ROOT(mp, &tdp); + vfs_unbusy(mp, p); + if (error) + break; + vput(vp); + vp = tdp; + } + if (error) { + vput(vp); return (error); - VREF(vp); + } + VOP_UNLOCK(vp, 0, p); vrele(fdp->fd_cdir); fdp->fd_cdir = vp; return (0); @@ -574,16 +735,18 @@ struct chdir_args { int chdir(p, uap, retval) struct proc *p; - struct chdir_args *uap; - int *retval; + struct chdir_args /* { + syscallarg(char *) path; + } */ *uap; + register_t *retval; { register struct filedesc *fdp = p->p_fd; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = change_dir(&nd, p); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = change_dir(&nd, p)) return (error); vrele(fdp->fd_cdir); fdp->fd_cdir = nd.ni_vp; @@ -602,8 +765,10 @@ struct chroot_args { int chroot(p, uap, retval) struct proc *p; - struct chroot_args *uap; - int *retval; + struct chroot_args /* { + syscallarg(char *) path; + } */ *uap; + register_t *retval; { register struct filedesc *fdp = p->p_fd; int error; @@ -612,9 +777,9 @@ chroot(p, uap, retval) error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = change_dir(&nd, p); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = change_dir(&nd, p)) return (error); if (fdp->fd_rdir != NULL) vrele(fdp->fd_rdir); @@ -641,9 +806,10 @@ change_dir(ndp, p) error = ENOTDIR; else error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); - VOP_UNLOCK(vp); if (error) - vrele(vp); + vput(vp); + else + VOP_UNLOCK(vp, 0, p); return (error); } @@ -661,8 +827,12 @@ struct open_args { int open(p, uap, retval) struct proc *p; - register struct open_args *uap; - int *retval; + register struct open_args /* { + syscallarg(char *) path; + syscallarg(int) flags; + syscallarg(int) mode; + } */ *uap; + register_t *retval; { register struct filedesc *fdp = p->p_fd; register struct file *fp; @@ -677,17 +847,17 @@ open(p, uap, retval) if (error) return (error); fp = nfp; - flags = FFLAGS(uap->flags); - cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); + flags = FFLAGS(SCARG(uap, flags)); + cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); p->p_dupfd = -indx - 1; /* XXX check for fdopen */ error = vn_open(&nd, flags, cmode); if (error) { ffree(fp); if ((error == ENODEV || error == ENXIO) && - p->p_dupfd >= 0 && /* XXX from fdopen */ + p->p_dupfd >= 0 && /* XXX from fdopen */ (error = - dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { + dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { *retval = indx; return (0); } @@ -714,18 +884,17 @@ open(p, uap, retval) type = F_FLOCK; if ((flags & FNONBLOCK) == 0) type |= F_WAIT; - VOP_UNLOCK(vp); - error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); - if (error) { + VOP_UNLOCK(vp, 0, p); + if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { (void) vn_close(vp, fp->f_flag, fp->f_cred, p); ffree(fp); fdp->fd_ofiles[indx] = NULL; return (error); } - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); fp->f_flag |= FHASLOCK; } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); *retval = indx; return (0); } @@ -743,15 +912,22 @@ struct ocreat_args { int ocreat(p, uap, retval) struct proc *p; - register struct ocreat_args *uap; - int *retval; + register struct ocreat_args /* { + syscallarg(char *) path; + syscallarg(int) mode; + } */ *uap; + register_t *retval; { - struct open_args openuap; - - openuap.path = uap->path; - openuap.mode = uap->mode; - openuap.flags = O_WRONLY | O_CREAT | O_TRUNC; - return (open(p, &openuap, retval)); + struct open_args /* { + syscallarg(char *) path; + syscallarg(int) flags; + syscallarg(int) mode; + } */ nuap; + + SCARG(&nuap, path) = SCARG(uap, path); + SCARG(&nuap, mode) = SCARG(uap, mode); + SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; + return (open(p, &nuap, retval)); } #endif /* COMPAT_43 */ @@ -769,30 +945,35 @@ struct mknod_args { int mknod(p, uap, retval) struct proc *p; - register struct mknod_args *uap; - int *retval; + register struct mknod_args /* { + syscallarg(char *) path; + syscallarg(int) mode; + syscallarg(int) dev; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; int error; + int whiteout; struct nameidata nd; error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; if (vp != NULL) error = EEXIST; else { VATTR_NULL(&vattr); - vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; - vattr.va_rdev = uap->dev; + vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; + vattr.va_rdev = SCARG(uap, dev); + whiteout = 0; - switch (uap->mode & S_IFMT) { + switch (SCARG(uap, mode) & S_IFMT) { case S_IFMT: /* used by badsect to flag bad sectors */ vattr.va_type = VBAD; break; @@ -802,14 +983,25 @@ mknod(p, uap, retval) case S_IFBLK: vattr.va_type = VBLK; break; + case S_IFWHT: + whiteout = 1; + break; default: error = EINVAL; break; } } if (!error) { - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + if (whiteout) { + error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); + if (error) + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + vput(nd.ni_dvp); + } else { + error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, + &nd.ni_cnd, &vattr); + } } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == vp) @@ -823,7 +1015,7 @@ mknod(p, uap, retval) } /* - * Create named pipe. + * Create a named pipe. */ #ifndef _SYS_SYSPROTO_H_ struct mkfifo_args { @@ -835,16 +1027,21 @@ struct mkfifo_args { int mkfifo(p, uap, retval) struct proc *p; - register struct mkfifo_args *uap; - int *retval; + register struct mkfifo_args /* { + syscallarg(char *) path; + syscallarg(int) mode; + } */ *uap; + register_t *retval; { +#ifndef FIFO + return (EOPNOTSUPP); +#else struct vattr vattr; int error; struct nameidata nd; - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); if (nd.ni_vp != NULL) { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -857,9 +1054,10 @@ mkfifo(p, uap, retval) } VATTR_NULL(&vattr); vattr.va_type = VFIFO; - vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); +#endif /* FIFO */ } /* @@ -875,22 +1073,24 @@ struct link_args { int link(p, uap, retval) struct proc *p; - register struct link_args *uap; - int *retval; + register struct link_args /* { + syscallarg(char *) path; + syscallarg(char *) link; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct nameidata nd; int error; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; if (vp->v_type == VDIR) error = EPERM; /* POSIX */ else { - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); error = namei(&nd); if (!error) { if (nd.ni_vp != NULL) { @@ -903,10 +1103,9 @@ link(p, uap, retval) vrele(nd.ni_vp); error = EEXIST; } else { - LEASE_CHECK(nd.ni_dvp, - p, p->p_ucred, LEASE_WRITE); - LEASE_CHECK(vp, - p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, + LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); } } @@ -928,8 +1127,11 @@ struct symlink_args { int symlink(p, uap, retval) struct proc *p; - register struct symlink_args *uap; - int *retval; + register struct symlink_args /* { + syscallarg(char *) path; + syscallarg(char *) link; + } */ *uap; + register_t *retval; { struct vattr vattr; char *path; @@ -937,12 +1139,10 @@ symlink(p, uap, retval) struct nameidata nd; MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); - error = copyinstr(uap->path, path, MAXPATHLEN, NULL); - if (error) + if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) goto out; - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); - error = namei(&nd); - if (error) + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); + if (error = namei(&nd)) goto out; if (nd.ni_vp) { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -956,7 +1156,7 @@ symlink(p, uap, retval) } VATTR_NULL(&vattr); vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); out: FREE(path, M_NAMEI); @@ -964,6 +1164,45 @@ out: } /* + * Delete a whiteout from the filesystem. + */ +/* ARGSUSED */ +int +undelete(p, uap, retval) + struct proc *p; + register struct undelete_args /* { + syscallarg(char *) path; + } */ *uap; + register_t *retval; +{ + int error; + struct nameidata nd; + + NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, + SCARG(uap, path), p); + error = namei(&nd); + if (error) + return (error); + + if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + if (nd.ni_vp) + vrele(nd.ni_vp); + return (EEXIST); + } + + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + vput(nd.ni_dvp); + return (error); +} + +/* * Delete a name from the filesystem. */ #ifndef _SYS_SYSPROTO_H_ @@ -975,20 +1214,21 @@ struct unlink_args { int unlink(p, uap, retval) struct proc *p; - struct unlink_args *uap; - int *retval; + struct unlink_args /* { + syscallarg(char *) path; + } */ *uap; + register_t *retval; { register struct vnode *vp; int error; struct nameidata nd; - NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (vp->v_type == VDIR) error = EPERM; /* POSIX */ @@ -1001,11 +1241,11 @@ unlink(p, uap, retval) if (vp->v_flag & VROOT) error = EBUSY; else - (void) vnode_pager_uncache(vp); + (void) vnode_pager_uncache(vp, p); } if (!error) { - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -1013,7 +1253,8 @@ unlink(p, uap, retval) vrele(nd.ni_dvp); else vput(nd.ni_dvp); - vput(vp); + if (vp != NULLVP) + vput(vp); } return (error); } @@ -1032,8 +1273,13 @@ struct lseek_args { int lseek(p, uap, retval) struct proc *p; - register struct lseek_args *uap; - int *retval; + register struct lseek_args /* { + syscallarg(int) fd; + syscallarg(int) pad; + syscallarg(off_t) offset; + syscallarg(int) whence; + } */ *uap; + register_t *retval; /* XXX */ { struct ucred *cred = p->p_ucred; register struct filedesc *fdp = p->p_fd; @@ -1041,23 +1287,23 @@ lseek(p, uap, retval) struct vattr vattr; int error; - if ((u_int)uap->fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[uap->fd]) == NULL) + if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || + (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) return (EBADF); if (fp->f_type != DTYPE_VNODE) return (ESPIPE); - switch (uap->whence) { + switch (SCARG(uap, whence)) { case L_INCR: - fp->f_offset += uap->offset; + fp->f_offset += SCARG(uap, offset); break; case L_XTND: error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p); if (error) return (error); - fp->f_offset = uap->offset + vattr.va_size; + fp->f_offset = SCARG(uap, offset) + vattr.va_size; break; case L_SET: - fp->f_offset = uap->offset; + fp->f_offset = SCARG(uap, offset); break; default: return (EINVAL); @@ -1080,17 +1326,26 @@ struct olseek_args { int olseek(p, uap, retval) struct proc *p; - register struct olseek_args *uap; - int *retval; + register struct olseek_args /* { + syscallarg(int) fd; + syscallarg(long) offset; + syscallarg(int) whence; + } */ *uap; + register_t *retval; { - struct lseek_args nuap; + struct lseek_args /* { + syscallarg(int) fd; + syscallarg(int) pad; + syscallarg(off_t) offset; + syscallarg(int) whence; + } */ nuap; off_t qret; int error; - nuap.fd = uap->fd; - nuap.offset = uap->offset; - nuap.whence = uap->whence; - error = lseek(p, &nuap, (int *)&qret); + SCARG(&nuap, fd) = SCARG(uap, fd); + SCARG(&nuap, offset) = SCARG(uap, offset); + SCARG(&nuap, whence) = SCARG(uap, whence); + error = lseek(p, &nuap, (register_t *) &qret); *(long *)retval = qret; return (error); } @@ -1108,8 +1363,11 @@ struct access_args { int access(p, uap, retval) struct proc *p; - register struct access_args *uap; - int *retval; + register struct access_args /* { + syscallarg(char *) path; + syscallarg(int) flags; + } */ *uap; + register_t *retval; { register struct ucred *cred = p->p_ucred; register struct vnode *vp; @@ -1120,20 +1378,20 @@ access(p, uap, retval) t_gid = cred->cr_groups[0]; cred->cr_uid = p->p_cred->p_ruid; cred->cr_groups[0] = p->p_cred->p_rgid; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) goto out1; vp = nd.ni_vp; /* Flags == 0 means only check for existence. */ - if (uap->flags) { + if (SCARG(uap, flags)) { flags = 0; - if (uap->flags & R_OK) + if (SCARG(uap, flags) & R_OK) flags |= VREAD; - if (uap->flags & W_OK) + if (SCARG(uap, flags) & W_OK) flags |= VWRITE; - if (uap->flags & X_OK) + if (SCARG(uap, flags) & X_OK) flags |= VEXEC; if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) error = VOP_ACCESS(vp, flags, cred, p); @@ -1159,24 +1417,27 @@ struct ostat_args { int ostat(p, uap, retval) struct proc *p; - register struct ostat_args *uap; - int *retval; + register struct ostat_args /* { + syscallarg(char *) path; + syscallarg(struct ostat *) ub; + } */ *uap; + register_t *retval; { struct stat sb; struct ostat osb; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); error = vn_stat(nd.ni_vp, &sb, p); vput(nd.ni_vp); if (error) return (error); cvtstat(&sb, &osb); - error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); + error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); return (error); } @@ -1193,8 +1454,11 @@ struct olstat_args { int olstat(p, uap, retval) struct proc *p; - register struct olstat_args *uap; - int *retval; + register struct olstat_args /* { + syscallarg(char *) path; + syscallarg(struct ostat *) ub; + } */ *uap; + register_t *retval; { struct vnode *vp, *dvp; struct stat sb, sb1; @@ -1203,9 +1467,8 @@ olstat(p, uap, retval) struct nameidata nd; NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, - uap->path, p); - error = namei(&nd); - if (error) + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); /* * For symbolic links, always return the attributes of its @@ -1240,7 +1503,7 @@ olstat(p, uap, retval) sb.st_blocks = sb1.st_blocks; } cvtstat(&sb, &osb); - error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); + error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); return (error); } @@ -1287,22 +1550,25 @@ struct stat_args { int stat(p, uap, retval) struct proc *p; - register struct stat_args *uap; - int *retval; + register struct stat_args /* { + syscallarg(char *) path; + syscallarg(struct stat *) ub; + } */ *uap; + register_t *retval; { struct stat sb; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); error = vn_stat(nd.ni_vp, &sb, p); vput(nd.ni_vp); if (error) return (error); - error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); + error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); return (error); } @@ -1319,8 +1585,11 @@ struct lstat_args { int lstat(p, uap, retval) struct proc *p; - register struct lstat_args *uap; - int *retval; + register struct lstat_args /* { + syscallarg(char *) path; + syscallarg(struct stat *) ub; + } */ *uap; + register_t *retval; { int error; struct vnode *vp, *dvp; @@ -1328,13 +1597,12 @@ lstat(p, uap, retval) struct nameidata nd; NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, - uap->path, p); - error = namei(&nd); - if (error) + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); /* - * For symbolic links, always return the attributes of its - * containing directory, except for mode, size, and links. + * For symbolic links, always return the attributes of its containing + * directory, except for mode, size, inode number, and links. */ vp = nd.ni_vp; dvp = nd.ni_dvp; @@ -1363,8 +1631,9 @@ lstat(p, uap, retval) sb.st_nlink = sb1.st_nlink; sb.st_size = sb1.st_size; sb.st_blocks = sb1.st_blocks; + sb.st_ino = sb1.st_ino; } - error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); + error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); return (error); } @@ -1381,17 +1650,20 @@ struct pathconf_args { int pathconf(p, uap, retval) struct proc *p; - register struct pathconf_args *uap; - int *retval; + register struct pathconf_args /* { + syscallarg(char *) path; + syscallarg(int) name; + } */ *uap; + register_t *retval; { int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); - error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); + error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); vput(nd.ni_vp); return (error); } @@ -1410,8 +1682,12 @@ struct readlink_args { int readlink(p, uap, retval) struct proc *p; - register struct readlink_args *uap; - int *retval; + register struct readlink_args /* { + syscallarg(char *) path; + syscallarg(char *) buf; + syscallarg(int) count; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct iovec aiov; @@ -1419,27 +1695,27 @@ readlink(p, uap, retval) int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; if (vp->v_type != VLNK) error = EINVAL; else { - aiov.iov_base = uap->buf; - aiov.iov_len = uap->count; + aiov.iov_base = SCARG(uap, buf); + aiov.iov_len = SCARG(uap, count); auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = 0; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_USERSPACE; auio.uio_procp = p; - auio.uio_resid = uap->count; + auio.uio_resid = SCARG(uap, count); error = VOP_READLINK(vp, &auio, p->p_ucred); } vput(vp); - *retval = uap->count - auio.uio_resid; + *retval = SCARG(uap, count) - auio.uio_resid; return (error); } @@ -1456,23 +1732,25 @@ struct chflags_args { int chflags(p, uap, retval) struct proc *p; - register struct chflags_args *uap; - int *retval; + register struct chflags_args /* { + syscallarg(char *) path; + syscallarg(int) flags; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); VATTR_NULL(&vattr); - vattr.va_flags = uap->flags; + vattr.va_flags = SCARG(uap, flags); error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); vput(vp); return (error); @@ -1491,24 +1769,26 @@ struct fchflags_args { int fchflags(p, uap, retval) struct proc *p; - register struct fchflags_args *uap; - int *retval; + register struct fchflags_args /* { + syscallarg(int) fd; + syscallarg(int) flags; + } */ *uap; + register_t *retval; { struct vattr vattr; struct vnode *vp; struct file *fp; int error; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); vp = (struct vnode *)fp->f_data; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); VATTR_NULL(&vattr); - vattr.va_flags = uap->flags; + vattr.va_flags = SCARG(uap, flags); error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1525,23 +1805,25 @@ struct chmod_args { int chmod(p, uap, retval) struct proc *p; - register struct chmod_args *uap; - int *retval; + register struct chmod_args /* { + syscallarg(char *) path; + syscallarg(int) mode; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); VATTR_NULL(&vattr); - vattr.va_mode = uap->mode & ALLPERMS; + vattr.va_mode = SCARG(uap, mode) & ALLPERMS; error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); vput(vp); return (error); @@ -1560,24 +1842,26 @@ struct fchmod_args { int fchmod(p, uap, retval) struct proc *p; - register struct fchmod_args *uap; - int *retval; + register struct fchmod_args /* { + syscallarg(int) fd; + syscallarg(int) mode; + } */ *uap; + register_t *retval; { struct vattr vattr; struct vnode *vp; struct file *fp; int error; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); vp = (struct vnode *)fp->f_data; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); VATTR_NULL(&vattr); - vattr.va_mode = uap->mode & ALLPERMS; + vattr.va_mode = SCARG(uap, mode) & ALLPERMS; error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1595,24 +1879,27 @@ struct chown_args { int chown(p, uap, retval) struct proc *p; - register struct chown_args *uap; - int *retval; + register struct chown_args /* { + syscallarg(char *) path; + syscallarg(int) uid; + syscallarg(int) gid; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); VATTR_NULL(&vattr); - vattr.va_uid = uap->uid; - vattr.va_gid = uap->gid; + vattr.va_uid = SCARG(uap, uid); + vattr.va_gid = SCARG(uap, gid); error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); vput(vp); return (error); @@ -1632,25 +1919,28 @@ struct fchown_args { int fchown(p, uap, retval) struct proc *p; - register struct fchown_args *uap; - int *retval; + register struct fchown_args /* { + syscallarg(int) fd; + syscallarg(int) uid; + syscallarg(int) gid; + } */ *uap; + register_t *retval; { struct vattr vattr; struct vnode *vp; struct file *fp; int error; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); vp = (struct vnode *)fp->f_data; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); VATTR_NULL(&vattr); - vattr.va_uid = uap->uid; - vattr.va_gid = uap->gid; + vattr.va_uid = SCARG(uap, uid); + vattr.va_gid = SCARG(uap, gid); error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1667,8 +1957,11 @@ struct utimes_args { int utimes(p, uap, retval) struct proc *p; - register struct utimes_args *uap; - int *retval; + register struct utimes_args /* { + syscallarg(char *) path; + syscallarg(struct timeval *) tptr; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct timeval tv[2]; @@ -1677,22 +1970,19 @@ utimes(p, uap, retval) struct nameidata nd; VATTR_NULL(&vattr); - if (uap->tptr == NULL) { + if (SCARG(uap, tptr) == NULL) { microtime(&tv[0]); tv[1] = tv[0]; vattr.va_vaflags |= VA_UTIMES_NULL; - } else { - error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); - if (error) - return (error); - } - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, + sizeof (tv))) + return (error); + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); vattr.va_atime.tv_sec = tv[0].tv_sec; vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; vattr.va_mtime.tv_sec = tv[1].tv_sec; @@ -1716,8 +2006,12 @@ struct truncate_args { int truncate(p, uap, retval) struct proc *p; - register struct truncate_args *uap; - int *retval; + register struct truncate_args /* { + syscallarg(char *) path; + syscallarg(int) pad; + syscallarg(off_t) length; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; @@ -1726,19 +2020,18 @@ truncate(p, uap, retval) if (uap->length < 0) return(EINVAL); - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (vp->v_type == VDIR) error = EISDIR; else if ((error = vn_writechk(vp)) == 0 && (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { VATTR_NULL(&vattr); - vattr.va_size = uap->length; + vattr.va_size = SCARG(uap, length); error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } vput(vp); @@ -1759,8 +2052,12 @@ struct ftruncate_args { int ftruncate(p, uap, retval) struct proc *p; - register struct ftruncate_args *uap; - int *retval; + register struct ftruncate_args /* { + syscallarg(int) fd; + syscallarg(int) pad; + syscallarg(off_t) length; + } */ *uap; + register_t *retval; { struct vattr vattr; struct vnode *vp; @@ -1769,22 +2066,21 @@ ftruncate(p, uap, retval) if (uap->length < 0) return(EINVAL); - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); if ((fp->f_flag & FWRITE) == 0) return (EINVAL); vp = (struct vnode *)fp->f_data; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (vp->v_type == VDIR) error = EISDIR; else if ((error = vn_writechk(vp)) == 0) { VATTR_NULL(&vattr); - vattr.va_size = uap->length; + vattr.va_size = SCARG(uap, length); error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1802,13 +2098,20 @@ struct otruncate_args { int otruncate(p, uap, retval) struct proc *p; - register struct otruncate_args *uap; - int *retval; + register struct otruncate_args /* { + syscallarg(char *) path; + syscallarg(long) length; + } */ *uap; + register_t *retval; { - struct truncate_args nuap; - - nuap.path = uap->path; - nuap.length = uap->length; + struct truncate_args /* { + syscallarg(char *) path; + syscallarg(int) pad; + syscallarg(off_t) length; + } */ nuap; + + SCARG(&nuap, path) = SCARG(uap, path); + SCARG(&nuap, length) = SCARG(uap, length); return (truncate(p, &nuap, retval)); } @@ -1825,13 +2128,20 @@ struct oftruncate_args { int oftruncate(p, uap, retval) struct proc *p; - register struct oftruncate_args *uap; - int *retval; + register struct oftruncate_args /* { + syscallarg(int) fd; + syscallarg(long) length; + } */ *uap; + register_t *retval; { - struct ftruncate_args nuap; - - nuap.fd = uap->fd; - nuap.length = uap->length; + struct ftruncate_args /* { + syscallarg(int) fd; + syscallarg(int) pad; + syscallarg(off_t) length; + } */ nuap; + + SCARG(&nuap, fd) = SCARG(uap, fd); + SCARG(&nuap, length) = SCARG(uap, length); return (ftruncate(p, &nuap, retval)); } #endif /* COMPAT_43 || COMPAT_SUNOS */ @@ -1848,24 +2158,25 @@ struct fsync_args { int fsync(p, uap, retval) struct proc *p; - struct fsync_args *uap; - int *retval; + struct fsync_args /* { + syscallarg(int) fd; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct file *fp; int error; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); vp = (struct vnode *)fp->f_data; - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (vp->v_object) { vm_object_page_clean(vp->v_object, 0, 0 ,0, FALSE); } error = VOP_FSYNC(vp, fp->f_cred, (vp->v_mount->mnt_flag & MNT_ASYNC) ? MNT_NOWAIT : MNT_WAIT, p); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1883,29 +2194,29 @@ struct rename_args { int rename(p, uap, retval) struct proc *p; - register struct rename_args *uap; - int *retval; + register struct rename_args /* { + syscallarg(char *) from; + syscallarg(char *) to; + } */ *uap; + register_t *retval; { register struct vnode *tvp, *fvp, *tdvp; struct nameidata fromnd, tond; int error; NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, - uap->from, p); - error = namei(&fromnd); - if (error) + SCARG(uap, from), p); + if (error = namei(&fromnd)) return (error); fvp = fromnd.ni_vp; NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, - UIO_USERSPACE, uap->to, p); + UIO_USERSPACE, SCARG(uap, to), p); if (fromnd.ni_vp->v_type == VDIR) tond.ni_cnd.cn_flags |= WILLBEDIR; - error = namei(&tond); - if (error) { + if (error = namei(&tond)) { /* Translate error code for rename("dir1", "dir2/."). */ if (error == EISDIR && fvp->v_type == VDIR) error = EINVAL; - VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); vrele(fromnd.ni_dvp); vrele(fvp); @@ -1936,13 +2247,12 @@ rename(p, uap, retval) error = -1; out: if (!error) { - LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); - if (fromnd.ni_dvp != tdvp) { - LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - } + VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); + if (fromnd.ni_dvp != tdvp) + VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); if (tvp) { - LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); - (void) vnode_pager_uncache(tvp); + VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); + (void) vnode_pager_uncache(tvp, p); } error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); @@ -1982,18 +2292,20 @@ struct mkdir_args { int mkdir(p, uap, retval) struct proc *p; - register struct mkdir_args *uap; - int *retval; + register struct mkdir_args /* { + syscallarg(char *) path; + syscallarg(int) mode; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); nd.ni_cnd.cn_flags |= WILLBEDIR; - error = namei(&nd); - if (error) + if (error = namei(&nd)) return (error); vp = nd.ni_vp; if (vp != NULL) { @@ -2007,8 +2319,8 @@ mkdir(p, uap, retval) } VATTR_NULL(&vattr); vattr.va_type = VDIR; - vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); if (!error) vput(nd.ni_vp); @@ -2027,16 +2339,18 @@ struct rmdir_args { int rmdir(p, uap, retval) struct proc *p; - struct rmdir_args *uap; - int *retval; + struct rmdir_args /* { + syscallarg(char *) path; + } */ *uap; + register_t *retval; { register struct vnode *vp; int error; struct nameidata nd; - NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; if (vp->v_type != VDIR) { @@ -2057,8 +2371,8 @@ rmdir(p, uap, retval) error = EBUSY; out: if (!error) { - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -2086,8 +2400,13 @@ struct ogetdirentries_args { int ogetdirentries(p, uap, retval) struct proc *p; - register struct ogetdirentries_args *uap; - int *retval; + register struct ogetdirentries_args /* { + syscallarg(int) fd; + syscallarg(char *) buf; + syscallarg(u_int) count; + syscallarg(long *) basep; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct file *fp; @@ -2095,30 +2414,31 @@ ogetdirentries(p, uap, retval) struct iovec aiov, kiov; struct dirent *dp, *edp; caddr_t dirbuf; - int error, readcnt; + int error, eofflag, readcnt; long loff; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); if ((fp->f_flag & FREAD) == 0) return (EBADF); vp = (struct vnode *)fp->f_data; +unionread: if (vp->v_type != VDIR) return (EINVAL); - aiov.iov_base = uap->buf; - aiov.iov_len = uap->count; + aiov.iov_base = SCARG(uap, buf); + aiov.iov_len = SCARG(uap, count); auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_USERSPACE; auio.uio_procp = p; - auio.uio_resid = uap->count; - VOP_LOCK(vp); + auio.uio_resid = SCARG(uap, count); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); loff = auio.uio_offset = fp->f_offset; # if (BYTE_ORDER != LITTLE_ENDIAN) if (vp->v_mount->mnt_maxsymlinklen <= 0) { - error = VOP_READDIR(vp, &auio, fp->f_cred, NULL, NULL, NULL); + error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, + NULL, NULL); fp->f_offset = auio.uio_offset; } else # endif @@ -2126,13 +2446,14 @@ ogetdirentries(p, uap, retval) kuio = auio; kuio.uio_iov = &kiov; kuio.uio_segflg = UIO_SYSSPACE; - kiov.iov_len = uap->count; - MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); + kiov.iov_len = SCARG(uap, count); + MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); kiov.iov_base = dirbuf; - error = VOP_READDIR(vp, &kuio, fp->f_cred, NULL, NULL, NULL); + error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, + NULL, NULL); fp->f_offset = kuio.uio_offset; if (error == 0) { - readcnt = uap->count - kuio.uio_resid; + readcnt = SCARG(uap, count) - kuio.uio_resid; edp = (struct dirent *)&dirbuf[readcnt]; for (dp = (struct dirent *)dirbuf; dp < edp; ) { # if (BYTE_ORDER == LITTLE_ENDIAN) @@ -2165,14 +2486,70 @@ ogetdirentries(p, uap, retval) } FREE(dirbuf, M_TEMP); } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); if (error) return (error); - error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); - *retval = uap->count - auio.uio_resid; + +#ifdef UNION +{ + extern int (**union_vnodeop_p)(); + extern struct vnode *union_dircache __P((struct vnode*, struct proc*)); + + if ((SCARG(uap, count) == auio.uio_resid) && + (vp->v_op == union_vnodeop_p)) { + struct vnode *lvp; + + lvp = union_dircache(vp, p); + if (lvp != NULLVP) { + struct vattr va; + + /* + * If the directory is opaque, + * then don't show lower entries + */ + error = VOP_GETATTR(vp, &va, fp->f_cred, p); + if (va.va_flags & OPAQUE) { + vput(lvp); + lvp = NULL; + } + } + + if (lvp != NULLVP) { + error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); + if (error) { + vput(lvp); + return (error); + } + VOP_UNLOCK(lvp, 0, p); + fp->f_data = (caddr_t) lvp; + fp->f_offset = 0; + error = vn_close(vp, FREAD, fp->f_cred, p); + if (error) + return (error); + vp = lvp; + goto unionread; + } + } +} +#endif /* UNION */ + + if ((SCARG(uap, count) == auio.uio_resid) && + (vp->v_flag & VROOT) && + (vp->v_mount->mnt_flag & MNT_UNION)) { + struct vnode *tvp = vp; + vp = vp->v_mount->mnt_vnodecovered; + VREF(vp); + fp->f_data = (caddr_t) vp; + fp->f_offset = 0; + vrele(tvp); + goto unionread; + } + error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), + sizeof(long)); + *retval = SCARG(uap, count) - auio.uio_resid; return (error); } -#endif +#endif /* COMPAT_43 */ /* * Read a block of directory entries in a file system independent format. @@ -2188,18 +2565,22 @@ struct getdirentries_args { int getdirentries(p, uap, retval) struct proc *p; - register struct getdirentries_args *uap; - int *retval; + register struct getdirentries_args /* { + syscallarg(int) fd; + syscallarg(char *) buf; + syscallarg(u_int) count; + syscallarg(long *) basep; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct file *fp; struct uio auio; struct iovec aiov; long loff; - int error; + int error, eofflag; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); if ((fp->f_flag & FREAD) == 0) return (EBADF); @@ -2207,51 +2588,66 @@ getdirentries(p, uap, retval) unionread: if (vp->v_type != VDIR) return (EINVAL); - aiov.iov_base = uap->buf; - aiov.iov_len = uap->count; + aiov.iov_base = SCARG(uap, buf); + aiov.iov_len = SCARG(uap, count); auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_USERSPACE; auio.uio_procp = p; - auio.uio_resid = uap->count; - VOP_LOCK(vp); + auio.uio_resid = SCARG(uap, count); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); loff = auio.uio_offset = fp->f_offset; - error = VOP_READDIR(vp, &auio, fp->f_cred, NULL, NULL, NULL); + error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL); fp->f_offset = auio.uio_offset; - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); if (error) return (error); #ifdef UNION { - if ((uap->count == auio.uio_resid) && + extern int (**union_vnodeop_p)(); + extern struct vnode *union_dircache __P((struct vnode*, struct proc*)); + + if ((SCARG(uap, count) == auio.uio_resid) && (vp->v_op == union_vnodeop_p)) { - struct vnode *tvp = vp; + struct vnode *lvp; + + lvp = union_dircache(vp, p); + if (lvp != NULLVP) { + struct vattr va; - vp = union_lowervp(vp); - if (vp != NULLVP) { - VOP_LOCK(vp); - error = VOP_OPEN(vp, FREAD, fp->f_cred, p); - VOP_UNLOCK(vp); + /* + * If the directory is opaque, + * then don't show lower entries + */ + error = VOP_GETATTR(vp, &va, fp->f_cred, p); + if (va.va_flags & OPAQUE) { + vput(lvp); + lvp = NULL; + } + } + if (lvp != NULLVP) { + error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); if (error) { - vrele(vp); + vput(lvp); return (error); } - fp->f_data = (caddr_t) vp; + VOP_UNLOCK(lvp, 0, p); + fp->f_data = (caddr_t) lvp; fp->f_offset = 0; - error = vn_close(tvp, FREAD, fp->f_cred, p); + error = vn_close(vp, FREAD, fp->f_cred, p); if (error) return (error); + vp = lvp; goto unionread; } } } -#endif +#endif /* UNION */ - if ((uap->count == auio.uio_resid) && - vp && + if ((SCARG(uap, count) == auio.uio_resid) && (vp->v_flag & VROOT) && (vp->v_mount->mnt_flag & MNT_UNION)) { struct vnode *tvp = vp; @@ -2262,8 +2658,9 @@ unionread: vrele(tvp); goto unionread; } - error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); - *retval = uap->count - auio.uio_resid; + error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), + sizeof(long)); + *retval = SCARG(uap, count) - auio.uio_resid; return (error); } @@ -2275,17 +2672,19 @@ struct umask_args { int newmask; }; #endif -mode_t /* XXX */ +int umask(p, uap, retval) struct proc *p; - struct umask_args *uap; - int *retval; + struct umask_args /* { + syscallarg(int) newmask; + } */ *uap; + int *retval; /* XXX */ { register struct filedesc *fdp; fdp = p->p_fd; *retval = fdp->fd_cmask; - fdp->fd_cmask = uap->newmask & ALLPERMS; + fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; return (0); } @@ -2302,31 +2701,27 @@ struct revoke_args { int revoke(p, uap, retval) struct proc *p; - register struct revoke_args *uap; - int *retval; + register struct revoke_args /* { + syscallarg(char *) path; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - if (vp->v_type != VCHR && vp->v_type != VBLK) { - error = EINVAL; - goto out; - } - error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); - if (error) + if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) goto out; if (p->p_ucred->cr_uid != vattr.va_uid && (error = suser(p->p_ucred, &p->p_acflag))) goto out; if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) - vgoneall(vp); + VOP_REVOKE(vp, REVOKEALL); out: vrele(vp); return (error); diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c index f4e96e4..161ff0c 100644 --- a/sys/kern/vfs_init.c +++ b/sys/kern/vfs_init.c @@ -76,8 +76,6 @@ extern struct linker_set vfs_opv_descs_; #define vfs_opv_descs ((struct vnodeopv_desc **)vfs_opv_descs_.ls_items) extern struct linker_set vfs_set; -struct vfsops *vfssw[MOUNT_MAXTYPE + 1]; -struct vfsconf *vfsconf[MOUNT_MAXTYPE + 1]; extern struct vnodeop_desc *vfs_op_descs[]; /* and the operations they perform */ @@ -239,23 +237,8 @@ static void vfsinit(dummy) void *dummy; { - struct vfsops **vfsp; struct vfsconf **vfc; - int i; - - /* - * Initialize the VFS switch table - */ - for(i = 0; i < MOUNT_MAXTYPE + 1; i++) { - vfsconf[i] = &void_vfsconf; - } - - vfc = (struct vfsconf **)vfs_set.ls_items; - while(*vfc) { - vfssw[(**vfc).vfc_index] = (**vfc).vfc_vfsops; - vfsconf[(**vfc).vfc_index] = *vfc; - vfc++; - } + int maxtypenum; /* * Initialize the vnode table @@ -274,11 +257,20 @@ vfsinit(dummy) * Initialize each file system type. */ vattr_null(&va_null); - for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { - if (*vfsp == NULL) - continue; - (*(*vfsp)->vfs_init)(); + maxtypenum = 0; + vfc = (struct vfsconf **)vfs_set.ls_items; + vfsconf = *vfc; /* simulate Lite2 vfsconf array */ + while (*vfc) { + struct vfsconf *vfsp = *vfc; + + vfc++; + vfsp->vfc_next = *vfc; + if (maxtypenum <= vfsp->vfc_typenum) + maxtypenum = vfsp->vfc_typenum + 1; + (*vfsp->vfc_vfsops->vfs_init)(vfsp); } + /* next vfc_typenum to be used */ + maxvfsconf = maxtypenum; } /* @@ -286,29 +278,81 @@ vfsinit(dummy) */ static int -sysctl_vfs_vfsconf SYSCTL_HANDLER_ARGS +sysctl_vfs_conf SYSCTL_HANDLER_ARGS { - int i, error; + int error; + struct vfsconf *vfsp; if (req->newptr) return EINVAL; - for(i = 0; i < MOUNT_MAXTYPE + 1; i++) { - error = SYSCTL_OUT(req, vfsconf[i], sizeof *vfsconf[i]); - if(error) + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) { + error = SYSCTL_OUT(req, vfsp, sizeof *vfsp); + if (error) return error; } - return (error); - + return 0; } SYSCTL_PROC(_vfs, VFS_VFSCONF, vfsconf, CTLTYPE_OPAQUE|CTLFLAG_RD, - 0, 0, sysctl_vfs_vfsconf, "S,vfsconf", ""); + 0, 0, sysctl_vfs_conf, "S,vfsconf", ""); + +#ifdef COMPAT_PRELITE2 + +#define OVFS_MAXNAMELEN 32 +struct ovfsconf { + void *vfc_vfsops; + char vfc_name[OVFS_MAXNAMELEN]; + int vfc_index; + int vfc_refcount; + int vfc_flags; +}; + +static int +sysctl_ovfs_conf SYSCTL_HANDLER_ARGS +{ + int error; + struct vfsconf *vfsp; + + if (req->newptr) + return EINVAL; + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) { + struct ovfsconf ovfs; + ovfs.vfc_vfsops = NULL; + strcpy(ovfs.vfc_name, vfsp->vfc_name); + ovfs.vfc_index = vfsp->vfc_typenum; + ovfs.vfc_refcount = vfsp->vfc_refcount; + ovfs.vfc_flags = vfsp->vfc_flags; + error = SYSCTL_OUT(req, &ovfs, sizeof ovfs); + if (error) + return error; + } + return 0; +} + +SYSCTL_PROC(_vfs, VFS_OVFSCONF, ovfsconf, CTLTYPE_OPAQUE|CTLFLAG_RD, + 0, 0, sysctl_ovfs_conf, "S,ovfsconf", ""); + +#endif /* COMPAT_PRELITE2 */ /* * This goop is here to support a loadable NFS module... grumble... */ -void (*lease_check) __P((struct vnode *, struct proc *, struct ucred *, int)) +int (*lease_check_hook) __P((struct vop_lease_args *)) = 0; void (*lease_updatetime) __P((int)) = 0; +int +lease_check(ap) + struct vop_lease_args /* { + struct vnode *a_vp; + struct proc *a_p; + struct ucred *a_cred; + int a_flag; + } */ *ap; +{ + if (lease_check_hook) + return (*lease_check_hook)(ap); + else + return 0; +} diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 1cadfd0..120821d 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -88,6 +88,7 @@ namei(ndp) struct uio auio; int error, linklen; struct componentname *cnp = &ndp->ni_cnd; + struct proc *p = cnp->cn_proc; ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred; #ifdef DIAGNOSTIC @@ -169,7 +170,7 @@ namei(ndp) return (0); } if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) - VOP_UNLOCK(ndp->ni_dvp); + VOP_UNLOCK(ndp->ni_dvp, 0, p); if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { error = ELOOP; break; @@ -269,6 +270,7 @@ lookup(ndp) int trailing_slash; int error = 0; struct componentname *cnp = &ndp->ni_cnd; + struct proc *p = cnp->cn_proc; /* * Setup: break out flag bits into variables. @@ -283,7 +285,7 @@ lookup(ndp) cnp->cn_flags &= ~ISSYMLINK; dp = ndp->ni_startdir; ndp->ni_startdir = NULLVP; - VOP_LOCK(dp); + vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); dirloop: /* @@ -351,21 +353,21 @@ dirloop: * e.g. like "/." or ".". */ if (cnp->cn_nameptr[0] == '\0') { - if (cnp->cn_nameiop != LOOKUP) { - error = EISDIR; - goto bad; - } if (dp->v_type != VDIR) { error = ENOTDIR; goto bad; } + if (cnp->cn_nameiop != LOOKUP) { + error = EISDIR; + goto bad; + } if (wantparent) { ndp->ni_dvp = dp; VREF(dp); } ndp->ni_vp = dp; if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) - VOP_UNLOCK(dp); + VOP_UNLOCK(dp, 0, p); if (cnp->cn_flags & SAVESTART) panic("lookup: SAVESTART"); return (0); @@ -396,7 +398,7 @@ dirloop: dp = dp->v_mount->mnt_vnodecovered; vput(tdp); VREF(dp); - VOP_LOCK(dp); + vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); } } @@ -405,8 +407,8 @@ dirloop: */ unionlookup: ndp->ni_dvp = dp; - error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp); - if (error) { + ndp->ni_vp = NULL; + if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) { #ifdef DIAGNOSTIC if (ndp->ni_vp != NULL) panic("leaf should be empty"); @@ -421,7 +423,7 @@ unionlookup: dp = dp->v_mount->mnt_vnodecovered; vput(tdp); VREF(dp); - VOP_LOCK(dp); + vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); goto unionlookup; } @@ -474,12 +476,10 @@ unionlookup: */ while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && (cnp->cn_flags & NOCROSSMOUNT) == 0) { - if (mp->mnt_flag & MNT_MLOCK) { - mp->mnt_flag |= MNT_MWAIT; - (void) tsleep((caddr_t)mp, PVFS, "lookup", 0); + if (vfs_busy(mp, 0, 0, p)) continue; - } - error = VFS_ROOT(dp->v_mountedhere, &tdp); + error = VFS_ROOT(mp, &tdp); + vfs_unbusy(mp, p); if (error) goto bad2; vput(dp); @@ -533,12 +533,12 @@ nextname: if (!wantparent) vrele(ndp->ni_dvp); if ((cnp->cn_flags & LOCKLEAF) == 0) - VOP_UNLOCK(dp); + VOP_UNLOCK(dp, 0, p); return (0); bad2: if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0') - VOP_UNLOCK(ndp->ni_dvp); + VOP_UNLOCK(ndp->ni_dvp, 0, p); vrele(ndp->ni_dvp); bad: vput(dp); @@ -555,7 +555,8 @@ relookup(dvp, vpp, cnp) struct vnode *dvp, **vpp; struct componentname *cnp; { - register struct vnode *dp = 0; /* the directory we are searching */ + struct proc *p = cnp->cn_proc; + struct vnode *dp = 0; /* the directory we are searching */ int docache; /* == 0 do not cache last component */ int wantparent; /* 1 => wantparent or lockparent flag */ int rdonly; /* lookup read-only flag bit */ @@ -576,7 +577,7 @@ relookup(dvp, vpp, cnp) rdonly = cnp->cn_flags & RDONLY; cnp->cn_flags &= ~ISSYMLINK; dp = dvp; - VOP_LOCK(dp); + vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); /* dirloop: */ /* @@ -615,7 +616,7 @@ relookup(dvp, vpp, cnp) goto bad; } if (!(cnp->cn_flags & LOCKLEAF)) - VOP_UNLOCK(dp); + VOP_UNLOCK(dp, 0, p); *vpp = dp; if (cnp->cn_flags & SAVESTART) panic("lookup: SAVESTART"); @@ -628,8 +629,7 @@ relookup(dvp, vpp, cnp) /* * We now have a segment name to search for, and a directory to search. */ - error = VOP_LOOKUP(dp, vpp, cnp); - if (error) { + if (error = VOP_LOOKUP(dp, vpp, cnp)) { #ifdef DIAGNOSTIC if (*vpp != NULL) panic("leaf should be empty"); @@ -675,16 +675,16 @@ relookup(dvp, vpp, cnp) /* ASSERT(dvp == ndp->ni_startdir) */ if (cnp->cn_flags & SAVESTART) VREF(dvp); - + if (!wantparent) vrele(dvp); if ((cnp->cn_flags & LOCKLEAF) == 0) - VOP_UNLOCK(dp); + VOP_UNLOCK(dp, 0, p); return (0); bad2: if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); vrele(dvp); bad: vput(dp); diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index fb8061b..5a84570 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1993 + * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. * Copyright (c) 1995 Artisoft, Inc. All Rights Reserved. * @@ -61,26 +61,33 @@ /* * GLOBALS */ -int (*mountroot) __P((void *)); + +/* + * These define the root filesystem, device, and root filesystem type. + */ +struct mount *rootfs; struct vnode *rootvnode; -struct vfsops *mountrootvfsops; +char *mountrootfsname; +/* + * vfs_init() will set maxvfsconf + * to the highest defined type number. + */ +int maxvfsconf; +struct vfsconf *vfsconf; /* * Common root mount code shared by all filesystems */ -#define ROOTDIR "/" #define ROOTNAME "root_device" - - /* - * vfs_mountroot + * vfs_mountrootfs * * Common entry point for root mounts * * PARAMETERS: - * data pointer to the vfs_ops for the FS type mounting + * fsname name of the filesystem * * RETURNS: 0 Success * !0 error number (errno.h) @@ -97,67 +104,44 @@ struct vfsops *mountrootvfsops; * fixing the other file systems, not this code! */ int -vfs_mountroot(data) - void *data; +vfs_mountrootfs(fsname) + char *fsname; { struct mount *mp; - u_int size; int err = 0; struct proc *p = curproc; /* XXX */ - struct vfsops *mnt_op = (struct vfsops *)data; /* * New root mount structure */ - mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); - bzero((char *)mp, (u_long)sizeof(struct mount)); - mp->mnt_op = mnt_op; - mp->mnt_flag = MNT_ROOTFS; - mp->mnt_vnodecovered = NULLVP; - - /* - * Lock mount point - */ - if( ( err = vfs_lock(mp)) != 0) - goto error_1; - - /* Save "last mounted on" info for mount point (NULL pad)*/ - copystr( ROOTDIR, /* mount point*/ - mp->mnt_stat.f_mntonname, /* save area*/ - MNAMELEN - 1, /* max size*/ - &size); /* real size*/ - bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size); - - /* Save "mounted from" info for mount point (NULL pad)*/ - copystr( ROOTNAME, /* device name*/ - mp->mnt_stat.f_mntfromname, /* save area*/ - MNAMELEN - 1, /* max size*/ - &size); /* real size*/ - bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); + err = vfs_rootmountalloc(fsname, ROOTNAME, &mp); + if (err) + return (err); + mp->mnt_flag |= MNT_ROOTFS; /* * Attempt the mount */ - err = VFS_MOUNT( mp, NULL, NULL, NULL, p); - if( err) + err = VFS_MOUNT(mp, NULL, NULL, NULL, p); + if (err) goto error_2; + simple_lock(&mountlist_slock); /* Add fs to list of mounted file systems*/ - CIRCLEQ_INSERT_TAIL( &mountlist, mp, mnt_list); + CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); + simple_unlock(&mountlist_slock); - /* Unlock mount point*/ - vfs_unlock(mp); + vfs_unbusy(mp, p); /* root mount, update system time from FS specific data*/ - inittodr( mp->mnt_time); + inittodr(mp->mnt_time); goto success; error_2: /* mount error*/ - /* unlock before failing*/ - vfs_unlock( mp); + vfs_unbusy(mp, p); error_1: /* lock error*/ diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 43f8669..0dea7bd 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)vfs_subr.c 8.13 (Berkeley) 4/18/94 + * @(#)vfs_subr.c 8.31 (Berkeley) 5/26/95 * $FreeBSD$ */ @@ -75,7 +75,9 @@ #ifdef DDB extern void printlockedvnodes __P((void)); #endif -extern void vclean __P((struct vnode *vp, int flags)); +static void vclean __P((struct vnode *vp, int flags, struct proc *p)); +extern void vgonel __P((struct vnode *vp, struct proc *p)); +unsigned long numvnodes; extern void vfs_unmountroot __P((struct mount *rootfs)); enum vtype iftovt_tab[16] = { @@ -91,15 +93,19 @@ int vttoif_tab[9] = { * Insq/Remq for the vnode usage lists. */ #define bufinsvn(bp, dp) LIST_INSERT_HEAD(dp, bp, b_vnbufs) -#define bufremvn(bp) { \ - LIST_REMOVE(bp, b_vnbufs); \ - (bp)->b_vnbufs.le_next = NOLIST; \ +#define bufremvn(bp) { \ + LIST_REMOVE(bp, b_vnbufs); \ + (bp)->b_vnbufs.le_next = NOLIST; \ } - TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */ static u_long freevnodes = 0; struct mntlist mountlist; /* mounted filesystem list */ +struct simplelock mountlist_slock; +static struct simplelock mntid_slock; +struct simplelock mntvnode_slock; +struct simplelock vnode_free_list_slock; +static struct simplelock spechash_slock; int desiredvnodes; SYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RW, &desiredvnodes, 0, ""); @@ -117,164 +123,153 @@ vntblinit() { desiredvnodes = maxproc + vm_object_cache_max; + simple_lock_init(&mntvnode_slock); + simple_lock_init(&mntid_slock); + simple_lock_init(&spechash_slock); TAILQ_INIT(&vnode_free_list); + simple_lock_init(&vnode_free_list_slock); CIRCLEQ_INIT(&mountlist); } /* - * Lock a filesystem. - * Used to prevent access to it while mounting and unmounting. + * Mark a mount point as busy. Used to synchronize access and to delay + * unmounting. Interlock is not released on failure. */ int -vfs_lock(mp) - register struct mount *mp; +vfs_busy(mp, flags, interlkp, p) + struct mount *mp; + int flags; + struct simplelock *interlkp; + struct proc *p; { + int lkflags; - while (mp->mnt_flag & MNT_MLOCK) { + if (mp->mnt_flag & MNT_UNMOUNT) { + if (flags & LK_NOWAIT) + return (ENOENT); mp->mnt_flag |= MNT_MWAIT; - (void) tsleep((caddr_t) mp, PVFS, "vfslck", 0); + if (interlkp) { + simple_unlock(interlkp); + } + /* + * Since all busy locks are shared except the exclusive + * lock granted when unmounting, the only place that a + * wakeup needs to be done is at the release of the + * exclusive lock at the end of dounmount. + */ + tsleep((caddr_t)mp, PVFS, "vfs_busy", 0); + if (interlkp) { + simple_lock(interlkp); + } + return (ENOENT); } - mp->mnt_flag |= MNT_MLOCK; + lkflags = LK_SHARED; + if (interlkp) + lkflags |= LK_INTERLOCK; + if (lockmgr(&mp->mnt_lock, lkflags, interlkp, p)) + panic("vfs_busy: unexpected lock failure"); return (0); } /* - * Unlock a locked filesystem. - * Panic if filesystem is not locked. + * Free a busy filesystem. */ void -vfs_unlock(mp) - register struct mount *mp; +vfs_unbusy(mp, p) + struct mount *mp; + struct proc *p; { - if ((mp->mnt_flag & MNT_MLOCK) == 0) - panic("vfs_unlock: not locked"); - mp->mnt_flag &= ~MNT_MLOCK; - if (mp->mnt_flag & MNT_MWAIT) { - mp->mnt_flag &= ~MNT_MWAIT; - wakeup((caddr_t) mp); - } + lockmgr(&mp->mnt_lock, LK_RELEASE, NULL, p); } /* - * Mark a mount point as busy. - * Used to synchronize access and to delay unmounting. + * Lookup a filesystem type, and if found allocate and initialize + * a mount structure for it. + * + * Devname is usually updated by mount(8) after booting. */ int -vfs_busy(mp) - register struct mount *mp; +vfs_rootmountalloc(fstypename, devname, mpp) + char *fstypename; + char *devname; + struct mount **mpp; { + struct proc *p = curproc; /* XXX */ + struct vfsconf *vfsp; + struct mount *mp; - while (mp->mnt_flag & MNT_MPBUSY) { - mp->mnt_flag |= MNT_MPWANT; - (void) tsleep((caddr_t) &mp->mnt_flag, PVFS, "vfsbsy", 0); - } - if (mp->mnt_flag & MNT_UNMOUNT) - return (1); - mp->mnt_flag |= MNT_MPBUSY; + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) + if (!strcmp(vfsp->vfc_name, fstypename)) + break; + if (vfsp == NULL) + return (ENODEV); + mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); + bzero((char *)mp, (u_long)sizeof(struct mount)); + lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); + (void)vfs_busy(mp, LK_NOWAIT, 0, p); + LIST_INIT(&mp->mnt_vnodelist); + mp->mnt_vfc = vfsp; + mp->mnt_op = vfsp->vfc_vfsops; + mp->mnt_flag = MNT_RDONLY; + mp->mnt_vnodecovered = NULLVP; + vfsp->vfc_refcount++; + mp->mnt_stat.f_type = vfsp->vfc_typenum; + mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; + strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); + mp->mnt_stat.f_mntonname[0] = '/'; + mp->mnt_stat.f_mntonname[1] = 0; + (void) copystr(devname, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 0); + *mpp = mp; return (0); } /* - * Free a busy filesystem. - * Panic if filesystem is not busy. - */ -void -vfs_unbusy(mp) - register struct mount *mp; -{ - - if ((mp->mnt_flag & MNT_MPBUSY) == 0) - panic("vfs_unbusy: not busy"); - mp->mnt_flag &= ~MNT_MPBUSY; - if (mp->mnt_flag & MNT_MPWANT) { - mp->mnt_flag &= ~MNT_MPWANT; - wakeup((caddr_t) &mp->mnt_flag); - } -} - -void -vfs_unmountroot(struct mount *rootfs) -{ - struct mount *mp = rootfs; - int error; - - if (vfs_busy(mp)) { - printf("failed to unmount root\n"); - return; - } - mp->mnt_flag |= MNT_UNMOUNT; - if ((error = vfs_lock(mp))) { - printf("lock of root filesystem failed (%d)\n", error); - return; - } - vnode_pager_umount(mp); /* release cached vnodes */ - cache_purgevfs(mp); /* remove cache entries for this file sys */ - - if ((error = VFS_SYNC(mp, MNT_WAIT, initproc->p_ucred, initproc))) - printf("sync of root filesystem failed (%d)\n", error); - - if ((error = VFS_UNMOUNT(mp, MNT_FORCE, initproc))) { - printf("unmount of root filesystem failed ("); - if (error == EBUSY) - printf("BUSY)\n"); - else - printf("%d)\n", error); - } - mp->mnt_flag &= ~MNT_UNMOUNT; - vfs_unbusy(mp); -} - -/* - * Unmount all filesystems. Should only be called by halt(). + * Find an appropriate filesystem to use for the root. If a filesystem + * has not been preselected, walk through the list of known filesystems + * trying those that have mountroot routines, and try them until one + * works or we have tried them all. */ -void -vfs_unmountall() +#ifdef notdef /* XXX JH */ +int +lite2_vfs_mountroot(void) { - struct mount *mp, *nmp, *rootfs = NULL; + struct vfsconf *vfsp; + extern int (*lite2_mountroot)(void); int error; - /* unmount all but rootfs */ - for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) { - nmp = mp->mnt_list.cqe_prev; - - if (mp->mnt_flag & MNT_ROOTFS) { - rootfs = mp; + if (lite2_mountroot != NULL) + return ((*lite2_mountroot)()); + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) { + if (vfsp->vfc_mountroot == NULL) continue; - } - error = dounmount(mp, MNT_FORCE, initproc); - if (error) { - printf("unmount of %s failed (", mp->mnt_stat.f_mntonname); - if (error == EBUSY) - printf("BUSY)\n"); - else - printf("%d)\n", error); - } - } - - /* and finally... */ - if (rootfs) { - vfs_unmountroot(rootfs); - } else { - printf("no root filesystem\n"); + if ((error = (*vfsp->vfc_mountroot)()) == 0) + return (0); + printf("%s_mountroot failed: %d\n", vfsp->vfc_name, error); } + return (ENODEV); } +#endif /* * Lookup a mount point by filesystem identifier. */ struct mount * -getvfs(fsid) +vfs_getvfs(fsid) fsid_t *fsid; { register struct mount *mp; + simple_lock(&mountlist_slock); for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = mp->mnt_list.cqe_next) { if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && - mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) + mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { + simple_unlock(&mountlist_slock); return (mp); + } } + simple_unlock(&mountlist_slock); return ((struct mount *) 0); } @@ -282,14 +277,16 @@ getvfs(fsid) * Get a new unique fsid */ void -getnewfsid(mp, mtype) +vfs_getnewfsid(mp) struct mount *mp; - int mtype; { static u_short xxxfs_mntid; fsid_t tfsid; + int mtype; + simple_lock(&mntid_slock); + mtype = mp->mnt_vfc->vfc_typenum; mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + mtype, 0); mp->mnt_stat.f_fsid.val[1] = mtype; if (xxxfs_mntid == 0) @@ -297,12 +294,13 @@ getnewfsid(mp, mtype) tfsid.val[0] = makedev(nblkdev + mtype, xxxfs_mntid); tfsid.val[1] = mtype; if (mountlist.cqh_first != (void *)&mountlist) { - while (getvfs(&tfsid)) { + while (vfs_getvfs(&tfsid)) { tfsid.val[0]++; xxxfs_mntid++; } } mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; + simple_unlock(&mntid_slock); } /* @@ -326,6 +324,35 @@ vattr_null(vap) vap->va_vaflags = 0; } +void +vfs_unmountroot(struct mount *rootfs) +{ + struct proc *p = curproc; /* XXX */ + struct mount *mp = rootfs; + int error; + + if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { + printf("failed to unmount root\n"); + return; + } + mp->mnt_flag |= MNT_UNMOUNT; + vnode_pager_umount(mp); /* release cached vnodes */ + cache_purgevfs(mp); /* remove cache entries for this file sys */ + + if ((error = VFS_SYNC(mp, MNT_WAIT, initproc->p_ucred, initproc))) + printf("sync of root filesystem failed (%d)\n", error); + + if ((error = VFS_UNMOUNT(mp, MNT_FORCE, initproc))) { + printf("unmount of root filesystem failed ("); + if (error == EBUSY) + printf("BUSY)\n"); + else + printf("%d)\n", error); + } + mp->mnt_flag &= ~MNT_UNMOUNT; + vfs_unbusy(mp, p); +} + /* * Routines having to do with the management of the vnode table. */ @@ -341,10 +368,11 @@ getnewvnode(tag, mp, vops, vpp) vop_t **vops; struct vnode **vpp; { - register struct vnode *vp; + struct proc *p = curproc; /* XXX */ + struct vnode *vp; + simple_lock(&vnode_free_list_slock); retry: - vp = vnode_free_list.tqh_first; /* * we allocate a new vnode if * 1. we don't have any free @@ -357,12 +385,31 @@ retry: */ if (freevnodes < (numvnodes >> 2) || numvnodes < desiredvnodes || - vp == NULL) { + vnode_free_list.tqh_first == NULL) { + simple_unlock(&vnode_free_list_slock); vp = (struct vnode *) malloc((u_long) sizeof *vp, M_VNODE, M_WAITOK); bzero((char *) vp, sizeof *vp); numvnodes++; } else { + for (vp = vnode_free_list.tqh_first; + vp != NULLVP; vp = vp->v_freelist.tqe_next) { + if (simple_lock_try(&vp->v_interlock)) + break; + } + /* + * Unless this is a bad time of the month, at most + * the first NCPUS items on the free list are + * locked, so this is close enough to being empty. + */ + if (vp == NULLVP) { + simple_unlock(&vnode_free_list_slock); + tablefull("vnode"); + *vpp = 0; + return (ENFILE); + } + if (vp->v_usecount) + panic("free vnode isn't"); TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); if (vp->v_usage > 0) { --vp->v_usage; @@ -370,14 +417,16 @@ retry: goto retry; } freevnodes--; - if (vp->v_usecount) - panic("free vnode isn't"); /* see comment on why 0xdeadb is set at end of vgone (below) */ vp->v_freelist.tqe_prev = (struct vnode **) 0xdeadb; + simple_unlock(&vnode_free_list_slock); vp->v_lease = NULL; if (vp->v_type != VBAD) - vgone(vp); + vgonel(vp, p); + else { + simple_unlock(&vp->v_interlock); + } #ifdef DIAGNOSTIC { @@ -421,6 +470,7 @@ insmntque(vp, mp) register struct mount *mp; { + simple_lock(&mntvnode_slock); /* * Delete from old mount point vnode list, if on one. */ @@ -429,9 +479,12 @@ insmntque(vp, mp) /* * Insert into list of vnodes for the new mount point, if available. */ - if ((vp->v_mount = mp) == NULL) + if ((vp->v_mount = mp) == NULL) { + simple_unlock(&mntvnode_slock); return; + } LIST_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes); + simple_unlock(&mntvnode_slock); } /* @@ -723,7 +776,8 @@ checkalias(nvp, nvp_rdev, mp) dev_t nvp_rdev; struct mount *mp; { - register struct vnode *vp; + struct proc *p = curproc; /* XXX */ + struct vnode *vp; struct vnode **vpp; if (nvp->v_type != VBLK && nvp->v_type != VCHR) @@ -731,18 +785,24 @@ checkalias(nvp, nvp_rdev, mp) vpp = &speclisth[SPECHASH(nvp_rdev)]; loop: + simple_lock(&spechash_slock); for (vp = *vpp; vp; vp = vp->v_specnext) { if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) continue; /* * Alias, but not in use, so flush it out. */ + simple_lock(&vp->v_interlock); if (vp->v_usecount == 0) { - vgone(vp); + simple_unlock(&spechash_slock); + vgonel(vp, p); goto loop; } - if (vget(vp, 1)) + simple_unlock(&spechash_slock); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) { goto loop; + } + simple_lock(&spechash_slock); break; } @@ -753,16 +813,19 @@ loop: nvp->v_hashchain = vpp; nvp->v_specnext = *vpp; nvp->v_specflags = 0; + simple_unlock(&spechash_slock); *vpp = nvp; - if (vp != NULL) { + if (vp != NULLVP) { nvp->v_flag |= VALIASED; vp->v_flag |= VALIASED; vput(vp); } return (NULLVP); } - VOP_UNLOCK(vp); - vclean(vp, 0); + simple_unlock(&spechash_slock); + VOP_UNLOCK(vp, 0, p); + simple_lock(&vp->v_interlock); + vclean(vp, 0, p); vp->v_op = nvp->v_op; vp->v_tag = nvp->v_tag; nvp->v_type = VNON; @@ -779,47 +842,162 @@ loop: * been changed to a new file system type). */ int -vget(vp, lockflag) +vget(vp, flags, p) register struct vnode *vp; - int lockflag; + int flags; + struct proc *p; { + int error; /* - * If the vnode is in the process of being cleaned out for another - * use, we wait for the cleaning to finish and then return failure. - * Cleaning is determined either by checking that the VXLOCK flag is - * set, or that the use count is zero with the back pointer set to - * show that it has been removed from the free list by getnewvnode. - * The VXLOCK flag may not have been set yet because vclean is blocked - * in the VOP_LOCK call waiting for the VOP_INACTIVE to complete. + * If the vnode is in the process of being cleaned out for + * another use, we wait for the cleaning to finish and then + * return failure. Cleaning is determined by checking that + * the VXLOCK flag is set. */ - if ((vp->v_flag & VXLOCK) || - (vp->v_usecount == 0 && - vp->v_freelist.tqe_prev == (struct vnode **) 0xdeadb)) { + if ((flags & LK_INTERLOCK) == 0) { + simple_lock(&vp->v_interlock); + } + if (vp->v_flag & VXLOCK) { vp->v_flag |= VXWANT; - (void) tsleep((caddr_t) vp, PINOD, "vget", 0); - return (1); + simple_unlock(&vp->v_interlock); + tsleep((caddr_t)vp, PINOD, "vget", 0); + return (ENOENT); } if (vp->v_usecount == 0) { + simple_lock(&vnode_free_list_slock); TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); + simple_unlock(&vnode_free_list_slock); freevnodes--; } vp->v_usecount++; - /* * Create the VM object, if needed */ if ((vp->v_type == VREG) && ((vp->v_object == NULL) || (vp->v_object->flags & OBJ_VFS_REF) == 0)) { + /* + * XXX vfs_object_create probably needs the interlock. + */ + simple_unlock(&vp->v_interlock); vfs_object_create(vp, curproc, curproc->p_ucred, 0); + simple_lock(&vp->v_interlock); + } + if (flags & LK_TYPE_MASK) { + if (error = vn_lock(vp, flags | LK_INTERLOCK, p)) + vrele(vp); + return (error); } - if (lockflag) - VOP_LOCK(vp); + simple_unlock(&vp->v_interlock); + return (0); +} + +/* + * Stubs to use when there is no locking to be done on the underlying object. + * A minimal shared lock is necessary to ensure that the underlying object + * is not revoked while an operation is in progress. So, an active shared + * count is maintained in an auxillary vnode lock structure. + */ +int +vop_nolock(ap) + struct vop_lock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; +{ +#ifdef notyet + /* + * This code cannot be used until all the non-locking filesystems + * (notably NFS) are converted to properly lock and release nodes. + * 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. Note that the inactive + * and lookup operations also change their lock state, but this + * cannot be avoided, so these two operations will always need + * to be handled in intermediate layers. + */ + struct vnode *vp = ap->a_vp; + int vnflags, flags = ap->a_flags; + if (vp->v_vnlock == NULL) { + if ((flags & LK_TYPE_MASK) == LK_DRAIN) + return (0); + MALLOC(vp->v_vnlock, struct lock *, sizeof(struct lock), + M_VNODE, M_WAITOK); + lockinit(vp->v_vnlock, PVFS, "vnlock", 0, 0); + } + switch (flags & LK_TYPE_MASK) { + case LK_DRAIN: + vnflags = LK_DRAIN; + break; + case LK_EXCLUSIVE: + case LK_SHARED: + vnflags = LK_SHARED; + break; + case LK_UPGRADE: + case LK_EXCLUPGRADE: + case LK_DOWNGRADE: + return (0); + case LK_RELEASE: + default: + panic("vop_nolock: bad operation %d", flags & LK_TYPE_MASK); + } + if (flags & LK_INTERLOCK) + vnflags |= LK_INTERLOCK; + return(lockmgr(vp->v_vnlock, vnflags, &vp->v_interlock, ap->a_p)); +#else /* for now */ + /* + * Since we are not using the lock manager, we must clear + * the interlock here. + */ + if (ap->a_flags & LK_INTERLOCK) { + simple_unlock(&ap->a_vp->v_interlock); + } return (0); +#endif +} + +/* + * Decrement the active use count. + */ +int +vop_nounlock(ap) + struct vop_unlock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + if (vp->v_vnlock == NULL) + return (0); + return (lockmgr(vp->v_vnlock, LK_RELEASE, NULL, ap->a_p)); +} + +/* + * Return whether or not the node is in use. + */ +int +vop_noislocked(ap) + struct vop_islocked_args /* { + struct vnode *a_vp; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + if (vp->v_vnlock == NULL) + return (0); + return (lockstatus(vp->v_vnlock)); } +/* #ifdef DIAGNOSTIC */ /* * Vnode reference, just increment the count */ @@ -827,6 +1005,7 @@ void vref(vp) struct vnode *vp; { + simple_lock(&vp->v_interlock); if (vp->v_usecount <= 0) panic("vref used where vget required"); @@ -840,8 +1019,11 @@ vref(vp) * the object is created. This is necessary to * keep the system from re-entrantly doing it * multiple times. + * XXX vfs_object_create probably needs the interlock? */ + simple_unlock(&vp->v_interlock); vfs_object_create(vp, curproc, curproc->p_ucred, 0); + simple_lock(&vp->v_interlock); } } @@ -850,9 +1032,9 @@ vref(vp) */ void vput(vp) - register struct vnode *vp; + struct vnode *vp; { - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, curproc); vrele(vp); } @@ -862,33 +1044,38 @@ vput(vp) */ void vrele(vp) - register struct vnode *vp; + struct vnode *vp; { + struct proc *p = curproc; /* XXX */ #ifdef DIAGNOSTIC if (vp == NULL) panic("vrele: null vp"); #endif - + simple_lock(&vp->v_interlock); vp->v_usecount--; if ((vp->v_usecount == 1) && vp->v_object && (vp->v_object->flags & OBJ_VFS_REF)) { vp->v_object->flags &= ~OBJ_VFS_REF; + simple_unlock(&vp->v_interlock); vm_object_deallocate(vp->v_object); return; } - if (vp->v_usecount > 0) + if (vp->v_usecount > 0) { + simple_unlock(&vp->v_interlock); return; + } if (vp->v_usecount < 0) { #ifdef DIAGNOSTIC vprint("vrele: negative ref count", vp); #endif - panic("vrele: negative reference cnt"); + panic("vrele: negative ref cnt"); } + simple_lock(&vnode_free_list_slock); if (vp->v_flag & VAGE) { if(vp->v_tag != VT_TFS) TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); @@ -898,9 +1085,12 @@ vrele(vp) if(vp->v_tag != VT_TFS) TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist); } + simple_unlock(&vnode_free_list_slock); + freevnodes++; - VOP_INACTIVE(vp); + if (vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK, p) == 0) + VOP_INACTIVE(vp, p); } #ifdef DIAGNOSTIC @@ -912,7 +1102,9 @@ vhold(vp) register struct vnode *vp; { + simple_lock(&vp->v_interlock); vp->v_holdcnt++; + simple_unlock(&vp->v_interlock); } /* @@ -923,9 +1115,11 @@ holdrele(vp) register struct vnode *vp; { + simple_lock(&vp->v_interlock); if (vp->v_holdcnt <= 0) panic("holdrele: holdcnt"); vp->v_holdcnt--; + simple_unlock(&vp->v_interlock); } #endif /* DIAGNOSTIC */ @@ -948,11 +1142,11 @@ vflush(mp, skipvp, flags) struct vnode *skipvp; int flags; { - register struct vnode *vp, *nvp; + struct proc *p = curproc; /* XXX */ + struct vnode *vp, *nvp; int busy = 0; - if ((mp->mnt_flag & MNT_MPBUSY) == 0) - panic("vflush: not busy"); + simple_lock(&mntvnode_slock); loop: for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { /* @@ -967,24 +1161,34 @@ loop: */ if (vp == skipvp) continue; + + simple_lock(&vp->v_interlock); /* * Skip over a vnodes marked VSYSTEM. */ - if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) + if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) { + simple_unlock(&vp->v_interlock); continue; + } /* * If WRITECLOSE is set, only flush out regular file vnodes * open for writing. */ if ((flags & WRITECLOSE) && - (vp->v_writecount == 0 || vp->v_type != VREG)) + (vp->v_writecount == 0 || vp->v_type != VREG)) { + simple_unlock(&vp->v_interlock); continue; + } if (vp->v_object && (vp->v_object->flags & OBJ_VFS_REF)) { + simple_unlock(&vp->v_interlock); + simple_unlock(&mntvnode_slock); vm_object_reference(vp->v_object); pager_cache(vp->v_object, FALSE); vp->v_object->flags &= ~OBJ_VFS_REF; vm_object_deallocate(vp->v_object); + simple_lock(&mntvnode_slock); + simple_lock(&vp->v_interlock); } /* @@ -992,7 +1196,9 @@ loop: * vnode data structures and we are done. */ if (vp->v_usecount == 0) { - vgone(vp); + simple_unlock(&mntvnode_slock); + vgonel(vp, p); + simple_lock(&mntvnode_slock); continue; } @@ -1002,21 +1208,25 @@ loop: * all other files, just kill them. */ if (flags & FORCECLOSE) { + simple_unlock(&mntvnode_slock); if (vp->v_type != VBLK && vp->v_type != VCHR) { - vgone(vp); + vgonel(vp, p); } else { - vclean(vp, 0); + vclean(vp, 0, p); vp->v_op = spec_vnodeop_p; insmntque(vp, (struct mount *) 0); } + simple_lock(&mntvnode_slock); continue; } #ifdef DIAGNOSTIC if (busyprt) vprint("vflush: busy vnode", vp); #endif + simple_unlock(&vp->v_interlock); busy++; } + simple_unlock(&mntvnode_slock); if (busy) return (EBUSY); return (0); @@ -1025,8 +1235,8 @@ loop: /* * Disassociate the underlying file system from a vnode. */ -void -vclean(struct vnode *vp, int flags) +static void +vclean(struct vnode *vp, int flags, struct proc *p) { int active; @@ -1036,15 +1246,7 @@ vclean(struct vnode *vp, int flags) * generate a race against ourselves to recycle it. */ if ((active = vp->v_usecount)) - VREF(vp); - /* - * Even if the count is zero, the VOP_INACTIVE routine may still have - * the object locked while it cleans it out. The VOP_LOCK ensures that - * the VOP_INACTIVE routine is done with its work. For active vnodes, - * it ensures that no other activity can occur while the underlying - * object is being cleaned out. - */ - VOP_LOCK(vp); + vp->v_usecount++; /* * Prevent the vnode from being recycled or brought into use while we * clean it out. @@ -1053,31 +1255,48 @@ vclean(struct vnode *vp, int flags) panic("vclean: deadlock"); vp->v_flag |= VXLOCK; /* - * Clean out any buffers associated with the vnode. + * Even if the count is zero, the VOP_INACTIVE routine may still + * have the object locked while it cleans it out. The VOP_LOCK + * ensures that the VOP_INACTIVE routine is done with its work. + * For active vnodes, it ensures that no other activity can + * occur while the underlying object is being cleaned out. */ - if (flags & DOCLOSE) - vinvalbuf(vp, V_SAVE, NOCRED, NULL, 0, 0); + VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, p); /* - * Any other processes trying to obtain this lock must first wait for - * VXLOCK to clear, then call the new lock operation. + * Clean out any buffers associated with the vnode. */ - VOP_UNLOCK(vp); + if (flags & DOCLOSE) + vinvalbuf(vp, V_SAVE, NOCRED, p, 0, 0); /* - * If purging an active vnode, it must be closed and deactivated - * before being reclaimed. + * If purging an active vnode, it must be closed and + * deactivated before being reclaimed. Note that the + * VOP_INACTIVE will unlock the vnode. */ if (active) { if (flags & DOCLOSE) - VOP_CLOSE(vp, FNONBLOCK, NOCRED, NULL); - VOP_INACTIVE(vp); + VOP_CLOSE(vp, IO_NDELAY, NOCRED, p); + VOP_INACTIVE(vp, p); + } else { + /* + * Any other processes trying to obtain this lock must first + * wait for VXLOCK to clear, then call the new lock operation. + */ + VOP_UNLOCK(vp, 0, p); } /* * Reclaim the vnode. */ - if (VOP_RECLAIM(vp)) + if (VOP_RECLAIM(vp, p)) panic("vclean: cannot reclaim"); if (active) vrele(vp); + cache_purge(vp); + if (vp->v_vnlock) { + if ((vp->v_vnlock->lk_flags & LK_DRAINED) == 0) + vprint("vclean: lock not drained", vp); + FREE(vp->v_vnlock, M_VNODE); + vp->v_vnlock = NULL; + } /* * Done with purge, notify sleepers of the grim news. @@ -1092,46 +1311,91 @@ vclean(struct vnode *vp, int flags) } /* - * Eliminate all activity associated with the requested vnode + * Eliminate all activity associated with the requested vnode * and with all vnodes aliased to the requested vnode. */ -void -vgoneall(vp) - register struct vnode *vp; +int +vop_revoke(ap) + struct vop_revoke_args /* { + struct vnode *a_vp; + int a_flags; + } */ *ap; { - register struct vnode *vq; + struct vnode *vp, *vq; + struct proc *p = curproc; /* XXX */ + +#ifdef DIAGNOSTIC + if ((ap->a_flags & REVOKEALL) == 0) + panic("vop_revoke"); +#endif + + vp = ap->a_vp; + simple_lock(&vp->v_interlock); if (vp->v_flag & VALIASED) { /* - * If a vgone (or vclean) is already in progress, wait until - * it is done and return. + * If a vgone (or vclean) is already in progress, + * wait until it is done and return. */ if (vp->v_flag & VXLOCK) { vp->v_flag |= VXWANT; - (void) tsleep((caddr_t) vp, PINOD, "vgall", 0); - return; + simple_unlock(&vp->v_interlock); + tsleep((caddr_t)vp, PINOD, "vop_revokeall", 0); + return (0); } /* - * Ensure that vp will not be vgone'd while we are eliminating - * its aliases. + * Ensure that vp will not be vgone'd while we + * are eliminating its aliases. */ vp->v_flag |= VXLOCK; + simple_unlock(&vp->v_interlock); while (vp->v_flag & VALIASED) { + simple_lock(&spechash_slock); for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type || vp == vq) continue; + simple_unlock(&spechash_slock); vgone(vq); break; } + if (vq == NULLVP) { + simple_unlock(&spechash_slock); + } } /* - * Remove the lock so that vgone below will really eliminate - * the vnode after which time vgone will awaken any sleepers. + * Remove the lock so that vgone below will + * really eliminate the vnode after which time + * vgone will awaken any sleepers. */ + simple_lock(&vp->v_interlock); vp->v_flag &= ~VXLOCK; } - vgone(vp); + vgonel(vp, p); + return (0); +} + +/* + * Recycle an unused vnode to the front of the free list. + * Release the passed interlock if the vnode will be recycled. + */ +int +vrecycle(vp, inter_lkp, p) + struct vnode *vp; + struct simplelock *inter_lkp; + struct proc *p; +{ + + simple_lock(&vp->v_interlock); + if (vp->v_usecount == 0) { + if (inter_lkp) { + simple_unlock(inter_lkp); + } + vgonel(vp, p); + return (1); + } + simple_unlock(&vp->v_interlock); + return (0); } /* @@ -1142,16 +1406,31 @@ void vgone(vp) register struct vnode *vp; { - register struct vnode *vq; + struct proc *p = curproc; /* XXX */ + + simple_lock(&vp->v_interlock); + vgonel(vp, p); +} + +/* + * vgone, with the vp interlock held. + */ +void +vgonel(vp, p) + struct vnode *vp; + struct proc *p; +{ + struct vnode *vq; struct vnode *vx; /* - * If a vgone (or vclean) is already in progress, wait until it is - * done and return. + * If a vgone (or vclean) is already in progress, + * wait until it is done and return. */ if (vp->v_flag & VXLOCK) { vp->v_flag |= VXWANT; - (void) tsleep((caddr_t) vp, PINOD, "vgone", 0); + simple_unlock(&vp->v_interlock); + tsleep((caddr_t)vp, PINOD, "vgone", 0); return; } @@ -1162,18 +1441,18 @@ vgone(vp) /* * Clean out the filesystem specific data. */ - vclean(vp, DOCLOSE); + vclean(vp, DOCLOSE, p); /* * Delete from old mount point vnode list, if on one. */ - if (vp->v_mount != NULL) { - LIST_REMOVE(vp, v_mntvnodes); - vp->v_mount = NULL; - } + if (vp->v_mount != NULL) + insmntque(vp, (struct mount *)0); /* - * If special device, remove it from special device alias list. + * If special device, remove it from special device alias list + * if it is on one. */ - if (vp->v_type == VBLK || vp->v_type == VCHR) { + if ((vp->v_type == VBLK || vp->v_type == VCHR) && vp->v_specinfo != 0) { + simple_lock(&spechash_slock); if (*vp->v_hashchain == vp) { *vp->v_hashchain = vp->v_specnext; } else { @@ -1202,28 +1481,34 @@ vgone(vp) vx->v_flag &= ~VALIASED; vp->v_flag &= ~VALIASED; } + simple_unlock(&spechash_slock); FREE(vp->v_specinfo, M_VNODE); vp->v_specinfo = NULL; } + /* - * If it is on the freelist and not already at the head, move it to - * the head of the list. The test of the back pointer and the - * reference count of zero is because it will be removed from the free - * list by getnewvnode, but will not have its reference count - * incremented until after calling vgone. If the reference count were - * incremented first, vgone would (incorrectly) try to close the - * previous instance of the underlying object. So, the back pointer is - * explicitly set to `0xdeadb' in getnewvnode after removing it from - * the freelist to ensure that we do not try to move it here. + * If it is on the freelist and not already at the head, + * move it to the head of the list. The test of the back + * pointer and the reference count of zero is because + * it will be removed from the free list by getnewvnode, + * but will not have its reference count incremented until + * after calling vgone. If the reference count were + * incremented first, vgone would (incorrectly) try to + * close the previous instance of the underlying object. + * So, the back pointer is explicitly set to `0xdeadb' in + * getnewvnode after removing it from the freelist to ensure + * that we do not try to move it here. */ - if (vp->v_usecount == 0 && - vp->v_freelist.tqe_prev != (struct vnode **) 0xdeadb && - vnode_free_list.tqh_first != vp) { - if(vp->v_tag != VT_TFS) { + if (vp->v_usecount == 0) { + simple_lock(&vnode_free_list_slock); + if ((vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb) && + vnode_free_list.tqh_first != vp) { TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); } + simple_unlock(&vnode_free_list_slock); } + vp->v_type = VBAD; } @@ -1254,7 +1539,7 @@ int vcount(vp) register struct vnode *vp; { - register struct vnode *vq, *vnext; + struct vnode *vq, *vnext; int count; loop: @@ -1354,6 +1639,7 @@ int kinfo_vgetfailed; static int sysctl_vnode SYSCTL_HANDLER_ARGS { + struct proc *p = curproc; /* XXX */ register struct mount *mp, *nmp; struct vnode *vp; int error; @@ -1368,7 +1654,7 @@ sysctl_vnode SYSCTL_HANDLER_ARGS for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { nmp = mp->mnt_list.cqe_next; - if (vfs_busy(mp)) + if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) continue; again: for (vp = mp->mnt_vnodelist.lh_first; @@ -1386,11 +1672,11 @@ again: } if ((error = SYSCTL_OUT(req, &vp, VPTRSZ)) || (error = SYSCTL_OUT(req, vp, VNODESZ))) { - vfs_unbusy(mp); + vfs_unbusy(mp, p); return (error); } } - vfs_unbusy(mp); + vfs_unbusy(mp, p); } return (0); @@ -1404,22 +1690,63 @@ SYSCTL_PROC(_kern, KERN_VNODE, vnode, CTLTYPE_OPAQUE|CTLFLAG_RD, */ int vfs_mountedon(vp) - register struct vnode *vp; + struct vnode *vp; { - register struct vnode *vq; + struct vnode *vq; + int error = 0; if (vp->v_specflags & SI_MOUNTEDON) return (EBUSY); if (vp->v_flag & VALIASED) { + simple_lock(&spechash_slock); for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) continue; - if (vq->v_specflags & SI_MOUNTEDON) - return (EBUSY); + if (vq->v_specflags & SI_MOUNTEDON) { + error = EBUSY; + break; + } } + simple_unlock(&spechash_slock); + } + return (error); +} + +/* + * Unmount all filesystems. The list is traversed in reverse order + * of mounting to avoid dependencies. Should only be called by halt(). + */ +void +vfs_unmountall() +{ + struct mount *mp, *nmp, *rootfs = NULL; + int error; + + /* unmount all but rootfs */ + for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) { + nmp = mp->mnt_list.cqe_prev; + + if (mp->mnt_flag & MNT_ROOTFS) { + rootfs = mp; + continue; + } + error = dounmount(mp, MNT_FORCE, initproc); + if (error) { + printf("unmount of %s failed (", mp->mnt_stat.f_mntonname); + if (error == EBUSY) + printf("BUSY)\n"); + else + printf("%d)\n", error); + } + } + + /* and finally... */ + if (rootfs) { + vfs_unmountroot(rootfs); + } else { + printf("no root filesystem\n"); } - return (0); } /* @@ -1565,8 +1892,8 @@ vfs_export_lookup(mp, nep, nam) rnh = nep->ne_rtable[saddr->sa_family]; if (rnh != NULL) { np = (struct netcred *) - (*rnh->rnh_matchaddr) ((caddr_t) saddr, - rnh); + (*rnh->rnh_matchaddr)((caddr_t)saddr, + rnh); if (np && np->netc_rnodes->rn_flags & RNF_ROOT) np = NULL; } @@ -1580,7 +1907,6 @@ vfs_export_lookup(mp, nep, nam) return (np); } - /* * perform msync on all vnodes under a mount point * the mount point must be locked. @@ -1639,10 +1965,10 @@ retry: } else { if (object->flags & OBJ_DEAD) { if (waslocked) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); tsleep(object, PVM, "vodead", 0); if (waslocked) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); goto retry; } if ((object->flags & OBJ_VFS_REF) == 0) { diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 22e16d84..83b6dec 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -50,6 +50,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/sysent.h> #include <sys/sysproto.h> #include <sys/namei.h> #include <sys/filedesc.h> @@ -64,9 +65,11 @@ #include <sys/malloc.h> #include <sys/dirent.h> +/* see if this is needed XXX JH #ifdef UNION #include <miscfs/union/union.h> #endif +*/ #include <vm/vm.h> #include <vm/vm_param.h> @@ -74,7 +77,8 @@ #include <vm/vm_extern.h> #include <sys/sysctl.h> -static int change_dir __P((struct nameidata *ndp, struct proc *p)); +static int change_dir __P((struct nameidata *ndp, struct proc *p)); +static void checkdirs __P((struct vnode *olddp)); /* * Virtual File System System Calls @@ -85,7 +89,7 @@ static int change_dir __P((struct nameidata *ndp, struct proc *p)); */ #ifndef _SYS_SYSPROTO_H_ struct mount_args { - int type; + char *type; char *path; int flags; caddr_t data; @@ -95,29 +99,32 @@ struct mount_args { int mount(p, uap, retval) struct proc *p; - register struct mount_args *uap; - int *retval; + register struct mount_args /* { + syscallarg(char *) type; + syscallarg(char *) path; + syscallarg(int) flags; + syscallarg(caddr_t) data; + } */ *uap; + register_t *retval; { - register struct vnode *vp; - register struct mount *mp; + struct vnode *vp; + struct mount *mp; + struct vfsconf *vfsp; int error, flag = 0; + struct vattr va; + u_long fstypenum; struct nameidata nd; + char fstypename[MFSNAMELEN]; /* - * Must be super user - */ - error = suser(p->p_ucred, &p->p_acflag); - if (error) - return (error); - /* * Get vnode to be covered */ - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - if (uap->flags & MNT_UPDATE) { + if (SCARG(uap, flags) & MNT_UPDATE) { if ((vp->v_flag & VROOT) == 0) { vput(vp); return (EINVAL); @@ -128,68 +135,135 @@ mount(p, uap, retval) * We only allow the filesystem to be reloaded if it * is currently mounted read-only. */ - if ((uap->flags & MNT_RELOAD) && + if ((SCARG(uap, flags) & MNT_RELOAD) && ((mp->mnt_flag & MNT_RDONLY) == 0)) { vput(vp); return (EOPNOTSUPP); /* Needs translation */ } mp->mnt_flag |= - uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); - VOP_UNLOCK(vp); + SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); + /* + * Only root, or the user that did the original mount is + * permitted to update it. + */ + if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && + (error = suser(p->p_ucred, &p->p_acflag))) { + vput(vp); + return (error); + } + /* + * Do not allow NFS export by non-root users. Silently + * enforce MNT_NOSUID and MNT_NODEV for non-root users. + */ + if (p->p_ucred->cr_uid != 0) { + if (SCARG(uap, flags) & MNT_EXPORTED) { + vput(vp); + return (EPERM); + } + SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; + } + if (vfs_busy(mp, LK_NOWAIT, 0, p)) { + vput(vp); + return (EBUSY); + } + VOP_UNLOCK(vp, 0, p); goto update; } - error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0); - if (error) + /* + * If the user is not root, ensure that they own the directory + * onto which we are attempting to mount. + */ + if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || + (va.va_uid != p->p_ucred->cr_uid && + (error = suser(p->p_ucred, &p->p_acflag)))) { + vput(vp); + return (error); + } + /* + * Do not allow NFS export by non-root users. Silently + * enforce MNT_NOSUID and MNT_NODEV for non-root users. + */ + if (p->p_ucred->cr_uid != 0) { + if (SCARG(uap, flags) & MNT_EXPORTED) { + vput(vp); + return (EPERM); + } + SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; + } + if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) return (error); if (vp->v_type != VDIR) { vput(vp); return (ENOTDIR); } - if ((u_long)uap->type > MOUNT_MAXTYPE || vfssw[uap->type] == NULL) { - vput(vp); - return (ENODEV); - } - +#ifdef COMPAT_43 /* - * Allocate and initialize the file system. + * Historically filesystem types were identified by number. If we + * get an integer for the filesystem type instead of a string, we + * check to see if it matches one of the historic filesystem types. */ - mp = (struct mount *)malloc((u_long)sizeof(struct mount), - M_MOUNT, M_WAITOK); - bzero((char *)mp, (u_long)sizeof(struct mount)); - mp->mnt_op = vfssw[uap->type]; - mp->mnt_vfc = vfsconf[uap->type]; - error = vfs_lock(mp); - if (error) { - free((caddr_t)mp, M_MOUNT); + fstypenum = (u_long)SCARG(uap, type); + if (fstypenum < maxvfsconf) { + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) + if (vfsp->vfc_typenum == fstypenum) + break; + if (vfsp == NULL) { + vput(vp); + return (ENODEV); + } + strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); + } else +#endif /* COMPAT_43 */ + if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) { vput(vp); return (error); } + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) + if (!strcmp(vfsp->vfc_name, fstypename)) + break; + if (vfsp == NULL) { + vput(vp); + return (ENODEV); + } if (vp->v_mountedhere != NULL) { - vfs_unlock(mp); - free((caddr_t)mp, M_MOUNT); vput(vp); return (EBUSY); } + + /* + * Allocate and initialize the filesystem. + */ + mp = (struct mount *)malloc((u_long)sizeof(struct mount), + M_MOUNT, M_WAITOK); + bzero((char *)mp, (u_long)sizeof(struct mount)); + lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); + (void)vfs_busy(mp, LK_NOWAIT, 0, p); + mp->mnt_op = vfsp->vfc_vfsops; + mp->mnt_vfc = vfsp; + vfsp->vfc_refcount++; + mp->mnt_stat.f_type = vfsp->vfc_typenum; + mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; + strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); vp->v_mountedhere = mp; mp->mnt_vnodecovered = vp; - vfsconf[uap->type]->vfc_refcount++; - + mp->mnt_stat.f_owner = p->p_ucred->cr_uid; update: /* * Set the mount level flags. */ - if (uap->flags & MNT_RDONLY) + if (SCARG(uap, flags) & MNT_RDONLY) mp->mnt_flag |= MNT_RDONLY; else if (mp->mnt_flag & MNT_RDONLY) mp->mnt_flag |= MNT_WANTRDWR; mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME); - mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | - MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE | MNT_NOATIME); + mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | + MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE | + MNT_NOATIME); /* * Mount the filesystem. */ - error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p); + error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); if (mp->mnt_flag & MNT_UPDATE) { vrele(vp); if (mp->mnt_flag & MNT_WANTRDWR) @@ -198,6 +272,7 @@ update: (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); if (error) mp->mnt_flag = flag; + vfs_unbusy(mp, p); return (error); } /* @@ -205,23 +280,63 @@ update: */ cache_purge(vp); if (!error) { + simple_lock(&mountlist_slock); CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); - VOP_UNLOCK(vp); - vfs_unlock(mp); - error = VFS_START(mp, 0, p); - if (error) + simple_unlock(&mountlist_slock); + checkdirs(vp); + VOP_UNLOCK(vp, 0, p); + vfs_unbusy(mp, p); + if (error = VFS_START(mp, 0, p)) vrele(vp); } else { mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; - vfs_unlock(mp); + mp->mnt_vfc->vfc_refcount--; + vfs_unbusy(mp, p); free((caddr_t)mp, M_MOUNT); vput(vp); - vfsconf[uap->type]->vfc_refcount--; } return (error); } /* + * Scan all active processes to see if any of them have a current + * or root directory onto which the new filesystem has just been + * mounted. If so, replace them with the new mount point. + */ +static void +checkdirs(olddp) + struct vnode *olddp; +{ + struct filedesc *fdp; + struct vnode *newdp; + struct proc *p; + + if (olddp->v_usecount == 1) + return; + if (VFS_ROOT(olddp->v_mountedhere, &newdp)) + panic("mount: lost mount"); + for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { + fdp = p->p_fd; + if (fdp->fd_cdir == olddp) { + vrele(fdp->fd_cdir); + VREF(newdp); + fdp->fd_cdir = newdp; + } + if (fdp->fd_rdir == olddp) { + vrele(fdp->fd_rdir); + VREF(newdp); + fdp->fd_rdir = newdp; + } + } + if (rootvnode == olddp) { + vrele(rootvnode); + VREF(newdp); + rootvnode = newdp; + } + vput(newdp); +} + +/* * Unmount a file system. * * Note: unmount takes a path to the vnode mounted on as argument, @@ -237,47 +352,51 @@ struct unmount_args { int unmount(p, uap, retval) struct proc *p; - register struct unmount_args *uap; - int *retval; + register struct unmount_args /* { + syscallarg(char *) path; + syscallarg(int) flags; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct mount *mp; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; + mp = vp->v_mount; /* - * Unless this is a user mount, then must - * have suser privilege. + * Only root, or the user that did the original mount is + * permitted to unmount this filesystem. */ - if (((vp->v_mount->mnt_flag & MNT_USER) == 0) && + if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && (error = suser(p->p_ucred, &p->p_acflag))) { vput(vp); return (error); } /* - * Must be the root of the filesystem + * Don't allow unmounting the root file system. */ - if ((vp->v_flag & VROOT) == 0) { + if (mp->mnt_flag & MNT_ROOTFS) { vput(vp); return (EINVAL); } - mp = vp->v_mount; - vput(vp); /* - * Don't allow unmount of the root filesystem + * Must be the root of the filesystem */ - if (mp->mnt_flag & MNT_ROOTFS) + if ((vp->v_flag & VROOT) == 0) { + vput(vp); return (EINVAL); - - return (dounmount(mp, uap->flags, p)); + } + vput(vp); + return (dounmount(mp, SCARG(uap, flags), p)); } /* @@ -292,74 +411,86 @@ dounmount(mp, flags, p) struct vnode *coveredvp; int error; - coveredvp = mp->mnt_vnodecovered; - if (vfs_busy(mp)) - return (EBUSY); + simple_lock(&mountlist_slock); mp->mnt_flag |= MNT_UNMOUNT; - error = vfs_lock(mp); - if (error) - return (error); - + lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p); mp->mnt_flag &=~ MNT_ASYNC; vfs_msync(mp, MNT_NOWAIT); vnode_pager_umount(mp); /* release cached vnodes */ cache_purgevfs(mp); /* remove cache entries for this file sys */ - if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || + if (((mp->mnt_flag & MNT_RDONLY) || + (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) || (flags & MNT_FORCE)) error = VFS_UNMOUNT(mp, flags, p); - mp->mnt_flag &= ~MNT_UNMOUNT; - vfs_unbusy(mp); + simple_lock(&mountlist_slock); if (error) { - vfs_unlock(mp); - } else { + mp->mnt_flag &= ~MNT_UNMOUNT; + lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE, + &mountlist_slock, p); + return (error); + } + CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); + if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) { + coveredvp->v_mountedhere = (struct mount *)0; vrele(coveredvp); - CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); - mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; - vfs_unlock(mp); - mp->mnt_vfc->vfc_refcount--; - if (mp->mnt_vnodelist.lh_first != NULL) - panic("unmount: dangling vnode"); - free((caddr_t)mp, M_MOUNT); } - return (error); + mp->mnt_vfc->vfc_refcount--; + if (mp->mnt_vnodelist.lh_first != NULL) + panic("unmount: dangling vnode"); + lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p); + if (mp->mnt_flag & MNT_MWAIT) + wakeup((caddr_t)mp); + free((caddr_t)mp, M_MOUNT); + return (0); } /* * Sync each mounted filesystem. */ - #ifndef _SYS_SYSPROTO_H_ struct sync_args { int dummy; }; #endif +#ifdef DEBUG +int syncprt = 0; +SYSCTL_INT(_debug, 0, syncprt, CTLFLAG_RW, &syncprt, 0, ""); +#endif + /* ARGSUSED */ int sync(p, uap, retval) struct proc *p; struct sync_args *uap; - int *retval; + register_t *retval; { - register struct mount *mp; + register struct mount *mp, *nmp; int asyncflag; - for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = mp->mnt_list.cqe_next) { - /* - * The lock check below is to avoid races with mount - * and unmount. - */ - if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && - !vfs_busy(mp)) { + simple_lock(&mountlist_slock); + for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { + if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { + nmp = mp->mnt_list.cqe_next; + continue; + } + if ((mp->mnt_flag & MNT_RDONLY) == 0) { asyncflag = mp->mnt_flag & MNT_ASYNC; mp->mnt_flag &= ~MNT_ASYNC; vfs_msync(mp, MNT_NOWAIT); VFS_SYNC(mp, MNT_NOWAIT, p != NULL ? p->p_ucred : NOCRED, p); if (asyncflag) mp->mnt_flag |= MNT_ASYNC; - vfs_unbusy(mp); } + simple_lock(&mountlist_slock); + nmp = mp->mnt_list.cqe_next; + vfs_unbusy(mp, p); } + simple_unlock(&mountlist_slock); +#ifdef DIAGNOSTIC + if (syncprt) + vfs_bufstats(); +#endif /* DIAGNOSTIC */ return (0); } @@ -378,20 +509,25 @@ struct quotactl_args { int quotactl(p, uap, retval) struct proc *p; - register struct quotactl_args *uap; - int *retval; + register struct quotactl_args /* { + syscallarg(char *) path; + syscallarg(int) cmd; + syscallarg(int) uid; + syscallarg(caddr_t) arg; + } */ *uap; + register_t *retval; { register struct mount *mp; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); mp = nd.ni_vp->v_mount; vrele(nd.ni_vp); - return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); + return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), + SCARG(uap, arg), p)); } /* @@ -407,17 +543,19 @@ struct statfs_args { int statfs(p, uap, retval) struct proc *p; - register struct statfs_args *uap; - int *retval; + register struct statfs_args /* { + syscallarg(char *) path; + syscallarg(struct statfs *) buf; + } */ *uap; + register_t *retval; { register struct mount *mp; register struct statfs *sp; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); mp = nd.ni_vp->v_mount; sp = &mp->mnt_stat; @@ -426,7 +564,7 @@ statfs(p, uap, retval) if (error) return (error); sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); + return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); } /* @@ -442,16 +580,18 @@ struct fstatfs_args { int fstatfs(p, uap, retval) struct proc *p; - register struct fstatfs_args *uap; - int *retval; + register struct fstatfs_args /* { + syscallarg(int) fd; + syscallarg(struct statfs *) buf; + } */ *uap; + register_t *retval; { struct file *fp; struct mount *mp; register struct statfs *sp; int error; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); mp = ((struct vnode *)fp->f_data)->v_mount; sp = &mp->mnt_stat; @@ -459,7 +599,7 @@ fstatfs(p, uap, retval) if (error) return (error); sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); + return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); } /* @@ -475,48 +615,55 @@ struct getfsstat_args { int getfsstat(p, uap, retval) struct proc *p; - register struct getfsstat_args *uap; - int *retval; + register struct getfsstat_args /* { + syscallarg(struct statfs *) buf; + syscallarg(long) bufsize; + syscallarg(int) flags; + } */ *uap; + register_t *retval; { register struct mount *mp, *nmp; register struct statfs *sp; caddr_t sfsp; long count, maxcount, error; - maxcount = uap->bufsize / sizeof(struct statfs); - sfsp = (caddr_t)uap->buf; + maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); + sfsp = (caddr_t)SCARG(uap, buf); count = 0; + simple_lock(&mountlist_slock); for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { - if (vfs_busy(mp)) { + if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { nmp = mp->mnt_list.cqe_next; continue; } - if (sfsp && count < maxcount && - ((mp->mnt_flag & MNT_MLOCK) == 0)) { + if (sfsp && count < maxcount) { sp = &mp->mnt_stat; /* * If MNT_NOWAIT is specified, do not refresh the * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. */ - if (((uap->flags & MNT_NOWAIT) == 0 || - (uap->flags & MNT_WAIT)) && + if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 || + (SCARG(uap, flags) & MNT_WAIT)) && (error = VFS_STATFS(mp, sp, p))) { + simple_lock(&mountlist_slock); nmp = mp->mnt_list.cqe_next; - vfs_unbusy(mp); + vfs_unbusy(mp, p); continue; } sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; error = copyout((caddr_t)sp, sfsp, sizeof(*sp)); if (error) { - vfs_unbusy(mp); + vfs_unbusy(mp, p); return (error); } sfsp += sizeof(*sp); } count++; + simple_lock(&mountlist_slock); nmp = mp->mnt_list.cqe_next; - vfs_unbusy(mp); + vfs_unbusy(mp, p); } + simple_unlock(&mountlist_slock); if (sfsp && count > maxcount) *retval = maxcount; else @@ -536,27 +683,41 @@ struct fchdir_args { int fchdir(p, uap, retval) struct proc *p; - struct fchdir_args *uap; - int *retval; + struct fchdir_args /* { + syscallarg(int) fd; + } */ *uap; + register_t *retval; { register struct filedesc *fdp = p->p_fd; - register struct vnode *vp; + struct vnode *vp, *tdp; + struct mount *mp; struct file *fp; int error; - error = getvnode(fdp, uap->fd, &fp); - if (error) + if (error = getvnode(fdp, SCARG(uap, fd), &fp)) return (error); vp = (struct vnode *)fp->f_data; - VOP_LOCK(vp); + VREF(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (vp->v_type != VDIR) error = ENOTDIR; else error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); - VOP_UNLOCK(vp); - if (error) + while (!error && (mp = vp->v_mountedhere) != NULL) { + if (vfs_busy(mp, 0, 0, p)) + continue; + error = VFS_ROOT(mp, &tdp); + vfs_unbusy(mp, p); + if (error) + break; + vput(vp); + vp = tdp; + } + if (error) { + vput(vp); return (error); - VREF(vp); + } + VOP_UNLOCK(vp, 0, p); vrele(fdp->fd_cdir); fdp->fd_cdir = vp; return (0); @@ -574,16 +735,18 @@ struct chdir_args { int chdir(p, uap, retval) struct proc *p; - struct chdir_args *uap; - int *retval; + struct chdir_args /* { + syscallarg(char *) path; + } */ *uap; + register_t *retval; { register struct filedesc *fdp = p->p_fd; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = change_dir(&nd, p); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = change_dir(&nd, p)) return (error); vrele(fdp->fd_cdir); fdp->fd_cdir = nd.ni_vp; @@ -602,8 +765,10 @@ struct chroot_args { int chroot(p, uap, retval) struct proc *p; - struct chroot_args *uap; - int *retval; + struct chroot_args /* { + syscallarg(char *) path; + } */ *uap; + register_t *retval; { register struct filedesc *fdp = p->p_fd; int error; @@ -612,9 +777,9 @@ chroot(p, uap, retval) error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = change_dir(&nd, p); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = change_dir(&nd, p)) return (error); if (fdp->fd_rdir != NULL) vrele(fdp->fd_rdir); @@ -641,9 +806,10 @@ change_dir(ndp, p) error = ENOTDIR; else error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); - VOP_UNLOCK(vp); if (error) - vrele(vp); + vput(vp); + else + VOP_UNLOCK(vp, 0, p); return (error); } @@ -661,8 +827,12 @@ struct open_args { int open(p, uap, retval) struct proc *p; - register struct open_args *uap; - int *retval; + register struct open_args /* { + syscallarg(char *) path; + syscallarg(int) flags; + syscallarg(int) mode; + } */ *uap; + register_t *retval; { register struct filedesc *fdp = p->p_fd; register struct file *fp; @@ -677,17 +847,17 @@ open(p, uap, retval) if (error) return (error); fp = nfp; - flags = FFLAGS(uap->flags); - cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); + flags = FFLAGS(SCARG(uap, flags)); + cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); p->p_dupfd = -indx - 1; /* XXX check for fdopen */ error = vn_open(&nd, flags, cmode); if (error) { ffree(fp); if ((error == ENODEV || error == ENXIO) && - p->p_dupfd >= 0 && /* XXX from fdopen */ + p->p_dupfd >= 0 && /* XXX from fdopen */ (error = - dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { + dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { *retval = indx; return (0); } @@ -714,18 +884,17 @@ open(p, uap, retval) type = F_FLOCK; if ((flags & FNONBLOCK) == 0) type |= F_WAIT; - VOP_UNLOCK(vp); - error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); - if (error) { + VOP_UNLOCK(vp, 0, p); + if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { (void) vn_close(vp, fp->f_flag, fp->f_cred, p); ffree(fp); fdp->fd_ofiles[indx] = NULL; return (error); } - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); fp->f_flag |= FHASLOCK; } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); *retval = indx; return (0); } @@ -743,15 +912,22 @@ struct ocreat_args { int ocreat(p, uap, retval) struct proc *p; - register struct ocreat_args *uap; - int *retval; + register struct ocreat_args /* { + syscallarg(char *) path; + syscallarg(int) mode; + } */ *uap; + register_t *retval; { - struct open_args openuap; - - openuap.path = uap->path; - openuap.mode = uap->mode; - openuap.flags = O_WRONLY | O_CREAT | O_TRUNC; - return (open(p, &openuap, retval)); + struct open_args /* { + syscallarg(char *) path; + syscallarg(int) flags; + syscallarg(int) mode; + } */ nuap; + + SCARG(&nuap, path) = SCARG(uap, path); + SCARG(&nuap, mode) = SCARG(uap, mode); + SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; + return (open(p, &nuap, retval)); } #endif /* COMPAT_43 */ @@ -769,30 +945,35 @@ struct mknod_args { int mknod(p, uap, retval) struct proc *p; - register struct mknod_args *uap; - int *retval; + register struct mknod_args /* { + syscallarg(char *) path; + syscallarg(int) mode; + syscallarg(int) dev; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; int error; + int whiteout; struct nameidata nd; error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; if (vp != NULL) error = EEXIST; else { VATTR_NULL(&vattr); - vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; - vattr.va_rdev = uap->dev; + vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; + vattr.va_rdev = SCARG(uap, dev); + whiteout = 0; - switch (uap->mode & S_IFMT) { + switch (SCARG(uap, mode) & S_IFMT) { case S_IFMT: /* used by badsect to flag bad sectors */ vattr.va_type = VBAD; break; @@ -802,14 +983,25 @@ mknod(p, uap, retval) case S_IFBLK: vattr.va_type = VBLK; break; + case S_IFWHT: + whiteout = 1; + break; default: error = EINVAL; break; } } if (!error) { - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + if (whiteout) { + error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); + if (error) + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + vput(nd.ni_dvp); + } else { + error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, + &nd.ni_cnd, &vattr); + } } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == vp) @@ -823,7 +1015,7 @@ mknod(p, uap, retval) } /* - * Create named pipe. + * Create a named pipe. */ #ifndef _SYS_SYSPROTO_H_ struct mkfifo_args { @@ -835,16 +1027,21 @@ struct mkfifo_args { int mkfifo(p, uap, retval) struct proc *p; - register struct mkfifo_args *uap; - int *retval; + register struct mkfifo_args /* { + syscallarg(char *) path; + syscallarg(int) mode; + } */ *uap; + register_t *retval; { +#ifndef FIFO + return (EOPNOTSUPP); +#else struct vattr vattr; int error; struct nameidata nd; - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); if (nd.ni_vp != NULL) { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -857,9 +1054,10 @@ mkfifo(p, uap, retval) } VATTR_NULL(&vattr); vattr.va_type = VFIFO; - vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); +#endif /* FIFO */ } /* @@ -875,22 +1073,24 @@ struct link_args { int link(p, uap, retval) struct proc *p; - register struct link_args *uap; - int *retval; + register struct link_args /* { + syscallarg(char *) path; + syscallarg(char *) link; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct nameidata nd; int error; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; if (vp->v_type == VDIR) error = EPERM; /* POSIX */ else { - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); error = namei(&nd); if (!error) { if (nd.ni_vp != NULL) { @@ -903,10 +1103,9 @@ link(p, uap, retval) vrele(nd.ni_vp); error = EEXIST; } else { - LEASE_CHECK(nd.ni_dvp, - p, p->p_ucred, LEASE_WRITE); - LEASE_CHECK(vp, - p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, + LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); } } @@ -928,8 +1127,11 @@ struct symlink_args { int symlink(p, uap, retval) struct proc *p; - register struct symlink_args *uap; - int *retval; + register struct symlink_args /* { + syscallarg(char *) path; + syscallarg(char *) link; + } */ *uap; + register_t *retval; { struct vattr vattr; char *path; @@ -937,12 +1139,10 @@ symlink(p, uap, retval) struct nameidata nd; MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); - error = copyinstr(uap->path, path, MAXPATHLEN, NULL); - if (error) + if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) goto out; - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); - error = namei(&nd); - if (error) + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); + if (error = namei(&nd)) goto out; if (nd.ni_vp) { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -956,7 +1156,7 @@ symlink(p, uap, retval) } VATTR_NULL(&vattr); vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); out: FREE(path, M_NAMEI); @@ -964,6 +1164,45 @@ out: } /* + * Delete a whiteout from the filesystem. + */ +/* ARGSUSED */ +int +undelete(p, uap, retval) + struct proc *p; + register struct undelete_args /* { + syscallarg(char *) path; + } */ *uap; + register_t *retval; +{ + int error; + struct nameidata nd; + + NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, + SCARG(uap, path), p); + error = namei(&nd); + if (error) + return (error); + + if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + if (nd.ni_vp) + vrele(nd.ni_vp); + return (EEXIST); + } + + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + vput(nd.ni_dvp); + return (error); +} + +/* * Delete a name from the filesystem. */ #ifndef _SYS_SYSPROTO_H_ @@ -975,20 +1214,21 @@ struct unlink_args { int unlink(p, uap, retval) struct proc *p; - struct unlink_args *uap; - int *retval; + struct unlink_args /* { + syscallarg(char *) path; + } */ *uap; + register_t *retval; { register struct vnode *vp; int error; struct nameidata nd; - NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (vp->v_type == VDIR) error = EPERM; /* POSIX */ @@ -1001,11 +1241,11 @@ unlink(p, uap, retval) if (vp->v_flag & VROOT) error = EBUSY; else - (void) vnode_pager_uncache(vp); + (void) vnode_pager_uncache(vp, p); } if (!error) { - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -1013,7 +1253,8 @@ unlink(p, uap, retval) vrele(nd.ni_dvp); else vput(nd.ni_dvp); - vput(vp); + if (vp != NULLVP) + vput(vp); } return (error); } @@ -1032,8 +1273,13 @@ struct lseek_args { int lseek(p, uap, retval) struct proc *p; - register struct lseek_args *uap; - int *retval; + register struct lseek_args /* { + syscallarg(int) fd; + syscallarg(int) pad; + syscallarg(off_t) offset; + syscallarg(int) whence; + } */ *uap; + register_t *retval; /* XXX */ { struct ucred *cred = p->p_ucred; register struct filedesc *fdp = p->p_fd; @@ -1041,23 +1287,23 @@ lseek(p, uap, retval) struct vattr vattr; int error; - if ((u_int)uap->fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[uap->fd]) == NULL) + if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || + (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) return (EBADF); if (fp->f_type != DTYPE_VNODE) return (ESPIPE); - switch (uap->whence) { + switch (SCARG(uap, whence)) { case L_INCR: - fp->f_offset += uap->offset; + fp->f_offset += SCARG(uap, offset); break; case L_XTND: error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p); if (error) return (error); - fp->f_offset = uap->offset + vattr.va_size; + fp->f_offset = SCARG(uap, offset) + vattr.va_size; break; case L_SET: - fp->f_offset = uap->offset; + fp->f_offset = SCARG(uap, offset); break; default: return (EINVAL); @@ -1080,17 +1326,26 @@ struct olseek_args { int olseek(p, uap, retval) struct proc *p; - register struct olseek_args *uap; - int *retval; + register struct olseek_args /* { + syscallarg(int) fd; + syscallarg(long) offset; + syscallarg(int) whence; + } */ *uap; + register_t *retval; { - struct lseek_args nuap; + struct lseek_args /* { + syscallarg(int) fd; + syscallarg(int) pad; + syscallarg(off_t) offset; + syscallarg(int) whence; + } */ nuap; off_t qret; int error; - nuap.fd = uap->fd; - nuap.offset = uap->offset; - nuap.whence = uap->whence; - error = lseek(p, &nuap, (int *)&qret); + SCARG(&nuap, fd) = SCARG(uap, fd); + SCARG(&nuap, offset) = SCARG(uap, offset); + SCARG(&nuap, whence) = SCARG(uap, whence); + error = lseek(p, &nuap, (register_t *) &qret); *(long *)retval = qret; return (error); } @@ -1108,8 +1363,11 @@ struct access_args { int access(p, uap, retval) struct proc *p; - register struct access_args *uap; - int *retval; + register struct access_args /* { + syscallarg(char *) path; + syscallarg(int) flags; + } */ *uap; + register_t *retval; { register struct ucred *cred = p->p_ucred; register struct vnode *vp; @@ -1120,20 +1378,20 @@ access(p, uap, retval) t_gid = cred->cr_groups[0]; cred->cr_uid = p->p_cred->p_ruid; cred->cr_groups[0] = p->p_cred->p_rgid; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) goto out1; vp = nd.ni_vp; /* Flags == 0 means only check for existence. */ - if (uap->flags) { + if (SCARG(uap, flags)) { flags = 0; - if (uap->flags & R_OK) + if (SCARG(uap, flags) & R_OK) flags |= VREAD; - if (uap->flags & W_OK) + if (SCARG(uap, flags) & W_OK) flags |= VWRITE; - if (uap->flags & X_OK) + if (SCARG(uap, flags) & X_OK) flags |= VEXEC; if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) error = VOP_ACCESS(vp, flags, cred, p); @@ -1159,24 +1417,27 @@ struct ostat_args { int ostat(p, uap, retval) struct proc *p; - register struct ostat_args *uap; - int *retval; + register struct ostat_args /* { + syscallarg(char *) path; + syscallarg(struct ostat *) ub; + } */ *uap; + register_t *retval; { struct stat sb; struct ostat osb; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); error = vn_stat(nd.ni_vp, &sb, p); vput(nd.ni_vp); if (error) return (error); cvtstat(&sb, &osb); - error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); + error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); return (error); } @@ -1193,8 +1454,11 @@ struct olstat_args { int olstat(p, uap, retval) struct proc *p; - register struct olstat_args *uap; - int *retval; + register struct olstat_args /* { + syscallarg(char *) path; + syscallarg(struct ostat *) ub; + } */ *uap; + register_t *retval; { struct vnode *vp, *dvp; struct stat sb, sb1; @@ -1203,9 +1467,8 @@ olstat(p, uap, retval) struct nameidata nd; NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, - uap->path, p); - error = namei(&nd); - if (error) + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); /* * For symbolic links, always return the attributes of its @@ -1240,7 +1503,7 @@ olstat(p, uap, retval) sb.st_blocks = sb1.st_blocks; } cvtstat(&sb, &osb); - error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); + error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); return (error); } @@ -1287,22 +1550,25 @@ struct stat_args { int stat(p, uap, retval) struct proc *p; - register struct stat_args *uap; - int *retval; + register struct stat_args /* { + syscallarg(char *) path; + syscallarg(struct stat *) ub; + } */ *uap; + register_t *retval; { struct stat sb; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); error = vn_stat(nd.ni_vp, &sb, p); vput(nd.ni_vp); if (error) return (error); - error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); + error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); return (error); } @@ -1319,8 +1585,11 @@ struct lstat_args { int lstat(p, uap, retval) struct proc *p; - register struct lstat_args *uap; - int *retval; + register struct lstat_args /* { + syscallarg(char *) path; + syscallarg(struct stat *) ub; + } */ *uap; + register_t *retval; { int error; struct vnode *vp, *dvp; @@ -1328,13 +1597,12 @@ lstat(p, uap, retval) struct nameidata nd; NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, - uap->path, p); - error = namei(&nd); - if (error) + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); /* - * For symbolic links, always return the attributes of its - * containing directory, except for mode, size, and links. + * For symbolic links, always return the attributes of its containing + * directory, except for mode, size, inode number, and links. */ vp = nd.ni_vp; dvp = nd.ni_dvp; @@ -1363,8 +1631,9 @@ lstat(p, uap, retval) sb.st_nlink = sb1.st_nlink; sb.st_size = sb1.st_size; sb.st_blocks = sb1.st_blocks; + sb.st_ino = sb1.st_ino; } - error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); + error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); return (error); } @@ -1381,17 +1650,20 @@ struct pathconf_args { int pathconf(p, uap, retval) struct proc *p; - register struct pathconf_args *uap; - int *retval; + register struct pathconf_args /* { + syscallarg(char *) path; + syscallarg(int) name; + } */ *uap; + register_t *retval; { int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); - error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); + error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); vput(nd.ni_vp); return (error); } @@ -1410,8 +1682,12 @@ struct readlink_args { int readlink(p, uap, retval) struct proc *p; - register struct readlink_args *uap; - int *retval; + register struct readlink_args /* { + syscallarg(char *) path; + syscallarg(char *) buf; + syscallarg(int) count; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct iovec aiov; @@ -1419,27 +1695,27 @@ readlink(p, uap, retval) int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; if (vp->v_type != VLNK) error = EINVAL; else { - aiov.iov_base = uap->buf; - aiov.iov_len = uap->count; + aiov.iov_base = SCARG(uap, buf); + aiov.iov_len = SCARG(uap, count); auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = 0; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_USERSPACE; auio.uio_procp = p; - auio.uio_resid = uap->count; + auio.uio_resid = SCARG(uap, count); error = VOP_READLINK(vp, &auio, p->p_ucred); } vput(vp); - *retval = uap->count - auio.uio_resid; + *retval = SCARG(uap, count) - auio.uio_resid; return (error); } @@ -1456,23 +1732,25 @@ struct chflags_args { int chflags(p, uap, retval) struct proc *p; - register struct chflags_args *uap; - int *retval; + register struct chflags_args /* { + syscallarg(char *) path; + syscallarg(int) flags; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); VATTR_NULL(&vattr); - vattr.va_flags = uap->flags; + vattr.va_flags = SCARG(uap, flags); error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); vput(vp); return (error); @@ -1491,24 +1769,26 @@ struct fchflags_args { int fchflags(p, uap, retval) struct proc *p; - register struct fchflags_args *uap; - int *retval; + register struct fchflags_args /* { + syscallarg(int) fd; + syscallarg(int) flags; + } */ *uap; + register_t *retval; { struct vattr vattr; struct vnode *vp; struct file *fp; int error; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); vp = (struct vnode *)fp->f_data; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); VATTR_NULL(&vattr); - vattr.va_flags = uap->flags; + vattr.va_flags = SCARG(uap, flags); error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1525,23 +1805,25 @@ struct chmod_args { int chmod(p, uap, retval) struct proc *p; - register struct chmod_args *uap; - int *retval; + register struct chmod_args /* { + syscallarg(char *) path; + syscallarg(int) mode; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); VATTR_NULL(&vattr); - vattr.va_mode = uap->mode & ALLPERMS; + vattr.va_mode = SCARG(uap, mode) & ALLPERMS; error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); vput(vp); return (error); @@ -1560,24 +1842,26 @@ struct fchmod_args { int fchmod(p, uap, retval) struct proc *p; - register struct fchmod_args *uap; - int *retval; + register struct fchmod_args /* { + syscallarg(int) fd; + syscallarg(int) mode; + } */ *uap; + register_t *retval; { struct vattr vattr; struct vnode *vp; struct file *fp; int error; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); vp = (struct vnode *)fp->f_data; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); VATTR_NULL(&vattr); - vattr.va_mode = uap->mode & ALLPERMS; + vattr.va_mode = SCARG(uap, mode) & ALLPERMS; error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1595,24 +1879,27 @@ struct chown_args { int chown(p, uap, retval) struct proc *p; - register struct chown_args *uap; - int *retval; + register struct chown_args /* { + syscallarg(char *) path; + syscallarg(int) uid; + syscallarg(int) gid; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); VATTR_NULL(&vattr); - vattr.va_uid = uap->uid; - vattr.va_gid = uap->gid; + vattr.va_uid = SCARG(uap, uid); + vattr.va_gid = SCARG(uap, gid); error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); vput(vp); return (error); @@ -1632,25 +1919,28 @@ struct fchown_args { int fchown(p, uap, retval) struct proc *p; - register struct fchown_args *uap; - int *retval; + register struct fchown_args /* { + syscallarg(int) fd; + syscallarg(int) uid; + syscallarg(int) gid; + } */ *uap; + register_t *retval; { struct vattr vattr; struct vnode *vp; struct file *fp; int error; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); vp = (struct vnode *)fp->f_data; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); VATTR_NULL(&vattr); - vattr.va_uid = uap->uid; - vattr.va_gid = uap->gid; + vattr.va_uid = SCARG(uap, uid); + vattr.va_gid = SCARG(uap, gid); error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1667,8 +1957,11 @@ struct utimes_args { int utimes(p, uap, retval) struct proc *p; - register struct utimes_args *uap; - int *retval; + register struct utimes_args /* { + syscallarg(char *) path; + syscallarg(struct timeval *) tptr; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct timeval tv[2]; @@ -1677,22 +1970,19 @@ utimes(p, uap, retval) struct nameidata nd; VATTR_NULL(&vattr); - if (uap->tptr == NULL) { + if (SCARG(uap, tptr) == NULL) { microtime(&tv[0]); tv[1] = tv[0]; vattr.va_vaflags |= VA_UTIMES_NULL; - } else { - error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); - if (error) - return (error); - } - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, + sizeof (tv))) + return (error); + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); vattr.va_atime.tv_sec = tv[0].tv_sec; vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; vattr.va_mtime.tv_sec = tv[1].tv_sec; @@ -1716,8 +2006,12 @@ struct truncate_args { int truncate(p, uap, retval) struct proc *p; - register struct truncate_args *uap; - int *retval; + register struct truncate_args /* { + syscallarg(char *) path; + syscallarg(int) pad; + syscallarg(off_t) length; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; @@ -1726,19 +2020,18 @@ truncate(p, uap, retval) if (uap->length < 0) return(EINVAL); - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (vp->v_type == VDIR) error = EISDIR; else if ((error = vn_writechk(vp)) == 0 && (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { VATTR_NULL(&vattr); - vattr.va_size = uap->length; + vattr.va_size = SCARG(uap, length); error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } vput(vp); @@ -1759,8 +2052,12 @@ struct ftruncate_args { int ftruncate(p, uap, retval) struct proc *p; - register struct ftruncate_args *uap; - int *retval; + register struct ftruncate_args /* { + syscallarg(int) fd; + syscallarg(int) pad; + syscallarg(off_t) length; + } */ *uap; + register_t *retval; { struct vattr vattr; struct vnode *vp; @@ -1769,22 +2066,21 @@ ftruncate(p, uap, retval) if (uap->length < 0) return(EINVAL); - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); if ((fp->f_flag & FWRITE) == 0) return (EINVAL); vp = (struct vnode *)fp->f_data; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); - VOP_LOCK(vp); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (vp->v_type == VDIR) error = EISDIR; else if ((error = vn_writechk(vp)) == 0) { VATTR_NULL(&vattr); - vattr.va_size = uap->length; + vattr.va_size = SCARG(uap, length); error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1802,13 +2098,20 @@ struct otruncate_args { int otruncate(p, uap, retval) struct proc *p; - register struct otruncate_args *uap; - int *retval; + register struct otruncate_args /* { + syscallarg(char *) path; + syscallarg(long) length; + } */ *uap; + register_t *retval; { - struct truncate_args nuap; - - nuap.path = uap->path; - nuap.length = uap->length; + struct truncate_args /* { + syscallarg(char *) path; + syscallarg(int) pad; + syscallarg(off_t) length; + } */ nuap; + + SCARG(&nuap, path) = SCARG(uap, path); + SCARG(&nuap, length) = SCARG(uap, length); return (truncate(p, &nuap, retval)); } @@ -1825,13 +2128,20 @@ struct oftruncate_args { int oftruncate(p, uap, retval) struct proc *p; - register struct oftruncate_args *uap; - int *retval; + register struct oftruncate_args /* { + syscallarg(int) fd; + syscallarg(long) length; + } */ *uap; + register_t *retval; { - struct ftruncate_args nuap; - - nuap.fd = uap->fd; - nuap.length = uap->length; + struct ftruncate_args /* { + syscallarg(int) fd; + syscallarg(int) pad; + syscallarg(off_t) length; + } */ nuap; + + SCARG(&nuap, fd) = SCARG(uap, fd); + SCARG(&nuap, length) = SCARG(uap, length); return (ftruncate(p, &nuap, retval)); } #endif /* COMPAT_43 || COMPAT_SUNOS */ @@ -1848,24 +2158,25 @@ struct fsync_args { int fsync(p, uap, retval) struct proc *p; - struct fsync_args *uap; - int *retval; + struct fsync_args /* { + syscallarg(int) fd; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct file *fp; int error; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); vp = (struct vnode *)fp->f_data; - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (vp->v_object) { vm_object_page_clean(vp->v_object, 0, 0 ,0, FALSE); } error = VOP_FSYNC(vp, fp->f_cred, (vp->v_mount->mnt_flag & MNT_ASYNC) ? MNT_NOWAIT : MNT_WAIT, p); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1883,29 +2194,29 @@ struct rename_args { int rename(p, uap, retval) struct proc *p; - register struct rename_args *uap; - int *retval; + register struct rename_args /* { + syscallarg(char *) from; + syscallarg(char *) to; + } */ *uap; + register_t *retval; { register struct vnode *tvp, *fvp, *tdvp; struct nameidata fromnd, tond; int error; NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, - uap->from, p); - error = namei(&fromnd); - if (error) + SCARG(uap, from), p); + if (error = namei(&fromnd)) return (error); fvp = fromnd.ni_vp; NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, - UIO_USERSPACE, uap->to, p); + UIO_USERSPACE, SCARG(uap, to), p); if (fromnd.ni_vp->v_type == VDIR) tond.ni_cnd.cn_flags |= WILLBEDIR; - error = namei(&tond); - if (error) { + if (error = namei(&tond)) { /* Translate error code for rename("dir1", "dir2/."). */ if (error == EISDIR && fvp->v_type == VDIR) error = EINVAL; - VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); vrele(fromnd.ni_dvp); vrele(fvp); @@ -1936,13 +2247,12 @@ rename(p, uap, retval) error = -1; out: if (!error) { - LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); - if (fromnd.ni_dvp != tdvp) { - LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - } + VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); + if (fromnd.ni_dvp != tdvp) + VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); if (tvp) { - LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); - (void) vnode_pager_uncache(tvp); + VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); + (void) vnode_pager_uncache(tvp, p); } error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); @@ -1982,18 +2292,20 @@ struct mkdir_args { int mkdir(p, uap, retval) struct proc *p; - register struct mkdir_args *uap; - int *retval; + register struct mkdir_args /* { + syscallarg(char *) path; + syscallarg(int) mode; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); + NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); nd.ni_cnd.cn_flags |= WILLBEDIR; - error = namei(&nd); - if (error) + if (error = namei(&nd)) return (error); vp = nd.ni_vp; if (vp != NULL) { @@ -2007,8 +2319,8 @@ mkdir(p, uap, retval) } VATTR_NULL(&vattr); vattr.va_type = VDIR; - vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); if (!error) vput(nd.ni_vp); @@ -2027,16 +2339,18 @@ struct rmdir_args { int rmdir(p, uap, retval) struct proc *p; - struct rmdir_args *uap; - int *retval; + struct rmdir_args /* { + syscallarg(char *) path; + } */ *uap; + register_t *retval; { register struct vnode *vp; int error; struct nameidata nd; - NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; if (vp->v_type != VDIR) { @@ -2057,8 +2371,8 @@ rmdir(p, uap, retval) error = EBUSY; out: if (!error) { - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -2086,8 +2400,13 @@ struct ogetdirentries_args { int ogetdirentries(p, uap, retval) struct proc *p; - register struct ogetdirentries_args *uap; - int *retval; + register struct ogetdirentries_args /* { + syscallarg(int) fd; + syscallarg(char *) buf; + syscallarg(u_int) count; + syscallarg(long *) basep; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct file *fp; @@ -2095,30 +2414,31 @@ ogetdirentries(p, uap, retval) struct iovec aiov, kiov; struct dirent *dp, *edp; caddr_t dirbuf; - int error, readcnt; + int error, eofflag, readcnt; long loff; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); if ((fp->f_flag & FREAD) == 0) return (EBADF); vp = (struct vnode *)fp->f_data; +unionread: if (vp->v_type != VDIR) return (EINVAL); - aiov.iov_base = uap->buf; - aiov.iov_len = uap->count; + aiov.iov_base = SCARG(uap, buf); + aiov.iov_len = SCARG(uap, count); auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_USERSPACE; auio.uio_procp = p; - auio.uio_resid = uap->count; - VOP_LOCK(vp); + auio.uio_resid = SCARG(uap, count); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); loff = auio.uio_offset = fp->f_offset; # if (BYTE_ORDER != LITTLE_ENDIAN) if (vp->v_mount->mnt_maxsymlinklen <= 0) { - error = VOP_READDIR(vp, &auio, fp->f_cred, NULL, NULL, NULL); + error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, + NULL, NULL); fp->f_offset = auio.uio_offset; } else # endif @@ -2126,13 +2446,14 @@ ogetdirentries(p, uap, retval) kuio = auio; kuio.uio_iov = &kiov; kuio.uio_segflg = UIO_SYSSPACE; - kiov.iov_len = uap->count; - MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); + kiov.iov_len = SCARG(uap, count); + MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); kiov.iov_base = dirbuf; - error = VOP_READDIR(vp, &kuio, fp->f_cred, NULL, NULL, NULL); + error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, + NULL, NULL); fp->f_offset = kuio.uio_offset; if (error == 0) { - readcnt = uap->count - kuio.uio_resid; + readcnt = SCARG(uap, count) - kuio.uio_resid; edp = (struct dirent *)&dirbuf[readcnt]; for (dp = (struct dirent *)dirbuf; dp < edp; ) { # if (BYTE_ORDER == LITTLE_ENDIAN) @@ -2165,14 +2486,70 @@ ogetdirentries(p, uap, retval) } FREE(dirbuf, M_TEMP); } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); if (error) return (error); - error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); - *retval = uap->count - auio.uio_resid; + +#ifdef UNION +{ + extern int (**union_vnodeop_p)(); + extern struct vnode *union_dircache __P((struct vnode*, struct proc*)); + + if ((SCARG(uap, count) == auio.uio_resid) && + (vp->v_op == union_vnodeop_p)) { + struct vnode *lvp; + + lvp = union_dircache(vp, p); + if (lvp != NULLVP) { + struct vattr va; + + /* + * If the directory is opaque, + * then don't show lower entries + */ + error = VOP_GETATTR(vp, &va, fp->f_cred, p); + if (va.va_flags & OPAQUE) { + vput(lvp); + lvp = NULL; + } + } + + if (lvp != NULLVP) { + error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); + if (error) { + vput(lvp); + return (error); + } + VOP_UNLOCK(lvp, 0, p); + fp->f_data = (caddr_t) lvp; + fp->f_offset = 0; + error = vn_close(vp, FREAD, fp->f_cred, p); + if (error) + return (error); + vp = lvp; + goto unionread; + } + } +} +#endif /* UNION */ + + if ((SCARG(uap, count) == auio.uio_resid) && + (vp->v_flag & VROOT) && + (vp->v_mount->mnt_flag & MNT_UNION)) { + struct vnode *tvp = vp; + vp = vp->v_mount->mnt_vnodecovered; + VREF(vp); + fp->f_data = (caddr_t) vp; + fp->f_offset = 0; + vrele(tvp); + goto unionread; + } + error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), + sizeof(long)); + *retval = SCARG(uap, count) - auio.uio_resid; return (error); } -#endif +#endif /* COMPAT_43 */ /* * Read a block of directory entries in a file system independent format. @@ -2188,18 +2565,22 @@ struct getdirentries_args { int getdirentries(p, uap, retval) struct proc *p; - register struct getdirentries_args *uap; - int *retval; + register struct getdirentries_args /* { + syscallarg(int) fd; + syscallarg(char *) buf; + syscallarg(u_int) count; + syscallarg(long *) basep; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct file *fp; struct uio auio; struct iovec aiov; long loff; - int error; + int error, eofflag; - error = getvnode(p->p_fd, uap->fd, &fp); - if (error) + if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) return (error); if ((fp->f_flag & FREAD) == 0) return (EBADF); @@ -2207,51 +2588,66 @@ getdirentries(p, uap, retval) unionread: if (vp->v_type != VDIR) return (EINVAL); - aiov.iov_base = uap->buf; - aiov.iov_len = uap->count; + aiov.iov_base = SCARG(uap, buf); + aiov.iov_len = SCARG(uap, count); auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_USERSPACE; auio.uio_procp = p; - auio.uio_resid = uap->count; - VOP_LOCK(vp); + auio.uio_resid = SCARG(uap, count); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); loff = auio.uio_offset = fp->f_offset; - error = VOP_READDIR(vp, &auio, fp->f_cred, NULL, NULL, NULL); + error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL); fp->f_offset = auio.uio_offset; - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); if (error) return (error); #ifdef UNION { - if ((uap->count == auio.uio_resid) && + extern int (**union_vnodeop_p)(); + extern struct vnode *union_dircache __P((struct vnode*, struct proc*)); + + if ((SCARG(uap, count) == auio.uio_resid) && (vp->v_op == union_vnodeop_p)) { - struct vnode *tvp = vp; + struct vnode *lvp; + + lvp = union_dircache(vp, p); + if (lvp != NULLVP) { + struct vattr va; - vp = union_lowervp(vp); - if (vp != NULLVP) { - VOP_LOCK(vp); - error = VOP_OPEN(vp, FREAD, fp->f_cred, p); - VOP_UNLOCK(vp); + /* + * If the directory is opaque, + * then don't show lower entries + */ + error = VOP_GETATTR(vp, &va, fp->f_cred, p); + if (va.va_flags & OPAQUE) { + vput(lvp); + lvp = NULL; + } + } + if (lvp != NULLVP) { + error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); if (error) { - vrele(vp); + vput(lvp); return (error); } - fp->f_data = (caddr_t) vp; + VOP_UNLOCK(lvp, 0, p); + fp->f_data = (caddr_t) lvp; fp->f_offset = 0; - error = vn_close(tvp, FREAD, fp->f_cred, p); + error = vn_close(vp, FREAD, fp->f_cred, p); if (error) return (error); + vp = lvp; goto unionread; } } } -#endif +#endif /* UNION */ - if ((uap->count == auio.uio_resid) && - vp && + if ((SCARG(uap, count) == auio.uio_resid) && (vp->v_flag & VROOT) && (vp->v_mount->mnt_flag & MNT_UNION)) { struct vnode *tvp = vp; @@ -2262,8 +2658,9 @@ unionread: vrele(tvp); goto unionread; } - error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); - *retval = uap->count - auio.uio_resid; + error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), + sizeof(long)); + *retval = SCARG(uap, count) - auio.uio_resid; return (error); } @@ -2275,17 +2672,19 @@ struct umask_args { int newmask; }; #endif -mode_t /* XXX */ +int umask(p, uap, retval) struct proc *p; - struct umask_args *uap; - int *retval; + struct umask_args /* { + syscallarg(int) newmask; + } */ *uap; + int *retval; /* XXX */ { register struct filedesc *fdp; fdp = p->p_fd; *retval = fdp->fd_cmask; - fdp->fd_cmask = uap->newmask & ALLPERMS; + fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; return (0); } @@ -2302,31 +2701,27 @@ struct revoke_args { int revoke(p, uap, retval) struct proc *p; - register struct revoke_args *uap; - int *retval; + register struct revoke_args /* { + syscallarg(char *) path; + } */ *uap; + register_t *retval; { register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); - error = namei(&nd); - if (error) + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if (error = namei(&nd)) return (error); vp = nd.ni_vp; - if (vp->v_type != VCHR && vp->v_type != VBLK) { - error = EINVAL; - goto out; - } - error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); - if (error) + if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) goto out; if (p->p_ucred->cr_uid != vattr.va_uid && (error = suser(p->p_ucred, &p->p_acflag))) goto out; if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) - vgoneall(vp); + VOP_REVOKE(vp, REVOKEALL); out: vrele(vp); return (error); diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 0ba5c45..98842c6 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -96,10 +96,11 @@ vn_open(ndp, fmode, cmode) VATTR_NULL(vap); vap->va_type = VREG; vap->va_mode = cmode; - LEASE_CHECK(ndp->ni_dvp, p, cred, LEASE_WRITE); - error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, - &ndp->ni_cnd, vap); - if (error) + if (fmode & O_EXCL) + vap->va_vaflags |= VA_EXCLUSIVE; + VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE); + if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, + &ndp->ni_cnd, vap)) return (error); fmode &= ~O_TRUNC; vp = ndp->ni_vp; @@ -149,9 +150,9 @@ vn_open(ndp, fmode, cmode) } } if (fmode & O_TRUNC) { - VOP_UNLOCK(vp); /* XXX */ - LEASE_CHECK(vp, p, cred, LEASE_WRITE); - VOP_LOCK(vp); /* XXX */ + VOP_UNLOCK(vp, 0, p); /* XXX */ + VOP_LEASE(vp, p, cred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ VATTR_NULL(vap); vap->va_size = 0; error = VOP_SETATTR(vp, vap, cred, p); @@ -179,8 +180,7 @@ bad: /* * Check for write permissions on the specified vnode. - * The read-only status of the file system is checked. - * Also, prototype text segments cannot be written. + * Prototype text segments cannot be written. */ int vn_writechk(vp) @@ -237,7 +237,7 @@ vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) int error; if ((ioflg & IO_NODELOCKED) == 0) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); auio.uio_iov = &aiov; auio.uio_iovcnt = 1; aiov.iov_base = base; @@ -258,7 +258,7 @@ vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) if (auio.uio_resid && error == 0) error = EIO; if ((ioflg & IO_NODELOCKED) == 0) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -271,12 +271,13 @@ vn_read(fp, uio, cred) struct uio *uio; struct ucred *cred; { - register struct vnode *vp = (struct vnode *)fp->f_data; + struct vnode *vp = (struct vnode *)fp->f_data; + struct proc *p = uio->uio_procp; int count, error; int flag, seq; - LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_READ); - VOP_LOCK(vp); + VOP_LEASE(vp, p, cred, LEASE_READ); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); uio->uio_offset = fp->f_offset; count = uio->uio_resid; flag = 0; @@ -313,7 +314,7 @@ vn_read(fp, uio, cred) error = VOP_READ(vp, uio, flag, cred); fp->f_offset += count - uio->uio_resid; fp->f_nextread = fp->f_offset; - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -326,15 +327,19 @@ vn_write(fp, uio, cred) struct uio *uio; struct ucred *cred; { - register struct vnode *vp = (struct vnode *)fp->f_data; - int count, error, ioflag = 0; + struct vnode *vp = (struct vnode *)fp->f_data; + struct proc *p = uio->uio_procp; + int count, error, ioflag = IO_UNIT; if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) ioflag |= IO_APPEND; if (fp->f_flag & FNONBLOCK) ioflag |= IO_NDELAY; - LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_WRITE); - VOP_LOCK(vp); + if ((fp->f_flag & O_FSYNC) || + (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS))) + ioflag |= IO_SYNC; + VOP_LEASE(vp, p, cred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); uio->uio_offset = fp->f_offset; count = uio->uio_resid; error = VOP_WRITE(vp, uio, ioflag, cred); @@ -342,7 +347,7 @@ vn_write(fp, uio, cred) fp->f_offset = uio->uio_offset; else fp->f_offset += count - uio->uio_resid; - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -402,7 +407,7 @@ vn_stat(vp, sb, p) sb->st_rdev = vap->va_rdev; sb->st_size = vap->va_size; sb->st_atimespec = vap->va_atime; - sb->st_mtimespec= vap->va_mtime; + sb->st_mtimespec = vap->va_mtime; sb->st_ctimespec = vap->va_ctime; sb->st_blksize = vap->va_blocksize; sb->st_flags = vap->va_flags; @@ -495,3 +500,34 @@ vn_closefile(fp, p) return (vn_close(((struct vnode *)fp->f_data), fp->f_flag, fp->f_cred, p)); } + +/* + * Check that the vnode is still valid, and if so + * acquire requested lock. + */ +int +vn_lock(vp, flags, p) + struct vnode *vp; + int flags; + struct proc *p; +{ + int error; + + do { + if ((flags & LK_INTERLOCK) == 0) { + simple_lock(&vp->v_interlock); + } + if (vp->v_flag & VXLOCK) { + vp->v_flag |= VXWANT; + simple_unlock(&vp->v_interlock); + tsleep((caddr_t)vp, PINOD, "vn_lock", 0); + error = ENOENT; + } else { + error = VOP_LOCK(vp, flags | LK_INTERLOCK, p); + if (error == 0) + return (error); + } + flags &= ~LK_INTERLOCK; + } while (flags & LK_RETRY); + return (error); +} diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src index a8fb13b..7e3338f 100644 --- a/sys/kern/vnode_if.src +++ b/sys/kern/vnode_if.src @@ -30,8 +30,33 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)vnode_if.src 8.3 (Berkeley) 2/3/94 -# $FreeBSD$ +# @(#)vnode_if.src 8.12 (Berkeley) 5/14/95 +# $Id: vnode_if.src,v 1.9.2000.1 1996/09/17 14:32:01 peter Exp $ +# + +# +# Above each of the vop descriptors is a specification of the locking +# protocol used by each vop call. The first column is the name of +# the variable, the remaining three columns are in, out and error +# respectively. The "in" column defines the lock state on input, +# the "out" column defines the state on succesful return, and the +# "error" column defines the locking state on error exit. +# +# The locking value can take the following values: +# L: locked. +# U: unlocked/ +# -: not applicable. vnode does not yet (or no longer) exists. +# =: the same on input and output, may be either L or U. +# X: locked if not nil. +# + +# +#% lookup dvp L ? ? +#% lookup vpp - L - +# +# XXX - the lookup locking protocol defies simple description and depends +# on the flags and operation fields in the (cnp) structure. Note +# especially that *vpp may equal dvp and both may be locked. # vop_lookup { IN struct vnode *dvp; @@ -39,6 +64,10 @@ vop_lookup { IN struct componentname *cnp; }; +# +#% create dvp L U U +#% create vpp - L - +# vop_create { IN WILLRELE struct vnode *dvp; OUT struct vnode **vpp; @@ -46,6 +75,21 @@ vop_create { IN struct vattr *vap; }; +# +#% whiteout dvp L L L +#% whiteout cnp - - - +#% whiteout flag - - - +# +vop_whiteout { + IN WILLRELE struct vnode *dvp; + IN struct componentname *cnp; + IN int flags; +}; + +# +#% mknod dvp L U U +#% mknod vpp - X - +# vop_mknod { IN WILLRELE struct vnode *dvp; OUT WILLRELE struct vnode **vpp; @@ -53,6 +97,9 @@ vop_mknod { IN struct vattr *vap; }; +# +#% open vp L L L +# vop_open { IN struct vnode *vp; IN int mode; @@ -60,6 +107,9 @@ vop_open { IN struct proc *p; }; +# +#% close vp U U U +# vop_close { IN struct vnode *vp; IN int fflag; @@ -67,6 +117,9 @@ vop_close { IN struct proc *p; }; +# +#% access vp L L L +# vop_access { IN struct vnode *vp; IN int mode; @@ -74,6 +127,9 @@ vop_access { IN struct proc *p; }; +# +#% getattr vp = = = +# vop_getattr { IN struct vnode *vp; IN struct vattr *vap; @@ -81,6 +137,9 @@ vop_getattr { IN struct proc *p; }; +# +#% setattr vp L L L +# vop_setattr { IN struct vnode *vp; IN struct vattr *vap; @@ -88,6 +147,9 @@ vop_setattr { IN struct proc *p; }; +# +#% read vp L L L +# vop_read { IN struct vnode *vp; INOUT struct uio *uio; @@ -95,6 +157,9 @@ vop_read { IN struct ucred *cred; }; +# +#% write vp L L L +# vop_write { IN struct vnode *vp; INOUT struct uio *uio; @@ -102,16 +167,33 @@ vop_write { IN struct ucred *cred; }; +# +#% lease vp = = = +# +vop_lease { + IN struct vnode *vp; + IN struct proc *p; + IN struct ucred *cred; + IN int flag; +}; + +# +#% ioctl vp U U U +# vop_ioctl { IN struct vnode *vp; - IN int command; + IN u_long command; IN caddr_t data; IN int fflag; IN struct ucred *cred; IN struct proc *p; }; +# +#% select vp U U U +# # Needs work? (fflags) +# vop_select { IN struct vnode *vp; IN int which; @@ -120,6 +202,17 @@ vop_select { IN struct proc *p; }; +# +#% revoke vp U U U +# +vop_revoke { + IN struct vnode *vp; + IN int flags; +}; + +# +# XXX - not used +# vop_mmap { IN struct vnode *vp; IN int fflags; @@ -127,6 +220,9 @@ vop_mmap { IN struct proc *p; }; +# +#% fsync vp L L L +# vop_fsync { IN struct vnode *vp; IN struct ucred *cred; @@ -134,7 +230,10 @@ vop_fsync { IN struct proc *p; }; -# Needs word: Is newoff right? What's it mean? +# +# XXX - not used +# Needs work: Is newoff right? What's it mean? +# vop_seek { IN struct vnode *vp; IN off_t oldoff; @@ -142,18 +241,32 @@ vop_seek { IN struct ucred *cred; }; +# +#% remove dvp L U U +#% remove vp L U U +# vop_remove { IN WILLRELE struct vnode *dvp; IN WILLRELE struct vnode *vp; IN struct componentname *cnp; }; +# +#% link vp U U U +#% link tdvp L U U +# vop_link { IN WILLRELE struct vnode *tdvp; IN struct vnode *vp; IN struct componentname *cnp; }; +# +#% rename fdvp U U U +#% rename fvp U U U +#% rename tdvp L U U +#% rename tvp X U U +# vop_rename { IN WILLRELE struct vnode *fdvp; IN WILLRELE struct vnode *fvp; @@ -163,6 +276,10 @@ vop_rename { IN struct componentname *tcnp; }; +# +#% mkdir dvp L U U +#% mkdir vpp - L - +# vop_mkdir { IN WILLRELE struct vnode *dvp; OUT struct vnode **vpp; @@ -170,12 +287,24 @@ vop_mkdir { IN struct vattr *vap; }; +# +#% rmdir dvp L U U +#% rmdir vp L U U +# vop_rmdir { IN WILLRELE struct vnode *dvp; IN WILLRELE struct vnode *vp; IN struct componentname *cnp; }; +# +#% symlink dvp L U U +#% symlink vpp - U - +# +# XXX - note that the return vnode has already been VRELE'ed +# by the filesystem layer. To use it you must use vget, +# possibly with a further namei. +# vop_symlink { IN WILLRELE struct vnode *dvp; OUT WILLRELE struct vnode **vpp; @@ -184,42 +313,73 @@ vop_symlink { IN char *target; }; +# +#% readdir vp L L L +# vop_readdir { IN struct vnode *vp; INOUT struct uio *uio; IN struct ucred *cred; INOUT int *eofflag; - INOUT int *ncookies; - INOUT u_int **cookies; + OUT int *ncookies; + INOUT u_long **cookies; }; +# +#% readlink vp L L L +# vop_readlink { IN struct vnode *vp; INOUT struct uio *uio; IN struct ucred *cred; }; +# +#% abortop dvp = = = +# vop_abortop { IN struct vnode *dvp; IN struct componentname *cnp; }; +# +#% inactive vp L U U +# vop_inactive { IN struct vnode *vp; + IN struct proc *p; }; +# +#% reclaim vp U U U +# vop_reclaim { IN struct vnode *vp; + IN struct proc *p; }; +# +#% lock vp U L U +# vop_lock { IN struct vnode *vp; + IN int flags; + IN struct proc *p; }; +# +#% unlock vp L U L +# vop_unlock { IN struct vnode *vp; + IN int flags; + IN struct proc *p; }; +# +#% bmap vp L L L +#% bmap vpp - U - +# vop_bmap { IN struct vnode *vp; IN daddr_t bn; @@ -229,24 +389,39 @@ vop_bmap { OUT int *runb; }; +# +# Needs work: no vp? +# #vop_strategy { # IN struct buf *bp; #}; +# +#% print vp = = = +# vop_print { IN struct vnode *vp; }; +# +#% islocked vp = = = +# vop_islocked { IN struct vnode *vp; }; +# +#% pathconf vp L L L +# vop_pathconf { IN struct vnode *vp; IN int name; - OUT int *retval; + OUT register_t *retval; }; +# +#% advlock vp U U U +# vop_advlock { IN struct vnode *vp; IN caddr_t id; @@ -255,6 +430,9 @@ vop_advlock { IN int flags; }; +# +#% blkatoff vp L L L +# vop_blkatoff { IN struct vnode *vp; IN off_t offset; @@ -262,6 +440,9 @@ vop_blkatoff { OUT struct buf **bpp; }; +# +#% valloc pvp L L L +# vop_valloc { IN struct vnode *pvp; IN int mode; @@ -269,17 +450,26 @@ vop_valloc { OUT struct vnode **vpp; }; +# +#% reallocblks vp L L L +# vop_reallocblks { IN struct vnode *vp; IN struct cluster_save *buflist; }; +# +#% vfree pvp L L L +# vop_vfree { IN struct vnode *pvp; IN ino_t ino; IN int mode; }; +# +#% truncate vp L L L +# vop_truncate { IN struct vnode *vp; IN off_t length; @@ -288,6 +478,9 @@ vop_truncate { IN struct proc *p; }; +# +#% update vp L L L +# vop_update { IN struct vnode *vp; IN struct timeval *access; @@ -312,7 +505,9 @@ vop_putpages { IN vm_ooffset_t offset; }; +# # Needs work: no vp? +# #vop_bwrite { # IN struct buf *bp; #}; diff --git a/sys/miscfs/deadfs/dead_vnops.c b/sys/miscfs/deadfs/dead_vnops.c index f22425c..6d83c61 100644 --- a/sys/miscfs/deadfs/dead_vnops.c +++ b/sys/miscfs/deadfs/dead_vnops.c @@ -77,11 +77,11 @@ static int dead_select __P((struct vop_select_args *)); #define dead_inactive ((int (*) __P((struct vop_inactive_args *)))nullop) #define dead_reclaim ((int (*) __P((struct vop_reclaim_args *)))nullop) static int dead_lock __P((struct vop_lock_args *)); -#define dead_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) +#define dead_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock) static int dead_bmap __P((struct vop_bmap_args *)); static int dead_strategy __P((struct vop_strategy_args *)); static int dead_print __P((struct vop_print_args *)); -#define dead_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) +#define dead_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked) #define dead_pathconf ((int (*) __P((struct vop_pathconf_args *)))dead_ebadf) #define dead_advlock ((int (*) __P((struct vop_advlock_args *)))dead_ebadf) #define dead_blkatoff ((int (*) __P((struct vop_blkatoff_args *)))dead_badop) @@ -191,11 +191,20 @@ dead_read(ap) if (chkvnlock(ap->a_vp)) panic("dead_read: lock"); +#if 0 + /* Lite2 behaviour */ + /* + * Return EOF for tty devices, EIO for others + */ + if ((ap->a_vp->v_flag & VISTTY) == 0) + return (EIO); +#else /* * Return EOF for character devices, EIO for others */ if (ap->a_vp->v_type != VCHR) return (EIO); +#endif return (0); } @@ -282,12 +291,23 @@ static int dead_lock(ap) struct vop_lock_args /* { struct vnode *a_vp; + int a_flags; + struct proc *a_p; } */ *ap; { + struct vnode *vp = ap->a_vp; - if (!chkvnlock(ap->a_vp)) + /* + * Since we are not using the lock manager, we must clear + * the interlock here. + */ + if (ap->a_flags & LK_INTERLOCK) { + simple_unlock(&vp->v_interlock); + ap->a_flags &= ~LK_INTERLOCK; + } + if (!chkvnlock(vp)) return (0); - return (VCALL(ap->a_vp, VOFFSET(vop_lock), ap)); + return (VCALL(vp, VOFFSET(vop_lock), ap)); } /* diff --git a/sys/miscfs/fdesc/fdesc.h b/sys/miscfs/fdesc/fdesc.h index d754655..b4eff1f 100644 --- a/sys/miscfs/fdesc/fdesc.h +++ b/sys/miscfs/fdesc/fdesc.h @@ -61,8 +61,7 @@ typedef enum { } fdntype; struct fdescnode { - struct fdescnode *fd_forw; /* Hash chain */ - struct fdescnode *fd_back; + LIST_ENTRY(fdescnode) fd_hash; /* Hash list */ struct vnode *fd_vnode; /* Back ptr to vnode */ fdntype fd_type; /* Type of this node */ unsigned fd_fd; /* Fd to be dup'ed */ @@ -74,7 +73,7 @@ struct fdescnode { #define VTOFDESC(vp) ((struct fdescnode *)(vp)->v_data) extern dev_t devctty; -extern int fdesc_init __P((void)); +extern int fdesc_init __P((struct vfsconf *)); extern int fdesc_root __P((struct mount *, struct vnode **)); extern int fdesc_allocvp __P((fdntype, int, struct mount *, struct vnode **)); extern vop_t **fdesc_vnodeop_p; diff --git a/sys/miscfs/fdesc/fdesc_vfsops.c b/sys/miscfs/fdesc/fdesc_vfsops.c index 5f6703b..135052e 100644 --- a/sys/miscfs/fdesc/fdesc_vfsops.c +++ b/sys/miscfs/fdesc/fdesc_vfsops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1992, 1993 + * Copyright (c) 1992, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software donated to Berkeley by @@ -108,7 +108,7 @@ fdesc_mount(mp, path, data, ndp, p) /* XXX -- don't mark as local to work around fts() problems */ /*mp->mnt_flag |= MNT_LOCAL;*/ mp->mnt_data = (qaddr_t) fmp; - getnewfsid(mp, MOUNT_FDESC); + vfs_getnewfsid(mp); (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); @@ -137,12 +137,8 @@ fdesc_unmount(mp, mntflags, p) int flags = 0; struct vnode *rootvp = VFSTOFDESC(mp)->f_root; - if (mntflags & MNT_FORCE) { - /* fdesc can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } /* * Clear out buffer cache. I don't think we @@ -176,6 +172,7 @@ fdesc_root(mp, vpp) struct mount *mp; struct vnode **vpp; { + struct proc *p = curproc; /* XXX */ struct vnode *vp; /* @@ -183,24 +180,12 @@ fdesc_root(mp, vpp) */ vp = VFSTOFDESC(mp)->f_root; VREF(vp); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); *vpp = vp; return (0); } static int -fdesc_quotactl(mp, cmd, uid, arg, p) - struct mount *mp; - int cmd; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - - return (EOPNOTSUPP); -} - -static int fdesc_statfs(mp, sbp, p) struct mount *mp; struct statfs *sbp; @@ -233,7 +218,6 @@ fdesc_statfs(mp, sbp, p) if (fdp->fd_nfiles < lim) freefd += (lim - fdp->fd_nfiles); - sbp->f_type = MOUNT_FDESC; sbp->f_flags = 0; sbp->f_bsize = DEV_BSIZE; sbp->f_iosize = DEV_BSIZE; @@ -243,6 +227,7 @@ fdesc_statfs(mp, sbp, p) sbp->f_files = lim + 1; /* Allow for "." */ sbp->f_ffree = freefd; /* See comments above */ if (sbp != &mp->mnt_stat) { + sbp->f_type = mp->mnt_vfc->vfc_typenum; bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); @@ -261,41 +246,15 @@ fdesc_sync(mp, waitfor, cred, p) return (0); } -/* - * Fdesc flat namespace lookup. - * Currently unsupported. - */ -static int -fdesc_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - - return (EOPNOTSUPP); -} - -static int -fdesc_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) - struct mount *mp; - struct fid *fhp; - struct mbuf *nam; - struct vnode **vpp; - int *exflagsp; - struct ucred **credanonp; -{ - - return (EOPNOTSUPP); -} - -static int -fdesc_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; -{ - - return (EOPNOTSUPP); -} +#define fdesc_fhtovp ((int (*) __P((struct mount *, struct fid *, \ + struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp) +#define fdesc_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \ + struct proc *)))eopnotsupp) +#define fdesc_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ + size_t, struct proc *)))eopnotsupp) +#define fdesc_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \ + eopnotsupp) +#define fdesc_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp) static struct vfsops fdesc_vfsops = { fdesc_mount, diff --git a/sys/miscfs/fdesc/fdesc_vnops.c b/sys/miscfs/fdesc/fdesc_vnops.c index 1fe511b..795dfd8 100644 --- a/sys/miscfs/fdesc/fdesc_vnops.c +++ b/sys/miscfs/fdesc/fdesc_vnops.c @@ -77,22 +77,14 @@ FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2 #endif #define NFDCACHE 4 -#define FD_NHASH(ix) ((ix) & NFDCACHE-1) - -/* - * Cache head - */ -struct fdcache { - struct fdescnode *fc_forw; - struct fdescnode *fc_back; -}; - -static struct fdcache fdcache[NFDCACHE]; +#define FD_NHASH(ix) \ + (&fdhashtbl[(ix) & fdhash]) +LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl; +u_long fdhash; static int fdesc_attr __P((int fd, struct vattr *vap, struct ucred *cred, struct proc *p)); static int fdesc_badop __P((void)); -static int fdesc_enotsupp __P((void)); static int fdesc_getattr __P((struct vop_getattr_args *ap)); static struct fdcache * fdesc_hash __P((int ix)); @@ -115,28 +107,15 @@ static int fdesc_write __P((struct vop_write_args *ap)); * Initialise cache headers */ int -fdesc_init() +fdesc_init(vfsp) + struct vfsconf *vfsp; { - struct fdcache *fc; devctty = makedev(nchrdev, 0); - - for (fc = fdcache; fc < fdcache + NFDCACHE; fc++) - fc->fc_forw = fc->fc_back = (struct fdescnode *) fc; + fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash); return (0); } -/* - * Compute hash list for given target vnode - */ -static struct fdcache * -fdesc_hash(ix) - int ix; -{ - - return (&fdcache[FD_NHASH(ix)]); -} - int fdesc_allocvp(ftype, ix, mp, vpp) fdntype ftype; @@ -144,15 +123,16 @@ fdesc_allocvp(ftype, ix, mp, vpp) struct mount *mp; struct vnode **vpp; { - struct fdcache *fc; + struct proc *p = curproc; /* XXX */ + struct fdhashhead *fc; struct fdescnode *fd; int error = 0; + fc = FD_NHASH(ix); loop: - fc = fdesc_hash(ix); - for (fd = fc->fc_forw; fd != (struct fdescnode *) fc; fd = fd->fd_forw) { + for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) { if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) { - if (vget(fd->fd_vnode, 0)) + if (vget(fd->fd_vnode, 0, p)) goto loop; *vpp = fd->fd_vnode; return (error); @@ -188,8 +168,7 @@ loop: fd->fd_fd = -1; fd->fd_link = 0; fd->fd_ix = ix; - fc = fdesc_hash(ix); - insque(fd, fc); + LIST_INSERT_HEAD(fc, fd, fd_hash); out:; fdcache_lock &= ~FDL_LOCKED; @@ -216,31 +195,28 @@ fdesc_lookup(ap) { struct vnode **vpp = ap->a_vpp; struct vnode *dvp = ap->a_dvp; - char *pname; - struct proc *p; - int nfiles; - unsigned fd = 0; + struct componentname *cnp = ap->a_cnp; + char *pname = cnp->cn_nameptr; + struct proc *p = cnp->cn_proc; + int nfiles = p->p_fd->fd_nfiles; + unsigned fd; int error; struct vnode *fvp; char *ln; - if (ap->a_cnp->cn_nameiop == DELETE || - ap->a_cnp->cn_nameiop == RENAME) { + if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { error = EROFS; goto bad; } - pname = ap->a_cnp->cn_nameptr; - if (ap->a_cnp->cn_namelen == 1 && *pname == '.') { + VOP_UNLOCK(dvp, 0, p); + if (cnp->cn_namelen == 1 && *pname == '.') { *vpp = dvp; - VREF(dvp); - VOP_LOCK(dvp); + VREF(dvp); + vn_lock(dvp, LK_SHARED | LK_RETRY, p); return (0); } - p = ap->a_cnp->cn_proc; - nfiles = p->p_fd->fd_nfiles; - switch (VTOFDESC(dvp)->fd_type) { default: case Flink: @@ -250,17 +226,17 @@ fdesc_lookup(ap) goto bad; case Froot: - if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) { + if (cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) { error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp); if (error) goto bad; *vpp = fvp; fvp->v_type = VDIR; - VOP_LOCK(fvp); + vn_lock(fvp, LK_SHARED | LK_RETRY, p); return (0); } - if (ap->a_cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) { + if (cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) { struct vnode *ttyvp = cttyvp(p); if (ttyvp == NULL) { error = ENXIO; @@ -271,12 +247,12 @@ fdesc_lookup(ap) goto bad; *vpp = fvp; fvp->v_type = VFIFO; - VOP_LOCK(fvp); + vn_lock(fvp, LK_SHARED | LK_RETRY, p); return (0); } ln = 0; - switch (ap->a_cnp->cn_namelen) { + switch (cnp->cn_namelen) { case 5: if (bcmp(pname, "stdin", 5) == 0) { ln = "fd/0"; @@ -302,7 +278,7 @@ fdesc_lookup(ap) VTOFDESC(fvp)->fd_link = ln; *vpp = fvp; fvp->v_type = VLNK; - VOP_LOCK(fvp); + vn_lock(fvp, LK_SHARED | LK_RETRY, p); return (0); } else { error = ENOENT; @@ -312,9 +288,10 @@ fdesc_lookup(ap) /* FALL THROUGH */ case Fdevfd: - if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) { - error = fdesc_root(dvp->v_mount, vpp); - return (error); + if (cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) { + if (error = fdesc_root(dvp->v_mount, vpp)) + goto bad; + return (0); } fd = 0; @@ -338,11 +315,13 @@ fdesc_lookup(ap) if (error) goto bad; VTOFDESC(fvp)->fd_fd = fd; + vn_lock(fvp, LK_SHARED | LK_RETRY, p); *vpp = fvp; return (0); } bad:; + vn_lock(dvp, LK_SHARED | LK_RETRY, p); *vpp = NULL; return (error); } @@ -402,10 +381,10 @@ fdesc_attr(fd, vap, cred, p) error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p); if (error == 0 && vap->va_type == VDIR) { /* - * don't allow directories to show up because - * that causes loops in the namespace. + * directories can cause loops in the namespace, + * so turn off the 'x' bits to avoid trouble. */ - vap->va_type = VFIFO; + vap->va_mode &= ~((VEXEC)|(VEXEC>>3)|(VEXEC>>6)); } break; @@ -591,6 +570,9 @@ fdesc_readdir(ap) struct vnode *a_vp; struct uio *a_uio; struct ucred *a_cred; + int *a_eofflag; + u_long *a_cookies; + int a_ncookies; } */ *ap; { struct uio *uio = ap->a_uio; @@ -598,6 +580,13 @@ fdesc_readdir(ap) int i; int error; + /* + * We don't allow exporting fdesc mounts, and currently local + * requests do not need cookies. + */ + if (ap->a_ncookies) + panic("fdesc_readdir: not hungry"); + switch (VTOFDESC(ap->a_vp)->fd_type) { case Fctty: return (0); @@ -814,6 +803,7 @@ static int fdesc_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { struct vnode *vp = ap->a_vp; @@ -822,6 +812,7 @@ fdesc_inactive(ap) * Clear out the v_type field to avoid * nasty things happening in vgone(). */ + VOP_UNLOCK(vp, 0, ap->a_p); vp->v_type = VNON; return (0); } @@ -833,8 +824,9 @@ fdesc_reclaim(ap) } */ *ap; { struct vnode *vp = ap->a_vp; + struct fdescnode *fd = VTOFDESC(vp); - remque(VTOFDESC(vp)); + LIST_REMOVE(fd, fd_hash); FREE(vp->v_data, M_TEMP); vp->v_data = 0; @@ -907,16 +899,6 @@ fdesc_vfree(ap) } /* - * /dev/fd vnode unsupported operation - */ -static int -fdesc_enotsupp() -{ - - return (EOPNOTSUPP); -} - -/* * /dev/fd "should never get here" operation */ static int @@ -927,38 +909,39 @@ fdesc_badop() /* NOTREACHED */ } -#define fdesc_create ((int (*) __P((struct vop_create_args *)))fdesc_enotsupp) -#define fdesc_mknod ((int (*) __P((struct vop_mknod_args *)))fdesc_enotsupp) +#define fdesc_create ((int (*) __P((struct vop_create_args *)))eopnotsupp) +#define fdesc_mknod ((int (*) __P((struct vop_mknod_args *)))eopnotsupp) #define fdesc_close ((int (*) __P((struct vop_close_args *)))nullop) #define fdesc_access ((int (*) __P((struct vop_access_args *)))nullop) -#define fdesc_mmap ((int (*) __P((struct vop_mmap_args *)))fdesc_enotsupp) +#define fdesc_mmap ((int (*) __P((struct vop_mmap_args *)))eopnotsupp) +#define fdesc_revoke vop_revoke #define fdesc_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) #define fdesc_seek ((int (*) __P((struct vop_seek_args *)))nullop) -#define fdesc_remove ((int (*) __P((struct vop_remove_args *)))fdesc_enotsupp) -#define fdesc_link ((int (*) __P((struct vop_link_args *)))fdesc_enotsupp) -#define fdesc_rename ((int (*) __P((struct vop_rename_args *)))fdesc_enotsupp) -#define fdesc_mkdir ((int (*) __P((struct vop_mkdir_args *)))fdesc_enotsupp) -#define fdesc_rmdir ((int (*) __P((struct vop_rmdir_args *)))fdesc_enotsupp) -#define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))fdesc_enotsupp) +#define fdesc_remove ((int (*) __P((struct vop_remove_args *)))eopnotsupp) +#define fdesc_link ((int (*) __P((struct vop_link_args *)))eopnotsupp) +#define fdesc_rename ((int (*) __P((struct vop_rename_args *)))eopnotsupp) +#define fdesc_mkdir ((int (*) __P((struct vop_mkdir_args *)))eopnotsupp) +#define fdesc_rmdir ((int (*) __P((struct vop_rmdir_args *)))eopnotsupp) +#define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))eopnotsupp) #define fdesc_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) -#define fdesc_lock ((int (*) __P((struct vop_lock_args *)))nullop) -#define fdesc_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) +#define fdesc_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock) +#define fdesc_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock) #define fdesc_bmap ((int (*) __P((struct vop_bmap_args *)))fdesc_badop) #define fdesc_strategy ((int (*) __P((struct vop_strategy_args *)))fdesc_badop) -#define fdesc_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) -#define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))fdesc_enotsupp) +#define fdesc_islocked \ + ((int (*) __P((struct vop_islocked_args *)))vop_noislocked) +#define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))eopnotsupp) #define fdesc_blkatoff \ - ((int (*) __P((struct vop_blkatoff_args *)))fdesc_enotsupp) -#define fdesc_vget ((int (*) __P((struct vop_vget_args *)))fdesc_enotsupp) + ((int (*) __P((struct vop_blkatoff_args *)))eopnotsupp) #define fdesc_valloc ((int(*) __P(( \ struct vnode *pvp, \ int mode, \ struct ucred *cred, \ - struct vnode **vpp))) fdesc_enotsupp) + struct vnode **vpp))) eopnotsupp) #define fdesc_truncate \ - ((int (*) __P((struct vop_truncate_args *)))fdesc_enotsupp) -#define fdesc_update ((int (*) __P((struct vop_update_args *)))fdesc_enotsupp) -#define fdesc_bwrite ((int (*) __P((struct vop_bwrite_args *)))fdesc_enotsupp) + ((int (*) __P((struct vop_truncate_args *)))eopnotsupp) +#define fdesc_update ((int (*) __P((struct vop_update_args *)))eopnotsupp) +#define fdesc_bwrite ((int (*) __P((struct vop_bwrite_args *)))eopnotsupp) static vop_t **fdesc_vnodeop_p; static struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = { @@ -975,6 +958,7 @@ static struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = { { &vop_write_desc, (vop_t *)fdesc_write }, /* write */ { &vop_ioctl_desc, (vop_t *)fdesc_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)fdesc_select }, /* select */ + { &vop_revoke_desc, (vop_t *)fdesc_revoke }, /* revoke */ { &vop_mmap_desc, (vop_t *)fdesc_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)fdesc_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)fdesc_seek }, /* seek */ diff --git a/sys/miscfs/fifofs/fifo.h b/sys/miscfs/fifofs/fifo.h index efeaf85..6562159 100644 --- a/sys/miscfs/fifofs/fifo.h +++ b/sys/miscfs/fifofs/fifo.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)fifo.h 8.2 (Berkeley) 2/2/94 + * @(#)fifo.h 8.6 (Berkeley) 5/21/95 * $FreeBSD$ */ @@ -51,8 +51,10 @@ int fifo_close __P((struct vop_close_args *)); #define fifo_setattr ((int (*) __P((struct vop_setattr_args *)))fifo_ebadf) int fifo_read __P((struct vop_read_args *)); int fifo_write __P((struct vop_write_args *)); +#define fifo_lease_check ((int (*) __P((struct vop_lease_args *)))nullop) int fifo_ioctl __P((struct vop_ioctl_args *)); int fifo_select __P((struct vop_select_args *)); +#define fifo_revoke vop_revoke #define fifo_mmap ((int (*) __P((struct vop_mmap_args *)))fifo_badop) #define fifo_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) #define fifo_seek ((int (*) __P((struct vop_seek_args *)))fifo_badop) @@ -65,11 +67,13 @@ int fifo_select __P((struct vop_select_args *)); #define fifo_readdir ((int (*) __P((struct vop_readdir_args *)))fifo_badop) #define fifo_readlink ((int (*) __P((struct vop_readlink_args *)))fifo_badop) #define fifo_abortop ((int (*) __P((struct vop_abortop_args *)))fifo_badop) -#define fifo_inactive ((int (*) __P((struct vop_inactive_args *)))nullop) +int fifo_inactive __P((struct vop_inactive_args *)); #define fifo_reclaim ((int (*) __P((struct vop_reclaim_args *)))nullop) +#define fifo_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock) +#define fifo_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock) int fifo_bmap __P((struct vop_bmap_args *)); #define fifo_strategy ((int (*) __P((struct vop_strategy_args *)))fifo_badop) -#define fifo_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) +#define fifo_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked) int fifo_pathconf __P((struct vop_pathconf_args *)); int fifo_advlock __P((struct vop_advlock_args *)); #define fifo_blkatoff ((int (*) __P((struct vop_blkatoff_args *)))fifo_badop) diff --git a/sys/miscfs/fifofs/fifo_vnops.c b/sys/miscfs/fifofs/fifo_vnops.c index 240354f..8f915ec 100644 --- a/sys/miscfs/fifofs/fifo_vnops.c +++ b/sys/miscfs/fifofs/fifo_vnops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1990, 1993 + * Copyright (c) 1990, 1993, 1995 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,12 +30,12 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)fifo_vnops.c 8.2 (Berkeley) 1/4/94 + * @(#)fifo_vnops.c 8.10 (Berkeley) 5/27/95 * $FreeBSD$ */ #include <sys/param.h> -#include <sys/kernel.h> +#include <sys/systm.h> #include <sys/proc.h> #include <sys/time.h> #include <sys/namei.h> @@ -44,7 +44,6 @@ #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/stat.h> -#include <sys/systm.h> #include <sys/ioctl.h> #include <sys/file.h> #include <sys/errno.h> @@ -64,8 +63,6 @@ struct fifoinfo { }; static int fifo_ebadf __P((void)); -static int fifo_unlock __P((struct vop_unlock_args *)); -static int fifo_lock __P((struct vop_lock_args *)); static int fifo_print __P((struct vop_print_args *)); vop_t **fifo_vnodeop_p; @@ -81,8 +78,10 @@ static struct vnodeopv_entry_desc fifo_vnodeop_entries[] = { { &vop_setattr_desc, (vop_t *)fifo_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)fifo_read }, /* read */ { &vop_write_desc, (vop_t *)fifo_write }, /* write */ + { &vop_lease_desc, (vop_t *)fifo_lease_check }, /* lease */ { &vop_ioctl_desc, (vop_t *)fifo_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)fifo_select }, /* select */ + { &vop_revoke_desc, (vop_t *)fifo_revoke }, /* revoke */ { &vop_mmap_desc, (vop_t *)fifo_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)fifo_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)fifo_seek }, /* seek */ @@ -149,8 +148,9 @@ fifo_open(ap) struct proc *a_p; } */ *ap; { - register struct vnode *vp = ap->a_vp; - register struct fifoinfo *fip; + struct vnode *vp = ap->a_vp; + struct fifoinfo *fip; + struct proc *p = ap->a_p; struct socket *rso, *wso; int error; static char openstr[] = "fifo"; @@ -158,14 +158,14 @@ fifo_open(ap) if ((fip = vp->v_fifoinfo) == NULL) { MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK); vp->v_fifoinfo = fip; - error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0, ap->a_p); + error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, ap->a_p); if (error) { free(fip, M_VNODE); vp->v_fifoinfo = NULL; return (error); } fip->fi_readsock = rso; - error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0, ap->a_p); + error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, ap->a_p); if (error) { (void)soclose(rso); free(fip, M_VNODE); @@ -185,60 +185,52 @@ fifo_open(ap) wso->so_state |= SS_CANTRCVMORE; rso->so_state |= SS_CANTSENDMORE; } - error = 0; - if ((ap->a_mode & (FREAD|FWRITE)) == (FREAD|FWRITE)) { - if (fip->fi_readers == 0) { + if (ap->a_mode & FREAD) { + fip->fi_readers++; + if (fip->fi_readers == 1) { fip->fi_writesock->so_state &= ~SS_CANTSENDMORE; if (fip->fi_writers > 0) wakeup((caddr_t)&fip->fi_writers); } - if (fip->fi_writers == 0) { + } + if (ap->a_mode & FWRITE) { + fip->fi_writers++; + if (fip->fi_writers == 1) { fip->fi_readsock->so_state &= ~SS_CANTRCVMORE; if (fip->fi_readers > 0) wakeup((caddr_t)&fip->fi_readers); } - fip->fi_readers++; - fip->fi_writers++; } - else if (ap->a_mode & FREAD) { - fip->fi_readers++; - if (fip->fi_readers == 1) { - fip->fi_writesock->so_state &= ~SS_CANTSENDMORE; - if (fip->fi_writers > 0) - wakeup((caddr_t)&fip->fi_writers); + if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) { + while (fip->fi_writers == 0) { + VOP_UNLOCK(vp, 0, p); + error = tsleep((caddr_t)&fip->fi_readers, + PCATCH | PSOCK, openstr, 0); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + if (error) + goto bad; } - if (!(ap->a_mode & O_NONBLOCK)) - while (fip->fi_writers == 0) { - VOP_UNLOCK(vp); - error = tsleep((caddr_t)&fip->fi_readers, - PCATCH | PSOCK, openstr, 0); - VOP_LOCK(vp); - if (error) - break; - } } - else { - fip->fi_writers++; - if (fip->fi_readers == 0 && (ap->a_mode & O_NONBLOCK)) { - error = ENXIO; - } else { - if (fip->fi_writers == 1) { - fip->fi_readsock->so_state &= ~SS_CANTRCVMORE; - if (fip->fi_readers > 0) - wakeup((caddr_t)&fip->fi_readers); + if (ap->a_mode & FWRITE) { + if (ap->a_mode & O_NONBLOCK) { + if (fip->fi_readers == 0) { + error = ENXIO; + goto bad; } + } else { while (fip->fi_readers == 0) { - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); error = tsleep((caddr_t)&fip->fi_writers, PCATCH | PSOCK, openstr, 0); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (error) - break; + goto bad; } } } - if (error) - VOP_CLOSE(vp, ap->a_mode, ap->a_cred, ap->a_p); + return (0); +bad: + VOP_CLOSE(vp, ap->a_mode, ap->a_cred, p); return (error); } @@ -255,8 +247,9 @@ fifo_read(ap) struct ucred *a_cred; } */ *ap; { - register struct uio *uio = ap->a_uio; - register struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock; + struct uio *uio = ap->a_uio; + struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock; + struct proc *p = uio->uio_procp; int error, startresid; #ifdef DIAGNOSTIC @@ -268,10 +261,10 @@ fifo_read(ap) if (ap->a_ioflag & IO_NDELAY) rso->so_state |= SS_NBIO; startresid = uio->uio_resid; - VOP_UNLOCK(ap->a_vp); - error = soreceive(rso, (struct mbuf **)0, uio, - (struct mbuf **)0, (struct mbuf **)0, (int*)0); - VOP_LOCK(ap->a_vp); + VOP_UNLOCK(ap->a_vp, 0, p); + error = soreceive(rso, (struct mbuf **)0, uio, (struct mbuf **)0, + (struct mbuf **)0, (int *)0); + vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p); /* * Clear EOF indication after first such return. */ @@ -296,6 +289,7 @@ fifo_write(ap) } */ *ap; { struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock; + struct proc *p = ap->a_uio->uio_procp; int error; #ifdef DIAGNOSTIC @@ -304,9 +298,9 @@ fifo_write(ap) #endif if (ap->a_ioflag & IO_NDELAY) wso->so_state |= SS_NBIO; - VOP_UNLOCK(ap->a_vp); + VOP_UNLOCK(ap->a_vp, 0, p); error = sosend(wso, (struct mbuf *)0, ap->a_uio, 0, (struct mbuf *)0, 0); - VOP_LOCK(ap->a_vp); + vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p); if (ap->a_ioflag & IO_NDELAY) wso->so_state &= ~SS_NBIO; return (error); @@ -328,14 +322,23 @@ fifo_ioctl(ap) } */ *ap; { struct file filetmp; + int error; if (ap->a_command == FIONBIO) return (0); - if (ap->a_fflag & FREAD) + if (ap->a_fflag & FREAD) { filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock; - else + error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p); + if (error) + return (error); + } + if (ap->a_fflag & FWRITE) { filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock; - return (soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p)); + error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p); + if (error) + return (error); + } + return (0); } /* ARGSUSED */ @@ -350,12 +353,33 @@ fifo_select(ap) } */ *ap; { struct file filetmp; + int ready; - if (ap->a_fflags & FREAD) + if (ap->a_fflags & FREAD) { filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock; - else + ready = soo_select(&filetmp, ap->a_which, ap->a_p); + if (ready) + return (ready); + } + if (ap->a_fflags & FWRITE) { filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock; - return (soo_select(&filetmp, ap->a_which, ap->a_p)); + ready = soo_select(&filetmp, ap->a_which, ap->a_p); + if (ready) + return (ready); + } + return (0); +} + +int +fifo_inactive(ap) + struct vop_inactive_args /* { + struct vnode *a_vp; + struct proc *a_p; + } */ *ap; +{ + + VOP_UNLOCK(ap->a_vp, 0, ap->a_p); + return (0); } /* @@ -385,31 +409,6 @@ fifo_bmap(ap) } /* - * At the moment we do not do any locking. - */ -/* ARGSUSED */ -static int -fifo_lock(ap) - struct vop_lock_args /* { - struct vnode *a_vp; - } */ *ap; -{ - - return (0); -} - -/* ARGSUSED */ -static int -fifo_unlock(ap) - struct vop_unlock_args /* { - struct vnode *a_vp; - } */ *ap; -{ - - return (0); -} - -/* * Device close routine */ /* ARGSUSED */ @@ -426,16 +425,16 @@ fifo_close(ap) register struct fifoinfo *fip = vp->v_fifoinfo; int error1, error2; - if (ap->a_fflag & FWRITE) { - fip->fi_writers--; - if (fip->fi_writers == 0) - socantrcvmore(fip->fi_readsock); - } if (ap->a_fflag & FREAD) { fip->fi_readers--; if (fip->fi_readers == 0) socantsendmore(fip->fi_writesock); } + if (ap->a_fflag & FWRITE) { + fip->fi_writers--; + if (fip->fi_writers == 0) + socantrcvmore(fip->fi_readsock); + } if (vp->v_usecount > 1) return (0); error1 = soclose(fip->fi_readsock); diff --git a/sys/miscfs/kernfs/kernfs.h b/sys/miscfs/kernfs/kernfs.h index 69496a4..2795bb3 100644 --- a/sys/miscfs/kernfs/kernfs.h +++ b/sys/miscfs/kernfs/kernfs.h @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)kernfs.h 8.4 (Berkeley) 1/21/94 + * @(#)kernfs.h 8.6 (Berkeley) 3/29/95 * $FreeBSD$ */ @@ -51,7 +51,18 @@ struct kernfs_node { #define VFSTOKERNFS(mp) ((struct kernfs_mount *)((mp)->mnt_data)) #define VTOKERN(vp) ((struct kernfs_node *)(vp)->v_data) +#define kernfs_fhtovp ((int (*) __P((struct mount *, struct fid *, \ + struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp) +#define kernfs_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \ + struct proc *)))eopnotsupp) +#define kernfs_sync ((int (*) __P((struct mount *, int, struct ucred *, \ + struct proc *)))nullop) +#define kernfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ + size_t, struct proc *)))eopnotsupp) +#define kernfs_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \ + eopnotsupp) +#define kernfs_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp) extern vop_t **kernfs_vnodeop_p; extern struct vfsops kernfs_vfsops; -extern struct vnode *rrootvp; +extern dev_t rrootdev; #endif /* KERNEL */ diff --git a/sys/miscfs/kernfs/kernfs_vfsops.c b/sys/miscfs/kernfs/kernfs_vfsops.c index 4c045e7..b774487 100644 --- a/sys/miscfs/kernfs/kernfs_vfsops.c +++ b/sys/miscfs/kernfs/kernfs_vfsops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1992, 1993 + * Copyright (c) 1992, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software donated to Berkeley by @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)kernfs_vfsops.c 8.4 (Berkeley) 1/21/94 + * @(#)kernfs_vfsops.c 8.10 (Berkeley) 5/14/95 * $FreeBSD$ */ @@ -55,88 +55,52 @@ #include <miscfs/specfs/specdev.h> #include <miscfs/kernfs/kernfs.h> -struct vnode *rrootvp; +dev_t rrootdev = NODEV; static int cdevvp __P((dev_t dev, struct vnode **vpp)); -static int kernfs_init __P((void)); +static int kernfs_init __P((struct vfsconf *vfsp)); static int kernfs_mount __P((struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct proc *p)); static int kernfs_start __P((struct mount *mp, int flags, struct proc *p)); static int kernfs_unmount __P((struct mount *mp, int mntflags, struct proc *p)); static int kernfs_root __P((struct mount *mp, struct vnode **vpp)); -static int kernfs_quotactl __P((struct mount *mp, int cmd, uid_t uid, - caddr_t arg, struct proc *p)); static int kernfs_statfs __P((struct mount *mp, struct statfs *sbp, struct proc *p)); -static int kernfs_sync __P((struct mount *mp, int waitfor, - struct ucred *cred, struct proc *p)); -static int kernfs_vget __P((struct mount *mp, ino_t ino, - struct vnode **vpp)); -static int kernfs_fhtovp __P((struct mount *mp, struct fid *fhp, - struct mbuf *nam, struct vnode **vpp, - int *exflagsp, struct ucred **credanonp)); -static int kernfs_vptofh __P((struct vnode *vp, struct fid *fhp)); -/* - * Create a vnode for a character device. - */ static int -cdevvp(dev, vpp) - dev_t dev; - struct vnode **vpp; +kernfs_init(vfsp) + struct vfsconf *vfsp; { - register struct vnode *vp; - struct vnode *nvp; - int error; - if (dev == NODEV) - return (0); - error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp); - if (error) { - *vpp = 0; - return (error); - } - vp = nvp; - vp->v_type = VCHR; - nvp = checkalias(vp, dev, (struct mount *)0); - if (nvp) { - vput(vp); - vp = nvp; - } - *vpp = vp; return (0); } -static int -kernfs_init() +void +kernfs_get_rrootdev() { - int cmaj; + static int tried = 0; int bmaj = major(rootdev); - int error = ENXIO; + int cmaj; -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_init\n"); /* printed during system boot */ -#endif + if (tried) { + /* Already did it once. */ + return; + } + tried = 1; if (!bdevsw[bmaj]) { panic("root dev has no bdevsw"); } + if (rootdev == NODEV) + return; for (cmaj = 0; cmaj < nchrdev; cmaj++) { - if (cdevsw[cmaj] - && (cdevsw[cmaj]->d_open == bdevsw[bmaj]->d_open)) { - dev_t cdev = makedev(cmaj, minor(rootdev)); - error = cdevvp(cdev, &rrootvp); - if (error == 0) - break; - } + rrootdev = makedev(cmaj, minor(rootdev)); + if (chrtoblk(rrootdev) == rootdev) + return; } - - if (error) { - printf("kernfs: no raw boot device\n"); - rrootvp = 0; - } - return (0); + rrootdev = NODEV; + printf("kernfs_get_rrootdev: no raw root device\n"); } /* @@ -182,7 +146,7 @@ kernfs_mount(mp, path, data, ndp, p) fmp->kf_root = rvp; mp->mnt_flag |= MNT_LOCAL; mp->mnt_data = (qaddr_t) fmp; - getnewfsid(mp, MOUNT_KERNFS); + vfs_getnewfsid(mp); (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); @@ -192,6 +156,8 @@ kernfs_mount(mp, path, data, ndp, p) #ifdef KERNFS_DIAGNOSTIC printf("kernfs_mount: at %s\n", mp->mnt_stat.f_mntonname); #endif + + kernfs_get_rrootdev(); return (0); } @@ -218,12 +184,8 @@ kernfs_unmount(mp, mntflags, p) printf("kernfs_unmount(mp = %x)\n", mp); #endif - if (mntflags & MNT_FORCE) { - /* kernfs can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } /* * Clear out buffer cache. I don't think we @@ -263,6 +225,7 @@ kernfs_root(mp, vpp) struct mount *mp; struct vnode **vpp; { + struct proc *p = curproc; /* XXX */ struct vnode *vp; #ifdef KERNFS_DIAGNOSTIC @@ -274,23 +237,12 @@ kernfs_root(mp, vpp) */ vp = VFSTOKERNFS(mp)->kf_root; VREF(vp); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); *vpp = vp; return (0); } static int -kernfs_quotactl(mp, cmd, uid, arg, p) - struct mount *mp; - int cmd; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - return (EOPNOTSUPP); -} - -static int kernfs_statfs(mp, sbp, p) struct mount *mp; struct statfs *sbp; @@ -300,7 +252,6 @@ kernfs_statfs(mp, sbp, p) printf("kernfs_statfs(mp = %x)\n", mp); #endif - sbp->f_type = MOUNT_KERNFS; sbp->f_flags = 0; sbp->f_bsize = DEV_BSIZE; sbp->f_iosize = DEV_BSIZE; @@ -310,6 +261,7 @@ kernfs_statfs(mp, sbp, p) sbp->f_files = 0; sbp->f_ffree = 0; if (sbp != &mp->mnt_stat) { + sbp->f_type = mp->mnt_vfc->vfc_typenum; bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); @@ -317,53 +269,6 @@ kernfs_statfs(mp, sbp, p) return (0); } -static int -kernfs_sync(mp, waitfor, cred, p) - struct mount *mp; - int waitfor; - struct ucred *cred; - struct proc *p; -{ - - return (0); -} - -/* - * Kernfs flat namespace lookup. - * Currently unsupported. - */ -static int -kernfs_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - - return (EOPNOTSUPP); -} - - -static int -kernfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) - struct mount *mp; - struct fid *fhp; - struct mbuf *nam; - struct vnode **vpp; - int *exflagsp; - struct ucred **credanonp; -{ - - return (EOPNOTSUPP); -} - -static int -kernfs_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; -{ - return (EOPNOTSUPP); -} - static struct vfsops kernfs_vfsops = { kernfs_mount, kernfs_start, diff --git a/sys/miscfs/kernfs/kernfs_vnops.c b/sys/miscfs/kernfs/kernfs_vnops.c index afd30e7..108c443 100644 --- a/sys/miscfs/kernfs/kernfs_vnops.c +++ b/sys/miscfs/kernfs/kernfs_vnops.c @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)kernfs_vnops.c 8.6 (Berkeley) 2/10/94 + * @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95 * $FreeBSD$ */ @@ -67,41 +67,44 @@ #define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) static struct kern_target { + u_char kt_type; + u_char kt_namlen; char *kt_name; void *kt_data; -#define KTT_NULL 1 -#define KTT_TIME 5 -#define KTT_INT 17 -#define KTT_STRING 31 -#define KTT_HOSTNAME 47 -#define KTT_BOOTFILE 49 -#define KTT_AVENRUN 53 - int kt_tag; - int kt_rw; - int kt_vtype; - struct vnode **kt_vp; +#define KTT_NULL 1 +#define KTT_TIME 5 +#define KTT_INT 17 +#define KTT_STRING 31 +#define KTT_HOSTNAME 47 +#define KTT_BOOTFILE 49 +#define KTT_AVENRUN 53 +#define KTT_DEVICE 71 + u_char kt_tag; + u_char kt_vtype; + mode_t kt_mode; } kern_targets[] = { /* NOTE: The name must be less than UIO_MX-16 chars in length */ - /* name data tag ro/rw type vnodep*/ - { ".", 0, KTT_NULL, VREAD, VDIR, NULL }, - { "..", 0, KTT_NULL, VREAD, VDIR, NULL }, - { "boottime", &boottime.tv_sec, KTT_INT, VREAD, VREG, NULL }, - { "copyright", copyright, KTT_STRING, VREAD, VREG, NULL }, - { "hostname", 0, KTT_HOSTNAME,VREAD|VWRITE,VREG, NULL }, - { "bootfile", 0, KTT_BOOTFILE, VREAD, VREG, NULL }, - { "hz", &hz, KTT_INT, VREAD, VREG, NULL }, - { "loadavg", 0, KTT_AVENRUN, VREAD, VREG, NULL }, - { "pagesize", &cnt.v_page_size, KTT_INT, VREAD, VREG, NULL }, - { "physmem", &physmem, KTT_INT, VREAD, VREG, NULL }, +#define N(s) sizeof(s)-1, s + /* name data tag type ro/rw */ + { DT_DIR, N("."), 0, KTT_NULL, VDIR, DIR_MODE }, + { DT_DIR, N(".."), 0, KTT_NULL, VDIR, DIR_MODE }, + { DT_REG, N("boottime"), &boottime.tv_sec, KTT_INT, VREG, READ_MODE }, + { DT_REG, N("copyright"), copyright, KTT_STRING, VREG, READ_MODE }, + { DT_REG, N("hostname"), 0, KTT_HOSTNAME, VREG, WRITE_MODE }, + { DT_REG, N("bootfile"), 0, KTT_BOOTFILE, VREG, READ_MODE }, + { DT_REG, N("hz"), &hz, KTT_INT, VREG, READ_MODE }, + { DT_REG, N("loadavg"), 0, KTT_AVENRUN, VREG, READ_MODE }, + { DT_REG, N("pagesize"), &cnt.v_page_size, KTT_INT, VREG, READ_MODE }, + { DT_REG, N("physmem"), &physmem, KTT_INT, VREG, READ_MODE }, #if 0 - { "root", 0, KTT_NULL, VREAD, VDIR, &rootdir}, - { "rootdev", 0, KTT_NULL, VREAD, VBLK, &rootvp }, - { "rrootdev", 0, KTT_NULL, VREAD, VCHR, &rrootvp}, + { DT_DIR, N("root"), 0, KTT_NULL, VDIR, DIR_MODE }, + { DT_BLK, N("rootdev"), &rootdev, KTT_DEVICE, VBLK, READ_MODE }, + { DT_CHR, N("rrootdev"), &rrootdev, KTT_DEVICE, VCHR, READ_MODE }, #endif - { "time", 0, KTT_TIME, VREAD, VREG, NULL }, - { "version", version, KTT_STRING, VREAD, VREG, NULL }, + { DT_REG, N("time"), 0, KTT_TIME, VREG, READ_MODE }, + { DT_REG, N("version"), version, KTT_STRING, VREG, READ_MODE }, +#undef N }; - static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]); static int kernfs_access __P((struct vop_access_args *ap)); @@ -130,6 +133,7 @@ kernfs_xread(kt, buf, len, lenp) int len; int *lenp; { + switch (kt->kt_tag) { case KTT_TIME: { struct timeval tv; @@ -183,14 +187,12 @@ kernfs_xread(kt, buf, len, lenp) case KTT_AVENRUN: sprintf(buf, "%ld %ld %ld %ld\n", - averunnable.ldavg[0], - averunnable.ldavg[1], - averunnable.ldavg[2], - averunnable.fscale); + averunnable.ldavg[0], averunnable.ldavg[1], + averunnable.ldavg[2], averunnable.fscale); break; default: - return (EINVAL); + return (EIO); } *lenp = strlen(buf); @@ -203,15 +205,15 @@ kernfs_xwrite(kt, buf, len) char *buf; int len; { + switch (kt->kt_tag) { - case KTT_HOSTNAME: { + case KTT_HOSTNAME: /* XXX BOGUS !!! no check for the length */ if (buf[len-1] == '\n') --len; bcopy(buf, hostname, len); hostname[len] = '\0'; return (0); - } default: return (EIO); @@ -231,26 +233,32 @@ kernfs_lookup(ap) struct componentname * a_cnp; } */ *ap; { + struct componentname *cnp = ap->a_cnp; struct vnode **vpp = ap->a_vpp; struct vnode *dvp = ap->a_dvp; - struct componentname *cnp = ap->a_cnp; + char *pname = cnp->cn_nameptr; + struct proc *p = cnp->cn_proc; + struct kern_target *kt; struct vnode *fvp; int nameiop = cnp->cn_nameiop; int error, i; - char *pname; #ifdef KERNFS_DIAGNOSTIC printf("kernfs_lookup(%x)\n", ap); printf("kernfs_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp, vpp, ap->a_cnp); -#endif - pname = cnp->cn_nameptr; -#ifdef KERNFS_DIAGNOSTIC printf("kernfs_lookup(%s)\n", pname); #endif + + *vpp = NULLVP; + + if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) + return (EROFS); + + VOP_UNLOCK(dvp, 0, p); if (cnp->cn_namelen == 1 && *pname == '.') { *vpp = dvp; VREF(dvp); - /*VOP_LOCK(dvp);*/ + vn_lock(dvp, LK_SHARED | LK_RETRY, p); return (0); } @@ -258,91 +266,58 @@ kernfs_lookup(ap) if (cnp->cn_namelen == 4 && bcmp(pname, "root", 4) == 0) { *vpp = rootdir; VREF(rootdir); - VOP_LOCK(rootdir); + vn_lock(rootdir, LK_SHARED | LK_RETRY, p) return (0); } #endif - error = ENOENT; - - for (i = 0; i < nkern_targets; i++) { - struct kern_target *kt = &kern_targets[i]; - if (cnp->cn_namelen == strlen(kt->kt_name) && - bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) { - error = 0; - break; - } + for (kt = kern_targets, i = 0; i < nkern_targets; kt++, i++) { + if (cnp->cn_namelen == kt->kt_namlen && + bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) + goto found; } #ifdef KERNFS_DIAGNOSTIC - printf("kernfs_lookup: i = %d, error = %d\n", i, error); + printf("kernfs_lookup: i = %d, failed", i); #endif - /* - * If the name wasn't found, and this is not a LOOKUP - * request, we return EOPNOTSUPP so that the initial namei() - * fails and the higher level routines will not try to call - * our VOP_* functions. - */ - if (error) { - if (nameiop != LOOKUP) - error = EOPNOTSUPP; - goto bad; - } - - /* - * DELETE requests are not supported. - */ - if (nameiop == DELETE) { - error = EOPNOTSUPP; - goto bad; - } + vn_lock(dvp, LK_SHARED | LK_RETRY, p); + return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); - /* - * Allow CREATE requests if the name in question can - * be written to. This allows open(name, O_RDWR | O_CREAT) - * to work. Otherwise CREATE requests are not supported. - */ - if (nameiop == CREATE && (kern_targets[i].kt_rw & VWRITE == 0)) { - error = EOPNOTSUPP; - goto bad; - } - - /* - * Check if this name has already has a vnode associated with it. - */ - if (kern_targets[i].kt_vp) { - if (*kern_targets[i].kt_vp) { - *vpp = *kern_targets[i].kt_vp; - VREF(*vpp); - VOP_LOCK(*vpp); - return (0); +found: + if (kt->kt_tag == KTT_DEVICE) { + dev_t *dp = kt->kt_data; + loop: + if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) { + vn_lock(dvp, LK_SHARED | LK_RETRY, p); + return (ENOENT); } - error = ENXIO; - goto bad; + *vpp = fvp; + if (vget(fvp, LK_EXCLUSIVE, p)) + goto loop; + return (0); } #ifdef KERNFS_DIAGNOSTIC printf("kernfs_lookup: allocate new vnode\n"); #endif - error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p, &fvp); - if (error) - goto bad; - MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP, M_WAITOK); - VTOKERN(fvp)->kf_kt = &kern_targets[i]; - fvp->v_type = VTOKERN(fvp)->kf_kt->kt_vtype; + if (error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p, + &fvp)) { + vn_lock(dvp, LK_SHARED | LK_RETRY, p); + return (error); + } + + MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP, + M_WAITOK); + VTOKERN(fvp)->kf_kt = kt; + fvp->v_type = kt->kt_vtype; + vn_lock(fvp, LK_SHARED | LK_RETRY, p); *vpp = fvp; + #ifdef KERNFS_DIAGNOSTIC printf("kernfs_lookup: newvp = %x\n", fvp); #endif return (0); - -bad:; - *vpp = NULL; -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_lookup: error = %d\n", error); -#endif - return (error); } static int @@ -354,22 +329,8 @@ kernfs_open(ap) struct proc *a_p; } */ *ap; { - struct vnode *vp = ap->a_vp; - - /* - * Can always open the root (modulo perms) - */ - if (vp->v_flag & VROOT) - return (0); - -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_open, mode = %x, file = %s\n", - ap->a_mode, VTOKERN(vp)->kf_kt->kt_name); -#endif - - if ((ap->a_mode & FWRITE) && !(VTOKERN(vp)->kf_kt->kt_rw & VWRITE)) - return (EOPNOTSUPP); + /* Only need to check access permissions. */ return (0); } @@ -382,33 +343,45 @@ kernfs_access(ap) struct proc *a_p; } */ *ap; { - struct vnode *vp = ap->a_vp; - struct ucred *cred = ap->a_cred; - mode_t mode = ap->a_mode; - - if (mode & VEXEC) { - if (vp->v_flag & VROOT) - return (0); - return (EACCES); - } + register struct vnode *vp = ap->a_vp; + register struct ucred *cred = ap->a_cred; + mode_t amode = ap->a_mode; + mode_t fmode = + (vp->v_flag & VROOT) ? DIR_MODE : VTOKERN(vp)->kf_kt->kt_mode; + mode_t mask = 0; + register gid_t *gp; + int i; - if (cred->cr_uid == 0) { - if ((vp->v_flag & VROOT) == 0) { - struct kern_target *kt = VTOKERN(vp)->kf_kt; + /* Some files are simply not modifiable. */ + if ((amode & VWRITE) && (fmode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0) + return (EPERM); - if ((mode & VWRITE) && !(kt->kt_rw & VWRITE)) - return (EROFS); - } + /* Root can do anything else. */ + if (cred->cr_uid == 0) return (0); - } - if (mode & VWRITE) - return (EACCES); + /* Check for group 0 (wheel) permissions. */ + for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) + if (*gp == 0) { + if (amode & VEXEC) + mask |= S_IXGRP; + if (amode & VREAD) + mask |= S_IRGRP; + if (amode & VWRITE) + mask |= S_IWGRP; + return ((fmode & mask) == mask ? 0 : EACCES); + } - return (0); + /* Otherwise, check everyone else. */ + if (amode & VEXEC) + mask |= S_IXOTH; + if (amode & VREAD) + mask |= S_IROTH; + if (amode & VWRITE) + mask |= S_IWOTH; + return ((fmode & mask) == mask ? 0 : EACCES); } - static int kernfs_getattr(ap) struct vop_getattr_args /* { @@ -420,6 +393,7 @@ kernfs_getattr(ap) { struct vnode *vp = ap->a_vp; struct vattr *vap = ap->a_vap; + struct timeval tv; int error = 0; char strbuf[KSTRING]; @@ -428,7 +402,7 @@ kernfs_getattr(ap) vap->va_uid = 0; vap->va_gid = 0; vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; - /* vap->va_qsize = 0; */ + vap->va_size = 0; vap->va_blocksize = DEV_BSIZE; { struct timeval tv; @@ -440,7 +414,6 @@ kernfs_getattr(ap) vap->va_gen = 0; vap->va_flags = 0; vap->va_rdev = 0; - /* vap->va_qbytes = 0; */ vap->va_bytes = 0; if (vp->v_flag & VROOT) { @@ -459,14 +432,13 @@ kernfs_getattr(ap) printf("kernfs_getattr: stat target %s\n", kt->kt_name); #endif vap->va_type = kt->kt_vtype; - vap->va_mode = (kt->kt_rw & VWRITE ? WRITE_MODE : READ_MODE); + vap->va_mode = kt->kt_mode; vap->va_nlink = 1; - vap->va_fileid = 3 + (kt - kern_targets) / sizeof(*kt); + vap->va_fileid = 1 + (kt - kern_targets) / sizeof(*kt); error = kernfs_xread(kt, strbuf, sizeof(strbuf), &nbytes); vap->va_size = nbytes; } - vp->v_type = vap->va_type; #ifdef KERNFS_DIAGNOSTIC printf("kernfs_getattr: return error %d\n", error); #endif @@ -509,7 +481,7 @@ kernfs_read(ap) int error, len; char *cp; - if (vp->v_flag & VROOT) + if (vp->v_type == VDIR) return (EOPNOTSUPP); kt = VTOKERN(vp)->kf_kt; @@ -519,12 +491,11 @@ kernfs_read(ap) #endif len = 0; - error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len); - if (error) + if (error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len)) return (error); - cp = strbuf + off; - len -= off; - return (uiomove(cp, len, uio)); + if (len <= off) + return (0); + return (uiomove(&strbuf[off], len - off, uio)); } static int @@ -542,8 +513,8 @@ kernfs_write(ap) int error, xlen; char strbuf[KSTRING]; - if (vp->v_flag & VROOT) - return (0); + if (vp->v_type == VDIR) + return (EOPNOTSUPP); kt = VTOKERN(vp)->kf_kt; @@ -551,8 +522,7 @@ kernfs_write(ap) return (EINVAL); xlen = min(uio->uio_resid, KSTRING-1); - error = uiomove(strbuf, xlen, uio); - if (error) + if (error = uiomove(strbuf, xlen, uio)) return (error); if (uio->uio_resid != 0) @@ -563,33 +533,52 @@ kernfs_write(ap) return (kernfs_xwrite(kt, strbuf, xlen)); } - static int kernfs_readdir(ap) struct vop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio; struct ucred *a_cred; + int *a_eofflag; + u_long *a_cookies; + int a_ncookies; } */ *ap; { + int error, i; struct uio *uio = ap->a_uio; - int i; - int error; + struct kern_target *kt; + struct dirent d; + + if (ap->a_vp->v_type != VDIR) + return (ENOTDIR); + + /* + * We don't allow exporting kernfs mounts, and currently local + * requests do not need cookies. + */ + if (ap->a_ncookies != NULL) + panic("kernfs_readdir: not hungry"); i = uio->uio_offset / UIO_MX; error = 0; - while (uio->uio_resid > 0 && i < nkern_targets) { - struct dirent d; + for (kt = &kern_targets[i]; + uio->uio_resid >= UIO_MX && i < nkern_targets; kt++, i++) { struct dirent *dp = &d; - struct kern_target *kt = &kern_targets[i]; #ifdef KERNFS_DIAGNOSTIC printf("kernfs_readdir: i = %d\n", i); #endif - bzero((caddr_t) dp, UIO_MX); + if (kt->kt_tag == KTT_DEVICE) { + dev_t *dp = kt->kt_data; + struct vnode *fvp; + + if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) + continue; + } - dp->d_namlen = strlen(kt->kt_name); - bcopy(kt->kt_name, dp->d_name, dp->d_namlen+1); + bzero((caddr_t)dp, UIO_MX); + dp->d_namlen = kt->kt_namlen; + bcopy(kt->kt_name, dp->d_name, kt->kt_namlen+1); #ifdef KERNFS_DIAGNOSTIC printf("kernfs_readdir: name = %s, len = %d\n", @@ -600,14 +589,12 @@ kernfs_readdir(ap) */ dp->d_reclen = UIO_MX; dp->d_fileno = i + 3; - dp->d_type = DT_UNKNOWN; /* XXX */ + dp->d_type = kt->kt_type; /* * And ship to userland */ - error = uiomove((caddr_t) dp, UIO_MX, uio); - if (error) + if (error = uiomove((caddr_t)dp, UIO_MX, uio)) break; - i++; } uio->uio_offset = i * UIO_MX; @@ -619,18 +606,20 @@ static int kernfs_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { struct vnode *vp = ap->a_vp; +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_inactive(%x)\n", vp); +#endif /* * Clear out the v_type field to avoid * nasty things happening in vgone(). */ + VOP_UNLOCK(vp, 0, ap->a_p); vp->v_type = VNON; -#ifdef KERNFS_DIAGNOSTIC - printf("kernfs_inactive(%x)\n", vp); -#endif return (0); } @@ -641,6 +630,7 @@ kernfs_reclaim(ap) } */ *ap; { struct vnode *vp = ap->a_vp; + #ifdef KERNFS_DIAGNOSTIC printf("kernfs_reclaim(%x)\n", vp); #endif @@ -717,16 +707,6 @@ kernfs_vfree(ap) } /* - * Kernfs vnode unsupported operation - */ -static int -kernfs_enotsupp() -{ - - return (EOPNOTSUPP); -} - -/* * Kernfs "should never get here" operation */ static int @@ -735,42 +715,42 @@ kernfs_badop() return (EIO); } -#define kernfs_create ((int (*) __P((struct vop_create_args *)))kernfs_enotsupp) -#define kernfs_mknod ((int (*) __P((struct vop_mknod_args *)))kernfs_enotsupp) +#define kernfs_create ((int (*) __P((struct vop_create_args *)))eopnotsupp) +#define kernfs_mknod ((int (*) __P((struct vop_mknod_args *)))eopnotsupp) #define kernfs_close ((int (*) __P((struct vop_close_args *)))nullop) -#define kernfs_ioctl ((int (*) __P((struct vop_ioctl_args *)))kernfs_enotsupp) -#define kernfs_select ((int (*) __P((struct vop_select_args *)))kernfs_enotsupp) -#define kernfs_mmap ((int (*) __P((struct vop_mmap_args *)))kernfs_enotsupp) +#define kernfs_ioctl ((int (*) __P((struct vop_ioctl_args *)))eopnotsupp) +#define kernfs_select ((int (*) __P((struct vop_select_args *)))eopnotsupp) +#define kernfs_revoke vop_revoke +#define kernfs_mmap ((int (*) __P((struct vop_mmap_args *)))eopnotsupp) #define kernfs_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) #define kernfs_seek ((int (*) __P((struct vop_seek_args *)))nullop) -#define kernfs_remove ((int (*) __P((struct vop_remove_args *)))kernfs_enotsupp) -#define kernfs_link ((int (*) __P((struct vop_link_args *)))kernfs_enotsupp) -#define kernfs_rename ((int (*) __P((struct vop_rename_args *)))kernfs_enotsupp) -#define kernfs_mkdir ((int (*) __P((struct vop_mkdir_args *)))kernfs_enotsupp) -#define kernfs_rmdir ((int (*) __P((struct vop_rmdir_args *)))kernfs_enotsupp) -#define kernfs_symlink ((int (*) __P((struct vop_symlink_args *)))kernfs_enotsupp) -#define kernfs_readlink \ - ((int (*) __P((struct vop_readlink_args *)))kernfs_enotsupp) +#define kernfs_remove ((int (*) __P((struct vop_remove_args *)))eopnotsupp) +#define kernfs_link ((int (*) __P((struct vop_link_args *)))eopnotsupp) +#define kernfs_rename ((int (*) __P((struct vop_rename_args *)))eopnotsupp) +#define kernfs_mkdir ((int (*) __P((struct vop_mkdir_args *)))eopnotsupp) +#define kernfs_rmdir ((int (*) __P((struct vop_rmdir_args *)))eopnotsupp) +#define kernfs_symlink ((int (*) __P((struct vop_symlink_args *)))eopnotsupp) +#define kernfs_readlink ((int (*) __P((struct vop_readlink_args *)))eopnotsupp) #define kernfs_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) -#define kernfs_lock ((int (*) __P((struct vop_lock_args *)))nullop) -#define kernfs_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) +#define kernfs_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock) +#define kernfs_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock) #define kernfs_bmap ((int (*) __P((struct vop_bmap_args *)))kernfs_badop) -#define kernfs_strategy ((int (*) __P((struct vop_strategy_args *)))kernfs_badop) -#define kernfs_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) -#define kernfs_advlock ((int (*) __P((struct vop_advlock_args *)))kernfs_enotsupp) -#define kernfs_blkatoff \ - ((int (*) __P((struct vop_blkatoff_args *)))kernfs_enotsupp) +#define kernfs_strategy \ + ((int (*) __P((struct vop_strategy_args *)))kernfs_badop) +#define kernfs_islocked \ + ((int (*) __P((struct vop_islocked_args *)))vop_noislocked) +#define kernfs_advlock ((int (*) __P((struct vop_advlock_args *)))eopnotsupp) +#define kernfs_blkatoff ((int (*) __P((struct vop_blkatoff_args *)))eopnotsupp) #define kernfs_valloc ((int(*) __P(( \ struct vnode *pvp, \ int mode, \ struct ucred *cred, \ - struct vnode **vpp))) kernfs_enotsupp) -#define kernfs_truncate \ - ((int (*) __P((struct vop_truncate_args *)))kernfs_enotsupp) -#define kernfs_update ((int (*) __P((struct vop_update_args *)))kernfs_enotsupp) -#define kernfs_bwrite ((int (*) __P((struct vop_bwrite_args *)))kernfs_enotsupp) + struct vnode **vpp))) eopnotsupp) +#define kernfs_truncate ((int (*) __P((struct vop_truncate_args *)))eopnotsupp) +#define kernfs_update ((int (*) __P((struct vop_update_args *)))eopnotsupp) +#define kernfs_bwrite ((int (*) __P((struct vop_bwrite_args *)))eopnotsupp) -vop_t **kernfs_vnodeop_p; +vop_t **kernfs_vnodeop_p; static struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = { { &vop_default_desc, (vop_t *)vn_default_error }, { &vop_lookup_desc, (vop_t *)kernfs_lookup }, /* lookup */ @@ -785,6 +765,7 @@ static struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = { { &vop_write_desc, (vop_t *)kernfs_write }, /* write */ { &vop_ioctl_desc, (vop_t *)kernfs_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)kernfs_select }, /* select */ + { &vop_revoke_desc, (vop_t *)kernfs_revoke }, /* revoke */ { &vop_mmap_desc, (vop_t *)kernfs_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)kernfs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)kernfs_seek }, /* seek */ diff --git a/sys/miscfs/nullfs/null.h b/sys/miscfs/nullfs/null.h index beadb42..70a81b2 100644 --- a/sys/miscfs/nullfs/null.h +++ b/sys/miscfs/nullfs/null.h @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)null.h 8.2 (Berkeley) 1/21/94 + * @(#)null.h 8.3 (Berkeley) 8/20/94 * * $FreeBSD$ */ @@ -52,8 +52,7 @@ struct null_mount { * A cache of vnode references */ struct null_node { - struct null_node *null_forw; /* Hash chain */ - struct null_node *null_back; + LIST_ENTRY(null_node) null_hash; /* Hash list */ struct vnode *null_lowervp; /* VREFed once */ struct vnode *null_vnode; /* Back pointer */ }; diff --git a/sys/miscfs/nullfs/null_subr.c b/sys/miscfs/nullfs/null_subr.c index a14a7e4..4418631 100644 --- a/sys/miscfs/nullfs/null_subr.c +++ b/sys/miscfs/nullfs/null_subr.c @@ -33,13 +33,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)null_subr.c 8.4 (Berkeley) 1/21/94 + * @(#)null_subr.c 8.7 (Berkeley) 5/14/95 * * $FreeBSD$ */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/proc.h> #include <sys/time.h> #include <sys/types.h> #include <sys/vnode.h> @@ -48,11 +49,8 @@ #include <sys/malloc.h> #include <miscfs/nullfs/null.h> -extern int nullfs_init __P((void)); - #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ #define NNULLNODECACHE 16 -#define NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1)) /* * Null layer cache: @@ -62,51 +60,32 @@ extern int nullfs_init __P((void)); * alias is removed the lower vnode is vrele'd. */ -/* - * Cache head - */ -struct null_node_cache { - struct null_node *ac_forw; - struct null_node *ac_back; -}; - -static struct null_node_cache null_node_cache[NNULLNODECACHE]; +#define NULL_NHASH(vp) \ + (&null_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & null_node_hash]) +LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl; +u_long null_node_hash; static int null_node_alloc __P((struct mount *mp, struct vnode *lowervp, struct vnode **vpp)); static struct vnode * null_node_find __P((struct mount *mp, struct vnode *lowervp)); -static struct null_node_cache * - null_node_hash __P((struct vnode *lowervp)); /* * Initialise cache headers */ int -nullfs_init() +nullfs_init(vfsp) + struct vfsconf *vfsp; { - struct null_node_cache *ac; + #ifdef NULLFS_DIAGNOSTIC printf("nullfs_init\n"); /* printed during system boot */ #endif - - for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) - ac->ac_forw = ac->ac_back = (struct null_node *) ac; + null_node_hashtbl = hashinit(NNULLNODECACHE, M_CACHE, &null_node_hash); return (0); } /* - * Compute hash list for given lower vnode - */ -static struct null_node_cache * -null_node_hash(lowervp) -struct vnode *lowervp; -{ - - return (&null_node_cache[NULL_NHASH(lowervp)]); -} - -/* * Return a VREF'ed alias for lower vnode if already exists, else 0. */ static struct vnode * @@ -114,7 +93,8 @@ null_node_find(mp, lowervp) struct mount *mp; struct vnode *lowervp; { - struct null_node_cache *hd; + struct proc *p = curproc; /* XXX */ + struct null_node_hashhead *hd; struct null_node *a; struct vnode *vp; @@ -124,9 +104,9 @@ null_node_find(mp, lowervp) * the lower vnode. If found, the increment the null_node * reference count (but NOT the lower vnode's VREF counter). */ - hd = null_node_hash(lowervp); + hd = NULL_NHASH(lowervp); loop: - for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) { + for (a = hd->lh_first; a != 0; a = a->null_hash.le_next) { if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { vp = NULLTOV(a); /* @@ -134,7 +114,7 @@ loop: * stuff, but we don't want to lock * the lower node. */ - if (vget(vp, 0)) { + if (vget(vp, 0, p)) { printf ("null_node_find: vget failed.\n"); goto loop; }; @@ -157,7 +137,7 @@ null_node_alloc(mp, lowervp, vpp) struct vnode *lowervp; struct vnode **vpp; { - struct null_node_cache *hd; + struct null_node_hashhead *hd; struct null_node *xp; struct vnode *othervp, *vp; int error; @@ -194,8 +174,8 @@ null_node_alloc(mp, lowervp, vpp) return 0; }; VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */ - hd = null_node_hash(lowervp); - insque(xp, hd); + hd = NULL_NHASH(lowervp); + LIST_INSERT_HEAD(hd, xp, null_hash); return 0; } @@ -250,9 +230,8 @@ null_node_create(mp, lowervp, newvpp) #ifdef DIAGNOSTIC if (lowervp->v_usecount < 1) { /* Should never happen... */ - vprint ("null_node_create: alias ",aliasvp); - vprint ("null_node_create: lower ",lowervp); - printf ("null_node_create: lower has 0 usecount.\n"); + vprint ("null_node_create: alias ", aliasvp); + vprint ("null_node_create: lower ", lowervp); panic ("null_node_create: lower has 0 usecount."); }; #endif diff --git a/sys/miscfs/nullfs/null_vfsops.c b/sys/miscfs/nullfs/null_vfsops.c index e2aeeba..339b7c1 100644 --- a/sys/miscfs/nullfs/null_vfsops.c +++ b/sys/miscfs/nullfs/null_vfsops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1992, 1993 + * Copyright (c) 1992, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software donated to Berkeley by @@ -46,7 +46,7 @@ #include <sys/param.h> #include <sys/systm.h> -#include <sys/kernel.h> +#include <sys/proc.h> #include <sys/time.h> #include <sys/types.h> #include <sys/vnode.h> @@ -55,7 +55,7 @@ #include <sys/malloc.h> #include <miscfs/nullfs/null.h> -extern int nullfs_init __P((void)); +extern int nullfs_init __P((struct vfsconf *)); static int nullfs_fhtovp __P((struct mount *mp, struct fid *fidp, struct mbuf *nam, struct vnode **vpp, @@ -146,7 +146,7 @@ nullfs_mount(mp, path, data, ndp, p) /* * Unlock the node (either the lower or the alias) */ - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); /* * Make sure the node alias worked */ @@ -166,7 +166,7 @@ nullfs_mount(mp, path, data, ndp, p) if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) mp->mnt_flag |= MNT_LOCAL; mp->mnt_data = (qaddr_t) xmp; - getnewfsid(mp, MOUNT_LOFS); + vfs_getnewfsid(mp); (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); @@ -212,12 +212,8 @@ nullfs_unmount(mp, mntflags, p) printf("nullfs_unmount(mp = %x)\n", mp); #endif - if (mntflags & MNT_FORCE) { - /* lofs can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } /* * Clear out buffer cache. I don't think we @@ -259,6 +255,7 @@ nullfs_root(mp, vpp) struct mount *mp; struct vnode **vpp; { + struct proc *p = curproc; /* XXX */ struct vnode *vp; #ifdef NULLFS_DIAGNOSTIC @@ -273,7 +270,7 @@ nullfs_root(mp, vpp) */ vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; VREF(vp); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); *vpp = vp; return 0; } diff --git a/sys/miscfs/nullfs/null_vnops.c b/sys/miscfs/nullfs/null_vnops.c index ec279bc..c1af96f 100644 --- a/sys/miscfs/nullfs/null_vnops.c +++ b/sys/miscfs/nullfs/null_vnops.c @@ -33,7 +33,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)null_vnops.c 8.1 (Berkeley) 6/10/93 + * @(#)null_vnops.c 8.6 (Berkeley) 5/27/95 + * + * Ancestors: + * @(#)lofs_vnops.c 1.2 (Berkeley) 6/18/92 + * $Id: null_vnops.c,v 1.11.2000.1 1996/09/17 14:32:31 peter Exp $ + * ...and... + * @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project * * $FreeBSD$ */ @@ -88,13 +94,21 @@ * in the arguments and, if a vnode is return by the operation, * stacks a null-node on top of the returned vnode. * - * Although bypass handles most operations, - * vop_getattr, _inactive, _reclaim, and _print are not bypassed. - * Vop_getattr must change the fsid being returned. + * Although bypass handles most operations, vop_getattr, vop_lock, + * vop_unlock, vop_inactive, vop_reclaim, and vop_print are not + * bypassed. Vop_getattr must change the fsid being returned. + * Vop_lock and vop_unlock must handle any locking for the + * current vnode as well as pass the lock request down. * Vop_inactive and vop_reclaim are not bypassed so that - * they can handle freeing null-layer specific data. - * Vop_print is not bypassed to avoid excessive debugging - * information. + * they can handle freeing null-layer specific data. Vop_print + * is not bypassed to avoid excessive debugging information. + * Also, certain vnode operations change the locking state within + * the operation (create, mknod, remove, link, rename, mkdir, rmdir, + * and symlink). Ideally these operations should not change the + * lock state, but should be changed to let the caller of the + * function unlock them. Otherwise all intermediate vnode layers + * (such as union, umapfs, etc) must catch these functions to do + * the necessary locking at their layer. * * * INSTANTIATING VNODE STACKS @@ -178,7 +192,7 @@ static int null_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ SYSCTL_INT(_debug, OID_AUTO, nullfs_bug_bypass, CTLFLAG_RW, &null_bug_bypass, 0, ""); -static int null_bypass __P((struct vop_generic_args *ap)); +int null_bypass __P((struct vop_generic_args *ap)); static int null_bwrite __P((struct vop_bwrite_args *ap)); static int null_getattr __P((struct vop_getattr_args *ap)); static int null_inactive __P((struct vop_inactive_args *ap)); @@ -211,7 +225,7 @@ static int null_strategy __P((struct vop_strategy_args *ap)); * - all mapped vnodes are of our vnode-type (NEEDSWORK: * problems on rmdir'ing mount points and renaming?) */ -static int +int null_bypass(ap) struct vop_generic_args /* { struct vnodeop_desc *a_desc; @@ -254,7 +268,8 @@ null_bypass(ap) * are of our type. Check for and don't map any * that aren't. (We must always map first vp or vclean fails.) */ - if (i && (*this_vp_p)->v_op != null_vnodeop_p) { + if (i && (*this_vp_p == NULL || + (*this_vp_p)->v_op != null_vnodeop_p)) { old_vps[i] = NULL; } else { old_vps[i] = *this_vp_p; @@ -317,6 +332,105 @@ null_bypass(ap) return (error); } +/* + * We have to carry on the locking protocol on the null layer vnodes + * as we progress through the tree. We also have to enforce read-only + * if this layer is mounted read-only. + */ +static int +null_lookup(ap) + struct vop_lookup_args /* { + struct vnode * a_dvp; + struct vnode ** a_vpp; + struct componentname * a_cnp; + } */ *ap; +{ + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; + int flags = cnp->cn_flags; + struct vop_lock_args lockargs; + struct vop_unlock_args unlockargs; + struct vnode *dvp, *vp; + int error; + + if ((flags & ISLASTCN) && (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) && + (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) + return (EROFS); + error = null_bypass(ap); + if (error == EJUSTRETURN && (flags & ISLASTCN) && + (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) && + (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) + error = EROFS; + /* + * We must do the same locking and unlocking at this layer as + * is done in the layers below us. We could figure this out + * based on the error return and the LASTCN, LOCKPARENT, and + * LOCKLEAF flags. However, it is more expidient to just find + * out the state of the lower level vnodes and set ours to the + * same state. + */ + dvp = ap->a_dvp; + vp = *ap->a_vpp; + if (dvp == vp) + return (error); + if (!VOP_ISLOCKED(dvp)) { + unlockargs.a_vp = dvp; + unlockargs.a_flags = 0; + unlockargs.a_p = p; + vop_nounlock(&unlockargs); + } + if (vp != NULL && VOP_ISLOCKED(vp)) { + lockargs.a_vp = vp; + lockargs.a_flags = LK_SHARED; + lockargs.a_p = p; + vop_nolock(&lockargs); + } + return (error); +} + +/* + * Setattr call. Disallow write attempts if the layer is mounted read-only. + */ +int +null_setattr(ap) + struct vop_setattr_args /* { + struct vnodeop_desc *a_desc; + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct vattr *vap = ap->a_vap; + + if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || + vap->va_gid != (gid_t)VNOVAL || vap->va_atime.ts_sec != VNOVAL || + vap->va_mtime.ts_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && + (vp->v_mount->mnt_flag & MNT_RDONLY)) + return (EROFS); + if (vap->va_size != VNOVAL) { + switch (vp->v_type) { + case VDIR: + return (EISDIR); + case VCHR: + case VBLK: + case VSOCK: + case VFIFO: + return (0); + case VREG: + case VLNK: + default: + /* + * Disallow write attempts if the filesystem is + * mounted read-only. + */ + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + } + } + return (null_bypass(ap)); +} /* * We handle getattr only to change the fsid. @@ -331,19 +445,90 @@ null_getattr(ap) } */ *ap; { int error; - error = null_bypass(ap); - if (error) + + if (error = null_bypass(ap)) return (error); /* Requires that arguments be restored. */ ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; return (0); } - static int +null_access(ap) + struct vop_access_args /* { + struct vnode *a_vp; + int a_mode; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + mode_t mode = ap->a_mode; + + /* + * Disallow write attempts on read-only layers; + * unless the file is a socket, fifo, or a block or + * character device resident on the file system. + */ + if (mode & VWRITE) { + switch (vp->v_type) { + case VDIR: + case VLNK: + case VREG: + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + break; + } + } + return (null_bypass(ap)); +} + +/* + * We need to process our own vnode lock and then clear the + * interlock flag as it applies only to our vnode, not the + * vnodes below us on the stack. + */ +int +null_lock(ap) + struct vop_lock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; +{ + + vop_nolock(ap); + if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN) + return (0); + ap->a_flags &= ~LK_INTERLOCK; + return (null_bypass(ap)); +} + +/* + * We need to process our own vnode unlock and then clear the + * interlock flag as it applies only to our vnode, not the + * vnodes below us on the stack. + */ +int +null_unlock(ap) + struct vop_unlock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + vop_nounlock(ap); + ap->a_flags &= ~LK_INTERLOCK; + return (null_bypass(ap)); +} + +int null_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { /* @@ -358,6 +543,7 @@ null_inactive(ap) * like they do in the name lookup cache code. * That's too much work for now. */ + VOP_UNLOCK(ap->a_vp, 0, ap->a_p); return (0); } @@ -365,6 +551,7 @@ static int null_reclaim(ap) struct vop_reclaim_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { struct vnode *vp = ap->a_vp; @@ -377,14 +564,13 @@ null_reclaim(ap) */ /* After this assignment, this node will not be re-used. */ xp->null_lowervp = NULL; - remque(xp); + LIST_REMOVE(xp, null_hash); FREE(vp->v_data, M_TEMP); vp->v_data = NULL; vrele (lowervp); return (0); } - static int null_print(ap) struct vop_print_args /* { @@ -396,7 +582,6 @@ null_print(ap) return (0); } - /* * XXX - vop_strategy must be hand coded because it has no * vnode in its arguments. @@ -422,7 +607,6 @@ null_strategy(ap) return (error); } - /* * XXX - like vop_strategy, vop_bwrite must be hand coded because it has no * vnode in its arguments. @@ -455,7 +639,12 @@ vop_t **null_vnodeop_p; static struct vnodeopv_entry_desc null_vnodeop_entries[] = { { &vop_default_desc, (vop_t *)null_bypass }, + { &vop_lookup_desc, (vop_t *)null_lookup }, + { &vop_setattr_desc, (vop_t *)null_setattr }, { &vop_getattr_desc, (vop_t *)null_getattr }, + { &vop_access_desc, (vop_t *)null_access }, + { &vop_lock_desc, (vop_t *)null_lock }, + { &vop_unlock_desc, (vop_t *)null_unlock }, { &vop_inactive_desc, (vop_t *)null_inactive }, { &vop_reclaim_desc, (vop_t *)null_reclaim }, { &vop_print_desc, (vop_t *)null_print }, diff --git a/sys/miscfs/portal/portal_vfsops.c b/sys/miscfs/portal/portal_vfsops.c index a980f65..74e1542 100644 --- a/sys/miscfs/portal/portal_vfsops.c +++ b/sys/miscfs/portal/portal_vfsops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1992, 1993 + * Copyright (c) 1992, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software donated to Berkeley by @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)portal_vfsops.c 8.6 (Berkeley) 1/21/94 + * @(#)portal_vfsops.c 8.11 (Berkeley) 5/14/95 * * $FreeBSD$ */ @@ -62,28 +62,18 @@ #include <sys/un.h> #include <miscfs/portal/portal.h> -static int portal_init __P((void)); static int portal_mount __P((struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct proc *p)); static int portal_start __P((struct mount *mp, int flags, struct proc *p)); static int portal_unmount __P((struct mount *mp, int mntflags, struct proc *p)); static int portal_root __P((struct mount *mp, struct vnode **vpp)); -static int portal_quotactl __P((struct mount *mp, int cmd, uid_t uid, - caddr_t arg, struct proc *p)); static int portal_statfs __P((struct mount *mp, struct statfs *sbp, struct proc *p)); -static int portal_sync __P((struct mount *mp, int waitfor, - struct ucred *cred, struct proc *p)); -static int portal_vget __P((struct mount *mp, ino_t ino, - struct vnode **vpp)); -static int portal_fhtovp __P((struct mount *mp, struct fid *fhp, - struct mbuf *nam, struct vnode **vpp, - int *exflagsp, struct ucred **credanonp)); -static int portal_vptofh __P((struct vnode *vp, struct fid *fhp)); static int -portal_init() +portal_init(vfsp) + struct vfsconf *vfsp; { return (0); @@ -150,7 +140,7 @@ portal_mount(mp, path, data, ndp, p) mp->mnt_flag |= MNT_LOCAL; mp->mnt_data = (qaddr_t) fmp; - getnewfsid(mp, MOUNT_PORTAL); + vfs_getnewfsid(mp); (void)copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); @@ -186,12 +176,8 @@ portal_unmount(mp, mntflags, p) int error, flags = 0; - if (mntflags & MNT_FORCE) { - /* portal can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } /* * Clear out buffer cache. I don't think we @@ -241,39 +227,26 @@ portal_root(mp, vpp) struct mount *mp; struct vnode **vpp; { + struct proc *p = curproc; /* XXX */ struct vnode *vp; - /* * Return locked reference to root. */ vp = VFSTOPORTAL(mp)->pm_root; VREF(vp); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); *vpp = vp; return (0); } static int -portal_quotactl(mp, cmd, uid, arg, p) - struct mount *mp; - int cmd; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - - return (EOPNOTSUPP); -} - -static int portal_statfs(mp, sbp, p) struct mount *mp; struct statfs *sbp; struct proc *p; { - sbp->f_type = MOUNT_PORTAL; sbp->f_flags = 0; sbp->f_bsize = DEV_BSIZE; sbp->f_iosize = DEV_BSIZE; @@ -283,6 +256,7 @@ portal_statfs(mp, sbp, p) sbp->f_files = 1; /* Allow for "." */ sbp->f_ffree = 0; /* See comments above */ if (sbp != &mp->mnt_stat) { + sbp->f_type = mp->mnt_vfc->vfc_typenum; bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); @@ -290,48 +264,17 @@ portal_statfs(mp, sbp, p) return (0); } -static int -portal_sync(mp, waitfor, cred, p) - struct mount *mp; - int waitfor; - struct ucred *cred; - struct proc *p; -{ - - return (0); -} - -static int -portal_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - - return (EOPNOTSUPP); -} - -static int -portal_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) - struct mount *mp; - struct fid *fhp; - struct mbuf *nam; - struct vnode **vpp; - int *exflagsp; - struct ucred **credanonp; -{ - - return (EOPNOTSUPP); -} - -static int -portal_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; -{ - - return (EOPNOTSUPP); -} +#define portal_fhtovp ((int (*) __P((struct mount *, struct fid *, \ + struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp) +#define portal_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \ + struct proc *)))eopnotsupp) +#define portal_sync ((int (*) __P((struct mount *, int, struct ucred *, \ + struct proc *)))nullop) +#define portal_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ + size_t, struct proc *)))eopnotsupp) +#define portal_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \ + eopnotsupp) +#define portal_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp) static struct vfsops portal_vfsops = { portal_mount, diff --git a/sys/miscfs/portal/portal_vnops.c b/sys/miscfs/portal/portal_vnops.c index 8135a5e..19b439c 100644 --- a/sys/miscfs/portal/portal_vnops.c +++ b/sys/miscfs/portal/portal_vnops.c @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)portal_vnops.c 8.8 (Berkeley) 1/21/94 + * @(#)portal_vnops.c 8.14 (Berkeley) 5/21/95 * * $FreeBSD$ */ @@ -112,17 +112,25 @@ portal_lookup(ap) struct componentname * a_cnp; } */ *ap; { - char *pname = ap->a_cnp->cn_nameptr; + struct componentname *cnp = ap->a_cnp; + struct vnode **vpp = ap->a_vpp; + struct vnode *dvp = ap->a_dvp; + char *pname = cnp->cn_nameptr; struct portalnode *pt; int error; struct vnode *fvp = 0; char *path; int size; - if (ap->a_cnp->cn_namelen == 1 && *pname == '.') { - *ap->a_vpp = ap->a_dvp; - VREF(ap->a_dvp); - /*VOP_LOCK(ap->a_dvp);*/ + *vpp = NULLVP; + + if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) + return (EROFS); + + if (cnp->cn_namelen == 1 && *pname == '.') { + *vpp = dvp; + VREF(dvp); + /*VOP_LOCK(dvp);*/ return (0); } @@ -134,7 +142,7 @@ portal_lookup(ap) MALLOC(pt, struct portalnode *, sizeof(struct portalnode), M_TEMP, M_WAITOK); - error = getnewvnode(VT_PORTAL, ap->a_dvp->v_mount, portal_vnodeop_p, &fvp); + error = getnewvnode(VT_PORTAL, dvp->v_mount, portal_vnodeop_p, &fvp); if (error) { FREE(pt, M_TEMP); goto bad; @@ -148,22 +156,20 @@ portal_lookup(ap) */ for (size = 0, path = pname; *path; path++) size++; - ap->a_cnp->cn_consume = size - ap->a_cnp->cn_namelen; + cnp->cn_consume = size - cnp->cn_namelen; pt->pt_arg = malloc(size+1, M_TEMP, M_WAITOK); pt->pt_size = size+1; bcopy(pname, pt->pt_arg, pt->pt_size); pt->pt_fileid = portal_fileid++; - *ap->a_vpp = fvp; + *vpp = fvp; /*VOP_LOCK(fvp);*/ return (0); bad:; - if (fvp) { + if (fvp) vrele(fvp); - } - *ap->a_vpp = NULL; return (error); } @@ -444,6 +450,7 @@ portal_getattr(ap) { struct vnode *vp = ap->a_vp; struct vattr *vap = ap->a_vap; + struct timeval tv; bzero(vap, sizeof(*vap)); vattr_null(vap); @@ -452,8 +459,8 @@ portal_getattr(ap) vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; vap->va_size = DEV_BSIZE; vap->va_blocksize = DEV_BSIZE; - microtime((struct timeval *)&vap->va_atime); - TIMEVAL_TO_TIMESPEC((struct timeval *)&vap->va_atime, (struct timespec *)&vap->va_atime); + microtime(&tv); + TIMEVAL_TO_TIMESPEC(&tv, &vap->va_atime); vap->va_mtime = vap->va_atime; vap->va_ctime = vap->va_ctime; vap->va_gen = 0; @@ -509,9 +516,19 @@ portal_readdir(ap) struct vnode *a_vp; struct uio *a_uio; struct ucred *a_cred; + int *a_eofflag; + u_long *a_cookies; + int a_ncookies; } */ *ap; { + /* + * We don't allow exporting portal mounts, and currently local + * requests do not need cookies. + */ + if (ap->a_ncookies) + panic("portal_readdir: not hungry"); + return (0); } @@ -519,9 +536,11 @@ static int portal_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { + VOP_UNLOCK(ap->a_vp, 0, ap->a_p); return (0); } @@ -639,6 +658,7 @@ portal_badop() #define portal_ioctl ((int (*) __P((struct vop_ioctl_args *)))portal_enotsupp) #define portal_select ((int (*) __P((struct vop_select_args *)))portal_enotsupp) #define portal_mmap ((int (*) __P((struct vop_mmap_args *)))portal_enotsupp) +#define portal_revoke vop_revoke #define portal_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) #define portal_seek ((int (*) __P((struct vop_seek_args *)))nullop) #define portal_remove ((int (*) __P((struct vop_remove_args *)))portal_enotsupp) @@ -651,12 +671,14 @@ portal_badop() #define portal_readlink \ ((int (*) __P((struct vop_readlink_args *)))portal_enotsupp) #define portal_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) -#define portal_lock ((int (*) __P((struct vop_lock_args *)))nullop) -#define portal_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) +#define portal_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock) +#define portal_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock) #define portal_bmap ((int (*) __P((struct vop_bmap_args *)))portal_badop) #define portal_strategy \ ((int (*) __P((struct vop_strategy_args *)))portal_badop) -#define portal_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) +#define portal_islocked \ + ((int (*) __P((struct vop_islocked_args *)))vop_noislocked) +#define fifo_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked) #define portal_advlock \ ((int (*) __P((struct vop_advlock_args *)))portal_enotsupp) #define portal_blkatoff \ @@ -687,6 +709,7 @@ static struct vnodeopv_entry_desc portal_vnodeop_entries[] = { { &vop_ioctl_desc, (vop_t *)portal_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)portal_select }, /* select */ { &vop_mmap_desc, (vop_t *)portal_mmap }, /* mmap */ + { &vop_revoke_desc, (vop_t *)portal_revoke }, /* revoke */ { &vop_fsync_desc, (vop_t *)portal_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)portal_seek }, /* seek */ { &vop_remove_desc, (vop_t *)portal_remove }, /* remove */ diff --git a/sys/miscfs/procfs/procfs.h b/sys/miscfs/procfs/procfs.h index df01a39..ef0d7eb 100644 --- a/sys/miscfs/procfs/procfs.h +++ b/sys/miscfs/procfs/procfs.h @@ -34,8 +34,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)procfs.h 8.6 (Berkeley) 2/3/94 + * @(#)procfs.h 8.9 (Berkeley) 5/14/95 * + * From: * $FreeBSD$ */ @@ -44,6 +45,7 @@ */ typedef enum { Proot, /* the filesystem root */ + Pcurproc, /* symbolic link for curproc */ Pproc, /* a process-specific sub-directory */ Pfile, /* the executable file */ Pmem, /* the process's memory image */ @@ -97,9 +99,9 @@ struct pfsdent { }; #define UIO_MX sizeof(struct pfsdent) #define PROCFS_FILENO(pid, type) \ - (((type) == Proot) ? \ - 2 : \ - ((((pid)+1) << 3) + ((int) (type)))) + (((type) < Pproc) ? \ + ((type) + 2) : \ + ((((pid)+1) << 4) + ((int) (type)))) /* * Convert between pfsnode vnode @@ -113,33 +115,33 @@ struct vfs_namemap { int nm_val; }; -extern int vfs_getuserstr __P((struct uio *, char *, int *)); -extern vfs_namemap_t *vfs_findname __P((vfs_namemap_t *, char *, int)); +int vfs_getuserstr __P((struct uio *, char *, int *)); +vfs_namemap_t *vfs_findname __P((vfs_namemap_t *, char *, int)); /* <machine/reg.h> */ struct reg; struct fpreg; #define PFIND(pid) ((pid) ? pfind(pid) : &proc0) -extern int procfs_freevp __P((struct vnode *)); -extern int procfs_allocvp __P((struct mount *, struct vnode **, long, pfstype)); -extern struct vnode *procfs_findtextvp __P((struct proc *)); -extern int procfs_sstep __P((struct proc *)); -extern void procfs_fix_sstep __P((struct proc *)); -extern int procfs_read_regs __P((struct proc *, struct reg *)); -extern int procfs_write_regs __P((struct proc *, struct reg *)); -extern int procfs_read_fpregs __P((struct proc *, struct fpreg *)); -extern int procfs_write_fpregs __P((struct proc *, struct fpreg *)); -extern int procfs_donote __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_doregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_dofpregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_doctl __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_dostatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_domap __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_dotype __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_freevp __P((struct vnode *)); +int procfs_allocvp __P((struct mount *, struct vnode **, long, pfstype)); +struct vnode *procfs_findtextvp __P((struct proc *)); +int procfs_sstep __P((struct proc *)); +void procfs_fix_sstep __P((struct proc *)); +int procfs_read_regs __P((struct proc *, struct reg *)); +int procfs_write_regs __P((struct proc *, struct reg *)); +int procfs_read_fpregs __P((struct proc *, struct fpreg *)); +int procfs_write_fpregs __P((struct proc *, struct fpreg *)); +int procfs_donote __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_doregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_dofpregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_doctl __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_dostatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_domap __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_dotype __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -/* check to see if the process has the "items" (regs/file) */ +/* functions to check whether or not files should be displayed */ int procfs_validfile __P((struct proc *)); int procfs_validfpregs __P((struct proc *)); int procfs_validregs __P((struct proc *)); diff --git a/sys/miscfs/procfs/procfs_ctl.c b/sys/miscfs/procfs/procfs_ctl.c index 4ddf7a7..68b93dd 100644 --- a/sys/miscfs/procfs/procfs_ctl.c +++ b/sys/miscfs/procfs/procfs_ctl.c @@ -34,8 +34,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)procfs_ctl.c 8.3 (Berkeley) 1/21/94 + * @(#)procfs_ctl.c 8.4 (Berkeley) 6/15/94 * + * From: * $FreeBSD$ */ @@ -51,13 +52,13 @@ #include <sys/resourcevar.h> #include <sys/signal.h> #include <sys/signalvar.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_extern.h> - +#include <sys/ptrace.h> #include <miscfs/procfs/procfs.h> +#ifndef FIX_SSTEP +#define FIX_SSTEP(p) +#endif + /* * True iff process (p) is in trace wait state * relative to process (curp) @@ -67,13 +68,6 @@ (p)->p_pptr == (curp) && \ ((p)->p_flag & P_TRACED)) -#ifdef notdef -#define FIX_SSTEP(p) { \ - procfs_fix_sstep(p); \ - } \ -} -#endif - #define PROCFS_CTL_ATTACH 1 #define PROCFS_CTL_DETACH 2 #define PROCFS_CTL_STEP 3 @@ -220,8 +214,10 @@ procfs_control(curp, p, op) */ case PROCFS_CTL_STEP: PHOLD(p); - procfs_sstep(p); + error = procfs_sstep(p); PRELE(p); + if (error) + return (error); break; /* diff --git a/sys/miscfs/procfs/procfs_fpregs.c b/sys/miscfs/procfs/procfs_fpregs.c index a3cad5f..841cf76 100644 --- a/sys/miscfs/procfs/procfs_fpregs.c +++ b/sys/miscfs/procfs/procfs_fpregs.c @@ -34,8 +34,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)procfs_fpregs.c 8.1 (Berkeley) 1/27/94 + * @(#)procfs_fpregs.c 8.2 (Berkeley) 6/15/94 * + * From: * $FreeBSD$ */ diff --git a/sys/miscfs/procfs/procfs_map.c b/sys/miscfs/procfs/procfs_map.c index 27c44fa..40c40d8 100644 --- a/sys/miscfs/procfs/procfs_map.c +++ b/sys/miscfs/procfs/procfs_map.c @@ -59,7 +59,7 @@ #include <vm/vm_param.h> #include <vm/vm_prot.h> #include <vm/vm_inherit.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_page.h> diff --git a/sys/miscfs/procfs/procfs_mem.c b/sys/miscfs/procfs/procfs_mem.c index 4e8fac6..06364e5 100644 --- a/sys/miscfs/procfs/procfs_mem.c +++ b/sys/miscfs/procfs/procfs_mem.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)procfs_mem.c 8.4 (Berkeley) 1/21/94 + * @(#)procfs_mem.c 8.5 (Berkeley) 6/15/94 * * $FreeBSD$ */ @@ -55,7 +55,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_kern.h> @@ -295,14 +295,11 @@ procfs_domem(curp, p, pfs, uio) struct pfsnode *pfs; struct uio *uio; { - int error; if (uio->uio_resid == 0) return (0); - error = procfs_rwmem(p, uio); - - return (error); + return (procfs_rwmem(p, uio)); } /* @@ -320,5 +317,6 @@ struct vnode * procfs_findtextvp(p) struct proc *p; { + return (p->p_textvp); } diff --git a/sys/miscfs/procfs/procfs_regs.c b/sys/miscfs/procfs/procfs_regs.c index 9282a3a..56ef233 100644 --- a/sys/miscfs/procfs/procfs_regs.c +++ b/sys/miscfs/procfs/procfs_regs.c @@ -34,8 +34,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)procfs_regs.c 8.3 (Berkeley) 1/27/94 + * @(#)procfs_regs.c 8.4 (Berkeley) 6/15/94 * + * From: * $FreeBSD$ */ diff --git a/sys/miscfs/procfs/procfs_status.c b/sys/miscfs/procfs/procfs_status.c index 432918d..76974b5 100644 --- a/sys/miscfs/procfs/procfs_status.c +++ b/sys/miscfs/procfs/procfs_status.c @@ -34,8 +34,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)procfs_status.c 8.3 (Berkeley) 2/17/94 + * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94 * + * From: * $FreeBSD$ */ @@ -142,7 +143,7 @@ procfs_dostatus(curp, p, pfs, uio) xlen = ps - psbuf; xlen -= uio->uio_offset; ps = psbuf + uio->uio_offset; - xlen = min(xlen, uio->uio_resid); + xlen = imin(xlen, uio->uio_resid); if (xlen <= 0) error = 0; else diff --git a/sys/miscfs/procfs/procfs_subr.c b/sys/miscfs/procfs/procfs_subr.c index d9b3d2f..5ee78f0 100644 --- a/sys/miscfs/procfs/procfs_subr.c +++ b/sys/miscfs/procfs/procfs_subr.c @@ -34,7 +34,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)procfs_subr.c 8.4 (Berkeley) 1/27/94 + * @(#)procfs_subr.c 8.6 (Berkeley) 5/14/95 * * $FreeBSD$ */ @@ -84,18 +84,21 @@ procfs_allocvp(mp, vpp, pid, pfs_type) long pid; pfstype pfs_type; { - int error; + struct proc *p = curproc; /* XXX */ struct pfsnode *pfs; + struct vnode *vp; struct pfsnode **pp; + int error; loop: for (pfs = pfshead; pfs != 0; pfs = pfs->pfs_next) { + vp = PFSTOV(pfs); if (pfs->pfs_pid == pid && pfs->pfs_type == pfs_type && - PFSTOV(pfs)->v_mount == mp) { - if (vget(pfs->pfs_vnode, 0)) + vp->v_mount == mp) { + if (vget(vp, 0, p)) goto loop; - *vpp = pfs->pfs_vnode; + *vpp = vp; return (0); } } @@ -118,17 +121,18 @@ loop: */ MALLOC(pfs, struct pfsnode *, sizeof(struct pfsnode), M_TEMP, M_WAITOK); - error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp); - if (error) { + if (error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp)) { FREE(pfs, M_TEMP); goto out; } + vp = *vpp; + + vp->v_data = pfs; - (*vpp)->v_data = pfs; pfs->pfs_next = 0; pfs->pfs_pid = (pid_t) pid; pfs->pfs_type = pfs_type; - pfs->pfs_vnode = *vpp; + pfs->pfs_vnode = vp; pfs->pfs_flags = 0; pfs->pfs_lockowner = 0; pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type); @@ -138,33 +142,41 @@ loop: pfs->pfs_mode = (VREAD|VEXEC) | (VREAD|VEXEC) >> 3 | (VREAD|VEXEC) >> 6; + vp->v_type = VDIR; + vp->v_flag = VROOT; + break; + + case Pcurproc: /* /proc/curproc = lr--r--r-- */ + pfs->pfs_mode = (VREAD) | + (VREAD >> 3) | + (VREAD >> 6); + vp->v_type = VLNK; break; case Pproc: pfs->pfs_mode = (VREAD|VEXEC) | (VREAD|VEXEC) >> 3 | (VREAD|VEXEC) >> 6; + vp->v_type = VDIR; break; case Pfile: - pfs->pfs_mode = (VREAD|VWRITE); - break; - case Pmem: pfs->pfs_mode = (VREAD|VWRITE) | (VREAD) >> 3;; break; case Pregs: - pfs->pfs_mode = (VREAD|VWRITE); - break; - case Pfpregs: pfs->pfs_mode = (VREAD|VWRITE); + vp->v_type = VREG; break; case Pctl: + case Pnote: + case Pnotepg: pfs->pfs_mode = (VWRITE); + vp->v_type = VREG; break; case Ptype: @@ -173,14 +185,7 @@ loop: pfs->pfs_mode = (VREAD) | (VREAD >> 3) | (VREAD >> 6); - break; - - case Pnote: - pfs->pfs_mode = (VWRITE); - break; - - case Pnotepg: - pfs->pfs_mode = (VWRITE); + vp->v_type = VREG; break; default: @@ -316,8 +321,7 @@ vfs_getuserstr(uio, buf, buflenp) return (EMSGSIZE); xlen = uio->uio_resid; - error = uiomove(buf, xlen, uio); - if (error) + if (error = uiomove(buf, xlen, uio)) return (error); /* allow multiple writes without seeks */ @@ -339,6 +343,7 @@ vfs_findname(nm, buf, buflen) char *buf; int buflen; { + for (; nm->nm_name; nm++) if (bcmp(buf, nm->nm_name, buflen+1) == 0) return (nm); diff --git a/sys/miscfs/procfs/procfs_vfsops.c b/sys/miscfs/procfs/procfs_vfsops.c index 433b391..5387126 100644 --- a/sys/miscfs/procfs/procfs_vfsops.c +++ b/sys/miscfs/procfs/procfs_vfsops.c @@ -34,7 +34,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)procfs_vfsops.c 8.4 (Berkeley) 1/21/94 + * @(#)procfs_vfsops.c 8.7 (Berkeley) 5/10/95 * * $FreeBSD$ */ @@ -56,24 +56,14 @@ #include <miscfs/procfs/procfs.h> #include <vm/vm.h> /* for PAGE_SIZE */ -static int procfs_fhtovp __P((struct mount *mp, struct fid *fhp, - struct mbuf *nam, struct vnode **vpp, - int *exflagsp, struct ucred **credanonp)); -static int procfs_init __P((void)); +static int procfs_init __P((struct vfsconf *vfsp)); static int procfs_mount __P((struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct proc *p)); -static int procfs_quotactl __P((struct mount *mp, int cmds, uid_t uid, - caddr_t arg, struct proc *p)); static int procfs_start __P((struct mount *mp, int flags, struct proc *p)); static int procfs_statfs __P((struct mount *mp, struct statfs *sbp, struct proc *p)); -static int procfs_sync __P((struct mount *mp, int waitfor, - struct ucred *cred, struct proc *p)); static int procfs_unmount __P((struct mount *mp, int mntflags, struct proc *p)); -static int procfs_vget __P((struct mount *mp, ino_t ino, - struct vnode **vpp)); -static int procfs_vptofh __P((struct vnode *vp, struct fid *fhp)); /* * VFS Operations. @@ -101,7 +91,7 @@ procfs_mount(mp, path, data, ndp, p) mp->mnt_flag |= MNT_LOCAL; mp->mnt_data = 0; - getnewfsid(mp, MOUNT_PROCFS); + vfs_getnewfsid(mp); (void) copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname, MNAMELEN, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); @@ -125,12 +115,8 @@ procfs_unmount(mp, mntflags, p) int error; int flags = 0; - if (mntflags & MNT_FORCE) { - /* procfs can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } error = vflush(mp, 0, flags); if (error) @@ -144,24 +130,10 @@ procfs_root(mp, vpp) struct mount *mp; struct vnode **vpp; { - struct pfsnode *pfs; - struct vnode *vp; - int error; - - error = procfs_allocvp(mp, &vp, (pid_t) 0, Proot); - if (error) - return (error); - - vp->v_type = VDIR; - vp->v_flag = VROOT; - pfs = VTOPFS(vp); - *vpp = vp; - return (0); + return (procfs_allocvp(mp, vpp, 0, Proot)); } -/* - */ /* ARGSUSED */ static int procfs_start(mp, flags, p) @@ -182,7 +154,6 @@ procfs_statfs(mp, sbp, p) struct statfs *sbp; struct proc *p; { - sbp->f_type = MOUNT_PROCFS; sbp->f_bsize = PAGE_SIZE; sbp->f_iosize = PAGE_SIZE; sbp->f_blocks = 1; /* avoid divide by zero in some df's */ @@ -192,6 +163,7 @@ procfs_statfs(mp, sbp, p) sbp->f_ffree = maxproc - nprocs; /* approx */ if (sbp != &mp->mnt_stat) { + sbp->f_type = mp->mnt_vfc->vfc_typenum; bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); @@ -200,68 +172,25 @@ procfs_statfs(mp, sbp, p) return (0); } - -static int -procfs_quotactl(mp, cmds, uid, arg, p) - struct mount *mp; - int cmds; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - - return (EOPNOTSUPP); -} - static int -procfs_sync(mp, waitfor, cred, p) - struct mount *mp; - int waitfor; - struct ucred *cred; - struct proc *p; +procfs_init(vfsp) + struct vfsconf *vfsp; { return (0); } -static int -procfs_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - - return (EOPNOTSUPP); -} - -static int -procfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) - struct mount *mp; - struct fid *fhp; - struct mbuf *nam; - struct vnode **vpp; - int *exflagsp; - struct ucred **credanonp; -{ - - return (EINVAL); -} - -static int -procfs_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; -{ - - return EINVAL; -} - -static int -procfs_init() -{ - - return (0); -} +#define procfs_fhtovp ((int (*) __P((struct mount *, struct fid *, \ + struct mbuf *, struct vnode **, int *, struct ucred **)))einval) +#define procfs_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \ + struct proc *)))eopnotsupp) +#define procfs_sync ((int (*) __P((struct mount *, int, struct ucred *, \ + struct proc *)))nullop) +#define procfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ + size_t, struct proc *)))eopnotsupp) +#define procfs_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \ + eopnotsupp) +#define procfs_vptofh ((int (*) __P((struct vnode *, struct fid *)))einval) static struct vfsops procfs_vfsops = { procfs_mount, diff --git a/sys/miscfs/procfs/procfs_vnops.c b/sys/miscfs/procfs/procfs_vnops.c index f497563..85be3ea 100644 --- a/sys/miscfs/procfs/procfs_vnops.c +++ b/sys/miscfs/procfs/procfs_vnops.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 + * Copyright (c) 1993, 1995 Jan-Simon Pendry + * Copyright (c) 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -34,7 +34,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)procfs_vnops.c 8.6 (Berkeley) 2/7/94 + * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95 * * $FreeBSD$ */ @@ -55,8 +55,9 @@ #include <sys/malloc.h> #include <sys/dirent.h> #include <sys/resourcevar.h> -#include <miscfs/procfs/procfs.h> #include <vm/vm.h> /* for PAGE_SIZE */ +#include <machine/reg.h> +#include <miscfs/procfs/procfs.h> static int procfs_abortop __P((struct vop_abortop_args *)); static int procfs_access __P((struct vop_access_args *)); @@ -78,29 +79,30 @@ static int procfs_setattr __P((struct vop_setattr_args *)); * process-specific sub-directories. It is * used in procfs_lookup and procfs_readdir */ -static struct pfsnames { - u_short d_namlen; - char d_name[PROCFS_NAMELEN]; - pfstype d_pfstype; - int (*d_valid) __P((struct proc *)); -} procent[] = { +struct proc_target { + u_char pt_type; + u_char pt_namlen; + char *pt_name; + pfstype pt_pfstype; + int (*pt_valid) __P((struct proc *p)); +} proc_targets[] = { #define N(s) sizeof(s)-1, s - /* namlen, nam, type validp */ - { N("."), Pproc, NULL }, - { N(".."), Proot, NULL }, - { N("file"), Pfile, procfs_validfile }, - { N("mem"), Pmem, NULL }, - { N("regs"), Pregs, procfs_validregs }, - { N("fpregs"), Pfpregs, procfs_validfpregs }, - { N("ctl"), Pctl, NULL }, - { N("status"), Pstatus, NULL }, - { N("note"), Pnote, NULL }, - { N("notepg"), Pnotepg, NULL }, - { N("map"), Pmap, procfs_validmap }, - { N("etype"), Ptype, procfs_validtype }, + /* name type validp */ + { DT_DIR, N("."), Pproc, NULL }, + { DT_DIR, N(".."), Proot, NULL }, + { DT_REG, N("file"), Pfile, procfs_validfile }, + { DT_REG, N("mem"), Pmem, NULL }, + { DT_REG, N("regs"), Pregs, procfs_validregs }, + { DT_REG, N("fpregs"), Pfpregs, procfs_validfpregs }, + { DT_REG, N("ctl"), Pctl, NULL }, + { DT_REG, N("status"), Pstatus, NULL }, + { DT_REG, N("note"), Pnote, NULL }, + { DT_REG, N("notepg"), Pnotepg, NULL }, + { DT_REG, N("map"), Pmap, procfs_validmap }, + { DT_REG, N("etype"), Ptype, procfs_validtype }, #undef N }; -#define Nprocent (sizeof(procent)/sizeof(procent[0])) +static const int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]); static pid_t atopid __P((const char *, u_int)); @@ -117,7 +119,12 @@ static pid_t atopid __P((const char *, u_int)); */ static int procfs_open(ap) - struct vop_open_args *ap; + struct vop_open_args /* { + struct vnode *a_vp; + int a_mode; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { struct pfsnode *pfs = VTOPFS(ap->a_vp); @@ -126,11 +133,10 @@ procfs_open(ap) if (PFIND(pfs->pfs_pid) == 0) return (ENOENT); /* was ESRCH, jsp */ - if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) || - ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) + if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) || + (pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)) return (EBUSY); - if (ap->a_mode & FWRITE) pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); @@ -152,7 +158,12 @@ procfs_open(ap) */ static int procfs_close(ap) - struct vop_close_args *ap; + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { struct pfsnode *pfs = VTOPFS(ap->a_vp); @@ -174,14 +185,51 @@ procfs_close(ap) */ static int procfs_ioctl(ap) - struct vop_ioctl_args *ap; + struct vop_ioctl_args /* { + struct vnode *a_vp; + int a_command; + caddr_t a_data; + int a_fflag; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { return (ENOTTY); } /* - * _inactive is called when the pfsnode + * do block mapping for pfsnode (vp). + * since we don't use the buffer cache + * for procfs this function should never + * be called. in any case, it's not clear + * what part of the kernel ever makes use + * of this function. for sanity, this is the + * usual no-op bmap, although returning + * (EIO) would be a reasonable alternative. + */ +int +procfs_bmap(ap) + struct vop_bmap_args /* { + struct vnode *a_vp; + daddr_t a_bn; + struct vnode **a_vpp; + daddr_t *a_bnp; + int *a_runp; + } */ *ap; +{ + + if (ap->a_vpp != NULL) + *ap->a_vpp = ap->a_vp; + if (ap->a_bnp != NULL) + *ap->a_bnp = ap->a_bn; + if (ap->a_runp != NULL) + *ap->a_runp = 0; + return (0); +} + +/* + * procfs_inactive is called when the pfsnode * is vrele'd and the reference count goes * to zero. (vp) will be on the vnode free * list, so to get it back vget() must be @@ -194,16 +242,20 @@ procfs_ioctl(ap) * chances are that the process will still be * there and PFIND is not free. * - * (vp) is not locked on entry or exit. + * (vp) is locked on entry, but must be unlocked on exit. */ static int procfs_inactive(ap) - struct vop_inactive_args *ap; + struct vop_inactive_args /* { + struct vnode *a_vp; + } */ *ap; { - struct pfsnode *pfs = VTOPFS(ap->a_vp); + struct vnode *vp = ap->a_vp; + struct pfsnode *pfs = VTOPFS(vp); + VOP_UNLOCK(vp, 0, ap->a_p); if (PFIND(pfs->pfs_pid) == 0) - vgone(ap->a_vp); + vgone(vp); return (0); } @@ -217,12 +269,12 @@ procfs_inactive(ap) */ static int procfs_reclaim(ap) - struct vop_reclaim_args *ap; + struct vop_reclaim_args /* { + struct vnode *a_vp; + } */ *ap; { - int error; - error = procfs_freevp(ap->a_vp); - return (error); + return (procfs_freevp(ap->a_vp)); } /* @@ -269,13 +321,14 @@ procfs_pathconf(ap) */ static int procfs_print(ap) - struct vop_print_args *ap; + struct vop_print_args /* { + struct vnode *a_vp; + } */ *ap; { struct pfsnode *pfs = VTOPFS(ap->a_vp); - printf("tag VT_PROCFS, pid %lu, mode %x, flags %lx\n", - pfs->pfs_pid, - pfs->pfs_mode, pfs->pfs_flags); + printf("tag VT_PROCFS, type %s, pid %d, mode %x, flags %x\n", + pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags); return (0); } @@ -287,7 +340,10 @@ procfs_print(ap) */ static int procfs_abortop(ap) - struct vop_abortop_args *ap; + struct vop_abortop_args /* { + struct vnode *a_dvp; + struct componentname *a_cnp; + } */ *ap; { if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) @@ -316,7 +372,12 @@ procfs_badop() */ static int procfs_getattr(ap) - struct vop_getattr_args *ap; + struct vop_getattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { struct pfsnode *pfs = VTOPFS(ap->a_vp); struct vattr *vap = ap->a_vap; @@ -329,6 +390,7 @@ procfs_getattr(ap) */ switch (pfs->pfs_type) { case Proot: + case Pcurproc: procp = 0; break; @@ -353,6 +415,21 @@ procfs_getattr(ap) vap->va_bytes = vap->va_size = 0; /* + * Make all times be current TOD. + * It would be possible to get the process start + * time from the p_stat structure, but there's + * no "file creation" time stamp anyway, and the + * p_stat structure is not addressible if u. gets + * swapped out for that process. + */ + { + struct timeval tv; + microtime(&tv); + TIMEVAL_TO_TIMESPEC(&tv, &vap->va_ctime); + } + vap->va_atime = vap->va_mtime = vap->va_ctime; + + /* * If the process has exercised some setuid or setgid * privilege, then rip away read/write permission so * that only root can gain access. @@ -376,21 +453,6 @@ procfs_getattr(ap) } /* - * Make all times be current TOD. - * It would be possible to get the process start - * time from the p_stat structure, but there's - * no "file creation" time stamp anyway, and the - * p_stat structure is not addressible if u. gets - * swapped out for that process. - */ - { - struct timeval tv; - microtime(&tv); - TIMEVAL_TO_TIMESPEC(&tv, &vap->va_ctime); - } - vap->va_atime = vap->va_mtime = vap->va_ctime; - - /* * now do the object specific fields * * The size could be set from struct reg, but it's hardly @@ -402,17 +464,30 @@ procfs_getattr(ap) switch (pfs->pfs_type) { case Proot: - vap->va_nlink = nprocs + 3; + /* + * Set nlink to 1 to tell fts(3) we don't actually know. + */ + vap->va_nlink = 1; + vap->va_uid = 0; + vap->va_gid = 0; + vap->va_size = vap->va_bytes = DEV_BSIZE; + break; + + case Pcurproc: { + char buf[16]; /* should be enough */ + vap->va_nlink = 1; vap->va_uid = 0; vap->va_gid = 0; - vap->va_bytes = vap->va_size = DEV_BSIZE; + vap->va_size = vap->va_bytes = + sprintf(buf, "%ld", (long)curproc->p_pid); break; + } case Pproc: - vap->va_nlink = Nprocent; + vap->va_nlink = nproc_targets; vap->va_uid = procp->p_ucred->cr_uid; vap->va_gid = procp->p_ucred->cr_gid; - vap->va_bytes = vap->va_size = DEV_BSIZE; + vap->va_size = vap->va_bytes = DEV_BSIZE; break; case Pfile: @@ -436,7 +511,15 @@ procfs_getattr(ap) case Ptype: case Pmap: case Pregs: + vap->va_bytes = vap->va_size = sizeof(struct reg); + vap->va_nlink = 1; + vap->va_uid = procp->p_ucred->cr_uid; + vap->va_gid = procp->p_ucred->cr_gid; + break; + case Pfpregs: + vap->va_bytes = vap->va_size = sizeof(struct fpreg); + case Pctl: case Pstatus: case Pnote: @@ -455,7 +538,12 @@ procfs_getattr(ap) static int procfs_setattr(ap) - struct vop_setattr_args *ap; + struct vop_setattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { /* * just fake out attribute setting @@ -484,7 +572,12 @@ procfs_setattr(ap) */ static int procfs_access(ap) - struct vop_access_args *ap; + struct vop_access_args /* { + struct vnode *a_vp; + int a_mode; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; { struct vattr *vap; struct vattr vattr; @@ -494,8 +587,9 @@ procfs_access(ap) * If you're the super-user, * you always get access. */ - if (ap->a_cred->cr_uid == (uid_t) 0) + if (ap->a_cred->cr_uid == 0) return (0); + vap = &vattr; error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p); if (error) @@ -510,7 +604,7 @@ procfs_access(ap) gid_t *gp; int i; - (ap->a_mode) >>= 3; + ap->a_mode >>= 3; gp = ap->a_cred->cr_groups; for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++) if (vap->va_gid == *gp) @@ -537,18 +631,23 @@ found: */ static int procfs_lookup(ap) - struct vop_lookup_args *ap; + struct vop_lookup_args /* { + struct vnode * a_dvp; + struct vnode ** a_vpp; + struct componentname * a_cnp; + } */ *ap; { struct componentname *cnp = ap->a_cnp; struct vnode **vpp = ap->a_vpp; struct vnode *dvp = ap->a_dvp; char *pname = cnp->cn_nameptr; + struct proc *curp = cnp->cn_proc; int error = 0; + struct proc_target *pt; + struct vnode *fvp; pid_t pid; - struct vnode *nvp; struct pfsnode *pfs; - struct proc *procp; - pfstype pfs_type; + struct proc *p; int i; *vpp = NULL; @@ -559,7 +658,7 @@ procfs_lookup(ap) if (cnp->cn_namelen == 1 && *pname == '.') { *vpp = dvp; VREF(dvp); - /*VOP_LOCK(dvp);*/ + /* vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, curp); */ return (0); } @@ -570,72 +669,52 @@ procfs_lookup(ap) return (EIO); if (CNEQ(cnp, "curproc", 7)) - pid = cnp->cn_proc->p_pid; - else - pid = atopid(pname, cnp->cn_namelen); - if (pid == NO_PID) - return (ENOENT); + return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc)); - procp = PFIND(pid); - if (procp == 0) - return (ENOENT); - - error = procfs_allocvp(dvp->v_mount, &nvp, pid, Pproc); - if (error) - return (error); + pid = atopid(pname, cnp->cn_namelen); + if (pid == NO_PID) + break; - nvp->v_type = VDIR; - pfs = VTOPFS(nvp); + p = PFIND(pid); + if (p == 0) + break; - *vpp = nvp; - return (0); + return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc)); case Pproc: - if (cnp->cn_flags & ISDOTDOT) { - error = procfs_root(dvp->v_mount, vpp); - return (error); - } - - procp = PFIND(pfs->pfs_pid); - if (procp == 0) - return (ENOENT); + if (cnp->cn_flags & ISDOTDOT) + return (procfs_root(dvp->v_mount, vpp)); - for (i = 0; i < Nprocent; i++) { - struct pfsnames *dp = &procent[i]; + p = PFIND(pfs->pfs_pid); + if (p == 0) + break; - if (cnp->cn_namelen == dp->d_namlen && - bcmp(pname, dp->d_name, dp->d_namlen) == 0 && - (dp->d_valid == NULL || (*dp->d_valid)(procp))) { - pfs_type = dp->d_pfstype; + for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) { + if (cnp->cn_namelen == pt->pt_namlen && + bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && + (pt->pt_valid == NULL || (*pt->pt_valid)(p))) goto found; - } } - return (ENOENT); + break; found: - if (pfs_type == Pfile) { - nvp = procfs_findtextvp(procp); - if (nvp) { - VREF(nvp); - VOP_LOCK(nvp); - } else { - error = ENXIO; - } - } else { - error = procfs_allocvp(dvp->v_mount, &nvp, - pfs->pfs_pid, pfs_type); - if (error) - return (error); - - nvp->v_type = VREG; - pfs = VTOPFS(nvp); + if (pt->pt_pfstype == Pfile) { + fvp = procfs_findtextvp(p); + /* We already checked that it exists. */ + VREF(fvp); + vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curp); + *vpp = fvp; + return (0); } - *vpp = nvp; - return (error); + + return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, + pt->pt_pfstype)); default: return (ENOTDIR); } + + return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); } /* @@ -645,6 +724,7 @@ int procfs_validfile(p) struct proc *p; { + return (procfs_findtextvp(p) != NULLVP); } @@ -662,7 +742,14 @@ procfs_validfile(p) */ static int procfs_readdir(ap) - struct vop_readdir_args *ap; + struct vop_readdir_args /* { + struct vnode *a_vp; + struct uio *a_uio; + struct ucred *a_cred; + int *a_eofflag; + u_long *a_cookies; + int a_ncookies; + } */ *ap; { struct uio *uio = ap->a_uio; struct pfsdent d; @@ -672,6 +759,13 @@ procfs_readdir(ap) int count; int i; + /* + * We don't allow exporting procfs mounts, and currently local + * requests do not need cookies. + */ + if (ap->a_ncookies) + panic("procfs_readdir: not hungry"); + pfs = VTOPFS(ap->a_vp); if (uio->uio_resid < UIO_MX) @@ -693,39 +787,28 @@ procfs_readdir(ap) */ case Pproc: { struct proc *p; + struct proc_target *pt; p = PFIND(pfs->pfs_pid); if (p == NULL) break; - while (uio->uio_resid >= UIO_MX) { - struct pfsnames *dt; - - if (i >= Nprocent) - break; - - dt = &procent[i]; - - /* see if we should show this one. */ - if (dt->d_valid && (*dt->d_valid)(p) == 0) { - i++; + for (pt = &proc_targets[i]; + uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) { + if (pt->pt_valid && (*pt->pt_valid)(p) == 0) continue; - } dp->d_reclen = UIO_MX; - dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, dt->d_pfstype); - dp->d_type = DT_REG; - dp->d_namlen = dt->d_namlen; - bcopy(dt->d_name, dp->d_name, sizeof(dt->d_name)-1); - error = uiomove((caddr_t) dp, UIO_MX, uio); - if (error) + dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype); + dp->d_namlen = pt->pt_namlen; + bcopy(pt->pt_name, dp->d_name, pt->pt_namlen + 1); + dp->d_type = pt->pt_type; + + if (error = uiomove((caddr_t)dp, UIO_MX, uio)) break; - count += UIO_MX; - i++; } break; - } /* @@ -738,63 +821,61 @@ procfs_readdir(ap) */ case Proot: { - int pcnt; #ifdef PROCFS_ZOMBIE int doingzomb = 0; #endif + int pcnt = 0; volatile struct proc *p = allproc.lh_first; -#define PROCFS_XFILES 3 /* number of other entries, like "curproc" */ - pcnt = PROCFS_XFILES; - - while (p && uio->uio_resid >= UIO_MX) { + again: + for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) { bzero((char *) dp, UIO_MX); - dp->d_type = DT_DIR; dp->d_reclen = UIO_MX; switch (i) { - case 0: + case 0: /* `.' */ + case 1: /* `..' */ dp->d_fileno = PROCFS_FILENO(0, Proot); - dp->d_namlen = sprintf(dp->d_name, "."); - break; - - case 1: - dp->d_fileno = PROCFS_FILENO(0, Proot); - dp->d_namlen = sprintf(dp->d_name, ".."); + dp->d_namlen = i + 1; + bcopy("..", dp->d_name, dp->d_namlen); + dp->d_name[i + 1] = '\0'; + dp->d_type = DT_DIR; break; case 2: - /* ship out entry for "curproc" */ - dp->d_fileno = PROCFS_FILENO(PID_MAX+1, Pproc); - dp->d_namlen = sprintf(dp->d_name, "curproc"); + dp->d_fileno = PROCFS_FILENO(0, Pcurproc); + dp->d_namlen = 7; + bcopy("curproc", dp->d_name, 8); + dp->d_type = DT_LNK; break; default: - if (pcnt >= i) { - dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); - dp->d_namlen = sprintf(dp->d_name, "%ld", (long) p->p_pid); + while (pcnt < i) { + pcnt++; + p = p->p_list.le_next; + if (!p) + goto done; } - + dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); + dp->d_namlen = sprintf(dp->d_name, "%ld", + (long)p->p_pid); + dp->d_type = DT_REG; p = p->p_list.le_next; - -#ifdef PROCFS_ZOMBIE - if (p == 0 && doingzomb == 0) { - doingzomb = 1; - p = zombproc.lh_first; - } -#endif - - if (pcnt++ < i) - continue; - break; } - error = uiomove((caddr_t) dp, UIO_MX, uio); - if (error) + + if (error = uiomove((caddr_t)dp, UIO_MX, uio)) break; - count += UIO_MX; - i++; } + done: + +#ifdef PROCFS_ZOMBIE + if (p == 0 && doingzomb == 0) { + doingzomb = 1; + p = zombproc.lh_first; + goto again; + } +#endif break; @@ -811,6 +892,25 @@ procfs_readdir(ap) } /* + * readlink reads the link of `curproc' + */ +int +procfs_readlink(ap) + struct vop_readlink_args *ap; +{ + struct uio *uio = ap->a_uio; + char buf[16]; /* should be enough */ + int len; + + if (VTOPFS(ap->a_vp)->pfs_fileno != PROCFS_FILENO(0, Pcurproc)) + return (EINVAL); + + len = sprintf(buf, "%ld", (long)curproc->p_pid); + + return (uiomove((caddr_t)buf, len, ap->a_uio)); +} + +/* * convert decimal ascii to pid_t */ static pid_t @@ -838,6 +938,7 @@ atopid(b, len) #define procfs_write procfs_rw #define procfs_select ((int (*) __P((struct vop_select_args *))) procfs_badop) #define procfs_mmap ((int (*) __P((struct vop_mmap_args *))) procfs_badop) +#define procfs_revoke vop_revoke #define procfs_fsync ((int (*) __P((struct vop_fsync_args *))) procfs_badop) #define procfs_seek ((int (*) __P((struct vop_seek_args *))) procfs_badop) #define procfs_remove ((int (*) __P((struct vop_remove_args *))) procfs_badop) @@ -849,7 +950,6 @@ atopid(b, len) #define procfs_readlink ((int (*) __P((struct vop_readlink_args *))) procfs_badop) #define procfs_lock ((int (*) __P((struct vop_lock_args *))) nullop) #define procfs_unlock ((int (*) __P((struct vop_unlock_args *))) nullop) -#define procfs_bmap ((int (*) __P((struct vop_bmap_args *))) procfs_badop) #define procfs_strategy ((int (*) __P((struct vop_strategy_args *))) procfs_badop) #define procfs_islocked ((int (*) __P((struct vop_islocked_args *))) nullop) #define procfs_advlock ((int (*) __P((struct vop_advlock_args *))) procfs_badop) @@ -859,6 +959,9 @@ atopid(b, len) #define procfs_truncate ((int (*) __P((struct vop_truncate_args *))) procfs_badop) #define procfs_update ((int (*) __P((struct vop_update_args *))) nullop) +/* + * procfs vnode operations. + */ vop_t **procfs_vnodeop_p; static struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { { &vop_default_desc, (vop_t *)vn_default_error }, @@ -875,6 +978,7 @@ static struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { { &vop_ioctl_desc, (vop_t *)procfs_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)procfs_select }, /* select */ { &vop_mmap_desc, (vop_t *)procfs_mmap }, /* mmap */ + { &vop_revoke_desc, (vop_t *)procfs_revoke }, /* revoke */ { &vop_fsync_desc, (vop_t *)procfs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)procfs_seek }, /* seek */ { &vop_remove_desc, (vop_t *)procfs_remove }, /* remove */ diff --git a/sys/miscfs/specfs/spec_vnops.c b/sys/miscfs/specfs/spec_vnops.c index 049f41e..2e8cc04 100644 --- a/sys/miscfs/specfs/spec_vnops.c +++ b/sys/miscfs/specfs/spec_vnops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1993 + * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)spec_vnops.c 8.6 (Berkeley) 4/9/94 + * @(#)spec_vnops.c 8.14 (Berkeley) 5/21/95 * $FreeBSD$ */ @@ -79,8 +79,10 @@ static struct vnodeopv_entry_desc spec_vnodeop_entries[] = { { &vop_setattr_desc, (vop_t *)spec_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)spec_read }, /* read */ { &vop_write_desc, (vop_t *)spec_write }, /* write */ + { &vop_lease_desc, (vop_t *)spec_lease_check }, /* lease */ { &vop_ioctl_desc, (vop_t *)spec_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)spec_select }, /* select */ + { &vop_revoke_desc, (vop_t *)spec_revoke }, /* revoke */ { &vop_mmap_desc, (vop_t *)spec_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)spec_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)spec_seek }, /* seek */ @@ -148,9 +150,10 @@ spec_open(ap) struct proc *a_p; } */ *ap; { + struct proc *p = ap->a_p; struct vnode *bvp, *vp = ap->a_vp; dev_t bdev, dev = (dev_t)vp->v_rdev; - register int maj = major(dev); + int maj = major(dev); int error; /* @@ -171,7 +174,9 @@ spec_open(ap) * When running in very secure mode, do not allow * opens for writing of any disk character devices. */ - if (securelevel >= 2 && isdisk(dev, VCHR)) + if (securelevel >= 2 + && cdevsw[maj]->d_bdev + && cdevsw[maj]->d_bdev->d_flags == D_DISK) return (EPERM); /* * When running in secure mode, do not allow opens @@ -189,9 +194,20 @@ spec_open(ap) return (EPERM); } } - VOP_UNLOCK(vp); - error = (*cdevsw[maj]->d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p); - VOP_LOCK(vp); +#if 0 + /* + * Lite2 stuff. We will almost certainly do this + * differently with devfs. The only use of this flag + * is in dead_read to make ttys return EOF instead of + * EIO when they are dead. Pre-lite2 FreeBSD returns + * EOF for all character devices. + */ + if (cdevsw[maj]->d_type == D_TTY) + vp->v_flag |= VISTTY; +#endif + VOP_UNLOCK(vp, 0, p); + error = (*cdevsw[maj]->d_open)(dev, ap->a_mode, S_IFCHR, p); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); return (error); case VBLK: @@ -204,7 +220,7 @@ spec_open(ap) * opens for writing of any disk block devices. */ if (securelevel >= 2 && ap->a_cred != FSCRED && - (ap->a_mode & FWRITE) && isdisk(dev, VBLK)) + (ap->a_mode & FWRITE) && bdevsw[maj]->d_flags == D_DISK) return (EPERM); /* * Do not allow opens of block devices that are @@ -213,9 +229,7 @@ spec_open(ap) error = vfs_mountedon(vp); if (error) return (error); - return ((*bdevsw[maj]->d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p)); - default: - break; + return ((*bdevsw[maj]->d_open)(dev, ap->a_mode, S_IFBLK, p)); } return (0); } @@ -257,10 +271,10 @@ spec_read(ap) switch (vp->v_type) { case VCHR: - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); error = (*cdevsw[major(vp->v_rdev)]->d_read) (vp->v_rdev, uio, ap->a_ioflag); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); return (error); case VBLK: @@ -335,10 +349,10 @@ spec_write(ap) switch (vp->v_type) { case VCHR: - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); error = (*cdevsw[major(vp->v_rdev)]->d_write) (vp->v_rdev, uio, ap->a_ioflag); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); return (error); case VBLK: @@ -408,7 +422,7 @@ spec_ioctl(ap) case VBLK: if (ap->a_command == 0 && (int)ap->a_data == B_TAPE) - if (bdevsw[major(dev)]->d_flags & B_TAPE) + if (bdevsw[major(dev)]->d_flags == D_TAPE) return (0); else return (1); @@ -498,6 +512,18 @@ loop: return (0); } +int +spec_inactive(ap) + struct vop_inactive_args /* { + struct vnode *a_vp; + struct proc *a_p; + } */ *ap; +{ + + VOP_UNLOCK(ap->a_vp, 0, ap->a_p); + return (0); +} + /* * Just call the device strategy routine */ @@ -539,31 +565,6 @@ spec_bmap(ap) } /* - * At the moment we do not do any locking. - */ -/* ARGSUSED */ -int -spec_lock(ap) - struct vop_lock_args /* { - struct vnode *a_vp; - } */ *ap; -{ - - return (0); -} - -/* ARGSUSED */ -int -spec_unlock(ap) - struct vop_unlock_args /* { - struct vnode *a_vp; - } */ *ap; -{ - - return (0); -} - -/* * Device close routine */ /* ARGSUSED */ @@ -577,6 +578,7 @@ spec_close(ap) } */ *ap; { register struct vnode *vp = ap->a_vp; + struct proc *p = ap->a_p; dev_t dev = vp->v_rdev; d_close_t *devclose; int mode, error; @@ -631,8 +633,11 @@ spec_close(ap) (vp->v_flag & VXLOCK) == 0) return (0); - if (vp->v_object) - vnode_pager_uncache(vp); + if (vp->v_object) { + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + vnode_pager_uncache(vp, p); + VOP_UNLOCK(vp, 0, p); + } devclose = bdevsw[major(dev)]->d_close; mode = S_IFBLK; diff --git a/sys/miscfs/specfs/specdev.h b/sys/miscfs/specfs/specdev.h index 8960040..091d628 100644 --- a/sys/miscfs/specfs/specdev.h +++ b/sys/miscfs/specfs/specdev.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)specdev.h 8.2 (Berkeley) 2/2/94 + * @(#)specdev.h 8.6 (Berkeley) 5/21/95 * $FreeBSD$ */ @@ -91,8 +91,10 @@ int spec_close __P((struct vop_close_args *)); #define spec_setattr ((int (*) __P((struct vop_setattr_args *)))spec_ebadf) int spec_read __P((struct vop_read_args *)); int spec_write __P((struct vop_write_args *)); +#define spec_lease_check ((int (*) __P((struct vop_lease_args *)))nullop) int spec_ioctl __P((struct vop_ioctl_args *)); int spec_select __P((struct vop_select_args *)); +#define spec_revoke vop_revoke #define spec_mmap ((int (*) __P((struct vop_mmap_args *)))spec_badop) int spec_fsync __P((struct vop_fsync_args *)); #define spec_seek ((int (*) __P((struct vop_seek_args *)))spec_badop) @@ -105,14 +107,14 @@ int spec_fsync __P((struct vop_fsync_args *)); #define spec_readdir ((int (*) __P((struct vop_readdir_args *)))spec_badop) #define spec_readlink ((int (*) __P((struct vop_readlink_args *)))spec_badop) #define spec_abortop ((int (*) __P((struct vop_abortop_args *)))spec_badop) -#define spec_inactive ((int (*) __P((struct vop_inactive_args *)))nullop) +int spec_inactive __P((struct vop_inactive_args *)); #define spec_reclaim ((int (*) __P((struct vop_reclaim_args *)))nullop) -int spec_lock __P((struct vop_lock_args *)); -int spec_unlock __P((struct vop_unlock_args *)); +#define spec_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock) +#define spec_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock) int spec_bmap __P((struct vop_bmap_args *)); int spec_strategy __P((struct vop_strategy_args *)); int spec_print __P((struct vop_print_args *)); -#define spec_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) +#define spec_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked) int spec_pathconf __P((struct vop_pathconf_args *)); int spec_advlock __P((struct vop_advlock_args *)); int spec_getpages __P((struct vop_getpages_args *)); diff --git a/sys/miscfs/umapfs/umap.h b/sys/miscfs/umapfs/umap.h index db1efd4..54ae097 100644 --- a/sys/miscfs/umapfs/umap.h +++ b/sys/miscfs/umapfs/umap.h @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)umap.h 8.3 (Berkeley) 1/21/94 + * @(#)umap.h 8.4 (Berkeley) 8/20/94 * * $FreeBSD$ */ @@ -67,8 +67,7 @@ struct umap_mount { * A cache of vnode references */ struct umap_node { - struct umap_node *umap_forw; /* Hash chain */ - struct umap_node *umap_back; + LIST_ENTRY(umap_node) umap_hash; /* Hash list */ struct vnode *umap_lowervp; /* Aliased vnode - VREFed once */ struct vnode *umap_vnode; /* Back pointer to vnode/umap_node */ }; diff --git a/sys/miscfs/umapfs/umap_subr.c b/sys/miscfs/umapfs/umap_subr.c index 8333943..3b3629d 100644 --- a/sys/miscfs/umapfs/umap_subr.c +++ b/sys/miscfs/umapfs/umap_subr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1992, 1993 + * Copyright (c) 1992, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software donated to Berkeley by @@ -33,13 +33,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)umap_subr.c 8.6 (Berkeley) 1/26/94 + * @(#)umap_subr.c 8.9 (Berkeley) 5/14/95 * * $FreeBSD$ */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/proc.h> #include <sys/time.h> #include <sys/types.h> #include <sys/vnode.h> @@ -48,11 +49,8 @@ #include <sys/malloc.h> #include <miscfs/umapfs/umap.h> -extern int umapfs_init __P((void)); - #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ #define NUMAPNODECACHE 16 -#define UMAP_NHASH(vp) ((((u_long) vp)>>LOG2_SIZEVNODE) & (NUMAPNODECACHE-1)) /* * Null layer cache: @@ -62,52 +60,33 @@ extern int umapfs_init __P((void)); * alias is removed the target vnode is vrele'd. */ -/* - * Cache head - */ -struct umap_node_cache { - struct umap_node *ac_forw; - struct umap_node *ac_back; -}; - -static struct umap_node_cache umap_node_cache[NUMAPNODECACHE]; +#define UMAP_NHASH(vp) \ + (&umap_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & umap_node_hash]) +LIST_HEAD(umap_node_hashhead, umap_node) *umap_node_hashtbl; +u_long umap_node_hash; static u_long umap_findid __P((u_long id, u_long map[][2], int nentries)); static int umap_node_alloc __P((struct mount *mp, struct vnode *lowervp, struct vnode **vpp)); static struct vnode * umap_node_find __P((struct mount *mp, struct vnode *targetvp)); -static struct umap_node_cache * - umap_node_hash __P((struct vnode *targetvp)); /* * Initialise cache headers */ int -umapfs_init() +umapfs_init(vfsp) + struct vfsconf *vfsp; { - struct umap_node_cache *ac; + #ifdef UMAPFS_DIAGNOSTIC printf("umapfs_init\n"); /* printed during system boot */ #endif - - for (ac = umap_node_cache; ac < umap_node_cache + NUMAPNODECACHE; ac++) - ac->ac_forw = ac->ac_back = (struct umap_node *) ac; + umap_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, &umap_node_hash); return (0); } /* - * Compute hash list for given target vnode - */ -static struct umap_node_cache * -umap_node_hash(targetvp) - struct vnode *targetvp; -{ - - return (&umap_node_cache[UMAP_NHASH(targetvp)]); -} - -/* * umap_findid is called by various routines in umap_vnodeops.c to * find a user or group id in a map. */ @@ -163,7 +142,8 @@ umap_node_find(mp, targetvp) struct mount *mp; struct vnode *targetvp; { - struct umap_node_cache *hd; + struct proc *p = curproc; /* XXX */ + struct umap_node_hashhead *hd; struct umap_node *a; struct vnode *vp; @@ -177,10 +157,9 @@ umap_node_find(mp, targetvp) * the target vnode. If found, the increment the umap_node * reference count (but NOT the target vnode's VREF counter). */ - hd = umap_node_hash(targetvp); - - loop: - for (a = hd->ac_forw; a != (struct umap_node *) hd; a = a->umap_forw) { + hd = UMAP_NHASH(targetvp); +loop: + for (a = hd->lh_first; a != 0; a = a->umap_hash.le_next) { if (a->umap_lowervp == targetvp && a->umap_vnode->v_mount == mp) { vp = UMAPTOV(a); @@ -189,7 +168,7 @@ umap_node_find(mp, targetvp) * stuff, but we don't want to lock * the lower node. */ - if (vget(vp, 0)) { + if (vget(vp, 0, p)) { #ifdef UMAPFS_DIAGNOSTIC printf ("umap_node_find: vget failed.\n"); #endif @@ -217,7 +196,7 @@ umap_node_alloc(mp, lowervp, vpp) struct vnode *lowervp; struct vnode **vpp; { - struct umap_node_cache *hd; + struct umap_node_hashhead *hd; struct umap_node *xp; struct vnode *othervp, *vp; int error; @@ -257,8 +236,8 @@ umap_node_alloc(mp, lowervp, vpp) return (0); } VREF(lowervp); /* Extra VREF will be vrele'd in umap_node_create */ - hd = umap_node_hash(lowervp); - insque(xp, hd); + hd = UMAP_NHASH(lowervp); + LIST_INSERT_HEAD(hd, xp, umap_hash); return (0); } diff --git a/sys/miscfs/umapfs/umap_vfsops.c b/sys/miscfs/umapfs/umap_vfsops.c index 517c291..897e2ce 100644 --- a/sys/miscfs/umapfs/umap_vfsops.c +++ b/sys/miscfs/umapfs/umap_vfsops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1992, 1993 + * Copyright (c) 1992, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software donated to Berkeley by @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)umap_vfsops.c 8.3 (Berkeley) 1/21/94 + * @(#)umap_vfsops.c 8.8 (Berkeley) 5/14/95 * * $FreeBSD$ */ @@ -46,6 +46,7 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/proc.h> #include <sys/time.h> #include <sys/types.h> #include <sys/vnode.h> @@ -54,7 +55,7 @@ #include <sys/malloc.h> #include <miscfs/umapfs/umap.h> -extern int umapfs_init __P((void)); +extern int umapfs_init __P((struct vfsconf *)); static int umapfs_fhtovp __P((struct mount *mp, struct fid *fidp, struct mbuf *nam, struct vnode **vpp, @@ -187,7 +188,7 @@ umapfs_mount(mp, path, data, ndp, p) /* * Unlock the node (either the lower or the alias) */ - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); /* * Make sure the node alias worked */ @@ -207,7 +208,7 @@ umapfs_mount(mp, path, data, ndp, p) if (UMAPVPTOLOWERVP(umapm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) mp->mnt_flag |= MNT_LOCAL; mp->mnt_data = (qaddr_t) amp; - getnewfsid(mp, MOUNT_LOFS); + vfs_getnewfsid(mp); (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); @@ -253,12 +254,8 @@ umapfs_unmount(mp, mntflags, p) printf("umapfs_unmount(mp = %x)\n", mp); #endif - if (mntflags & MNT_FORCE) { - /* lofs can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } /* * Clear out buffer cache. I don't think we @@ -300,6 +297,7 @@ umapfs_root(mp, vpp) struct mount *mp; struct vnode **vpp; { + struct proc *p = curproc; /* XXX */ struct vnode *vp; #ifdef UMAPFS_DIAGNOSTIC @@ -314,7 +312,7 @@ umapfs_root(mp, vpp) */ vp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp; VREF(vp); - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); *vpp = vp; return (0); } @@ -429,4 +427,3 @@ static struct vfsops umap_vfsops = { }; VFS_SET(umap_vfsops, umap, MOUNT_UMAP, VFCF_LOOPBACK); - diff --git a/sys/miscfs/umapfs/umap_vnops.c b/sys/miscfs/umapfs/umap_vnops.c index 7c14cda..17064f4 100644 --- a/sys/miscfs/umapfs/umap_vnops.c +++ b/sys/miscfs/umapfs/umap_vnops.c @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)umap_vnops.c 8.3 (Berkeley) 1/5/94 + * @(#)umap_vnops.c 8.6 (Berkeley) 5/22/95 * $FreeBSD$ */ @@ -336,10 +336,52 @@ umap_getattr(ap) return (0); } +/* + * We need to process our own vnode lock and then clear the + * interlock flag as it applies only to our vnode, not the + * vnodes below us on the stack. + */ +int +umap_lock(ap) + struct vop_lock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; +{ + + vop_nolock(ap); + if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN) + return (0); + ap->a_flags &= ~LK_INTERLOCK; + return (null_bypass(ap)); +} + +/* + * We need to process our own vnode unlock and then clear the + * interlock flag as it applies only to our vnode, not the + * vnodes below us on the stack. + */ +int +umap_unlock(ap) + struct vop_unlock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + vop_nounlock(ap); + ap->a_flags &= ~LK_INTERLOCK; + return (null_bypass(ap)); +} + static int umap_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { /* @@ -349,6 +391,7 @@ umap_inactive(ap) * cache and reusable. * */ + VOP_UNLOCK(ap->a_vp, 0, ap->a_p); return (0); } @@ -364,7 +407,7 @@ umap_reclaim(ap) /* After this assignment, this node will not be re-used. */ xp->umap_lowervp = NULL; - remque(xp); + LIST_REMOVE(xp, umap_hash); FREE(vp->v_data, M_TEMP); vp->v_data = NULL; vrele(lowervp); @@ -487,6 +530,8 @@ static struct vnodeopv_entry_desc umap_vnodeop_entries[] = { { &vop_default_desc, (vop_t *)umap_bypass }, { &vop_getattr_desc, (vop_t *)umap_getattr }, + { &vop_lock_desc, (vop_t *)umap_lock }, + { &vop_unlock_desc, (vop_t *)umap_unlock }, { &vop_inactive_desc, (vop_t *)umap_inactive }, { &vop_reclaim_desc, (vop_t *)umap_reclaim }, { &vop_print_desc, (vop_t *)umap_print }, diff --git a/sys/miscfs/union/union.h b/sys/miscfs/union/union.h index 9c740d3..c956921 100644 --- a/sys/miscfs/union/union.h +++ b/sys/miscfs/union/union.h @@ -34,7 +34,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)union.h 8.2 (Berkeley) 2/17/94 + * @(#)union.h 8.9 (Berkeley) 12/10/94 * $FreeBSD$ */ @@ -75,10 +75,14 @@ struct union_node { struct vnode *un_uppervp; /* overlaying object */ struct vnode *un_lowervp; /* underlying object */ struct vnode *un_dirvp; /* Parent dir of uppervp */ + struct vnode *un_pvp; /* Parent vnode */ char *un_path; /* saved component name */ int un_hash; /* saved un_path hash value */ int un_openl; /* # of opens on lowervp */ - int un_flags; + unsigned int un_flags; + struct vnode **un_dircache; /* cached union stack */ + off_t un_uppersz; /* size of upper object */ + off_t un_lowersz; /* size of lower object */ #ifdef DIAGNOSTIC pid_t un_pid; #endif @@ -88,16 +92,23 @@ struct union_node { #define UN_LOCKED 0x02 #define UN_ULOCK 0x04 /* Upper node is locked */ #define UN_KLOCK 0x08 /* Keep upper node locked on vput */ +#define UN_CACHED 0x10 /* In union cache */ extern int union_allocvp __P((struct vnode **, struct mount *, struct vnode *, struct vnode *, struct componentname *, struct vnode *, - struct vnode *)); + struct vnode *, int)); extern int union_freevp __P((struct vnode *)); -extern int union_copyfile __P((struct proc *, struct ucred *, - struct vnode *, struct vnode *)); +extern int union_copyfile __P((struct vnode *, struct vnode *, + struct ucred *, struct proc *)); +extern int union_copyup __P((struct union_node *, int, struct ucred *, + struct proc *)); +extern int union_dowhiteout __P((struct union_node *, struct ucred *, + struct proc *)); extern int union_mkshadow __P((struct union_mount *, struct vnode *, struct componentname *, struct vnode **)); +extern int union_mkwhiteout __P((struct union_mount *, struct vnode *, + struct componentname *, char *)); extern int union_vn_create __P((struct vnode **, struct union_node *, struct proc *)); extern int union_vn_close __P((struct vnode *, int, struct ucred *, @@ -108,6 +119,7 @@ extern void union_removed_upper __P((struct union_node *un)); extern struct vnode *union_lowervp __P((struct vnode *)); extern void union_newlower __P((struct union_node *, struct vnode *)); extern void union_newupper __P((struct union_node *, struct vnode *)); +extern void union_newsize __P((struct vnode *, off_t, off_t)); #define MOUNTTOUNIONMOUNT(mp) ((struct union_mount *)((mp)->mnt_data)) #define VTOUNION(vp) ((struct union_node *)(vp)->v_data) diff --git a/sys/miscfs/union/union_subr.c b/sys/miscfs/union/union_subr.c index 6549f7d..63e25e6 100644 --- a/sys/miscfs/union/union_subr.c +++ b/sys/miscfs/union/union_subr.c @@ -34,7 +34,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)union_subr.c 8.4 (Berkeley) 2/17/94 + * @(#)union_subr.c 8.20 (Berkeley) 5/20/95 * $FreeBSD$ */ @@ -48,6 +48,9 @@ #include <sys/file.h> #include <sys/filedesc.h> #include <sys/queue.h> +#include <sys/mount.h> +#include <sys/stat.h> +#include <vm/vm.h> /* for vnode_pager_setsize */ #include <miscfs/union/union.h> #include <sys/proc.h> @@ -118,31 +121,38 @@ union_updatevp(un, uppervp, lowervp) { int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp); int nhash = UNION_HASH(uppervp, lowervp); + int docache = (lowervp != NULLVP || uppervp != NULLVP); + int lhash, hhash, uhash; - if (ohash != nhash) { - /* - * Ensure locking is ordered from lower to higher - * to avoid deadlocks. - */ - if (nhash < ohash) { - int t = ohash; - ohash = nhash; - nhash = t; - } + /* + * Ensure locking is ordered from lower to higher + * to avoid deadlocks. + */ + if (nhash < ohash) { + lhash = nhash; + uhash = ohash; + } else { + lhash = ohash; + uhash = nhash; + } - while (union_list_lock(ohash)) + if (lhash != uhash) + while (union_list_lock(lhash)) continue; - while (union_list_lock(nhash)) - continue; + while (union_list_lock(uhash)) + continue; - LIST_REMOVE(un, un_cache); - union_list_unlock(ohash); - } else { - while (union_list_lock(nhash)) - continue; + if (ohash != nhash || !docache) { + if (un->un_flags & UN_CACHED) { + un->un_flags &= ~UN_CACHED; + LIST_REMOVE(un, un_cache); + } } + if (ohash != nhash) + union_list_unlock(ohash); + if (un->un_lowervp != lowervp) { if (un->un_lowervp) { vrele(un->un_lowervp); @@ -156,6 +166,7 @@ union_updatevp(un, uppervp, lowervp) } } un->un_lowervp = lowervp; + un->un_lowersz = VNOVAL; } if (un->un_uppervp != uppervp) { @@ -163,10 +174,13 @@ union_updatevp(un, uppervp, lowervp) vrele(un->un_uppervp); un->un_uppervp = uppervp; + un->un_uppersz = VNOVAL; } - if (ohash != nhash) + if (docache && (ohash != nhash)) { LIST_INSERT_HEAD(&unhead[nhash], un, un_cache); + un->un_flags |= UN_CACHED; + } union_list_unlock(nhash); } @@ -190,6 +204,47 @@ union_newupper(un, uppervp) } /* + * Keep track of size changes in the underlying vnodes. + * If the size changes, then callback to the vm layer + * giving priority to the upper layer size. + */ +void +union_newsize(vp, uppersz, lowersz) + struct vnode *vp; + off_t uppersz, lowersz; +{ + struct union_node *un; + off_t sz; + + /* only interested in regular files */ + if (vp->v_type != VREG) + return; + + un = VTOUNION(vp); + sz = VNOVAL; + + if ((uppersz != VNOVAL) && (un->un_uppersz != uppersz)) { + un->un_uppersz = uppersz; + if (sz == VNOVAL) + sz = un->un_uppersz; + } + + if ((lowersz != VNOVAL) && (un->un_lowersz != lowersz)) { + un->un_lowersz = lowersz; + if (sz == VNOVAL) + sz = un->un_lowersz; + } + + if (sz != VNOVAL) { +#ifdef UNION_DIAGNOSTIC + printf("union: %s size now %ld\n", + uppersz != VNOVAL ? "upper" : "lower", (long) sz); +#endif + vnode_pager_setsize(vp, sz); + } +} + +/* * allocate a union_node/vnode pair. the vnode is * referenced and locked. the new vnode is returned * via (vpp). (mp) is the mountpoint of the union filesystem, @@ -221,19 +276,22 @@ union_newupper(un, uppervp) * the vnode free list. */ int -union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp) +union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp, docache) struct vnode **vpp; struct mount *mp; - struct vnode *undvp; + struct vnode *undvp; /* parent union vnode */ struct vnode *dvp; /* may be null */ struct componentname *cnp; /* may be null */ struct vnode *uppervp; /* may be null */ struct vnode *lowervp; /* may be null */ + int docache; { int error; struct union_node *un = 0; struct vnode *xlowervp = NULLVP; - int hash = 0; + struct union_mount *um = MOUNTTOUNIONMOUNT(mp); + int hash; + int vflag; int try; if (uppervp == NULLVP && lowervp == NULLVP) @@ -244,8 +302,22 @@ union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp) lowervp = NULLVP; } + /* detect the root vnode (and aliases) */ + vflag = 0; + if ((uppervp == um->um_uppervp) && + ((lowervp == NULLVP) || lowervp == um->um_lowervp)) { + if (lowervp == NULLVP) { + lowervp = um->um_lowervp; + if (lowervp != NULLVP) + VREF(lowervp); + } + vflag = VROOT; + } + loop: - for (try = 0; try < 3; try++) { + if (!docache) { + un = 0; + } else for (try = 0; try < 3; try++) { switch (try) { case 0: if (lowervp == NULLVP) @@ -276,7 +348,8 @@ loop: (un->un_uppervp == uppervp || un->un_uppervp == NULLVP) && (UNIONTOV(un)->v_mount == mp)) { - if (vget(UNIONTOV(un), 0)) { + if (vget(UNIONTOV(un), 0, + cnp ? cnp->cn_proc : NULL)) { union_list_unlock(hash); goto loop; } @@ -359,8 +432,7 @@ loop: */ if (lowervp != un->un_lowervp) { union_newlower(un, lowervp); - if (cnp && (lowervp != NULLVP) && - (lowervp->v_type == VREG)) { + if (cnp && (lowervp != NULLVP)) { un->un_hash = cnp->cn_hash; un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); @@ -377,14 +449,16 @@ loop: return (0); } - /* - * otherwise lock the vp list while we call getnewvnode - * since that can block. - */ - hash = UNION_HASH(uppervp, lowervp); + if (docache) { + /* + * otherwise lock the vp list while we call getnewvnode + * since that can block. + */ + hash = UNION_HASH(uppervp, lowervp); - if (union_list_lock(hash)) - goto loop; + if (union_list_lock(hash)) + goto loop; + } error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp); if (error) { @@ -403,6 +477,7 @@ loop: MALLOC((*vpp)->v_data, void *, sizeof(struct union_node), M_TEMP, M_WAITOK); + (*vpp)->v_flag |= vflag; if (uppervp) (*vpp)->v_type = uppervp->v_type; else @@ -410,7 +485,13 @@ loop: un = VTOUNION(*vpp); un->un_vnode = *vpp; un->un_uppervp = uppervp; + un->un_uppersz = VNOVAL; un->un_lowervp = lowervp; + un->un_lowersz = VNOVAL; + un->un_pvp = undvp; + if (undvp != NULLVP) + VREF(undvp); + un->un_dircache = 0; un->un_openl = 0; un->un_flags = UN_LOCKED; if (un->un_uppervp) @@ -421,7 +502,7 @@ loop: else un->un_pid = -1; #endif - if (cnp && (lowervp != NULLVP) && (lowervp->v_type == VREG)) { + if (cnp && (lowervp != NULLVP)) { un->un_hash = cnp->cn_hash; un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); @@ -434,13 +515,17 @@ loop: un->un_dirvp = 0; } - LIST_INSERT_HEAD(&unhead[hash], un, un_cache); + if (docache) { + LIST_INSERT_HEAD(&unhead[hash], un, un_cache); + un->un_flags |= UN_CACHED; + } if (xlowervp) vrele(xlowervp); out: - union_list_unlock(hash); + if (docache) + union_list_unlock(hash); return (error); } @@ -451,13 +536,18 @@ union_freevp(vp) { struct union_node *un = VTOUNION(vp); - LIST_REMOVE(un, un_cache); + if (un->un_flags & UN_CACHED) { + un->un_flags &= ~UN_CACHED; + LIST_REMOVE(un, un_cache); + } - if (un->un_uppervp) + if (un->un_pvp != NULLVP) + vrele(un->un_pvp); + if (un->un_uppervp != NULLVP) vrele(un->un_uppervp); - if (un->un_lowervp) + if (un->un_lowervp != NULLVP) vrele(un->un_lowervp); - if (un->un_dirvp) + if (un->un_dirvp != NULLVP) vrele(un->un_dirvp); if (un->un_path) free(un->un_path, M_TEMP); @@ -474,11 +564,11 @@ union_freevp(vp) * and (tvp) are locked on entry and exit. */ int -union_copyfile(p, cred, fvp, tvp) - struct proc *p; - struct ucred *cred; +union_copyfile(fvp, tvp, cred, p) struct vnode *fvp; struct vnode *tvp; + struct ucred *cred; + struct proc *p; { char *buf; struct uio uio; @@ -497,12 +587,12 @@ union_copyfile(p, cred, fvp, tvp) uio.uio_segflg = UIO_SYSSPACE; uio.uio_offset = 0; - VOP_UNLOCK(fvp); /* XXX */ - LEASE_CHECK(fvp, p, cred, LEASE_READ); - VOP_LOCK(fvp); /* XXX */ - VOP_UNLOCK(tvp); /* XXX */ - LEASE_CHECK(tvp, p, cred, LEASE_WRITE); - VOP_LOCK(tvp); /* XXX */ + VOP_UNLOCK(fvp, 0, p); /* XXX */ + VOP_LEASE(fvp, p, cred, LEASE_READ); + vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ + VOP_UNLOCK(tvp, 0, p); /* XXX */ + VOP_LEASE(tvp, p, cred, LEASE_WRITE); + vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK); @@ -542,6 +632,123 @@ union_copyfile(p, cred, fvp, tvp) } /* + * (un) is assumed to be locked on entry and remains + * locked on exit. + */ +int +union_copyup(un, docopy, cred, p) + struct union_node *un; + int docopy; + struct ucred *cred; + struct proc *p; +{ + int error; + struct vnode *lvp, *uvp; + + error = union_vn_create(&uvp, un, p); + if (error) + return (error); + + /* at this point, uppervp is locked */ + union_newupper(un, uvp); + un->un_flags |= UN_ULOCK; + + lvp = un->un_lowervp; + + if (docopy) { + /* + * XX - should not ignore errors + * from VOP_CLOSE + */ + vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, p); + error = VOP_OPEN(lvp, FREAD, cred, p); + if (error == 0) { + error = union_copyfile(lvp, uvp, cred, p); + VOP_UNLOCK(lvp, 0, p); + (void) VOP_CLOSE(lvp, FREAD, cred, p); + } +#ifdef UNION_DIAGNOSTIC + if (error == 0) + uprintf("union: copied up %s\n", un->un_path); +#endif + + } + un->un_flags &= ~UN_ULOCK; + VOP_UNLOCK(uvp, 0, p); + union_vn_close(uvp, FWRITE, cred, p); + vn_lock(uvp, LK_EXCLUSIVE | LK_RETRY, p); + un->un_flags |= UN_ULOCK; + + /* + * Subsequent IOs will go to the top layer, so + * call close on the lower vnode and open on the + * upper vnode to ensure that the filesystem keeps + * its references counts right. This doesn't do + * the right thing with (cred) and (FREAD) though. + * Ignoring error returns is not right, either. + */ + if (error == 0) { + int i; + + for (i = 0; i < un->un_openl; i++) { + (void) VOP_CLOSE(lvp, FREAD, cred, p); + (void) VOP_OPEN(uvp, FREAD, cred, p); + } + un->un_openl = 0; + } + + return (error); + +} + +static int +union_relookup(um, dvp, vpp, cnp, cn, path, pathlen) + struct union_mount *um; + struct vnode *dvp; + struct vnode **vpp; + struct componentname *cnp; + struct componentname *cn; + char *path; + int pathlen; +{ + int error; + + /* + * A new componentname structure must be faked up because + * there is no way to know where the upper level cnp came + * from or what it is being used for. This must duplicate + * some of the work done by NDINIT, some of the work done + * by namei, some of the work done by lookup and some of + * the work done by VOP_LOOKUP when given a CREATE flag. + * Conclusion: Horrible. + * + * The pathname buffer will be FREEed by VOP_MKDIR. + */ + cn->cn_namelen = pathlen; + cn->cn_pnbuf = malloc(cn->cn_namelen+1, M_NAMEI, M_WAITOK); + bcopy(path, cn->cn_pnbuf, cn->cn_namelen); + cn->cn_pnbuf[cn->cn_namelen] = '\0'; + + cn->cn_nameiop = CREATE; + cn->cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN); + cn->cn_proc = cnp->cn_proc; + if (um->um_op == UNMNT_ABOVE) + cn->cn_cred = cnp->cn_cred; + else + cn->cn_cred = um->um_cred; + cn->cn_nameptr = cn->cn_pnbuf; + cn->cn_hash = cnp->cn_hash; + cn->cn_consume = cnp->cn_consume; + + VREF(dvp); + error = relookup(dvp, vpp, cn); + if (!error) + vrele(dvp); + + return (error); +} + +/* * Create a shadow directory in the upper layer. * The new vnode is returned locked. * @@ -565,6 +772,19 @@ union_mkshadow(um, dvp, cnp, vpp) struct proc *p = cnp->cn_proc; struct componentname cn; + error = union_relookup(um, dvp, vpp, cnp, &cn, + cnp->cn_nameptr, cnp->cn_namelen); + if (error) + return (error); + + if (*vpp) { + VOP_ABORTOP(dvp, &cn); + VOP_UNLOCK(dvp, 0, p); + vrele(*vpp); + *vpp = NULLVP; + return (EEXIST); + } + /* * policy: when creating the shadow directory in the * upper layer, create it owned by the user who did @@ -573,55 +793,62 @@ union_mkshadow(um, dvp, cnp, vpp) * mkdir syscall). (jsp, kb) */ - /* - * A new componentname structure must be faked up because - * there is no way to know where the upper level cnp came - * from or what it is being used for. This must duplicate - * some of the work done by NDINIT, some of the work done - * by namei, some of the work done by lookup and some of - * the work done by VOP_LOOKUP when given a CREATE flag. - * Conclusion: Horrible. - * - * The pathname buffer will be FREEed by VOP_MKDIR. - */ - cn.cn_pnbuf = malloc(cnp->cn_namelen+1, M_NAMEI, M_WAITOK); - bcopy(cnp->cn_nameptr, cn.cn_pnbuf, cnp->cn_namelen); - cn.cn_pnbuf[cnp->cn_namelen] = '\0'; + VATTR_NULL(&va); + va.va_type = VDIR; + va.va_mode = um->um_cmode; - cn.cn_nameiop = CREATE; - cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN); - cn.cn_proc = cnp->cn_proc; - if (um->um_op == UNMNT_ABOVE) - cn.cn_cred = cnp->cn_cred; - else - cn.cn_cred = um->um_cred; - cn.cn_nameptr = cn.cn_pnbuf; - cn.cn_namelen = cnp->cn_namelen; - cn.cn_hash = cnp->cn_hash; - cn.cn_consume = cnp->cn_consume; + /* VOP_LEASE: dvp is locked */ + VOP_LEASE(dvp, p, cn.cn_cred, LEASE_WRITE); - VREF(dvp); - error = relookup(dvp, vpp, &cn); - if (error) + error = VOP_MKDIR(dvp, vpp, &cn, &va); + return (error); +} + +/* + * Create a whiteout entry in the upper layer. + * + * (um) points to the union mount structure for access to the + * the mounting process's credentials. + * (dvp) is the directory in which to create the whiteout. + * it is locked on entry and exit. + * (cnp) is the componentname to be created. + */ +int +union_mkwhiteout(um, dvp, cnp, path) + struct union_mount *um; + struct vnode *dvp; + struct componentname *cnp; + char *path; +{ + int error; + struct vattr va; + struct proc *p = cnp->cn_proc; + struct vnode *wvp; + struct componentname cn; + + VOP_UNLOCK(dvp, 0, p); + error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path)); + if (error) { + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); return (error); - vrele(dvp); + } - if (*vpp) { + if (wvp) { VOP_ABORTOP(dvp, &cn); - VOP_UNLOCK(dvp); - vrele(*vpp); - *vpp = NULLVP; + vrele(dvp); + vrele(wvp); return (EEXIST); } - VATTR_NULL(&va); - va.va_type = VDIR; - va.va_mode = um->um_cmode; + /* VOP_LEASE: dvp is locked */ + VOP_LEASE(dvp, p, p->p_ucred, LEASE_WRITE); + + error = VOP_WHITEOUT(dvp, &cn, CREATE); + if (error) + VOP_ABORTOP(dvp, &cn); - /* LEASE_CHECK: dvp is locked */ - LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE); + vrele(dvp); - error = VOP_MKDIR(dvp, vpp, &cn, &va); return (error); } @@ -699,9 +926,8 @@ union_vn_create(vpp, un, p) VATTR_NULL(vap); vap->va_type = VREG; vap->va_mode = cmode; - LEASE_CHECK(un->un_dirvp, p, cred, LEASE_WRITE); - error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap); - if (error) + VOP_LEASE(un->un_dirvp, p, cred, LEASE_WRITE); + if (error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap)) return (error); error = VOP_OPEN(vp, fmode, cred, p); @@ -722,6 +948,7 @@ union_vn_close(vp, fmode, cred, p) struct ucred *cred; struct proc *p; { + if (fmode & FWRITE) --vp->v_writecount; return (VOP_CLOSE(vp, fmode, cred, p)); @@ -731,24 +958,137 @@ void union_removed_upper(un) struct union_node *un; { + struct proc *p = curproc; /* XXX */ + + union_newupper(un, NULLVP); + if (un->un_flags & UN_CACHED) { + un->un_flags &= ~UN_CACHED; + LIST_REMOVE(un, un_cache); + } + if (un->un_flags & UN_ULOCK) { un->un_flags &= ~UN_ULOCK; - VOP_UNLOCK(un->un_uppervp); + VOP_UNLOCK(un->un_uppervp, 0, p); } - - union_newupper(un, NULLVP); } +#if 0 struct vnode * union_lowervp(vp) struct vnode *vp; { struct union_node *un = VTOUNION(vp); - if (un->un_lowervp && (vp->v_type == un->un_lowervp->v_type)) { - if (vget(un->un_lowervp, 0)) - return (NULLVP); + if ((un->un_lowervp != NULLVP) && + (vp->v_type == un->un_lowervp->v_type)) { + if (vget(un->un_lowervp, 0) == 0) + return (un->un_lowervp); } - return (un->un_lowervp); + return (NULLVP); +} +#endif + +/* + * determine whether a whiteout is needed + * during a remove/rmdir operation. + */ +int +union_dowhiteout(un, cred, p) + struct union_node *un; + struct ucred *cred; + struct proc *p; +{ + struct vattr va; + + if (un->un_lowervp != NULLVP) + return (1); + + if (VOP_GETATTR(un->un_uppervp, &va, cred, p) == 0 && + (va.va_flags & OPAQUE)) + return (1); + + return (0); +} + +static void +union_dircache_r(vp, vppp, cntp) + struct vnode *vp; + struct vnode ***vppp; + int *cntp; +{ + struct union_node *un; + + if (vp->v_op != union_vnodeop_p) { + if (vppp) { + VREF(vp); + *(*vppp)++ = vp; + if (--(*cntp) == 0) + panic("union: dircache table too small"); + } else { + (*cntp)++; + } + + return; + } + + un = VTOUNION(vp); + if (un->un_uppervp != NULLVP) + union_dircache_r(un->un_uppervp, vppp, cntp); + if (un->un_lowervp != NULLVP) + union_dircache_r(un->un_lowervp, vppp, cntp); +} + +struct vnode * +union_dircache(vp, p) + struct vnode *vp; + struct proc *p; +{ + int cnt; + struct vnode *nvp; + struct vnode **vpp; + struct vnode **dircache; + struct union_node *un; + int error; + + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + dircache = VTOUNION(vp)->un_dircache; + + nvp = NULLVP; + + if (dircache == 0) { + cnt = 0; + union_dircache_r(vp, 0, &cnt); + cnt++; + dircache = (struct vnode **) + malloc(cnt * sizeof(struct vnode *), + M_TEMP, M_WAITOK); + vpp = dircache; + union_dircache_r(vp, &vpp, &cnt); + *vpp = NULLVP; + vpp = dircache + 1; + } else { + vpp = dircache; + do { + if (*vpp++ == VTOUNION(vp)->un_uppervp) + break; + } while (*vpp != NULLVP); + } + + if (*vpp == NULLVP) + goto out; + + vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, p); + VREF(*vpp); + error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, 0, *vpp, NULLVP, 0); + if (error) + goto out; + + VTOUNION(vp)->un_dircache = 0; + un = VTOUNION(nvp); + un->un_dircache = dircache; + +out: + VOP_UNLOCK(vp, 0, p); + return (nvp); } diff --git a/sys/miscfs/union/union_vfsops.c b/sys/miscfs/union/union_vfsops.c index a1a6a0d..0295961 100644 --- a/sys/miscfs/union/union_vfsops.c +++ b/sys/miscfs/union/union_vfsops.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994 Jan-Simon Pendry. + * Copyright (c) 1994, 1995 The Regents of the University of California. + * Copyright (c) 1994, 1995 Jan-Simon Pendry. * All rights reserved. * * This code is derived from software donated to Berkeley by @@ -34,7 +34,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)union_vfsops.c 8.7 (Berkeley) 3/5/94 + * @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95 * $FreeBSD$ */ @@ -56,7 +56,7 @@ #include <sys/queue.h> #include <miscfs/union/union.h> -extern int union_init __P((void)); +extern int union_init __P((struct vfsconf *)); extern int union_fhtovp __P((struct mount *mp, struct fid *fidp, struct mbuf *nam, struct vnode **vpp, @@ -92,7 +92,7 @@ union_mount(mp, path, data, ndp, p) struct union_args args; struct vnode *lowerrootvp = NULLVP; struct vnode *upperrootvp = NULLVP; - struct union_mount *um; + struct union_mount *um = 0; struct ucred *cred = 0; struct ucred *scred; struct vattr va; @@ -118,34 +118,6 @@ union_mount(mp, path, data, ndp, p) } /* - * Take a copy of the process's credentials. This isn't - * quite right since the euid will always be zero and we - * want to get the "real" users credentials. So fix up - * the uid field after taking the copy. - */ - cred = crdup(p->p_ucred); - cred->cr_uid = p->p_cred->p_ruid; - - /* - * Ensure the *real* user has write permission on the - * mounted-on directory. This allows the mount_union - * command to be made setuid root so allowing anyone - * to do union mounts onto any directory on which they - * have write permission and which they also own. - */ - error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p); - if (error) - goto bad; - if ((va.va_uid != cred->cr_uid) && - (cred->cr_uid != 0)) { - error = EACCES; - goto bad; - } - error = VOP_ACCESS(mp->mnt_vnodecovered, VWRITE, cred, p); - if (error) - goto bad; - - /* * Get argument */ error = copyin(data, (caddr_t)&args, sizeof(struct union_args)); @@ -156,18 +128,10 @@ union_mount(mp, path, data, ndp, p) VREF(lowerrootvp); /* - * Find upper node. Use the real process credentials, - * not the effective ones since this will have come - * through a setuid process (mount_union). All this - * messing around with permissions is entirely bogus - * and should be removed by allowing any user straight - * past the mount system call. + * Find upper node. */ - scred = p->p_ucred; - p->p_ucred = cred; NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT, UIO_USERSPACE, args.target, p); - p->p_ucred = scred; error = namei(ndp); if (error) @@ -218,7 +182,18 @@ union_mount(mp, path, data, ndp, p) goto bad; } - um->um_cred = cred; + /* + * Unless the mount is readonly, ensure that the top layer + * supports whiteout operations + */ + if ((mp->mnt_flag & MNT_RDONLY) == 0) { + error = VOP_WHITEOUT(um->um_uppervp, (struct componentname *) 0, LOOKUP); + if (error) + goto bad; + } + + um->um_cred = p->p_ucred; + crhold(um->um_cred); um->um_cmode = UN_DIRMODE &~ p->p_fd->fd_cmask; /* @@ -246,24 +221,18 @@ union_mount(mp, path, data, ndp, p) */ mp->mnt_flag |= (um->um_uppervp->v_mount->mnt_flag & MNT_RDONLY); - /* - * This is a user mount. Privilege check for unmount - * will be done in union_unmount. - */ - mp->mnt_flag |= MNT_USER; - mp->mnt_data = (qaddr_t) um; - getnewfsid(mp, MOUNT_UNION); + vfs_getnewfsid(mp); (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); switch (um->um_op) { case UNMNT_ABOVE: - cp = "<above>"; + cp = "<above>:"; break; case UNMNT_BELOW: - cp = "<below>"; + cp = "<below>:"; break; case UNMNT_REPLACE: cp = ""; @@ -287,6 +256,8 @@ union_mount(mp, path, data, ndp, p) return (0); bad: + if (um) + free(um, M_UFSMNT); if (cred) crfree(cred); if (upperrootvp) @@ -323,40 +294,55 @@ union_unmount(mp, mntflags, p) struct union_mount *um = MOUNTTOUNIONMOUNT(mp); struct vnode *um_rootvp; int error; + int freeing; int flags = 0; #ifdef UNION_DIAGNOSTIC printf("union_unmount(mp = %x)\n", mp); #endif - /* only the mounter, or superuser can unmount */ - if ((p->p_cred->p_ruid != um->um_cred->cr_uid) && - (error = suser(p->p_ucred, &p->p_acflag))) + if (mntflags & MNT_FORCE) + flags |= FORCECLOSE; + + if (error = union_root(mp, &um_rootvp)) return (error); - if (mntflags & MNT_FORCE) { - /* union can never be rootfs so don't check for it */ - if (!doforce) - return (EINVAL); - flags |= FORCECLOSE; + /* + * Keep flushing vnodes from the mount list. + * This is needed because of the un_pvp held + * reference to the parent vnode. + * If more vnodes have been freed on a given pass, + * the try again. The loop will iterate at most + * (d) times, where (d) is the maximum tree depth + * in the filesystem. + */ + for (freeing = 0; vflush(mp, um_rootvp, flags) != 0;) { + struct vnode *vp; + int n; + + /* count #vnodes held on mount list */ + for (n = 0, vp = mp->mnt_vnodelist.lh_first; + vp != NULLVP; + vp = vp->v_mntvnodes.le_next) + n++; + + /* if this is unchanged then stop */ + if (n == freeing) + break; + + /* otherwise try once more time */ + freeing = n; } - error = union_root(mp, &um_rootvp); - if (error) - return (error); + /* At this point the root vnode should have a single reference */ if (um_rootvp->v_usecount > 1) { vput(um_rootvp); return (EBUSY); } - error = vflush(mp, um_rootvp, flags); - if (error) { - vput(um_rootvp); - return (error); - } #ifdef UNION_DIAGNOSTIC - vprint("alias root of lower", um_rootvp); -#endif + vprint("union root", um_rootvp); +#endif /* * Discard references to upper and lower target vnodes. */ @@ -385,16 +371,11 @@ union_root(mp, vpp) struct mount *mp; struct vnode **vpp; { + struct proc *p = curproc; /* XXX */ struct union_mount *um = MOUNTTOUNIONMOUNT(mp); int error; int loselock; -#ifdef UNION_DIAGNOSTIC - printf("union_root(mp = %x, lvp = %x, uvp = %x)\n", mp, - um->um_lowervp, - um->um_uppervp); -#endif - /* * Return locked reference to root. */ @@ -403,7 +384,7 @@ union_root(mp, vpp) VOP_ISLOCKED(um->um_uppervp)) { loselock = 1; } else { - VOP_LOCK(um->um_uppervp); + vn_lock(um->um_uppervp, LK_EXCLUSIVE | LK_RETRY, p); loselock = 0; } if (um->um_lowervp) @@ -413,16 +394,17 @@ union_root(mp, vpp) (struct vnode *) 0, (struct componentname *) 0, um->um_uppervp, - um->um_lowervp); + um->um_lowervp, + 1); if (error) { - if (!loselock) - VOP_UNLOCK(um->um_uppervp); - vrele(um->um_uppervp); + if (loselock) + vrele(um->um_uppervp); + else + vput(um->um_uppervp); if (um->um_lowervp) vrele(um->um_lowervp); } else { - (*vpp)->v_flag |= VROOT; if (loselock) VTOUNION(*vpp)->un_flags &= ~UN_ULOCK; } @@ -431,18 +413,6 @@ union_root(mp, vpp) } int -union_quotactl(mp, cmd, uid, arg, p) - struct mount *mp; - int cmd; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - - return (EOPNOTSUPP); -} - -int union_statfs(mp, sbp, p) struct mount *mp; struct statfs *sbp; @@ -485,7 +455,6 @@ union_statfs(mp, sbp, p) if (error) return (error); - sbp->f_type = MOUNT_UNION; sbp->f_flags = mstat.f_flags; sbp->f_bsize = mstat.f_bsize; sbp->f_iosize = mstat.f_iosize; @@ -496,18 +465,23 @@ union_statfs(mp, sbp, p) * kind of sense. none of this makes sense though. */ - if (mstat.f_bsize != lbsize) { + if (mstat.f_bsize != lbsize) sbp->f_blocks = sbp->f_blocks * lbsize / mstat.f_bsize; - sbp->f_bfree = sbp->f_bfree * lbsize / mstat.f_bsize; - sbp->f_bavail = sbp->f_bavail * lbsize / mstat.f_bsize; - } + + /* + * The "total" fields count total resources in all layers, + * the "free" fields count only those resources which are + * free in the upper layer (since only the upper layer + * is writeable). + */ sbp->f_blocks += mstat.f_blocks; - sbp->f_bfree += mstat.f_bfree; - sbp->f_bavail += mstat.f_bavail; + sbp->f_bfree = mstat.f_bfree; + sbp->f_bavail = mstat.f_bavail; sbp->f_files += mstat.f_files; - sbp->f_ffree += mstat.f_ffree; + sbp->f_ffree = mstat.f_ffree; if (sbp != &mp->mnt_stat) { + sbp->f_type = mp->mnt_vfc->vfc_typenum; bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); @@ -515,51 +489,21 @@ union_statfs(mp, sbp, p) return (0); } -int -union_sync(mp, waitfor, cred, p) - struct mount *mp; - int waitfor; - struct ucred *cred; - struct proc *p; -{ - - /* - * XXX - Assumes no data cached at union layer. - */ - return (0); -} - -int -union_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; -{ - - return (EOPNOTSUPP); -} - -int -union_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp) - struct mount *mp; - struct fid *fidp; - struct mbuf *nam; - struct vnode **vpp; - int *exflagsp; - struct ucred **credanonp; -{ - - return (EOPNOTSUPP); -} - -int -union_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; -{ - - return (EOPNOTSUPP); -} +/* + * XXX - Assumes no data cached at union layer. + */ +#define union_sync ((int (*) __P((struct mount *, int, struct ucred *, \ + struct proc *)))nullop) + +#define union_fhtovp ((int (*) __P((struct mount *, struct fid *, \ + struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp) +#define union_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \ + struct proc *)))eopnotsupp) +#define union_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ + size_t, struct proc *)))eopnotsupp) +#define union_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \ + eopnotsupp) +#define union_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp) struct vfsops union_vfsops = { union_mount, diff --git a/sys/miscfs/union/union_vnops.c b/sys/miscfs/union/union_vnops.c index 5940243..4a66dc0 100644 --- a/sys/miscfs/union/union_vnops.c +++ b/sys/miscfs/union/union_vnops.c @@ -1,7 +1,7 @@ /* - * Copyright (c) 1992, 1993, 1994 The Regents of the University of California. - * Copyright (c) 1992, 1993, 1994 Jan-Simon Pendry. - * All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry. + * Copyright (c) 1992, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Jan-Simon Pendry. @@ -34,7 +34,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)union_vnops.c 8.6 (Berkeley) 2/17/94 + * @(#)union_vnops.c 8.32 (Berkeley) 6/23/95 * $FreeBSD$ */ @@ -43,7 +43,7 @@ #include <sys/proc.h> #include <sys/file.h> #include <sys/time.h> -#include <sys/kernel.h> +#include <sys/stat.h> #include <sys/types.h> #include <sys/vnode.h> #include <sys/mount.h> @@ -51,16 +51,12 @@ #include <sys/malloc.h> #include <sys/buf.h> #include <sys/queue.h> +#include <sys/lock.h> #include <miscfs/union/union.h> -/* FIXUP throws the lock on the uppervp vnode if the union_node is already - * locked and the uppervp vnode is not. Before, this was thrown regardless - * of the state of the union_node which resulted in locked vnodes which - * were never unlocked (since the union would never be unlocked). - */ -#define FIXUP(un) { \ - if (((un)->un_flags & (UN_LOCKED|UN_ULOCK)) == UN_LOCKED) { \ - union_fixup(un); \ +#define FIXUP(un, p) { \ + if (((un)->un_flags & UN_ULOCK) == 0) { \ + union_fixup(un, p); \ } \ } @@ -70,7 +66,7 @@ extern int union_advlock __P((struct vop_advlock_args *ap)); extern int union_bmap __P((struct vop_bmap_args *ap)); extern int union_close __P((struct vop_close_args *ap)); extern int union_create __P((struct vop_create_args *ap)); -static void union_fixup __P((struct union_node *un)); +static void union_fixup __P((struct union_node *un, struct proc *p)); extern int union_fsync __P((struct vop_fsync_args *ap)); extern int union_getattr __P((struct vop_getattr_args *ap)); extern int union_inactive __P((struct vop_inactive_args *ap)); @@ -79,7 +75,7 @@ extern int union_islocked __P((struct vop_islocked_args *ap)); extern int union_link __P((struct vop_link_args *ap)); extern int union_lock __P((struct vop_lock_args *ap)); extern int union_lookup __P((struct vop_lookup_args *ap)); -static int union_lookup1 __P((struct vnode *udvp, struct vnode *dvp, +static int union_lookup1 __P((struct vnode *udvp, struct vnode **dvpp, struct vnode **vpp, struct componentname *cnp)); extern int union_mkdir __P((struct vop_mkdir_args *ap)); @@ -100,29 +96,34 @@ extern int union_select __P((struct vop_select_args *ap)); extern int union_setattr __P((struct vop_setattr_args *ap)); extern int union_strategy __P((struct vop_strategy_args *ap)); extern int union_symlink __P((struct vop_symlink_args *ap)); -extern int union_unlock __P((struct vop_lock_args *ap)); +extern int union_unlock __P((struct vop_unlock_args *ap)); extern int union_write __P((struct vop_read_args *ap)); static void -union_fixup(un) +union_fixup(un, p) struct union_node *un; + struct proc *p; { - VOP_LOCK(un->un_uppervp); + vn_lock(un->un_uppervp, LK_EXCLUSIVE | LK_RETRY, p); un->un_flags |= UN_ULOCK; } static int -union_lookup1(udvp, dvp, vpp, cnp) +union_lookup1(udvp, dvpp, vpp, cnp) struct vnode *udvp; - struct vnode *dvp; + struct vnode **dvpp; struct vnode **vpp; struct componentname *cnp; { int error; + struct proc *p = cnp->cn_proc; struct vnode *tdvp; + struct vnode *dvp; struct mount *mp; + dvp = *dvpp; + /* * If stepping up the directory tree, check for going * back across the mount point, in which case do what @@ -130,21 +131,18 @@ union_lookup1(udvp, dvp, vpp, cnp) * hierarchy. */ if (cnp->cn_flags & ISDOTDOT) { - for (;;) { + while ((dvp != udvp) && (dvp->v_flag & VROOT)) { /* * Don't do the NOCROSSMOUNT check * at this level. By definition, * union fs deals with namespaces, not * filesystems. */ - if ((dvp->v_flag & VROOT) == 0) - break; - tdvp = dvp; - dvp = dvp->v_mount->mnt_vnodecovered; + *dvpp = dvp = dvp->v_mount->mnt_vnodecovered; vput(tdvp); VREF(dvp); - VOP_LOCK(dvp); + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); } } @@ -158,7 +156,7 @@ union_lookup1(udvp, dvp, vpp, cnp) * here to allow it to be unlocked again (phew) in union_lookup. */ if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN)) - VOP_LOCK(dvp); + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); dvp = tdvp; @@ -170,13 +168,11 @@ union_lookup1(udvp, dvp, vpp, cnp) while (dvp != udvp && (dvp->v_type == VDIR) && (mp = dvp->v_mountedhere)) { - if (mp->mnt_flag & MNT_MLOCK) { - mp->mnt_flag |= MNT_MWAIT; - (void) tsleep((caddr_t) mp, PVFS, "unlkup", 0); + if (vfs_busy(mp, 0, 0, p)) continue; - } error = VFS_ROOT(mp, &tdvp); + vfs_unbusy(mp, p); if (error) { vput(dvp); return (error); @@ -206,9 +202,28 @@ union_lookup(ap) struct vnode *dvp = ap->a_dvp; struct union_node *dun = VTOUNION(dvp); struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; int lockparent = cnp->cn_flags & LOCKPARENT; struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount); - struct ucred *saved_cred = 0; + struct ucred *saved_cred; + int iswhiteout; + struct vattr va; + +#ifdef notyet + if (cnp->cn_namelen == 3 && + cnp->cn_nameptr[2] == '.' && + cnp->cn_nameptr[1] == '.' && + cnp->cn_nameptr[0] == '.') { + dvp = *ap->a_vpp = LOWERVP(ap->a_dvp); + if (dvp == NULLVP) + return (ENOENT); + VREF(dvp); + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); + if (!lockparent || !(cnp->cn_flags & ISLASTCN)) + VOP_UNLOCK(ap->a_dvp, 0, p); + return (0); + } +#endif cnp->cn_flags |= LOCKPARENT; @@ -216,6 +231,7 @@ union_lookup(ap) lowerdvp = dun->un_lowervp; uppervp = NULLVP; lowervp = NULLVP; + iswhiteout = 0; /* * do the lookup in the upper level. @@ -223,9 +239,9 @@ union_lookup(ap) * then assume that something special is going * on and just return that vnode. */ - if (upperdvp) { - FIXUP(dun); - uerror = union_lookup1(um->um_uppervp, upperdvp, + if (upperdvp != NULLVP) { + FIXUP(dun, p); + uerror = union_lookup1(um->um_uppervp, &upperdvp, &uppervp, cnp); /*if (uppervp == upperdvp) dun->un_flags |= UN_KLOCK;*/ @@ -236,6 +252,16 @@ union_lookup(ap) cnp->cn_flags &= ~LOCKPARENT; return (uerror); } + if (uerror == ENOENT || uerror == EJUSTRETURN) { + if (cnp->cn_flags & ISWHITEOUT) { + iswhiteout = 1; + } else if (lowerdvp != NULLVP) { + lerror = VOP_GETATTR(upperdvp, &va, + cnp->cn_cred, cnp->cn_proc); + if (lerror == 0 && (va.va_flags & OPAQUE)) + iswhiteout = 1; + } + } } else { uerror = ENOENT; } @@ -247,10 +273,10 @@ union_lookup(ap) * back from the upper layer and return the lower vnode * instead. */ - if (lowerdvp) { + if (lowerdvp != NULLVP && !iswhiteout) { int nameiop; - VOP_LOCK(lowerdvp); + vn_lock(lowerdvp, LK_EXCLUSIVE | LK_RETRY, p); /* * Only do a LOOKUP on the bottom node, since @@ -262,17 +288,17 @@ union_lookup(ap) saved_cred = cnp->cn_cred; cnp->cn_cred = um->um_cred; } - lerror = union_lookup1(um->um_lowervp, lowerdvp, + lerror = union_lookup1(um->um_lowervp, &lowerdvp, &lowervp, cnp); if (um->um_op == UNMNT_BELOW) cnp->cn_cred = saved_cred; cnp->cn_nameiop = nameiop; if (lowervp != lowerdvp) - VOP_UNLOCK(lowerdvp); + VOP_UNLOCK(lowerdvp, 0, p); if (cnp->cn_consume != 0) { - if (uppervp) { + if (uppervp != NULLVP) { if (uppervp == upperdvp) vrele(uppervp); else @@ -286,6 +312,14 @@ union_lookup(ap) } } else { lerror = ENOENT; + if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) { + lowervp = LOWERVP(dun->un_pvp); + if (lowervp != NULLVP) { + VREF(lowervp); + vn_lock(lowervp, LK_EXCLUSIVE | LK_RETRY, p); + lerror = 0; + } + } } if (!lockparent) @@ -326,13 +360,13 @@ union_lookup(ap) if (uerror != 0 /* && (lerror == 0) */ ) { if (lowervp->v_type == VDIR) { /* case 2b. */ dun->un_flags &= ~UN_ULOCK; - VOP_UNLOCK(upperdvp); + VOP_UNLOCK(upperdvp, 0, p); uerror = union_mkshadow(um, upperdvp, cnp, &uppervp); - VOP_LOCK(upperdvp); + vn_lock(upperdvp, LK_EXCLUSIVE | LK_RETRY, p); dun->un_flags |= UN_ULOCK; if (uerror) { - if (lowervp) { + if (lowervp != NULLVP) { vput(lowervp); lowervp = NULLVP; } @@ -341,21 +375,21 @@ union_lookup(ap) } } - if (lowervp) - VOP_UNLOCK(lowervp); + if (lowervp != NULLVP) + VOP_UNLOCK(lowervp, 0, p); error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp, - uppervp, lowervp); + uppervp, lowervp, 1); if (error) { - if (uppervp) + if (uppervp != NULLVP) vput(uppervp); - if (lowervp) + if (lowervp != NULLVP) vrele(lowervp); } else { if (*ap->a_vpp != dvp) if (!lockparent || !(cnp->cn_flags & ISLASTCN)) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); } return (error); @@ -372,28 +406,26 @@ union_create(ap) { struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; - if (dvp) { + if (dvp != NULLVP) { int error; struct vnode *vp; + struct mount *mp; - FIXUP(un); + FIXUP(un, p); VREF(dvp); un->un_flags |= UN_KLOCK; + mp = ap->a_dvp->v_mount; vput(ap->a_dvp); - error = VOP_CREATE(dvp, &vp, ap->a_cnp, ap->a_vap); + error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap); if (error) return (error); - error = union_allocvp( - ap->a_vpp, - ap->a_dvp->v_mount, - ap->a_dvp, - NULLVP, - ap->a_cnp, - vp, - NULLVP); + error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, cnp, vp, + NULLVP, 1); if (error) vput(vp); return (error); @@ -404,6 +436,25 @@ union_create(ap) } int +union_whiteout(ap) + struct vop_whiteout_args /* { + struct vnode *a_dvp; + struct componentname *a_cnp; + int a_flags; + } */ *ap; +{ + struct union_node *un = VTOUNION(ap->a_dvp); + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; + + if (un->un_uppervp == NULLVP) + return (EOPNOTSUPP); + + FIXUP(un, p); + return (VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags)); +} + +int union_mknod(ap) struct vop_mknod_args /* { struct vnode *a_dvp; @@ -414,29 +465,27 @@ union_mknod(ap) { struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; - if (dvp) { + if (dvp != NULLVP) { int error; struct vnode *vp; + struct mount *mp; - FIXUP(un); + FIXUP(un, p); VREF(dvp); un->un_flags |= UN_KLOCK; + mp = ap->a_dvp->v_mount; vput(ap->a_dvp); - error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap); + error = VOP_MKNOD(dvp, &vp, cnp, ap->a_vap); if (error) return (error); - if (vp) { - error = union_allocvp( - ap->a_vpp, - ap->a_dvp->v_mount, - ap->a_dvp, - NULLVP, - ap->a_cnp, - vp, - NULLVP); + if (vp != NULLVP) { + error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, + cnp, vp, NULLVP, 1); if (error) vput(vp); } @@ -476,77 +525,7 @@ union_open(ap) */ tvp = un->un_lowervp; if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) { - struct vnode *vp; - int i; - - /* - * Open the named file in the upper layer. Note that - * the file may have come into existence *since* the - * lookup was done, since the upper layer may really - * be a loopback mount of some other filesystem... - * so open the file with exclusive create and barf if - * it already exists. - * XXX - perhaps should re-lookup the node (once more - * with feeling) and simply open that. Who knows. - */ - error = union_vn_create(&vp, un, p); - if (error) - return (error); - - /* at this point, uppervp is locked */ - union_newupper(un, vp); - un->un_flags |= UN_ULOCK; - - /* - * Now, if the file is being opened with truncation, - * then the (new) upper vnode is ready to fly, - * otherwise the data from the lower vnode must be - * copied to the upper layer first. This only works - * for regular files (check is made above). - */ - if ((mode & O_TRUNC) == 0) { - /* - * XXX - should not ignore errors - * from VOP_CLOSE - */ - VOP_LOCK(tvp); - error = VOP_OPEN(tvp, FREAD, cred, p); - if (error == 0) { - error = union_copyfile(p, cred, - tvp, un->un_uppervp); - VOP_UNLOCK(tvp); - (void) VOP_CLOSE(tvp, FREAD, cred, p); - } else { - VOP_UNLOCK(tvp); - } - -#ifdef UNION_DIAGNOSTIC - if (!error) - uprintf("union: copied up %s\n", - un->un_path); -#endif - } - - un->un_flags &= ~UN_ULOCK; - VOP_UNLOCK(un->un_uppervp); - union_vn_close(un->un_uppervp, FWRITE, cred, p); - VOP_LOCK(un->un_uppervp); - un->un_flags |= UN_ULOCK; - - /* - * Subsequent IOs will go to the top layer, so - * call close on the lower vnode and open on the - * upper vnode to ensure that the filesystem keeps - * its references counts right. This doesn't do - * the right thing with (cred) and (FREAD) though. - * Ignoring error returns is not righ, either. - */ - for (i = 0; i < un->un_openl; i++) { - (void) VOP_CLOSE(tvp, FREAD, cred, p); - (void) VOP_OPEN(un->un_uppervp, FREAD, cred, p); - } - un->un_openl = 0; - + error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p); if (error == 0) error = VOP_OPEN(un->un_uppervp, mode, cred, p); return (error); @@ -556,14 +535,14 @@ union_open(ap) * Just open the lower vnode */ un->un_openl++; - VOP_LOCK(tvp); + vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_OPEN(tvp, mode, cred, p); - VOP_UNLOCK(tvp); + VOP_UNLOCK(tvp, 0, p); return (error); } - FIXUP(un); + FIXUP(un, p); error = VOP_OPEN(tvp, mode, cred, p); @@ -582,9 +561,7 @@ union_close(ap) struct union_node *un = VTOUNION(ap->a_vp); struct vnode *vp; - if (un->un_uppervp) { - vp = un->un_uppervp; - } else { + if ((vp = un->un_uppervp) == NULLVP) { #ifdef UNION_DIAGNOSTIC if (un->un_openl <= 0) panic("union: un_openl cnt"); @@ -593,7 +570,8 @@ union_close(ap) vp = un->un_lowervp; } - return (VOP_CLOSE(vp, ap->a_fflag, ap->a_cred, ap->a_p)); + ap->a_vp = vp; + return (VCALL(vp, VOFFSET(vop_close), ap)); } /* @@ -615,27 +593,29 @@ union_access(ap) } */ *ap; { struct union_node *un = VTOUNION(ap->a_vp); + struct proc *p = ap->a_p; int error = EACCES; struct vnode *vp; - vp = un->un_uppervp; - if (vp) { - FIXUP(un); - return (VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p)); + if ((vp = un->un_uppervp) != NULLVP) { + FIXUP(un, p); + ap->a_vp = vp; + return (VCALL(vp, VOFFSET(vop_access), ap)); } - vp = un->un_lowervp; - if (vp) { - VOP_LOCK(vp); - error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p); + if ((vp = un->un_lowervp) != NULLVP) { + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + ap->a_vp = vp; + error = VCALL(vp, VOFFSET(vop_access), ap); if (error == 0) { struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount); - if (um->um_op == UNMNT_BELOW) - error = VOP_ACCESS(vp, ap->a_mode, - um->um_cred, ap->a_p); + if (um->um_op == UNMNT_BELOW) { + ap->a_cred = um->um_cred; + error = VCALL(vp, VOFFSET(vop_access), ap); + } } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); if (error) return (error); } @@ -644,7 +624,8 @@ union_access(ap) } /* - * We handle getattr only to change the fsid. + * We handle getattr only to change the fsid and + * track object sizes */ int union_getattr(ap) @@ -658,6 +639,7 @@ union_getattr(ap) int error; struct union_node *un = VTOUNION(ap->a_vp); struct vnode *vp = un->un_uppervp; + struct proc *p = ap->a_p; struct vattr *vap; struct vattr va; @@ -675,10 +657,21 @@ union_getattr(ap) vp = un->un_uppervp; if (vp != NULLVP) { - FIXUP(un); + /* + * It's not clear whether VOP_GETATTR is to be + * called with the vnode locked or not. stat() calls + * it with (vp) locked, and fstat calls it with + * (vp) unlocked. + * In the mean time, compensate here by checking + * the union_node's lock flag. + */ + if (un->un_flags & UN_LOCKED) + FIXUP(un, p); + error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); if (error) return (error); + union_newsize(ap->a_vp, vap->va_size, VNOVAL); } if (vp == NULLVP) { @@ -691,17 +684,16 @@ union_getattr(ap) } if (vp != NULLVP) { - VOP_LOCK(vp); error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); - VOP_UNLOCK(vp); if (error) return (error); + union_newsize(ap->a_vp, VNOVAL, vap->va_size); } if ((vap != ap->a_vap) && (vap->va_type == VDIR)) ap->a_vap->va_nlink += vap->va_nlink; - vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; + ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; return (0); } @@ -715,6 +707,7 @@ union_setattr(ap) } */ *ap; { struct union_node *un = VTOUNION(ap->a_vp); + struct proc *p = ap->a_p; int error; /* @@ -724,21 +717,11 @@ union_setattr(ap) */ if ((un->un_uppervp == NULLVP) && /* assert(un->un_lowervp != NULLVP) */ - (un->un_lowervp->v_type == VREG) && - (ap->a_vap->va_size == 0)) { - struct vnode *vp; - - error = union_vn_create(&vp, un, ap->a_p); + (un->un_lowervp->v_type == VREG)) { + error = union_copyup(un, (ap->a_vap->va_size != 0), + ap->a_cred, ap->a_p); if (error) return (error); - - /* at this point, uppervp is locked */ - union_newupper(un, vp); - - VOP_UNLOCK(vp); - union_vn_close(un->un_uppervp, FWRITE, ap->a_cred, ap->a_p); - VOP_LOCK(vp); - un->un_flags |= UN_ULOCK; } /* @@ -746,9 +729,11 @@ union_setattr(ap) * otherwise return read-only filesystem error. */ if (un->un_uppervp != NULLVP) { - FIXUP(un); + FIXUP(un, p); error = VOP_SETATTR(un->un_uppervp, ap->a_vap, ap->a_cred, ap->a_p); + if ((error == 0) && (ap->a_vap->va_size != VNOVAL)) + union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL); } else { error = EROFS; } @@ -766,16 +751,36 @@ union_read(ap) } */ *ap; { int error; + struct proc *p = ap->a_uio->uio_procp; struct vnode *vp = OTHERVP(ap->a_vp); int dolock = (vp == LOWERVP(ap->a_vp)); if (dolock) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp)); + FIXUP(VTOUNION(ap->a_vp), p); error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); if (dolock) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); + + /* + * XXX + * perhaps the size of the underlying object has changed under + * our feet. take advantage of the offset information present + * in the uio structure. + */ + if (error == 0) { + struct union_node *un = VTOUNION(ap->a_vp); + off_t cur = ap->a_uio->uio_offset; + + if (vp == un->un_uppervp) { + if (cur > un->un_uppersz) + union_newsize(ap->a_vp, cur, VNOVAL); + } else { + if (cur > un->un_lowersz) + union_newsize(ap->a_vp, VNOVAL, cur); + } + } return (error); } @@ -790,21 +795,47 @@ union_write(ap) } */ *ap; { int error; - struct vnode *vp = OTHERVP(ap->a_vp); - int dolock = (vp == LOWERVP(ap->a_vp)); + struct vnode *vp; + struct union_node *un = VTOUNION(ap->a_vp); + struct proc *p = ap->a_uio->uio_procp; - if (dolock) - VOP_LOCK(vp); - else - FIXUP(VTOUNION(ap->a_vp)); + vp = UPPERVP(ap->a_vp); + if (vp == NULLVP) + panic("union: missing upper layer in write"); + + FIXUP(un, p); error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); - if (dolock) - VOP_UNLOCK(vp); + + /* + * the size of the underlying object may be changed by the + * write. + */ + if (error == 0) { + off_t cur = ap->a_uio->uio_offset; + + if (cur > un->un_uppersz) + union_newsize(ap->a_vp, cur, VNOVAL); + } return (error); } int +union_lease(ap) + struct vop_lease_args /* { + struct vnode *a_vp; + struct proc *a_p; + struct ucred *a_cred; + int a_flag; + } */ *ap; +{ + register struct vnode *ovp = OTHERVP(ap->a_vp); + + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_lease), ap)); +} + +int union_ioctl(ap) struct vop_ioctl_args /* { struct vnode *a_vp; @@ -815,9 +846,10 @@ union_ioctl(ap) struct proc *a_p; } */ *ap; { + register struct vnode *ovp = OTHERVP(ap->a_vp); - return (VOP_IOCTL(OTHERVP(ap->a_vp), ap->a_command, ap->a_data, - ap->a_fflag, ap->a_cred, ap->a_p)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_ioctl), ap)); } int @@ -830,9 +862,28 @@ union_select(ap) struct proc *a_p; } */ *ap; { + register struct vnode *ovp = OTHERVP(ap->a_vp); - return (VOP_SELECT(OTHERVP(ap->a_vp), ap->a_which, ap->a_fflags, - ap->a_cred, ap->a_p)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_select), ap)); +} + +int +union_revoke(ap) + struct vop_revoke_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + if (UPPERVP(vp)) + VOP_REVOKE(UPPERVP(vp), ap->a_flags); + if (LOWERVP(vp)) + VOP_REVOKE(LOWERVP(vp), ap->a_flags); + vgone(vp); + return (0); } int @@ -844,9 +895,10 @@ union_mmap(ap) struct proc *a_p; } */ *ap; { + register struct vnode *ovp = OTHERVP(ap->a_vp); - return (VOP_MMAP(OTHERVP(ap->a_vp), ap->a_fflags, - ap->a_cred, ap->a_p)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_mmap), ap)); } int @@ -859,19 +911,19 @@ union_fsync(ap) } */ *ap; { int error = 0; + struct proc *p = ap->a_p; struct vnode *targetvp = OTHERVP(ap->a_vp); - if (targetvp) { + if (targetvp != NULLVP) { int dolock = (targetvp == LOWERVP(ap->a_vp)); if (dolock) - VOP_LOCK(targetvp); + vn_lock(targetvp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp)); - error = VOP_FSYNC(targetvp, ap->a_cred, - ap->a_waitfor, ap->a_p); + FIXUP(VTOUNION(ap->a_vp), p); + error = VOP_FSYNC(targetvp, ap->a_cred, ap->a_waitfor, p); if (dolock) - VOP_UNLOCK(targetvp); + VOP_UNLOCK(targetvp, 0, p); } return (error); @@ -886,8 +938,10 @@ union_seek(ap) struct ucred *a_cred; } */ *ap; { + register struct vnode *ovp = OTHERVP(ap->a_vp); - return (VOP_SEEK(OTHERVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_seek), ap)); } int @@ -901,34 +955,37 @@ union_remove(ap) int error; struct union_node *dun = VTOUNION(ap->a_dvp); struct union_node *un = VTOUNION(ap->a_vp); + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; - if (dun->un_uppervp && un->un_uppervp) { + if (dun->un_uppervp == NULLVP) + panic("union remove: null upper vnode"); + + if (un->un_uppervp != NULLVP) { struct vnode *dvp = dun->un_uppervp; struct vnode *vp = un->un_uppervp; - FIXUP(dun); + FIXUP(dun, p); VREF(dvp); dun->un_flags |= UN_KLOCK; vput(ap->a_dvp); - FIXUP(un); + FIXUP(un, p); VREF(vp); un->un_flags |= UN_KLOCK; vput(ap->a_vp); - error = VOP_REMOVE(dvp, vp, ap->a_cnp); + if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc)) + cnp->cn_flags |= DOWHITEOUT; + error = VOP_REMOVE(dvp, vp, cnp); if (!error) union_removed_upper(un); - - /* - * XXX: should create a whiteout here - */ } else { - /* - * XXX: should create a whiteout here - */ + FIXUP(dun, p); + error = union_mkwhiteout( + MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount), + dun->un_uppervp, ap->a_cnp, un->un_path); vput(ap->a_dvp); vput(ap->a_vp); - error = EROFS; } return (error); @@ -942,34 +999,51 @@ union_link(ap) struct componentname *a_cnp; } */ *ap; { - int error; - struct union_node *dun = VTOUNION(ap->a_vp); - struct union_node *un = VTOUNION(ap->a_tdvp); - - if (dun->un_uppervp && un->un_uppervp) { - struct vnode *dvp = dun->un_uppervp; - struct vnode *vp = un->un_uppervp; + int error = 0; + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; + struct union_node *un; + struct vnode *vp; + struct vnode *tdvp; - FIXUP(dun); - VREF(dvp); - dun->un_flags |= UN_KLOCK; - vput(ap->a_vp); - FIXUP(un); - VREF(vp); - vrele(ap->a_tdvp); + un = VTOUNION(ap->a_tdvp); - error = VOP_LINK(dvp, vp, ap->a_cnp); + if (ap->a_tdvp->v_op != ap->a_vp->v_op) { + vp = ap->a_vp; } else { - /* - * XXX: need to copy to upper layer - * and do the link there. - */ - vput(ap->a_vp); - vrele(ap->a_tdvp); + struct union_node *tun = VTOUNION(ap->a_vp); + if (tun->un_uppervp == NULLVP) { + vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p); + if (un->un_uppervp == tun->un_dirvp) { + un->un_flags &= ~UN_ULOCK; + VOP_UNLOCK(un->un_uppervp, 0, p); + } + error = union_copyup(tun, 1, cnp->cn_cred, p); + if (un->un_uppervp == tun->un_dirvp) { + vn_lock(un->un_uppervp, + LK_EXCLUSIVE | LK_RETRY, p); + un->un_flags |= UN_ULOCK; + } + VOP_UNLOCK(ap->a_vp, 0, p); + } + vp = tun->un_uppervp; + } + + tdvp = un->un_uppervp; + if (tdvp == NULLVP) error = EROFS; + + if (error) { + vput(ap->a_tdvp); + return (error); } - return (error); + FIXUP(un, p); + VREF(tdvp); + un->un_flags |= UN_KLOCK; + vput(ap->a_tdvp); + + return (VOP_LINK(vp, tdvp, cnp)); } int @@ -993,11 +1067,16 @@ union_rename(ap) if (fdvp->v_op == union_vnodeop_p) { /* always true */ struct union_node *un = VTOUNION(fdvp); if (un->un_uppervp == NULLVP) { - error = EROFS; + /* + * this should never happen in normal + * operation but might if there was + * a problem creating the top-level shadow + * directory. + */ + error = EXDEV; goto bad; } - FIXUP(un); fdvp = un->un_uppervp; VREF(fdvp); vrele(ap->a_fdvp); @@ -1006,11 +1085,14 @@ union_rename(ap) if (fvp->v_op == union_vnodeop_p) { /* always true */ struct union_node *un = VTOUNION(fvp); if (un->un_uppervp == NULLVP) { - error = EROFS; + /* XXX: should do a copyup */ + error = EXDEV; goto bad; } - FIXUP(un); + if (un->un_lowervp != NULLVP) + ap->a_fcnp->cn_flags |= DOWHITEOUT; + fvp = un->un_uppervp; VREF(fvp); vrele(ap->a_fvp); @@ -1019,7 +1101,13 @@ union_rename(ap) if (tdvp->v_op == union_vnodeop_p) { struct union_node *un = VTOUNION(tdvp); if (un->un_uppervp == NULLVP) { - error = EROFS; + /* + * this should never happen in normal + * operation but might if there was + * a problem creating the top-level shadow + * directory. + */ + error = EXDEV; goto bad; } @@ -1029,16 +1117,14 @@ union_rename(ap) vput(ap->a_tdvp); } - if (tvp && tvp->v_op == union_vnodeop_p) { + if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) { struct union_node *un = VTOUNION(tvp); - if (un->un_uppervp == NULLVP) { - error = EROFS; - goto bad; - } tvp = un->un_uppervp; - VREF(tvp); - un->un_flags |= UN_KLOCK; + if (tvp != NULLVP) { + VREF(tvp); + un->un_flags |= UN_KLOCK; + } vput(ap->a_tvp); } @@ -1048,7 +1134,7 @@ bad: vrele(fdvp); vrele(fvp); vput(tdvp); - if (tvp) + if (tvp != NULLVP) vput(tvp); return (error); @@ -1065,27 +1151,26 @@ union_mkdir(ap) { struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; - if (dvp) { + if (dvp != NULLVP) { int error; struct vnode *vp; - FIXUP(un); + FIXUP(un, p); VREF(dvp); un->un_flags |= UN_KLOCK; - vput(ap->a_dvp); - error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap); - if (error) + VOP_UNLOCK(ap->a_dvp, 0, p); + error = VOP_MKDIR(dvp, &vp, cnp, ap->a_vap); + if (error) { + vrele(ap->a_dvp); return (error); + } - error = union_allocvp( - ap->a_vpp, - ap->a_dvp->v_mount, - ap->a_dvp, - NULLVP, - ap->a_cnp, - vp, - NULLVP); + error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount, ap->a_dvp, + NULLVP, cnp, vp, NULLVP, 1); + vrele(ap->a_dvp); if (error) vput(vp); return (error); @@ -1106,34 +1191,37 @@ union_rmdir(ap) int error; struct union_node *dun = VTOUNION(ap->a_dvp); struct union_node *un = VTOUNION(ap->a_vp); + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; - if (dun->un_uppervp && un->un_uppervp) { + if (dun->un_uppervp == NULLVP) + panic("union rmdir: null upper vnode"); + + if (un->un_uppervp != NULLVP) { struct vnode *dvp = dun->un_uppervp; struct vnode *vp = un->un_uppervp; - FIXUP(dun); + FIXUP(dun, p); VREF(dvp); dun->un_flags |= UN_KLOCK; vput(ap->a_dvp); - FIXUP(un); + FIXUP(un, p); VREF(vp); un->un_flags |= UN_KLOCK; vput(ap->a_vp); + if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc)) + cnp->cn_flags |= DOWHITEOUT; error = VOP_RMDIR(dvp, vp, ap->a_cnp); if (!error) union_removed_upper(un); - - /* - * XXX: should create a whiteout here - */ } else { - /* - * XXX: should create a whiteout here - */ + FIXUP(dun, p); + error = union_mkwhiteout( + MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount), + dun->un_uppervp, ap->a_cnp, un->un_path); vput(ap->a_dvp); vput(ap->a_vp); - error = EROFS; } return (error); @@ -1151,17 +1239,18 @@ union_symlink(ap) { struct union_node *un = VTOUNION(ap->a_dvp); struct vnode *dvp = un->un_uppervp; + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; - if (dvp) { + if (dvp != NULLVP) { int error; struct vnode *vp; - FIXUP(un); + FIXUP(un, p); VREF(dvp); un->un_flags |= UN_KLOCK; vput(ap->a_dvp); - error = VOP_SYMLINK(dvp, &vp, ap->a_cnp, - ap->a_vap, ap->a_target); + error = VOP_SYMLINK(dvp, &vp, cnp, ap->a_vap, ap->a_target); *ap->a_vpp = NULLVP; return (error); } @@ -1183,17 +1272,21 @@ union_readdir(ap) struct vnode *a_vp; struct uio *a_uio; struct ucred *a_cred; + int *a_eofflag; + u_long *a_cookies; + int a_ncookies; } */ *ap; { - int error = 0; struct union_node *un = VTOUNION(ap->a_vp); + struct vnode *uvp = un->un_uppervp; + struct proc *p = ap->a_uio->uio_procp; - if (un->un_uppervp) { - FIXUP(un); - error = VOP_READDIR(un->un_uppervp, ap->a_uio, ap->a_cred, NULL, NULL, NULL); - } + if (uvp == NULLVP) + return (0); - return (error); + FIXUP(un, p); + ap->a_vp = uvp; + return (VCALL(uvp, VOFFSET(vop_readdir), ap)); } int @@ -1205,16 +1298,19 @@ union_readlink(ap) } */ *ap; { int error; + struct uio *uio = ap->a_uio; + struct proc *p = uio->uio_procp; struct vnode *vp = OTHERVP(ap->a_vp); int dolock = (vp == LOWERVP(ap->a_vp)); if (dolock) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp)); - error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); + FIXUP(VTOUNION(ap->a_vp), p); + ap->a_vp = vp; + error = VCALL(vp, VOFFSET(vop_readlink), ap); if (dolock) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1227,6 +1323,8 @@ union_abortop(ap) } */ *ap; { int error; + struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; struct vnode *vp = OTHERVP(ap->a_dvp); struct union_node *un = VTOUNION(ap->a_dvp); int islocked = un->un_flags & UN_LOCKED; @@ -1234,13 +1332,14 @@ union_abortop(ap) if (islocked) { if (dolock) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_dvp)); + FIXUP(VTOUNION(ap->a_dvp), p); } - error = VOP_ABORTOP(vp, ap->a_cnp); + ap->a_dvp = vp; + error = VCALL(vp, VOFFSET(vop_abortop), ap); if (islocked && dolock) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1249,8 +1348,13 @@ int union_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { + struct vnode *vp = ap->a_vp; + struct proc *p = ap->a_p; + struct union_node *un = VTOUNION(vp); + struct vnode **vpp; /* * Do nothing (and _don't_ bypass). @@ -1265,12 +1369,17 @@ union_inactive(ap) * That's too much work for now. */ -#ifdef UNION_DIAGNOSTIC - struct union_node *un = VTOUNION(ap->a_vp); + if (un->un_dircache != 0) { + for (vpp = un->un_dircache; *vpp != NULLVP; vpp++) + vrele(*vpp); + free(un->un_dircache, M_TEMP); + un->un_dircache = 0; + } - if (un->un_flags & UN_LOCKED) - panic("union: inactivating locked node"); -#endif + VOP_UNLOCK(vp, 0, p); + + if ((un->un_flags & UN_CACHED) == 0) + vgone(vp); return (0); } @@ -1292,24 +1401,39 @@ union_lock(ap) struct vop_lock_args *ap; { struct vnode *vp = ap->a_vp; + struct proc *p = ap->a_p; + int flags = ap->a_flags; struct union_node *un; + int error; -start: - while (vp->v_flag & VXLOCK) { - vp->v_flag |= VXWANT; - (void) tsleep((caddr_t)vp, PINOD, "unnlk1", 0); - } + vop_nolock(ap); + /* + * Need to do real lockmgr-style locking here. + * in the mean time, draining won't work quite right, + * which could lead to a few race conditions. + * the following test was here, but is not quite right, we + * still need to take the lock: + if ((flags & LK_TYPE_MASK) == LK_DRAIN) + return (0); + */ + flags &= ~LK_INTERLOCK; +start: un = VTOUNION(vp); - if (un->un_uppervp) { - if ((un->un_flags & UN_ULOCK) == 0) { + if (un->un_uppervp != NULLVP) { + if (((un->un_flags & UN_ULOCK) == 0) && + (vp->v_usecount != 0)) { + error = vn_lock(un->un_uppervp, flags, p); + if (error) + return (error); un->un_flags |= UN_ULOCK; - VOP_LOCK(un->un_uppervp); } #ifdef DIAGNOSTIC - if (un->un_flags & UN_KLOCK) - panic("union: dangling upper lock"); + if (un->un_flags & UN_KLOCK) { + vprint("union: dangling klock", vp); + panic("union: dangling upper lock (%lx)", vp); + } #endif } @@ -1320,7 +1444,7 @@ start: panic("union: locking against myself"); #endif un->un_flags |= UN_WANT; - (void) tsleep((caddr_t) &un->un_flags, PINOD, "unnlk2", 0); + tsleep((caddr_t)&un->un_flags, PINOD, "unionlk2", 0); goto start; } @@ -1335,11 +1459,27 @@ start: return (0); } +/* + * When operations want to vput() a union node yet retain a lock on + * the upper vnode (say, to do some further operations like link(), + * mkdir(), ...), they set UN_KLOCK on the union node, then call + * vput() which calls VOP_UNLOCK() and comes here. union_unlock() + * unlocks the union node (leaving the upper vnode alone), clears the + * KLOCK flag, and then returns to vput(). The caller then does whatever + * is left to do with the upper vnode, and ensures that it gets unlocked. + * + * If UN_KLOCK isn't set, then the upper vnode is unlocked here. + */ int union_unlock(ap) - struct vop_lock_args *ap; + struct vop_unlock_args /* { + struct vnode *a_vp; + int a_flags; + struct proc *a_p; + } */ *ap; { struct union_node *un = VTOUNION(ap->a_vp); + struct proc *p = ap->a_p; #ifdef DIAGNOSTIC if ((un->un_flags & UN_LOCKED) == 0) @@ -1352,7 +1492,7 @@ union_unlock(ap) un->un_flags &= ~UN_LOCKED; if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK) - VOP_UNLOCK(un->un_uppervp); + VOP_UNLOCK(un->un_uppervp, 0, p); un->un_flags &= ~(UN_ULOCK|UN_KLOCK); @@ -1364,6 +1504,7 @@ union_unlock(ap) #ifdef DIAGNOSTIC un->un_pid = 0; #endif + vop_nounlock(ap); return (0); } @@ -1380,16 +1521,18 @@ union_bmap(ap) } */ *ap; { int error; + struct proc *p = curproc; /* XXX */ struct vnode *vp = OTHERVP(ap->a_vp); int dolock = (vp == LOWERVP(ap->a_vp)); if (dolock) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp)); - error = VOP_BMAP(vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp, ap->a_runb); + FIXUP(VTOUNION(ap->a_vp), p); + ap->a_vp = vp; + error = VCALL(vp, VOFFSET(vop_bmap), ap); if (dolock) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1404,6 +1547,11 @@ union_print(ap) printf("\ttag VT_UNION, vp=%p, uppervp=%p, lowervp=%p\n", vp, UPPERVP(vp), LOWERVP(vp)); + if (UPPERVP(vp) != NULLVP) + vprint("union: upper", UPPERVP(vp)); + if (LOWERVP(vp) != NULLVP) + vprint("union: lower", LOWERVP(vp)); + return (0); } @@ -1426,16 +1574,18 @@ union_pathconf(ap) } */ *ap; { int error; + struct proc *p = curproc; /* XXX */ struct vnode *vp = OTHERVP(ap->a_vp); int dolock = (vp == LOWERVP(ap->a_vp)); if (dolock) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); else - FIXUP(VTOUNION(ap->a_vp)); - error = VOP_PATHCONF(vp, ap->a_name, ap->a_retval); + FIXUP(VTOUNION(ap->a_vp), p); + ap->a_vp = vp; + error = VCALL(vp, VOFFSET(vop_pathconf), ap); if (dolock) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -1450,9 +1600,10 @@ union_advlock(ap) int a_flags; } */ *ap; { + register struct vnode *ovp = OTHERVP(ap->a_vp); - return (VOP_ADVLOCK(OTHERVP(ap->a_vp), ap->a_id, ap->a_op, - ap->a_fl, ap->a_flags)); + ap->a_vp = ovp; + return (VCALL(ovp, VOFFSET(vop_advlock), ap)); } @@ -1496,6 +1647,7 @@ struct vnodeopv_entry_desc union_vnodeop_entries[] = { { &vop_default_desc, (vop_t *)vn_default_error }, { &vop_lookup_desc, (vop_t *)union_lookup }, /* lookup */ { &vop_create_desc, (vop_t *)union_create }, /* create */ + { &vop_whiteout_desc, (vop_t *)union_whiteout }, /* whiteout */ { &vop_mknod_desc, (vop_t *)union_mknod }, /* mknod */ { &vop_open_desc, (vop_t *)union_open }, /* open */ { &vop_close_desc, (vop_t *)union_close }, /* close */ @@ -1504,8 +1656,10 @@ struct vnodeopv_entry_desc union_vnodeop_entries[] = { { &vop_setattr_desc, (vop_t *)union_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)union_read }, /* read */ { &vop_write_desc, (vop_t *)union_write }, /* write */ + { &vop_lease_desc, (vop_t *)union_lease }, /* lease */ { &vop_ioctl_desc, (vop_t *)union_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)union_select }, /* select */ + { &vop_revoke_desc, (vop_t *)union_revoke }, /* revoke */ { &vop_mmap_desc, (vop_t *)union_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)union_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)union_seek }, /* seek */ diff --git a/sys/msdosfs/msdosfs_denode.c b/sys/msdosfs/msdosfs_denode.c index de4bf5e..a891ddc 100644 --- a/sys/msdosfs/msdosfs_denode.c +++ b/sys/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/msdosfs/msdosfs_lookup.c b/sys/msdosfs/msdosfs_lookup.c index 60236b8..6617f9e 100644 --- a/sys/msdosfs/msdosfs_lookup.c +++ b/sys/msdosfs/msdosfs_lookup.c @@ -54,6 +54,7 @@ #include <sys/vnode.h> #include <sys/mount.h> #include <sys/systm.h> +#include <sys/proc.h> #include <msdosfs/bpb.h> #include <msdosfs/direntry.h> @@ -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/msdosfs/msdosfs_vfsops.c b/sys/msdosfs/msdosfs_vfsops.c index 5669c63..d0c8cdb 100644 --- a/sys/msdosfs/msdosfs_vfsops.c +++ b/sys/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/msdosfs/msdosfs_vnops.c b/sys/msdosfs/msdosfs_vnops.c index bc4e12e..0f4deae 100644 --- a/sys/msdosfs/msdosfs_vnops.c +++ b/sys/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/msdosfs/msdosfsmount.h b/sys/msdosfs/msdosfsmount.h index 7b0a22e..77c6add 100644 --- a/sys/msdosfs/msdosfsmount.h +++ b/sys/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/nfs/nfs.h b/sys/nfs/nfs.h index db41859..73a018c 100644 --- a/sys/nfs/nfs.h +++ b/sys/nfs/nfs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1993 + * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -33,19 +33,19 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs.h 8.1 (Berkeley) 6/10/93 + * @(#)nfs.h 8.4 (Berkeley) 5/1/95 * $FreeBSD$ */ #ifndef _NFS_NFS_H_ #define _NFS_NFS_H_ -#include <nfs/rpcv2.h> - /* * Tunable constants for nfs */ +#ifdef KERNEL + #define NFS_MAXIOVEC 34 #define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */ #define NFS_HZ (hz / nfs_ticks) /* Ticks/sec */ @@ -69,7 +69,7 @@ #define NFS_DEFRAHEAD 1 /* Def. read ahead # blocks */ #define NFS_MAXRAHEAD 4 /* Max. read ahead # blocks */ #define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */ -#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runnable */ +#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */ #define NFS_MAXGATHERDELAY 100 /* Max. write gather delay (msec) */ #ifndef NFS_GATHERDELAY #define NFS_GATHERDELAY 10 /* Default write gather delay (msec) */ @@ -89,30 +89,9 @@ /* * XXX - * sys/buf.h should be edited to change B_APPENDWRITE --> B_NEEDCOMMIT, but - * until then... - * Same goes for sys/malloc.h, which needs M_NFSDIROFF, - * M_NFSRVDESC and M_NFSBIGFH added. - * The VA_EXCLUSIVE flag should be added for va_vaflags and set for an - * exclusive create. * The B_INVAFTERWRITE flag should be set to whatever is required by the * buffer cache code to say "Invalidate the block after it is written back". */ -#ifndef B_NEEDCOMMIT -#define B_NEEDCOMMIT B_APPENDWRITE -#endif -#ifndef M_NFSRVDESC -#define M_NFSRVDESC M_TEMP -#endif -#ifndef M_NFSDIROFF -#define M_NFSDIROFF M_TEMP -#endif -#ifndef M_NFSBIGFH -#define M_NFSBIGFH M_TEMP -#endif -#ifndef VA_EXCLUSIVE -#define VA_EXCLUSIVE 0 -#endif #ifdef __FreeBSD__ #define B_INVAFTERWRITE B_NOCACHE #else @@ -120,20 +99,6 @@ #endif /* - * These ifdefs try to handle the differences between the various 4.4BSD-Lite - * based vfs interfaces. - * btw: NetBSD-current does have a VOP_LEASDE(), but I don't know how to - * differentiate between NetBSD-1.0 and NetBSD-current, so.. - * I also don't know about BSDi's 2.0 release. - */ -#if !defined(HAS_VOPLEASE) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#define HAS_VOPLEASE 1 -#endif -#if !defined(HAS_VOPREVOKE) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#define HAS_VOPREVOKE 1 -#endif - -/* * The IO_METASYNC flag should be implemented for local file systems. * (Until then, it is nothin at all.) */ @@ -164,13 +129,114 @@ #define NFS_SVCALLOC 256 #define NFS_UIDALLOC 128 +#endif /* KERNEL */ + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ + +/* + * Arguments to mount NFS + */ +#define NFS_ARGSVERSION 3 /* change when nfs_args changes */ +struct nfs_args { + int version; /* args structure version number */ + struct sockaddr *addr; /* file server address */ + int addrlen; /* length of address */ + int sotype; /* Socket type */ + int proto; /* and Protocol */ + u_char *fh; /* File handle to be mounted */ + int fhsize; /* Size, in bytes, of fh */ + int flags; /* flags */ + int wsize; /* write size in bytes */ + int rsize; /* read size in bytes */ + int readdirsize; /* readdir size in bytes */ + int timeo; /* initial timeout in .1 secs */ + int retrans; /* times to retry send */ + int maxgrouplist; /* Max. size of group list */ + int readahead; /* # of blocks to readahead */ + int leaseterm; /* Term (sec) of lease */ + int deadthresh; /* Retrans threshold */ + char *hostname; /* server's name */ +}; + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ + /* * Structures for the nfssvc(2) syscall. Not that anyone but nfsd and mount_nfs * should ever try and use it. */ struct nfsd_args { int sock; /* Socket to serve */ - caddr_t name; /* Client address for connection based sockets */ + caddr_t name; /* Client addr for connection based sockets */ int namelen; /* Length of name */ }; @@ -200,6 +266,10 @@ struct nfsd_cargs { }; /* + * XXX to allow amd to include nfs.h without nfsproto.h + */ +#ifdef NFS_NPROCS +/* * Stats structure */ struct nfsstats { @@ -237,6 +307,7 @@ struct nfsstats { int srvnqnfs_getleases; int srvvop_writes; }; +#endif /* * Flags for nfssvc() system call. @@ -267,7 +338,7 @@ struct nfsstats { * such as SIGALRM will not expect file I/O system calls to be interrupted * by them and break. */ -#if defined(KERNEL) || defined(_KERNEL) +#ifdef KERNEL struct uio; struct buf; struct vattr; struct nameidata; /* XXX */ @@ -482,6 +553,8 @@ extern int nfsd_head_flag; !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ sizeof (struct ucred))) + +int nfs_init __P((struct vfsconf *vfsp)); int nfs_reply __P((struct nfsreq *)); int nfs_getreq __P((struct nfsrv_descript *,struct nfsd *,int)); int nfs_send __P((struct socket *,struct mbuf *,struct mbuf *,struct nfsreq *)); @@ -516,14 +589,12 @@ int nfs_adv __P((struct mbuf **,caddr_t *,int,int)); void nfs_nhinit __P((void)); void nfs_timer __P((void*)); u_long nfs_hash __P((nfsfh_t *,int)); -void nfsrv_slpderef __P((struct nfssvc_sock *slp)); int nfsrv_dorec __P((struct nfssvc_sock *,struct nfsd *,struct nfsrv_descript **)); -void nfsrv_cleancache __P((void)); int nfsrv_getcache __P((struct nfsrv_descript *,struct nfssvc_sock *,struct mbuf **)); -int nfs_init __P((void)); void nfsrv_updatecache __P((struct nfsrv_descript *,int,struct mbuf *)); +void nfsrv_cleancache __P((void)); int nfs_connect __P((struct nfsmount *,struct nfsreq *)); -void nfs_disconnect __P((struct nfsmount *nmp)); +void nfs_disconnect __P((struct nfsmount *)); int nfs_getattrcache __P((struct vnode *,struct vattr *)); int nfsm_strtmbuf __P((struct mbuf **,char **,char *,long)); int nfs_bioread __P((struct vnode *,struct uio *,int,struct ucred *)); @@ -531,7 +602,6 @@ int nfsm_uiotombuf __P((struct uio *,struct mbuf **,int,caddr_t *)); void nfsrv_init __P((int)); void nfs_clearcommit __P((struct mount *)); int nfsrv_errmap __P((struct nfsrv_descript *, int)); -void nfsrv_rcv __P((struct socket *so, caddr_t arg, int waitflag)); void nfsrvw_sort __P((gid_t [],int)); void nfsrv_setcred __P((struct ucred *,struct ucred *)); int nfs_writebp __P((struct buf *,int)); @@ -594,8 +664,8 @@ int nfsrv_symlink __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_write __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); - - +void nfsrv_rcv __P((struct socket *so, caddr_t arg, int waitflag)); +void nfsrv_slpderef __P((struct nfssvc_sock *slp)); #endif /* KERNEL */ #endif diff --git a/sys/nfs/nfs_bio.c b/sys/nfs/nfs_bio.c index d67a3c0..0f636b0 100644 --- a/sys/nfs/nfs_bio.c +++ b/sys/nfs/nfs_bio.c @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_bio.c 8.5 (Berkeley) 1/4/94 + * @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95 * $FreeBSD$ */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/resourcevar.h> @@ -66,19 +67,6 @@ extern int nfs_numasync; extern struct nfsstats nfsstats; /* - * Ifdefs for FreeBSD-current's merged VM/buffer cache. It is unfortunate - * that this isn't done inside getblk() and brelse() so these calls - * wouldn't need to be here. - */ -#ifdef B_VMIO -#define vnode_pager_uncache(vp) -#else -#define vfs_busy_pages(bp, f) -#define vfs_unbusy_pages(bp) -#define vfs_dirty_pages(bp) -#endif - -/* * Vnode op for read using bio * Any similarity to readip() is purely coincidental */ @@ -195,7 +183,7 @@ nfs_bioread(vp, uio, ioflag, cred) case VDIR: break; default: - printf(" NQNFSNONCACHE: type %x unexpected\n", + printf(" NQNFSNONCACHE: type %x unexpected\n", vp->v_type); }; } @@ -225,9 +213,8 @@ nfs_bioread(vp, uio, ioflag, cred) vfs_unbusy_pages(rabp); brelse(rabp); } - } else { + } else brelse(rabp); - } } } } @@ -270,6 +257,7 @@ again: if (not_readin && n > 0) { if (on < bp->b_validoff || (on + n) > bp->b_validend) { bp->b_flags |= B_NOCACHE; + bp->b_flags |= B_INVAFTERWRITE; if (bp->b_dirtyend > 0) { if ((bp->b_flags & B_DELWRI) == 0) panic("nfsbioread"); @@ -475,10 +463,6 @@ nfs_write(ap) */ biosize = vp->v_mount->mnt_stat.f_iosize; do { - - /* - * XXX make sure we aren't cached in the VM page cache - */ /* * Check for a valid write lease. */ diff --git a/sys/nfs/nfs_common.c b/sys/nfs/nfs_common.c index 1feadd6..5f83bf5 100644 --- a/sys/nfs/nfs_common.c +++ b/sys/nfs/nfs_common.c @@ -100,6 +100,7 @@ enum vtype nv3tov_type[8]= { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; +int nfs_mount_type; int nfs_ticks; struct nfs_reqq nfs_reqq; @@ -1093,7 +1094,8 @@ nfsm_strtmbuf(mb, bpos, cp, siz) * Called once to initialize data structures... */ int -nfs_init() +nfs_init(vfsp) + struct vfsconf *vfsp; { register int i; @@ -1116,6 +1118,7 @@ nfs_init() printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC); printf("Try unionizing the nu_nickname and nu_flag fields\n"); } + nfs_mount_type = vfsp->vfc_typenum; nfsrtt.pos = 0; rpc_vers = txdr_unsigned(RPC_VER2); rpc_call = txdr_unsigned(RPC_CALL); @@ -1170,10 +1173,10 @@ nfs_init() * of the system can call us, if we are loadable. */ #ifndef NFS_NOSERVER - lease_check = nfs_lease_check; + lease_check_hook = nqnfs_vop_lease_check; #endif lease_updatetime = nfs_lease_updatetime; - vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */ + vfsp->vfc_refcount++; /* make us non-unloadable */ #ifdef VFS_LKM sysent[SYS_nfssvc].sy_narg = 2; sysent[SYS_nfssvc].sy_call = nfssvc; @@ -1212,7 +1215,6 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) register struct vattr *vap; register struct nfs_fattr *fp; register struct nfsnode *np; - register struct nfsnodehashhead *nhpp; register long t1; caddr_t cp2; int error = 0, rdev; @@ -1222,6 +1224,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) struct timespec mtime; struct vnode *nvp; int v3 = NFS_ISV3(vp); + struct proc *p = curproc; md = *mdp; t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; @@ -1284,7 +1287,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) * then release it here. */ if (vtyp != VREG && VOP_ISLOCKED(vp)) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); vp->v_type = vtyp; if (vp->v_type == VFIFO) { vp->v_op = fifo_nfsv2nodeop_p; @@ -1295,8 +1298,11 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) if (nvp) { /* * Discard unneeded vnode, but save its nfsnode. + * Since the nfsnode does not have a lock, its + * vnode lock has to be carried over. */ - LIST_REMOVE(np, n_hash); + nvp->v_vnlock = vp->v_vnlock; + vp->v_vnlock = NULL; nvp->v_data = vp->v_data; vp->v_data = NULL; vp->v_op = spec_vnodeop_p; @@ -1306,8 +1312,6 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) * Reinitialize aliased node. */ np->n_vnode = nvp; - nhpp = NFSNOHASH(nfs_hash(np->n_fhp, np->n_fhsize)); - LIST_INSERT_HEAD(nhpp, np, n_hash); *vpp = vp = nvp; } } @@ -1714,13 +1718,14 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) int *rdonlyp; int kerbflag; { + struct proc *p = curproc; /* XXX */ register struct mount *mp; register int i; struct ucred *credanon; int error, exflags; *vpp = (struct vnode *)0; - mp = getvfs(&fhp->fh_fsid); + mp = vfs_getvfs(&fhp->fh_fsid); if (!mp) return (ESTALE); error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); @@ -1751,7 +1756,7 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) nfsrv_object_create(*vpp); if (!lockflag) - VOP_UNLOCK(*vpp); + VOP_UNLOCK(*vpp, 0, p); return (0); } @@ -1947,3 +1952,4 @@ nfsrv_object_create(struct vnode *vp) { return vfs_object_create(vp, curproc, curproc?curproc->p_ucred:NULL, 1); } #endif /* NFS_NOSERVER */ + diff --git a/sys/nfs/nfs_common.h b/sys/nfs/nfs_common.h index ac1a159..cd37c59 100644 --- a/sys/nfs/nfs_common.h +++ b/sys/nfs/nfs_common.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsm_subs.h 8.1 (Berkeley) 6/16/93 + * @(#)nfsm_subs.h 8.2 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_NFSM_SUBS_H_ #define _NFS_NFSM_SUBS_H_ diff --git a/sys/nfs/nfs_node.c b/sys/nfs/nfs_node.c index 2ddb4a6..8403f55 100644 --- a/sys/nfs/nfs_node.c +++ b/sys/nfs/nfs_node.c @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_node.c 8.2 (Berkeley) 12/30/93 + * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95 * $FreeBSD$ */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/proc.h> @@ -108,7 +109,8 @@ nfs_nget(mntp, fhp, fhsize, npp) int fhsize; struct nfsnode **npp; { - register struct nfsnode *np; + struct proc *p = curproc; /* XXX */ + struct nfsnode *np; struct nfsnodehashhead *nhpp; register struct vnode *vp; struct vnode *nvp; @@ -121,7 +123,7 @@ loop: bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize)) continue; vp = NFSTOV(np); - if (vget(vp, 1)) + if (vget(vp, LK_EXCLUSIVE, p)) goto loop; *npp = np; return(0); @@ -178,7 +180,7 @@ loop: /* * Lock the new nfsnode. */ - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); return (0); } @@ -187,6 +189,7 @@ int nfs_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { register struct nfsnode *np; @@ -213,6 +216,7 @@ nfs_inactive(ap) } np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NQNFSEVICTED | NQNFSNONCACHE | NQNFSWRITE); + VOP_UNLOCK(ap->a_vp, 0, ap->a_p); return (0); } @@ -265,6 +269,7 @@ nfs_reclaim(ap) return (0); } +#if 0 /* * Lock an nfsnode */ @@ -355,6 +360,7 @@ nfs_islocked(ap) { return VTONFS(ap->a_vp)->n_flag & NLOCKED ? 1 : 0; } +#endif /* * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually diff --git a/sys/nfs/nfs_nqlease.c b/sys/nfs/nfs_nqlease.c index 2fa8360..1740b82 100644 --- a/sys/nfs/nfs_nqlease.c +++ b/sys/nfs/nfs_nqlease.c @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_nqlease.c 8.3 (Berkeley) 1/4/94 + * @(#)nfs_nqlease.c 8.9 (Berkeley) 5/20/95 * $FreeBSD$ */ + /* * References: * Cary G. Gray and David R. Cheriton, "Leases: An Efficient Fault-Tolerant @@ -84,11 +85,8 @@ struct vop_lease_args; static int nqsrv_cmpnam __P((struct nfssvc_sock *,struct mbuf *, struct nqhost *)); -extern void nqnfs_lease_check __P((struct vnode *vp, struct proc *p, - struct ucred *cred, int flag)); extern void nqnfs_lease_updatetime __P((int deltat)); static int nqnfs_vacated __P((struct vnode *vp, struct ucred *cred)); -extern int nqnfs_vop_lease_check __P((struct vop_lease_args *ap)); static void nqsrv_addhost __P((struct nqhost *lph, struct nfssvc_sock *slp, struct mbuf *nam)); static void nqsrv_instimeq __P((struct nqlease *lp, u_long duration)); @@ -136,6 +134,7 @@ extern nfstype nfsv3_type[9]; extern struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock; extern int nfsd_waiting; extern struct nfsstats nfsstats; +extern int nfs_mount_type; #define TRUE 1 #define FALSE 0 @@ -349,7 +348,6 @@ nqnfs_lease_check(vp, p, cred, flag) #endif /* NFS_NOSERVER */ -#ifdef HAS_VOPLEASE int nqnfs_vop_lease_check(ap) struct vop_lease_args /* { @@ -367,7 +365,6 @@ nqnfs_vop_lease_check(ap) NQLOCALSLP, ap->a_p, (struct mbuf *)0, &cache, &frev, ap->a_cred); return (0); } -#endif /* * Add a host to an nqhost structure for a lease. @@ -1090,7 +1087,7 @@ nqnfs_clientd(nmp, cred, ncd, flag, argp, p) vp = NFSTOV(np); vpid = vp->v_id; if (np->n_expiry < time.tv_sec) { - if (vget(vp, 1) == 0) { + if (vget(vp, LK_EXCLUSIVE, p) == 0) { nmp->nm_inprog = vp; if (vpid == vp->v_id) { CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer); @@ -1115,7 +1112,7 @@ nqnfs_clientd(nmp, cred, ncd, flag, argp, p) } else if ((np->n_expiry - NQ_RENEWAL) < time.tv_sec) { if ((np->n_flag & (NQNFSWRITE | NQNFSNONCACHE)) == NQNFSWRITE && vp->v_dirtyblkhd.lh_first && - vget(vp, 1) == 0) { + vget(vp, LK_EXCLUSIVE, p) == 0) { nmp->nm_inprog = vp; if (vpid == vp->v_id && nqnfs_getlease(vp, ND_WRITE, cred, p)==0) @@ -1179,9 +1176,10 @@ void nqnfs_lease_updatetime(deltat) register int deltat; { - register struct nqlease *lp; - register struct nfsnode *np; - struct mount *mp; + struct proc *p = curproc; /* XXX */ + struct nqlease *lp; + struct nfsnode *np; + struct mount *mp, *nxtmp; struct nfsmount *nmp; int s; @@ -1197,13 +1195,13 @@ nqnfs_lease_updatetime(deltat) * Search the mount list for all nqnfs mounts and do their timer * queues. */ - for (mp = mountlist.cqh_first; mp != (void *)&mountlist; - mp = mp->mnt_list.cqe_next) { -#ifdef __NetBSD__ - if (!strcmp(&mp->mnt_stat.f_fstypename[0], MOUNT_NFS)) { -#else - if (mp->mnt_stat.f_fsid.val[1] == MOUNT_NFS) { -#endif + simple_lock(&mountlist_slock); + for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nxtmp) { + if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { + nxtmp = mp->mnt_list.cqe_next; + continue; + } + if (mp->mnt_stat.f_type == nfs_mount_type) { nmp = VFSTONFS(mp); if (nmp->nm_flag & NFSMNT_NQNFS) { for (np = nmp->nm_timerhead.cqh_first; @@ -1213,7 +1211,11 @@ nqnfs_lease_updatetime(deltat) } } } + simple_lock(&mountlist_slock); + nxtmp = mp->mnt_list.cqe_next; + vfs_unbusy(mp, p); } + simple_unlock(&mountlist_slock); } /* diff --git a/sys/nfs/nfs_serv.c b/sys/nfs/nfs_serv.c index 3946778..28a705a 100644 --- a/sys/nfs/nfs_serv.c +++ b/sys/nfs/nfs_serv.c @@ -1723,7 +1723,7 @@ nfsrv_remove(nfsd, slp, procp, mrq) } out: if (!error) { - vnode_pager_uncache(vp); + vnode_pager_uncache(vp, procp); nqsrv_getl(nd.ni_dvp, ND_WRITE); nqsrv_getl(vp, ND_WRITE); @@ -1900,7 +1900,7 @@ out: nqsrv_getl(tdvp, ND_WRITE); if (tvp) { nqsrv_getl(tvp, ND_WRITE); - (void) vnode_pager_uncache(tvp); + (void) vnode_pager_uncache(tvp, procp); } error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); @@ -2027,11 +2027,7 @@ out: if (!error) { nqsrv_getl(vp, ND_WRITE); nqsrv_getl(xp, ND_WRITE); -#if defined(__NetBSD__) || defined(__FreeBSD__) - error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); -#else error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd); -#endif } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == nd.ni_vp) @@ -2479,7 +2475,7 @@ nfsrv_readdir(nfsd, slp, procp, mrq) int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies; int v3 = (nfsd->nd_flag & ND_NFSV3); u_quad_t frev, off, toff, verf; - u_int *cookies = NULL, *cookiep; + u_long *cookies = NULL, *cookiep; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); @@ -2520,7 +2516,7 @@ nfsrv_readdir(nfsd, slp, procp, mrq) nfsm_srvpostop_attr(getret, &at); return (0); } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, procp); MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); #ifdef __NetBSD__ ncookies = siz / (5 * NFSX_UNSIGNED); /*7 for V3, but it's an est. so*/ @@ -2538,16 +2534,12 @@ again: io.uio_rw = UIO_READ; io.uio_procp = (struct proc *)0; eofflag = 0; - VOP_LOCK(vp); -#ifndef __NetBSD__ + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp); if (cookies) { free((caddr_t)cookies, M_TEMP); cookies = NULL; } error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); -#else - error = VOP_READDIR(vp, &io, cred, &eofflag, cookies, ncookies); -#endif off = (off_t)io.uio_offset; if (!cookies && !error) error = NFSERR_PERM; @@ -2556,7 +2548,7 @@ again: if (!error) error = getret; } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, procp); if (error) { vrele(vp); free((caddr_t)rbuf, M_TEMP); @@ -2751,7 +2743,7 @@ nfsrv_readdirplus(nfsd, slp, procp, mrq) int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies; u_quad_t frev, off, toff, verf; - u_int *cookies = NULL, *cookiep; + u_long *cookies = NULL, *cookiep; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); @@ -2787,7 +2779,7 @@ nfsrv_readdirplus(nfsd, slp, procp, mrq) nfsm_srvpostop_attr(getret, &at); return (0); } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, procp); MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); #ifdef __NetBSD__ ncookies = siz / (7 * NFSX_UNSIGNED); @@ -2805,19 +2797,15 @@ again: io.uio_rw = UIO_READ; io.uio_procp = (struct proc *)0; eofflag = 0; - VOP_LOCK(vp); -#ifndef __NetBSD__ + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp); if (cookies) { free((caddr_t)cookies, M_TEMP); cookies = NULL; } error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); -#else - error = VOP_READDIR(vp, &io, cred, &eofflag, cookies, ncookies); -#endif off = (u_quad_t)io.uio_offset; getret = VOP_GETATTR(vp, &at, cred, procp); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, procp); if (!cookies && !error) error = NFSERR_PERM; if (!error) diff --git a/sys/nfs/nfs_socket.c b/sys/nfs/nfs_socket.c index addd59f..ed16333 100644 --- a/sys/nfs/nfs_socket.c +++ b/sys/nfs/nfs_socket.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1991, 1993 + * Copyright (c) 1989, 1991, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_socket.c 8.3 (Berkeley) 1/12/94 + * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95 * $FreeBSD$ */ @@ -1925,6 +1925,9 @@ nfs_getreq(nd, nfsd, has_header) struct mbuf *mrep, *md; register struct nfsuid *nuidp; struct timeval tvin, tvout; +#if 0 /* until encrypted keys are implemented */ + NFSKERBKEYSCHED_T keys; /* stores key schedule */ +#endif mrep = nd->nd_mrep; md = nd->nd_md; diff --git a/sys/nfs/nfs_srvcache.c b/sys/nfs/nfs_srvcache.c index 835ec06..efff221 100644 --- a/sys/nfs/nfs_srvcache.c +++ b/sys/nfs/nfs_srvcache.c @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_srvcache.c 8.1 (Berkeley) 6/10/93 + * @(#)nfs_srvcache.c 8.3 (Berkeley) 3/30/95 * $FreeBSD$ */ diff --git a/sys/nfs/nfs_subs.c b/sys/nfs/nfs_subs.c index 1feadd6..5f83bf5 100644 --- a/sys/nfs/nfs_subs.c +++ b/sys/nfs/nfs_subs.c @@ -100,6 +100,7 @@ enum vtype nv3tov_type[8]= { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; +int nfs_mount_type; int nfs_ticks; struct nfs_reqq nfs_reqq; @@ -1093,7 +1094,8 @@ nfsm_strtmbuf(mb, bpos, cp, siz) * Called once to initialize data structures... */ int -nfs_init() +nfs_init(vfsp) + struct vfsconf *vfsp; { register int i; @@ -1116,6 +1118,7 @@ nfs_init() printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC); printf("Try unionizing the nu_nickname and nu_flag fields\n"); } + nfs_mount_type = vfsp->vfc_typenum; nfsrtt.pos = 0; rpc_vers = txdr_unsigned(RPC_VER2); rpc_call = txdr_unsigned(RPC_CALL); @@ -1170,10 +1173,10 @@ nfs_init() * of the system can call us, if we are loadable. */ #ifndef NFS_NOSERVER - lease_check = nfs_lease_check; + lease_check_hook = nqnfs_vop_lease_check; #endif lease_updatetime = nfs_lease_updatetime; - vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */ + vfsp->vfc_refcount++; /* make us non-unloadable */ #ifdef VFS_LKM sysent[SYS_nfssvc].sy_narg = 2; sysent[SYS_nfssvc].sy_call = nfssvc; @@ -1212,7 +1215,6 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) register struct vattr *vap; register struct nfs_fattr *fp; register struct nfsnode *np; - register struct nfsnodehashhead *nhpp; register long t1; caddr_t cp2; int error = 0, rdev; @@ -1222,6 +1224,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) struct timespec mtime; struct vnode *nvp; int v3 = NFS_ISV3(vp); + struct proc *p = curproc; md = *mdp; t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; @@ -1284,7 +1287,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) * then release it here. */ if (vtyp != VREG && VOP_ISLOCKED(vp)) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); vp->v_type = vtyp; if (vp->v_type == VFIFO) { vp->v_op = fifo_nfsv2nodeop_p; @@ -1295,8 +1298,11 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) if (nvp) { /* * Discard unneeded vnode, but save its nfsnode. + * Since the nfsnode does not have a lock, its + * vnode lock has to be carried over. */ - LIST_REMOVE(np, n_hash); + nvp->v_vnlock = vp->v_vnlock; + vp->v_vnlock = NULL; nvp->v_data = vp->v_data; vp->v_data = NULL; vp->v_op = spec_vnodeop_p; @@ -1306,8 +1312,6 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) * Reinitialize aliased node. */ np->n_vnode = nvp; - nhpp = NFSNOHASH(nfs_hash(np->n_fhp, np->n_fhsize)); - LIST_INSERT_HEAD(nhpp, np, n_hash); *vpp = vp = nvp; } } @@ -1714,13 +1718,14 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) int *rdonlyp; int kerbflag; { + struct proc *p = curproc; /* XXX */ register struct mount *mp; register int i; struct ucred *credanon; int error, exflags; *vpp = (struct vnode *)0; - mp = getvfs(&fhp->fh_fsid); + mp = vfs_getvfs(&fhp->fh_fsid); if (!mp) return (ESTALE); error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); @@ -1751,7 +1756,7 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) nfsrv_object_create(*vpp); if (!lockflag) - VOP_UNLOCK(*vpp); + VOP_UNLOCK(*vpp, 0, p); return (0); } @@ -1947,3 +1952,4 @@ nfsrv_object_create(struct vnode *vp) { return vfs_object_create(vp, curproc, curproc?curproc->p_ucred:NULL, 1); } #endif /* NFS_NOSERVER */ + diff --git a/sys/nfs/nfs_syscalls.c b/sys/nfs/nfs_syscalls.c index 734fe79..24d4bd6 100644 --- a/sys/nfs/nfs_syscalls.c +++ b/sys/nfs/nfs_syscalls.c @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_syscalls.c 8.3 (Berkeley) 1/4/94 + * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 * $FreeBSD$ */ @@ -97,7 +97,6 @@ static int nfssvc_iod __P((struct proc *)); static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; - #ifndef NFS_NOSERVER int nfsd_waiting = 0; static struct nfsdrt nfsdrt; @@ -1051,6 +1050,7 @@ nfsmout: } #ifndef NFS_NOSERVER + /* * Derefence a server socket structure. If it has no more references and * is no longer valid, you can throw it away. diff --git a/sys/nfs/nfs_vfsops.c b/sys/nfs/nfs_vfsops.c index 937c2d5..06457f1 100644 --- a/sys/nfs/nfs_vfsops.c +++ b/sys/nfs/nfs_vfsops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1993 + * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_vfsops.c 8.3 (Berkeley) 1/4/94 + * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95 * $FreeBSD$ */ @@ -121,7 +121,7 @@ static struct vfsops nfs_vfsops = { nfs_vget, nfs_fhtovp, nfs_vptofh, - nfs_init, + nfs_init }; VFS_SET(nfs_vfsops, nfs, MOUNT_NFS, VFCF_NETWORK); @@ -152,8 +152,10 @@ SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_swapaddr, CTLFLAG_RD, void nfsargs_ntoh __P((struct nfs_args *)); -static struct mount *nfs_mountdiskless __P((char *, char *, int, - struct sockaddr_in *, struct nfs_args *, register struct vnode **)); +static int nfs_mountdiskless __P((char *, char *, int, + struct sockaddr_in *, struct nfs_args *, + struct proc *, struct vnode **, + struct mount **)); static int nfs_iosize(nmp) struct nfsmount* nmp; @@ -329,8 +331,8 @@ nfs_fsinfo(nmp, vp, cred, p) int nfs_mountroot() { - register struct mount *mp; - register struct nfs_diskless *nd = &nfs_diskless; + struct mount *mp, *swap_mp; + struct nfs_diskless *nd = &nfs_diskless; struct socket *so; struct vnode *vp; struct proc *p = curproc; /* XXX */ @@ -406,6 +408,7 @@ nfs_mountroot() panic("nfs_mountroot: RTM_ADD: %d", error); } + swap_mp = NULL; if (nd->swap_nblks) { /* Convert to DEV_BSIZE instead of Kilobyte */ @@ -426,8 +429,10 @@ nfs_mountroot() (l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, (l >> 0) & 0xff,nd->swap_hostnam); printf("NFS SWAP: %s\n",buf); - (void) nfs_mountdiskless(buf, "/swap", 0, - &nd->swap_saddr, &nd->swap_args, &vp); + if (error = nfs_mountdiskless(buf, "/swap", 0, + &nd->swap_saddr, &nd->swap_args, p, &vp, &swap_mp)) + return (error); + vfs_unbusy(swap_mp, p); VTONFS(vp)->n_size = VTONFS(vp)->n_vattr.va_size = nd->swap_nblks * DEV_BSIZE ; @@ -455,16 +460,22 @@ nfs_mountroot() (l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, (l >> 0) & 0xff,nd->root_hostnam); printf("NFS ROOT: %s\n",buf); - mp = nfs_mountdiskless(buf, "/", MNT_RDONLY, - &nd->root_saddr, &nd->root_args, &vp); + if (error = nfs_mountdiskless(buf, "/", MNT_RDONLY, + &nd->root_saddr, &nd->root_args, p, &vp, &mp)) { + if (swap_mp) { + mp->mnt_vfc->vfc_refcount--; + free(swap_mp, M_MOUNT); + } + return (error); + } - if (vfs_lock(mp)) - panic("nfs_mountroot: vfs_lock"); + simple_lock(&mountlist_slock); CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); + simple_unlock(&mountlist_slock); mp->mnt_flag |= MNT_ROOTFS; mp->mnt_vnodecovered = NULLVP; - vfs_unlock(mp); rootvp = vp; + vfs_unbusy(mp, p); /* * This is not really an nfs issue, but it is much easier to @@ -483,39 +494,65 @@ nfs_mountroot() /* * Internal version of mount system call for diskless setup. */ -static struct mount * -nfs_mountdiskless(path, which, mountflag, sin, args, vpp) +static int +nfs_mountdiskless(path, which, mountflag, sin, args, p, vpp, mpp) char *path; char *which; int mountflag; struct sockaddr_in *sin; struct nfs_args *args; - register struct vnode **vpp; + struct proc *p; + struct vnode **vpp; + struct mount **mpp; { - register struct mount *mp; - register struct mbuf *m; - register int error; - - mp = (struct mount *)malloc((u_long)sizeof(struct mount), - M_MOUNT, M_NOWAIT); - if (mp == NULL) - panic("nfs_mountroot: %s mount malloc", which); - bzero((char *)mp, (u_long)sizeof(struct mount)); - mp->mnt_op = &nfs_vfsops; - mp->mnt_flag = mountflag; + struct mount *mp; + struct mbuf *m; + int error; - MGET(m, MT_SONAME, M_DONTWAIT); - if (m == NULL) - panic("nfs_mountroot: %s mount mbuf", which); + if (error = vfs_rootmountalloc("nfs", path, &mp)) { + printf("nfs_mountroot: NFS not configured"); + return (error); + } + mp->mnt_flag = mountflag; + MGET(m, MT_SONAME, M_WAITOK); bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len); m->m_len = sin->sin_len; - error = mountnfs(args, mp, m, which, path, vpp); - if (error) - panic("nfs_mountroot: mount %s on %s: %d", path, which, error); - - return (mp); + if (error = mountnfs(args, mp, m, which, path, vpp)) { + printf("nfs_mountroot: mount %s on %s: %d", path, which, error); + mp->mnt_vfc->vfc_refcount--; + vfs_unbusy(mp, p); + free(mp, M_MOUNT); + return (error); + } + (void) copystr(which, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0); + *mpp = mp; + return (0); } +#ifdef COMPAT_PRELITE2 +/* + * Old arguments to mount NFS + */ +struct onfs_args { + struct sockaddr *addr; /* file server address */ + int addrlen; /* length of address */ + int sotype; /* Socket type */ + int proto; /* and Protocol */ + u_char *fh; /* File handle to be mounted */ + int fhsize; /* Size, in bytes, of fh */ + int flags; /* flags */ + int wsize; /* write size in bytes */ + int rsize; /* read size in bytes */ + int readdirsize; /* readdir size in bytes */ + int timeo; /* initial timeout in .1 secs */ + int retrans; /* times to retry send */ + int maxgrouplist; /* Max. size of group list */ + int readahead; /* # of blocks to readahead */ + int leaseterm; /* Term (sec) of lease */ + int deadthresh; /* Retrans threshold */ + char *hostname; /* server's name */ +}; +#endif /* * VFS Operations. @@ -546,6 +583,39 @@ nfs_mount(mp, path, data, ndp, p) error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)); if (error) return (error); + if (args.version != NFS_ARGSVERSION) { +#ifdef COMPAT_PRELITE2 + /* + * If the argument version is unknown, then assume the + * caller is a pre-lite2 4.4BSD client and convert its + * arguments. + */ + struct onfs_args oargs; + error = copyin(data, (caddr_t)&oargs, sizeof (struct onfs_args)); + if (error) + return (error); + args.version = NFS_ARGSVERSION; + args.addr = oargs.addr; + args.addrlen = oargs.addrlen; + args.sotype = oargs.sotype; + args.proto = oargs.proto; + args.fh = oargs.fh; + args.fhsize = oargs.fhsize; + args.flags = oargs.flags; + args.wsize = oargs.wsize; + args.rsize = oargs.rsize; + args.readdirsize = oargs.readdirsize; + args.timeo = oargs.timeo; + args.retrans = oargs.retrans; + args.maxgrouplist = oargs.maxgrouplist; + args.readahead = oargs.readahead; + args.leaseterm = oargs.leaseterm; + args.deadthresh = oargs.deadthresh; + args.hostname = oargs.hostname; +#else /* COMPAT_PRELITE2 */ + return (EPROGMISMATCH); +#endif /* COMPAT_PRELITE2 */ + } error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize); if (error) return (error); @@ -595,7 +665,7 @@ mountnfs(argp, mp, nam, pth, hst, vpp) TAILQ_INIT(&nmp->nm_bufq); mp->mnt_data = (qaddr_t)nmp; } - getnewfsid(mp, MOUNT_NFS); + vfs_getnewfsid(mp); nmp->nm_mountp = mp; nmp->nm_flag = argp->flags; if (nmp->nm_flag & NFSMNT_NQNFS) @@ -619,15 +689,6 @@ mountnfs(argp, mp, nam, pth, hst, vpp) nmp->nm_inprog = NULLVP; nmp->nm_fhsize = argp->fhsize; bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); -#ifdef __NetBSD__ -#ifdef COMPAT_09 - mp->mnt_stat.f_type = 2; -#else - mp->mnt_stat.f_type = 0; -#endif -#else - mp->mnt_stat.f_type = MOUNT_NFS; -#endif bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); nmp->nm_nam = nam; @@ -741,7 +802,7 @@ mountnfs(argp, mp, nam, pth, hst, vpp) /* * Lose the lock but keep the ref. */ - VOP_UNLOCK(*vpp); + VOP_UNLOCK(*vpp, 0, curproc); return (0); bad: @@ -765,11 +826,8 @@ nfs_unmount(mp, mntflags, p) struct vnode *vp; int error, flags = 0; - if (mntflags & MNT_FORCE) { - if (!doforce) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } nmp = VFSTONFS(mp); /* * Goes something like this.. @@ -846,7 +904,7 @@ nfs_root(mp, vpp) if (error) return (error); vp = NFSTOV(np); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, curproc); if (vp->v_type == VNON) vp->v_type = VDIR; vp->v_flag = VROOT; @@ -885,7 +943,7 @@ loop: goto loop; if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL) continue; - if (vget(vp, 1)) + if (vget(vp, LK_EXCLUSIVE, p)) goto loop; error = VOP_FSYNC(vp, cred, waitfor, p); if (error) @@ -969,4 +1027,3 @@ nfs_quotactl(mp, cmd, uid, arg, p) return (EOPNOTSUPP); } - diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c index b8ff396..905bb22 100644 --- a/sys/nfs/nfs_vnops.c +++ b/sys/nfs/nfs_vnops.c @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_vnops.c 8.5 (Berkeley) 2/13/94 + * @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95 * $FreeBSD$ */ + /* * vnode op calls for Sun NFS version 2 and 3 */ @@ -151,14 +152,10 @@ static struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { { &vop_setattr_desc, (vop_t *)nfs_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)nfs_read }, /* read */ { &vop_write_desc, (vop_t *)nfs_write }, /* write */ -#ifdef HAS_VOPLEASE { &vop_lease_desc, (vop_t *)nfs_lease_check }, /* lease */ -#endif { &vop_ioctl_desc, (vop_t *)nfs_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)nfs_select }, /* select */ -#ifdef HAS_VOPREVOKE { &vop_revoke_desc, (vop_t *)nfs_revoke }, /* revoke */ -#endif { &vop_mmap_desc, (vop_t *)nfs_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)nfs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)nfs_seek }, /* seek */ @@ -212,14 +209,10 @@ static struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { { &vop_setattr_desc, (vop_t *)nfs_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)nfsspec_read }, /* read */ { &vop_write_desc, (vop_t *)nfsspec_write }, /* write */ -#ifdef HAS_VOPLEASE { &vop_lease_desc, (vop_t *)spec_lease_check }, /* lease */ -#endif { &vop_ioctl_desc, (vop_t *)spec_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)spec_select }, /* select */ -#ifdef HAS_VOPREVOKE { &vop_revoke_desc, (vop_t *)spec_revoke }, /* revoke */ -#endif { &vop_mmap_desc, (vop_t *)spec_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)nfs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)spec_seek }, /* seek */ @@ -270,14 +263,10 @@ static struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { { &vop_setattr_desc, (vop_t *)nfs_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)nfsfifo_read }, /* read */ { &vop_write_desc, (vop_t *)nfsfifo_write }, /* write */ -#ifdef HAS_VOPLEASE { &vop_lease_desc, (vop_t *)fifo_lease_check }, /* lease */ -#endif { &vop_ioctl_desc, (vop_t *)fifo_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)fifo_select }, /* select */ -#ifdef HAS_VOPREVOKE { &vop_revoke_desc, (vop_t *)fifo_revoke }, /* revoke */ -#endif { &vop_mmap_desc, (vop_t *)fifo_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)nfs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)fifo_seek }, /* seek */ @@ -469,7 +458,7 @@ nfs_open(ap) if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1)) == EINTR) return (error); - (void) vnode_pager_uncache(vp); + (void) vnode_pager_uncache(vp, ap->a_p); np->n_brev = np->n_lrev; } } @@ -588,7 +577,7 @@ nfs_getattr(ap) int error = 0; struct mbuf *mreq, *mrep, *md, *mb, *mb2; int v3 = NFS_ISV3(vp); - + /* * Update local times for special files. */ @@ -634,7 +623,7 @@ nfs_setattr(ap) /* * Disallow write attempts if the filesystem is mounted read-only. */ - if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || + if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && (vp->v_mount->mnt_flag & MNT_RDONLY)) @@ -645,6 +634,8 @@ nfs_setattr(ap) return (EISDIR); case VCHR: case VBLK: + case VSOCK: + case VFIFO: if (vap->va_mtime.tv_sec == VNOVAL && vap->va_atime.tv_sec == VNOVAL && vap->va_mode == (u_short)VNOVAL && @@ -660,20 +651,22 @@ nfs_setattr(ap) */ if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); - if (vap->va_size == 0) + if (np->n_flag & NMODIFIED) { + if (vap->va_size == 0) error = nfs_vinvalbuf(vp, 0, ap->a_cred, ap->a_p, 1); - else + else error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1); - if (error) + if (error) return (error); + } tsize = np->n_size; np->n_size = np->n_vattr.va_size = vap->va_size; vnode_pager_setsize(vp, (u_long)np->n_size); }; } else if ((vap->va_mtime.tv_sec != VNOVAL || - vap->va_atime.tv_sec != VNOVAL) && + vap->va_atime.tv_sec != VNOVAL) && (np->n_flag & NMODIFIED) && vp->v_type == VREG && (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1)) == EINTR) @@ -826,6 +819,7 @@ nfs_lookup(ap) struct nfsnode *np; int lockparent, wantparent, error = 0, attrflag, fhsize; int v3 = NFS_ISV3(dvp); + struct proc *p = cnp->cn_proc; if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) @@ -851,18 +845,18 @@ nfs_lookup(ap) VREF(newvp); error = 0; } else if (flags & ISDOTDOT) { - VOP_UNLOCK(dvp); - error = vget(newvp, 1); + VOP_UNLOCK(dvp, 0, p); + error = vget(newvp, LK_EXCLUSIVE, p); if (!error && lockparent && (flags & ISLASTCN)) - error = VOP_LOCK(dvp); + error = vn_lock(dvp, LK_EXCLUSIVE, p); } else { - error = vget(newvp, 1); + error = vget(newvp, LK_EXCLUSIVE, p); if (!lockparent || error || !(flags & ISLASTCN)) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); } if (!error) { if (vpid == newvp->v_id) { - if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc) + if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, p) && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) { nfsstats.lookupcache_hits++; if (cnp->cn_nameiop != LOOKUP && @@ -874,9 +868,9 @@ nfs_lookup(ap) } vput(newvp); if (lockparent && dvp != newvp && (flags & ISLASTCN)) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); } - error = VOP_LOCK(dvp); + error = vn_lock(dvp, LK_EXCLUSIVE, p); if (error) return (error); *vpp = NULLVP; @@ -920,20 +914,20 @@ nfs_lookup(ap) m_freem(mrep); cnp->cn_flags |= SAVENAME; if (!lockparent) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); return (0); } if (flags & ISDOTDOT) { - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); if (error) { - VOP_LOCK(dvp); + vn_lock(dvp, LK_EXCLUSIVE + LK_RETRY, p); return (error); } newvp = NFSTOV(np); if (lockparent && (flags & ISLASTCN) && - (error = VOP_LOCK(dvp))) { + (error = vn_lock(dvp, LK_EXCLUSIVE, p))) { vput(newvp); return (error); } @@ -946,7 +940,7 @@ nfs_lookup(ap) return (error); } if (!lockparent || !(flags & ISLASTCN)) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); newvp = NFSTOV(np); } if (v3) { @@ -969,7 +963,7 @@ nfs_lookup(ap) if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && (flags & ISLASTCN) && error == ENOENT) { if (!lockparent) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); if (dvp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; else @@ -2110,7 +2104,7 @@ nfs_readdirrpc(vp, uiop, cred) } nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); more_dirs = fxdr_unsigned(int, *tl); - + /* loop thru the dir entries, doctoring them to 4bsd form */ while (more_dirs && bigenough) { if (v3) { @@ -2923,6 +2917,9 @@ loop: } } if (vp->v_dirtyblkhd.lh_first && commit) { +#ifndef DIAGNOSTIC + vprint("nfs_fsync: dirty", vp); +#endif goto loop; } } @@ -3131,7 +3128,7 @@ nfs_writebp(bp, force) * an actual write will have to be scheduled via. VOP_STRATEGY(). * If B_WRITEINPROG is already set, then push it with a write anyhow. */ - if (oldflags & (B_NEEDCOMMIT | B_WRITEINPROG) == B_NEEDCOMMIT) { + if ((oldflags & (B_NEEDCOMMIT | B_WRITEINPROG)) == B_NEEDCOMMIT) { off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff; bp->b_flags |= B_WRITEINPROG; retv = nfs_commit(bp->b_vp, off, bp->b_dirtyend-bp->b_dirtyoff, @@ -3205,7 +3202,7 @@ nfsspec_access(ap) if (cred->cr_uid == 0) return (0); vap = &vattr; - error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p); + error = VOP_GETATTR(vp, vap, cred, ap->a_p); if (error) return (error); /* diff --git a/sys/nfs/nfsdiskless.h b/sys/nfs/nfsdiskless.h index 117548b..4777818 100644 --- a/sys/nfs/nfsdiskless.h +++ b/sys/nfs/nfsdiskless.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsdiskless.h 8.1 (Berkeley) 6/10/93 + * @(#)nfsdiskless.h 8.2 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_NFSDISKLESS_H_ #define _NFS_NFSDISKLESS_H_ @@ -46,8 +47,8 @@ * vnodes plus do a partial ifconfig(8) and route(8) so that the critical net * interface can communicate with the server. * The primary bootstrap is expected to fill in the appropriate fields before - * starting the kernel. Whether or not the swap area is nfs mounted is determined - * by the value in swdevt[0]. (equal to NODEV --> swap over nfs) + * starting the kernel. Whether or not the swap area is nfs mounted is + * determined by the value in swdevt[0]. (equal to NODEV --> swap over nfs) * Currently only works for AF_INET protocols. * NB: All fields are stored in net byte order to avoid hassles with * client/server byte ordering differences. diff --git a/sys/nfs/nfsm_subs.h b/sys/nfs/nfsm_subs.h index ac1a159..cd37c59 100644 --- a/sys/nfs/nfsm_subs.h +++ b/sys/nfs/nfsm_subs.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsm_subs.h 8.1 (Berkeley) 6/16/93 + * @(#)nfsm_subs.h 8.2 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_NFSM_SUBS_H_ #define _NFS_NFSM_SUBS_H_ diff --git a/sys/nfs/nfsmount.h b/sys/nfs/nfsmount.h index ea48bca..1545ada 100644 --- a/sys/nfs/nfsmount.h +++ b/sys/nfs/nfsmount.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsmount.h 8.1 (Berkeley) 6/10/93 + * @(#)nfsmount.h 8.3 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_NFSMOUNT_H_ #define _NFS_NFSMOUNT_H_ diff --git a/sys/nfs/nfsnode.h b/sys/nfs/nfsnode.h index 4408fe2..e52a3dd 100644 --- a/sys/nfs/nfsnode.h +++ b/sys/nfs/nfsnode.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsnode.h 8.4 (Berkeley) 2/13/94 + * @(#)nfsnode.h 8.9 (Berkeley) 5/14/95 * $FreeBSD$ */ + #ifndef _NFS_NFSNODE_H_ #define _NFS_NFSNODE_H_ @@ -161,26 +162,16 @@ extern vop_t **spec_nfsv2nodeop_p; * Prototypes for NFS vnode operations */ int nfs_write __P((struct vop_write_args *)); -#ifdef HAS_VOPLEASE #define nfs_lease_check ((int (*) __P((struct vop_lease_args *)))nullop) -#define nqnfs_vop_lease_check lease_check -#else -#ifdef __FreeBSD__ -#define nqnfs_lease_check nfs_lease_check -#else -#define nqnfs_lease_check lease_check -#endif -#endif -#ifdef HAS_VOPREVOKE +int nqnfs_vop_lease_check __P((struct vop_lease_args *)); #define nfs_revoke vop_revoke -#endif #define nfs_seek ((int (*) __P((struct vop_seek_args *)))nullop) int nfs_abortop __P((struct vop_abortop_args *)); int nfs_inactive __P((struct vop_inactive_args *)); int nfs_reclaim __P((struct vop_reclaim_args *)); -int nfs_lock __P((struct vop_lock_args *)); -int nfs_unlock __P((struct vop_unlock_args *)); -int nfs_islocked __P((struct vop_islocked_args *)); +#define nfs_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock) +#define nfs_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock) +#define nfs_islocked ((int (*) __P((struct vop_islocked_args *)))vop_noislocked) #define nfs_reallocblks \ ((int (*) __P((struct vop_reallocblks_args *)))eopnotsupp) @@ -190,11 +181,7 @@ int nfs_nget __P((struct mount *,nfsfh_t *,int,struct nfsnode **)); nfsuint64 *nfs_getcookie __P((struct nfsnode *, off_t, int)); void nfs_invaldir __P((struct vnode *)); -#ifdef __FreeBSD__ #define nqnfs_lease_updatetime nfs_lease_updatetime -#else -#define nqnfs_lease_updatetime lease_updatetime -#endif #endif /* KERNEL */ diff --git a/sys/nfs/nfsrtt.h b/sys/nfs/nfsrtt.h index 291427f..a67b6c9 100644 --- a/sys/nfs/nfsrtt.h +++ b/sys/nfs/nfsrtt.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsrtt.h 8.1 (Berkeley) 6/10/93 + * @(#)nfsrtt.h 8.2 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_NFSRTT_H_ #define _NFS_NFSRTT_H_ diff --git a/sys/nfs/nfsrvcache.h b/sys/nfs/nfsrvcache.h index 38c9657..2cfa694 100644 --- a/sys/nfs/nfsrvcache.h +++ b/sys/nfs/nfsrvcache.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsrvcache.h 8.1 (Berkeley) 6/10/93 + * @(#)nfsrvcache.h 8.3 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_NFSRVCACHE_H_ #define _NFS_NFSRVCACHE_H_ diff --git a/sys/nfs/nqnfs.h b/sys/nfs/nqnfs.h index af55a23..91942b2 100644 --- a/sys/nfs/nqnfs.h +++ b/sys/nfs/nqnfs.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nqnfs.h 8.1 (Berkeley) 6/10/93 + * @(#)nqnfs.h 8.3 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_NQNFS_H_ #define _NFS_NQNFS_H_ diff --git a/sys/nfs/rpcv2.h b/sys/nfs/rpcv2.h index 418c80d..afe7972 100644 --- a/sys/nfs/rpcv2.h +++ b/sys/nfs/rpcv2.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)rpcv2.h 8.1 (Berkeley) 6/10/93 + * @(#)rpcv2.h 8.2 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_RPCV2_H_ #define _NFS_RPCV2_H_ diff --git a/sys/nfs/xdr_subs.h b/sys/nfs/xdr_subs.h index 46016f2..cbaec88 100644 --- a/sys/nfs/xdr_subs.h +++ b/sys/nfs/xdr_subs.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)xdr_subs.h 8.1 (Berkeley) 6/10/93 + * @(#)xdr_subs.h 8.3 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_XDR_SUBS_H_ #define _NFS_XDR_SUBS_H_ diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h index db41859..73a018c 100644 --- a/sys/nfsclient/nfs.h +++ b/sys/nfsclient/nfs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1993 + * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -33,19 +33,19 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs.h 8.1 (Berkeley) 6/10/93 + * @(#)nfs.h 8.4 (Berkeley) 5/1/95 * $FreeBSD$ */ #ifndef _NFS_NFS_H_ #define _NFS_NFS_H_ -#include <nfs/rpcv2.h> - /* * Tunable constants for nfs */ +#ifdef KERNEL + #define NFS_MAXIOVEC 34 #define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */ #define NFS_HZ (hz / nfs_ticks) /* Ticks/sec */ @@ -69,7 +69,7 @@ #define NFS_DEFRAHEAD 1 /* Def. read ahead # blocks */ #define NFS_MAXRAHEAD 4 /* Max. read ahead # blocks */ #define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */ -#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runnable */ +#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */ #define NFS_MAXGATHERDELAY 100 /* Max. write gather delay (msec) */ #ifndef NFS_GATHERDELAY #define NFS_GATHERDELAY 10 /* Default write gather delay (msec) */ @@ -89,30 +89,9 @@ /* * XXX - * sys/buf.h should be edited to change B_APPENDWRITE --> B_NEEDCOMMIT, but - * until then... - * Same goes for sys/malloc.h, which needs M_NFSDIROFF, - * M_NFSRVDESC and M_NFSBIGFH added. - * The VA_EXCLUSIVE flag should be added for va_vaflags and set for an - * exclusive create. * The B_INVAFTERWRITE flag should be set to whatever is required by the * buffer cache code to say "Invalidate the block after it is written back". */ -#ifndef B_NEEDCOMMIT -#define B_NEEDCOMMIT B_APPENDWRITE -#endif -#ifndef M_NFSRVDESC -#define M_NFSRVDESC M_TEMP -#endif -#ifndef M_NFSDIROFF -#define M_NFSDIROFF M_TEMP -#endif -#ifndef M_NFSBIGFH -#define M_NFSBIGFH M_TEMP -#endif -#ifndef VA_EXCLUSIVE -#define VA_EXCLUSIVE 0 -#endif #ifdef __FreeBSD__ #define B_INVAFTERWRITE B_NOCACHE #else @@ -120,20 +99,6 @@ #endif /* - * These ifdefs try to handle the differences between the various 4.4BSD-Lite - * based vfs interfaces. - * btw: NetBSD-current does have a VOP_LEASDE(), but I don't know how to - * differentiate between NetBSD-1.0 and NetBSD-current, so.. - * I also don't know about BSDi's 2.0 release. - */ -#if !defined(HAS_VOPLEASE) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#define HAS_VOPLEASE 1 -#endif -#if !defined(HAS_VOPREVOKE) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#define HAS_VOPREVOKE 1 -#endif - -/* * The IO_METASYNC flag should be implemented for local file systems. * (Until then, it is nothin at all.) */ @@ -164,13 +129,114 @@ #define NFS_SVCALLOC 256 #define NFS_UIDALLOC 128 +#endif /* KERNEL */ + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ + +/* + * Arguments to mount NFS + */ +#define NFS_ARGSVERSION 3 /* change when nfs_args changes */ +struct nfs_args { + int version; /* args structure version number */ + struct sockaddr *addr; /* file server address */ + int addrlen; /* length of address */ + int sotype; /* Socket type */ + int proto; /* and Protocol */ + u_char *fh; /* File handle to be mounted */ + int fhsize; /* Size, in bytes, of fh */ + int flags; /* flags */ + int wsize; /* write size in bytes */ + int rsize; /* read size in bytes */ + int readdirsize; /* readdir size in bytes */ + int timeo; /* initial timeout in .1 secs */ + int retrans; /* times to retry send */ + int maxgrouplist; /* Max. size of group list */ + int readahead; /* # of blocks to readahead */ + int leaseterm; /* Term (sec) of lease */ + int deadthresh; /* Retrans threshold */ + char *hostname; /* server's name */ +}; + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ + /* * Structures for the nfssvc(2) syscall. Not that anyone but nfsd and mount_nfs * should ever try and use it. */ struct nfsd_args { int sock; /* Socket to serve */ - caddr_t name; /* Client address for connection based sockets */ + caddr_t name; /* Client addr for connection based sockets */ int namelen; /* Length of name */ }; @@ -200,6 +266,10 @@ struct nfsd_cargs { }; /* + * XXX to allow amd to include nfs.h without nfsproto.h + */ +#ifdef NFS_NPROCS +/* * Stats structure */ struct nfsstats { @@ -237,6 +307,7 @@ struct nfsstats { int srvnqnfs_getleases; int srvvop_writes; }; +#endif /* * Flags for nfssvc() system call. @@ -267,7 +338,7 @@ struct nfsstats { * such as SIGALRM will not expect file I/O system calls to be interrupted * by them and break. */ -#if defined(KERNEL) || defined(_KERNEL) +#ifdef KERNEL struct uio; struct buf; struct vattr; struct nameidata; /* XXX */ @@ -482,6 +553,8 @@ extern int nfsd_head_flag; !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ sizeof (struct ucred))) + +int nfs_init __P((struct vfsconf *vfsp)); int nfs_reply __P((struct nfsreq *)); int nfs_getreq __P((struct nfsrv_descript *,struct nfsd *,int)); int nfs_send __P((struct socket *,struct mbuf *,struct mbuf *,struct nfsreq *)); @@ -516,14 +589,12 @@ int nfs_adv __P((struct mbuf **,caddr_t *,int,int)); void nfs_nhinit __P((void)); void nfs_timer __P((void*)); u_long nfs_hash __P((nfsfh_t *,int)); -void nfsrv_slpderef __P((struct nfssvc_sock *slp)); int nfsrv_dorec __P((struct nfssvc_sock *,struct nfsd *,struct nfsrv_descript **)); -void nfsrv_cleancache __P((void)); int nfsrv_getcache __P((struct nfsrv_descript *,struct nfssvc_sock *,struct mbuf **)); -int nfs_init __P((void)); void nfsrv_updatecache __P((struct nfsrv_descript *,int,struct mbuf *)); +void nfsrv_cleancache __P((void)); int nfs_connect __P((struct nfsmount *,struct nfsreq *)); -void nfs_disconnect __P((struct nfsmount *nmp)); +void nfs_disconnect __P((struct nfsmount *)); int nfs_getattrcache __P((struct vnode *,struct vattr *)); int nfsm_strtmbuf __P((struct mbuf **,char **,char *,long)); int nfs_bioread __P((struct vnode *,struct uio *,int,struct ucred *)); @@ -531,7 +602,6 @@ int nfsm_uiotombuf __P((struct uio *,struct mbuf **,int,caddr_t *)); void nfsrv_init __P((int)); void nfs_clearcommit __P((struct mount *)); int nfsrv_errmap __P((struct nfsrv_descript *, int)); -void nfsrv_rcv __P((struct socket *so, caddr_t arg, int waitflag)); void nfsrvw_sort __P((gid_t [],int)); void nfsrv_setcred __P((struct ucred *,struct ucred *)); int nfs_writebp __P((struct buf *,int)); @@ -594,8 +664,8 @@ int nfsrv_symlink __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_write __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); - - +void nfsrv_rcv __P((struct socket *so, caddr_t arg, int waitflag)); +void nfsrv_slpderef __P((struct nfssvc_sock *slp)); #endif /* KERNEL */ #endif diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c index d67a3c0..0f636b0 100644 --- a/sys/nfsclient/nfs_bio.c +++ b/sys/nfsclient/nfs_bio.c @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_bio.c 8.5 (Berkeley) 1/4/94 + * @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95 * $FreeBSD$ */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/resourcevar.h> @@ -66,19 +67,6 @@ extern int nfs_numasync; extern struct nfsstats nfsstats; /* - * Ifdefs for FreeBSD-current's merged VM/buffer cache. It is unfortunate - * that this isn't done inside getblk() and brelse() so these calls - * wouldn't need to be here. - */ -#ifdef B_VMIO -#define vnode_pager_uncache(vp) -#else -#define vfs_busy_pages(bp, f) -#define vfs_unbusy_pages(bp) -#define vfs_dirty_pages(bp) -#endif - -/* * Vnode op for read using bio * Any similarity to readip() is purely coincidental */ @@ -195,7 +183,7 @@ nfs_bioread(vp, uio, ioflag, cred) case VDIR: break; default: - printf(" NQNFSNONCACHE: type %x unexpected\n", + printf(" NQNFSNONCACHE: type %x unexpected\n", vp->v_type); }; } @@ -225,9 +213,8 @@ nfs_bioread(vp, uio, ioflag, cred) vfs_unbusy_pages(rabp); brelse(rabp); } - } else { + } else brelse(rabp); - } } } } @@ -270,6 +257,7 @@ again: if (not_readin && n > 0) { if (on < bp->b_validoff || (on + n) > bp->b_validend) { bp->b_flags |= B_NOCACHE; + bp->b_flags |= B_INVAFTERWRITE; if (bp->b_dirtyend > 0) { if ((bp->b_flags & B_DELWRI) == 0) panic("nfsbioread"); @@ -475,10 +463,6 @@ nfs_write(ap) */ biosize = vp->v_mount->mnt_stat.f_iosize; do { - - /* - * XXX make sure we aren't cached in the VM page cache - */ /* * Check for a valid write lease. */ diff --git a/sys/nfsclient/nfs_nfsiod.c b/sys/nfsclient/nfs_nfsiod.c index 734fe79..24d4bd6 100644 --- a/sys/nfsclient/nfs_nfsiod.c +++ b/sys/nfsclient/nfs_nfsiod.c @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_syscalls.c 8.3 (Berkeley) 1/4/94 + * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 * $FreeBSD$ */ @@ -97,7 +97,6 @@ static int nfssvc_iod __P((struct proc *)); static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; - #ifndef NFS_NOSERVER int nfsd_waiting = 0; static struct nfsdrt nfsdrt; @@ -1051,6 +1050,7 @@ nfsmout: } #ifndef NFS_NOSERVER + /* * Derefence a server socket structure. If it has no more references and * is no longer valid, you can throw it away. diff --git a/sys/nfsclient/nfs_node.c b/sys/nfsclient/nfs_node.c index 2ddb4a6..8403f55 100644 --- a/sys/nfsclient/nfs_node.c +++ b/sys/nfsclient/nfs_node.c @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_node.c 8.2 (Berkeley) 12/30/93 + * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95 * $FreeBSD$ */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/proc.h> @@ -108,7 +109,8 @@ nfs_nget(mntp, fhp, fhsize, npp) int fhsize; struct nfsnode **npp; { - register struct nfsnode *np; + struct proc *p = curproc; /* XXX */ + struct nfsnode *np; struct nfsnodehashhead *nhpp; register struct vnode *vp; struct vnode *nvp; @@ -121,7 +123,7 @@ loop: bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize)) continue; vp = NFSTOV(np); - if (vget(vp, 1)) + if (vget(vp, LK_EXCLUSIVE, p)) goto loop; *npp = np; return(0); @@ -178,7 +180,7 @@ loop: /* * Lock the new nfsnode. */ - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); return (0); } @@ -187,6 +189,7 @@ int nfs_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { register struct nfsnode *np; @@ -213,6 +216,7 @@ nfs_inactive(ap) } np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NQNFSEVICTED | NQNFSNONCACHE | NQNFSWRITE); + VOP_UNLOCK(ap->a_vp, 0, ap->a_p); return (0); } @@ -265,6 +269,7 @@ nfs_reclaim(ap) return (0); } +#if 0 /* * Lock an nfsnode */ @@ -355,6 +360,7 @@ nfs_islocked(ap) { return VTONFS(ap->a_vp)->n_flag & NLOCKED ? 1 : 0; } +#endif /* * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually diff --git a/sys/nfsclient/nfs_socket.c b/sys/nfsclient/nfs_socket.c index addd59f..ed16333 100644 --- a/sys/nfsclient/nfs_socket.c +++ b/sys/nfsclient/nfs_socket.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1991, 1993 + * Copyright (c) 1989, 1991, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_socket.c 8.3 (Berkeley) 1/12/94 + * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95 * $FreeBSD$ */ @@ -1925,6 +1925,9 @@ nfs_getreq(nd, nfsd, has_header) struct mbuf *mrep, *md; register struct nfsuid *nuidp; struct timeval tvin, tvout; +#if 0 /* until encrypted keys are implemented */ + NFSKERBKEYSCHED_T keys; /* stores key schedule */ +#endif mrep = nd->nd_mrep; md = nd->nd_md; diff --git a/sys/nfsclient/nfs_subs.c b/sys/nfsclient/nfs_subs.c index 1feadd6..5f83bf5 100644 --- a/sys/nfsclient/nfs_subs.c +++ b/sys/nfsclient/nfs_subs.c @@ -100,6 +100,7 @@ enum vtype nv3tov_type[8]= { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; +int nfs_mount_type; int nfs_ticks; struct nfs_reqq nfs_reqq; @@ -1093,7 +1094,8 @@ nfsm_strtmbuf(mb, bpos, cp, siz) * Called once to initialize data structures... */ int -nfs_init() +nfs_init(vfsp) + struct vfsconf *vfsp; { register int i; @@ -1116,6 +1118,7 @@ nfs_init() printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC); printf("Try unionizing the nu_nickname and nu_flag fields\n"); } + nfs_mount_type = vfsp->vfc_typenum; nfsrtt.pos = 0; rpc_vers = txdr_unsigned(RPC_VER2); rpc_call = txdr_unsigned(RPC_CALL); @@ -1170,10 +1173,10 @@ nfs_init() * of the system can call us, if we are loadable. */ #ifndef NFS_NOSERVER - lease_check = nfs_lease_check; + lease_check_hook = nqnfs_vop_lease_check; #endif lease_updatetime = nfs_lease_updatetime; - vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */ + vfsp->vfc_refcount++; /* make us non-unloadable */ #ifdef VFS_LKM sysent[SYS_nfssvc].sy_narg = 2; sysent[SYS_nfssvc].sy_call = nfssvc; @@ -1212,7 +1215,6 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) register struct vattr *vap; register struct nfs_fattr *fp; register struct nfsnode *np; - register struct nfsnodehashhead *nhpp; register long t1; caddr_t cp2; int error = 0, rdev; @@ -1222,6 +1224,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) struct timespec mtime; struct vnode *nvp; int v3 = NFS_ISV3(vp); + struct proc *p = curproc; md = *mdp; t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; @@ -1284,7 +1287,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) * then release it here. */ if (vtyp != VREG && VOP_ISLOCKED(vp)) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); vp->v_type = vtyp; if (vp->v_type == VFIFO) { vp->v_op = fifo_nfsv2nodeop_p; @@ -1295,8 +1298,11 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) if (nvp) { /* * Discard unneeded vnode, but save its nfsnode. + * Since the nfsnode does not have a lock, its + * vnode lock has to be carried over. */ - LIST_REMOVE(np, n_hash); + nvp->v_vnlock = vp->v_vnlock; + vp->v_vnlock = NULL; nvp->v_data = vp->v_data; vp->v_data = NULL; vp->v_op = spec_vnodeop_p; @@ -1306,8 +1312,6 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) * Reinitialize aliased node. */ np->n_vnode = nvp; - nhpp = NFSNOHASH(nfs_hash(np->n_fhp, np->n_fhsize)); - LIST_INSERT_HEAD(nhpp, np, n_hash); *vpp = vp = nvp; } } @@ -1714,13 +1718,14 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) int *rdonlyp; int kerbflag; { + struct proc *p = curproc; /* XXX */ register struct mount *mp; register int i; struct ucred *credanon; int error, exflags; *vpp = (struct vnode *)0; - mp = getvfs(&fhp->fh_fsid); + mp = vfs_getvfs(&fhp->fh_fsid); if (!mp) return (ESTALE); error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); @@ -1751,7 +1756,7 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) nfsrv_object_create(*vpp); if (!lockflag) - VOP_UNLOCK(*vpp); + VOP_UNLOCK(*vpp, 0, p); return (0); } @@ -1947,3 +1952,4 @@ nfsrv_object_create(struct vnode *vp) { return vfs_object_create(vp, curproc, curproc?curproc->p_ucred:NULL, 1); } #endif /* NFS_NOSERVER */ + diff --git a/sys/nfsclient/nfs_vfsops.c b/sys/nfsclient/nfs_vfsops.c index 937c2d5..06457f1 100644 --- a/sys/nfsclient/nfs_vfsops.c +++ b/sys/nfsclient/nfs_vfsops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1993 + * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_vfsops.c 8.3 (Berkeley) 1/4/94 + * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95 * $FreeBSD$ */ @@ -121,7 +121,7 @@ static struct vfsops nfs_vfsops = { nfs_vget, nfs_fhtovp, nfs_vptofh, - nfs_init, + nfs_init }; VFS_SET(nfs_vfsops, nfs, MOUNT_NFS, VFCF_NETWORK); @@ -152,8 +152,10 @@ SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_swapaddr, CTLFLAG_RD, void nfsargs_ntoh __P((struct nfs_args *)); -static struct mount *nfs_mountdiskless __P((char *, char *, int, - struct sockaddr_in *, struct nfs_args *, register struct vnode **)); +static int nfs_mountdiskless __P((char *, char *, int, + struct sockaddr_in *, struct nfs_args *, + struct proc *, struct vnode **, + struct mount **)); static int nfs_iosize(nmp) struct nfsmount* nmp; @@ -329,8 +331,8 @@ nfs_fsinfo(nmp, vp, cred, p) int nfs_mountroot() { - register struct mount *mp; - register struct nfs_diskless *nd = &nfs_diskless; + struct mount *mp, *swap_mp; + struct nfs_diskless *nd = &nfs_diskless; struct socket *so; struct vnode *vp; struct proc *p = curproc; /* XXX */ @@ -406,6 +408,7 @@ nfs_mountroot() panic("nfs_mountroot: RTM_ADD: %d", error); } + swap_mp = NULL; if (nd->swap_nblks) { /* Convert to DEV_BSIZE instead of Kilobyte */ @@ -426,8 +429,10 @@ nfs_mountroot() (l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, (l >> 0) & 0xff,nd->swap_hostnam); printf("NFS SWAP: %s\n",buf); - (void) nfs_mountdiskless(buf, "/swap", 0, - &nd->swap_saddr, &nd->swap_args, &vp); + if (error = nfs_mountdiskless(buf, "/swap", 0, + &nd->swap_saddr, &nd->swap_args, p, &vp, &swap_mp)) + return (error); + vfs_unbusy(swap_mp, p); VTONFS(vp)->n_size = VTONFS(vp)->n_vattr.va_size = nd->swap_nblks * DEV_BSIZE ; @@ -455,16 +460,22 @@ nfs_mountroot() (l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, (l >> 0) & 0xff,nd->root_hostnam); printf("NFS ROOT: %s\n",buf); - mp = nfs_mountdiskless(buf, "/", MNT_RDONLY, - &nd->root_saddr, &nd->root_args, &vp); + if (error = nfs_mountdiskless(buf, "/", MNT_RDONLY, + &nd->root_saddr, &nd->root_args, p, &vp, &mp)) { + if (swap_mp) { + mp->mnt_vfc->vfc_refcount--; + free(swap_mp, M_MOUNT); + } + return (error); + } - if (vfs_lock(mp)) - panic("nfs_mountroot: vfs_lock"); + simple_lock(&mountlist_slock); CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); + simple_unlock(&mountlist_slock); mp->mnt_flag |= MNT_ROOTFS; mp->mnt_vnodecovered = NULLVP; - vfs_unlock(mp); rootvp = vp; + vfs_unbusy(mp, p); /* * This is not really an nfs issue, but it is much easier to @@ -483,39 +494,65 @@ nfs_mountroot() /* * Internal version of mount system call for diskless setup. */ -static struct mount * -nfs_mountdiskless(path, which, mountflag, sin, args, vpp) +static int +nfs_mountdiskless(path, which, mountflag, sin, args, p, vpp, mpp) char *path; char *which; int mountflag; struct sockaddr_in *sin; struct nfs_args *args; - register struct vnode **vpp; + struct proc *p; + struct vnode **vpp; + struct mount **mpp; { - register struct mount *mp; - register struct mbuf *m; - register int error; - - mp = (struct mount *)malloc((u_long)sizeof(struct mount), - M_MOUNT, M_NOWAIT); - if (mp == NULL) - panic("nfs_mountroot: %s mount malloc", which); - bzero((char *)mp, (u_long)sizeof(struct mount)); - mp->mnt_op = &nfs_vfsops; - mp->mnt_flag = mountflag; + struct mount *mp; + struct mbuf *m; + int error; - MGET(m, MT_SONAME, M_DONTWAIT); - if (m == NULL) - panic("nfs_mountroot: %s mount mbuf", which); + if (error = vfs_rootmountalloc("nfs", path, &mp)) { + printf("nfs_mountroot: NFS not configured"); + return (error); + } + mp->mnt_flag = mountflag; + MGET(m, MT_SONAME, M_WAITOK); bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len); m->m_len = sin->sin_len; - error = mountnfs(args, mp, m, which, path, vpp); - if (error) - panic("nfs_mountroot: mount %s on %s: %d", path, which, error); - - return (mp); + if (error = mountnfs(args, mp, m, which, path, vpp)) { + printf("nfs_mountroot: mount %s on %s: %d", path, which, error); + mp->mnt_vfc->vfc_refcount--; + vfs_unbusy(mp, p); + free(mp, M_MOUNT); + return (error); + } + (void) copystr(which, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0); + *mpp = mp; + return (0); } +#ifdef COMPAT_PRELITE2 +/* + * Old arguments to mount NFS + */ +struct onfs_args { + struct sockaddr *addr; /* file server address */ + int addrlen; /* length of address */ + int sotype; /* Socket type */ + int proto; /* and Protocol */ + u_char *fh; /* File handle to be mounted */ + int fhsize; /* Size, in bytes, of fh */ + int flags; /* flags */ + int wsize; /* write size in bytes */ + int rsize; /* read size in bytes */ + int readdirsize; /* readdir size in bytes */ + int timeo; /* initial timeout in .1 secs */ + int retrans; /* times to retry send */ + int maxgrouplist; /* Max. size of group list */ + int readahead; /* # of blocks to readahead */ + int leaseterm; /* Term (sec) of lease */ + int deadthresh; /* Retrans threshold */ + char *hostname; /* server's name */ +}; +#endif /* * VFS Operations. @@ -546,6 +583,39 @@ nfs_mount(mp, path, data, ndp, p) error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)); if (error) return (error); + if (args.version != NFS_ARGSVERSION) { +#ifdef COMPAT_PRELITE2 + /* + * If the argument version is unknown, then assume the + * caller is a pre-lite2 4.4BSD client and convert its + * arguments. + */ + struct onfs_args oargs; + error = copyin(data, (caddr_t)&oargs, sizeof (struct onfs_args)); + if (error) + return (error); + args.version = NFS_ARGSVERSION; + args.addr = oargs.addr; + args.addrlen = oargs.addrlen; + args.sotype = oargs.sotype; + args.proto = oargs.proto; + args.fh = oargs.fh; + args.fhsize = oargs.fhsize; + args.flags = oargs.flags; + args.wsize = oargs.wsize; + args.rsize = oargs.rsize; + args.readdirsize = oargs.readdirsize; + args.timeo = oargs.timeo; + args.retrans = oargs.retrans; + args.maxgrouplist = oargs.maxgrouplist; + args.readahead = oargs.readahead; + args.leaseterm = oargs.leaseterm; + args.deadthresh = oargs.deadthresh; + args.hostname = oargs.hostname; +#else /* COMPAT_PRELITE2 */ + return (EPROGMISMATCH); +#endif /* COMPAT_PRELITE2 */ + } error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize); if (error) return (error); @@ -595,7 +665,7 @@ mountnfs(argp, mp, nam, pth, hst, vpp) TAILQ_INIT(&nmp->nm_bufq); mp->mnt_data = (qaddr_t)nmp; } - getnewfsid(mp, MOUNT_NFS); + vfs_getnewfsid(mp); nmp->nm_mountp = mp; nmp->nm_flag = argp->flags; if (nmp->nm_flag & NFSMNT_NQNFS) @@ -619,15 +689,6 @@ mountnfs(argp, mp, nam, pth, hst, vpp) nmp->nm_inprog = NULLVP; nmp->nm_fhsize = argp->fhsize; bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); -#ifdef __NetBSD__ -#ifdef COMPAT_09 - mp->mnt_stat.f_type = 2; -#else - mp->mnt_stat.f_type = 0; -#endif -#else - mp->mnt_stat.f_type = MOUNT_NFS; -#endif bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); nmp->nm_nam = nam; @@ -741,7 +802,7 @@ mountnfs(argp, mp, nam, pth, hst, vpp) /* * Lose the lock but keep the ref. */ - VOP_UNLOCK(*vpp); + VOP_UNLOCK(*vpp, 0, curproc); return (0); bad: @@ -765,11 +826,8 @@ nfs_unmount(mp, mntflags, p) struct vnode *vp; int error, flags = 0; - if (mntflags & MNT_FORCE) { - if (!doforce) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } nmp = VFSTONFS(mp); /* * Goes something like this.. @@ -846,7 +904,7 @@ nfs_root(mp, vpp) if (error) return (error); vp = NFSTOV(np); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, curproc); if (vp->v_type == VNON) vp->v_type = VDIR; vp->v_flag = VROOT; @@ -885,7 +943,7 @@ loop: goto loop; if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL) continue; - if (vget(vp, 1)) + if (vget(vp, LK_EXCLUSIVE, p)) goto loop; error = VOP_FSYNC(vp, cred, waitfor, p); if (error) @@ -969,4 +1027,3 @@ nfs_quotactl(mp, cmd, uid, arg, p) return (EOPNOTSUPP); } - diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c index b8ff396..905bb22 100644 --- a/sys/nfsclient/nfs_vnops.c +++ b/sys/nfsclient/nfs_vnops.c @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_vnops.c 8.5 (Berkeley) 2/13/94 + * @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95 * $FreeBSD$ */ + /* * vnode op calls for Sun NFS version 2 and 3 */ @@ -151,14 +152,10 @@ static struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { { &vop_setattr_desc, (vop_t *)nfs_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)nfs_read }, /* read */ { &vop_write_desc, (vop_t *)nfs_write }, /* write */ -#ifdef HAS_VOPLEASE { &vop_lease_desc, (vop_t *)nfs_lease_check }, /* lease */ -#endif { &vop_ioctl_desc, (vop_t *)nfs_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)nfs_select }, /* select */ -#ifdef HAS_VOPREVOKE { &vop_revoke_desc, (vop_t *)nfs_revoke }, /* revoke */ -#endif { &vop_mmap_desc, (vop_t *)nfs_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)nfs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)nfs_seek }, /* seek */ @@ -212,14 +209,10 @@ static struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { { &vop_setattr_desc, (vop_t *)nfs_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)nfsspec_read }, /* read */ { &vop_write_desc, (vop_t *)nfsspec_write }, /* write */ -#ifdef HAS_VOPLEASE { &vop_lease_desc, (vop_t *)spec_lease_check }, /* lease */ -#endif { &vop_ioctl_desc, (vop_t *)spec_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)spec_select }, /* select */ -#ifdef HAS_VOPREVOKE { &vop_revoke_desc, (vop_t *)spec_revoke }, /* revoke */ -#endif { &vop_mmap_desc, (vop_t *)spec_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)nfs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)spec_seek }, /* seek */ @@ -270,14 +263,10 @@ static struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { { &vop_setattr_desc, (vop_t *)nfs_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)nfsfifo_read }, /* read */ { &vop_write_desc, (vop_t *)nfsfifo_write }, /* write */ -#ifdef HAS_VOPLEASE { &vop_lease_desc, (vop_t *)fifo_lease_check }, /* lease */ -#endif { &vop_ioctl_desc, (vop_t *)fifo_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)fifo_select }, /* select */ -#ifdef HAS_VOPREVOKE { &vop_revoke_desc, (vop_t *)fifo_revoke }, /* revoke */ -#endif { &vop_mmap_desc, (vop_t *)fifo_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)nfs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)fifo_seek }, /* seek */ @@ -469,7 +458,7 @@ nfs_open(ap) if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1)) == EINTR) return (error); - (void) vnode_pager_uncache(vp); + (void) vnode_pager_uncache(vp, ap->a_p); np->n_brev = np->n_lrev; } } @@ -588,7 +577,7 @@ nfs_getattr(ap) int error = 0; struct mbuf *mreq, *mrep, *md, *mb, *mb2; int v3 = NFS_ISV3(vp); - + /* * Update local times for special files. */ @@ -634,7 +623,7 @@ nfs_setattr(ap) /* * Disallow write attempts if the filesystem is mounted read-only. */ - if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || + if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && (vp->v_mount->mnt_flag & MNT_RDONLY)) @@ -645,6 +634,8 @@ nfs_setattr(ap) return (EISDIR); case VCHR: case VBLK: + case VSOCK: + case VFIFO: if (vap->va_mtime.tv_sec == VNOVAL && vap->va_atime.tv_sec == VNOVAL && vap->va_mode == (u_short)VNOVAL && @@ -660,20 +651,22 @@ nfs_setattr(ap) */ if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); - if (vap->va_size == 0) + if (np->n_flag & NMODIFIED) { + if (vap->va_size == 0) error = nfs_vinvalbuf(vp, 0, ap->a_cred, ap->a_p, 1); - else + else error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1); - if (error) + if (error) return (error); + } tsize = np->n_size; np->n_size = np->n_vattr.va_size = vap->va_size; vnode_pager_setsize(vp, (u_long)np->n_size); }; } else if ((vap->va_mtime.tv_sec != VNOVAL || - vap->va_atime.tv_sec != VNOVAL) && + vap->va_atime.tv_sec != VNOVAL) && (np->n_flag & NMODIFIED) && vp->v_type == VREG && (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1)) == EINTR) @@ -826,6 +819,7 @@ nfs_lookup(ap) struct nfsnode *np; int lockparent, wantparent, error = 0, attrflag, fhsize; int v3 = NFS_ISV3(dvp); + struct proc *p = cnp->cn_proc; if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) @@ -851,18 +845,18 @@ nfs_lookup(ap) VREF(newvp); error = 0; } else if (flags & ISDOTDOT) { - VOP_UNLOCK(dvp); - error = vget(newvp, 1); + VOP_UNLOCK(dvp, 0, p); + error = vget(newvp, LK_EXCLUSIVE, p); if (!error && lockparent && (flags & ISLASTCN)) - error = VOP_LOCK(dvp); + error = vn_lock(dvp, LK_EXCLUSIVE, p); } else { - error = vget(newvp, 1); + error = vget(newvp, LK_EXCLUSIVE, p); if (!lockparent || error || !(flags & ISLASTCN)) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); } if (!error) { if (vpid == newvp->v_id) { - if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc) + if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, p) && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) { nfsstats.lookupcache_hits++; if (cnp->cn_nameiop != LOOKUP && @@ -874,9 +868,9 @@ nfs_lookup(ap) } vput(newvp); if (lockparent && dvp != newvp && (flags & ISLASTCN)) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); } - error = VOP_LOCK(dvp); + error = vn_lock(dvp, LK_EXCLUSIVE, p); if (error) return (error); *vpp = NULLVP; @@ -920,20 +914,20 @@ nfs_lookup(ap) m_freem(mrep); cnp->cn_flags |= SAVENAME; if (!lockparent) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); return (0); } if (flags & ISDOTDOT) { - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); if (error) { - VOP_LOCK(dvp); + vn_lock(dvp, LK_EXCLUSIVE + LK_RETRY, p); return (error); } newvp = NFSTOV(np); if (lockparent && (flags & ISLASTCN) && - (error = VOP_LOCK(dvp))) { + (error = vn_lock(dvp, LK_EXCLUSIVE, p))) { vput(newvp); return (error); } @@ -946,7 +940,7 @@ nfs_lookup(ap) return (error); } if (!lockparent || !(flags & ISLASTCN)) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); newvp = NFSTOV(np); } if (v3) { @@ -969,7 +963,7 @@ nfs_lookup(ap) if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && (flags & ISLASTCN) && error == ENOENT) { if (!lockparent) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp, 0, p); if (dvp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; else @@ -2110,7 +2104,7 @@ nfs_readdirrpc(vp, uiop, cred) } nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); more_dirs = fxdr_unsigned(int, *tl); - + /* loop thru the dir entries, doctoring them to 4bsd form */ while (more_dirs && bigenough) { if (v3) { @@ -2923,6 +2917,9 @@ loop: } } if (vp->v_dirtyblkhd.lh_first && commit) { +#ifndef DIAGNOSTIC + vprint("nfs_fsync: dirty", vp); +#endif goto loop; } } @@ -3131,7 +3128,7 @@ nfs_writebp(bp, force) * an actual write will have to be scheduled via. VOP_STRATEGY(). * If B_WRITEINPROG is already set, then push it with a write anyhow. */ - if (oldflags & (B_NEEDCOMMIT | B_WRITEINPROG) == B_NEEDCOMMIT) { + if ((oldflags & (B_NEEDCOMMIT | B_WRITEINPROG)) == B_NEEDCOMMIT) { off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff; bp->b_flags |= B_WRITEINPROG; retv = nfs_commit(bp->b_vp, off, bp->b_dirtyend-bp->b_dirtyoff, @@ -3205,7 +3202,7 @@ nfsspec_access(ap) if (cred->cr_uid == 0) return (0); vap = &vattr; - error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p); + error = VOP_GETATTR(vp, vap, cred, ap->a_p); if (error) return (error); /* diff --git a/sys/nfsclient/nfsargs.h b/sys/nfsclient/nfsargs.h index db41859..73a018c 100644 --- a/sys/nfsclient/nfsargs.h +++ b/sys/nfsclient/nfsargs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1993 + * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -33,19 +33,19 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs.h 8.1 (Berkeley) 6/10/93 + * @(#)nfs.h 8.4 (Berkeley) 5/1/95 * $FreeBSD$ */ #ifndef _NFS_NFS_H_ #define _NFS_NFS_H_ -#include <nfs/rpcv2.h> - /* * Tunable constants for nfs */ +#ifdef KERNEL + #define NFS_MAXIOVEC 34 #define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */ #define NFS_HZ (hz / nfs_ticks) /* Ticks/sec */ @@ -69,7 +69,7 @@ #define NFS_DEFRAHEAD 1 /* Def. read ahead # blocks */ #define NFS_MAXRAHEAD 4 /* Max. read ahead # blocks */ #define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */ -#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runnable */ +#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */ #define NFS_MAXGATHERDELAY 100 /* Max. write gather delay (msec) */ #ifndef NFS_GATHERDELAY #define NFS_GATHERDELAY 10 /* Default write gather delay (msec) */ @@ -89,30 +89,9 @@ /* * XXX - * sys/buf.h should be edited to change B_APPENDWRITE --> B_NEEDCOMMIT, but - * until then... - * Same goes for sys/malloc.h, which needs M_NFSDIROFF, - * M_NFSRVDESC and M_NFSBIGFH added. - * The VA_EXCLUSIVE flag should be added for va_vaflags and set for an - * exclusive create. * The B_INVAFTERWRITE flag should be set to whatever is required by the * buffer cache code to say "Invalidate the block after it is written back". */ -#ifndef B_NEEDCOMMIT -#define B_NEEDCOMMIT B_APPENDWRITE -#endif -#ifndef M_NFSRVDESC -#define M_NFSRVDESC M_TEMP -#endif -#ifndef M_NFSDIROFF -#define M_NFSDIROFF M_TEMP -#endif -#ifndef M_NFSBIGFH -#define M_NFSBIGFH M_TEMP -#endif -#ifndef VA_EXCLUSIVE -#define VA_EXCLUSIVE 0 -#endif #ifdef __FreeBSD__ #define B_INVAFTERWRITE B_NOCACHE #else @@ -120,20 +99,6 @@ #endif /* - * These ifdefs try to handle the differences between the various 4.4BSD-Lite - * based vfs interfaces. - * btw: NetBSD-current does have a VOP_LEASDE(), but I don't know how to - * differentiate between NetBSD-1.0 and NetBSD-current, so.. - * I also don't know about BSDi's 2.0 release. - */ -#if !defined(HAS_VOPLEASE) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#define HAS_VOPLEASE 1 -#endif -#if !defined(HAS_VOPREVOKE) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#define HAS_VOPREVOKE 1 -#endif - -/* * The IO_METASYNC flag should be implemented for local file systems. * (Until then, it is nothin at all.) */ @@ -164,13 +129,114 @@ #define NFS_SVCALLOC 256 #define NFS_UIDALLOC 128 +#endif /* KERNEL */ + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ + +/* + * Arguments to mount NFS + */ +#define NFS_ARGSVERSION 3 /* change when nfs_args changes */ +struct nfs_args { + int version; /* args structure version number */ + struct sockaddr *addr; /* file server address */ + int addrlen; /* length of address */ + int sotype; /* Socket type */ + int proto; /* and Protocol */ + u_char *fh; /* File handle to be mounted */ + int fhsize; /* Size, in bytes, of fh */ + int flags; /* flags */ + int wsize; /* write size in bytes */ + int rsize; /* read size in bytes */ + int readdirsize; /* readdir size in bytes */ + int timeo; /* initial timeout in .1 secs */ + int retrans; /* times to retry send */ + int maxgrouplist; /* Max. size of group list */ + int readahead; /* # of blocks to readahead */ + int leaseterm; /* Term (sec) of lease */ + int deadthresh; /* Retrans threshold */ + char *hostname; /* server's name */ +}; + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ + /* * Structures for the nfssvc(2) syscall. Not that anyone but nfsd and mount_nfs * should ever try and use it. */ struct nfsd_args { int sock; /* Socket to serve */ - caddr_t name; /* Client address for connection based sockets */ + caddr_t name; /* Client addr for connection based sockets */ int namelen; /* Length of name */ }; @@ -200,6 +266,10 @@ struct nfsd_cargs { }; /* + * XXX to allow amd to include nfs.h without nfsproto.h + */ +#ifdef NFS_NPROCS +/* * Stats structure */ struct nfsstats { @@ -237,6 +307,7 @@ struct nfsstats { int srvnqnfs_getleases; int srvvop_writes; }; +#endif /* * Flags for nfssvc() system call. @@ -267,7 +338,7 @@ struct nfsstats { * such as SIGALRM will not expect file I/O system calls to be interrupted * by them and break. */ -#if defined(KERNEL) || defined(_KERNEL) +#ifdef KERNEL struct uio; struct buf; struct vattr; struct nameidata; /* XXX */ @@ -482,6 +553,8 @@ extern int nfsd_head_flag; !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ sizeof (struct ucred))) + +int nfs_init __P((struct vfsconf *vfsp)); int nfs_reply __P((struct nfsreq *)); int nfs_getreq __P((struct nfsrv_descript *,struct nfsd *,int)); int nfs_send __P((struct socket *,struct mbuf *,struct mbuf *,struct nfsreq *)); @@ -516,14 +589,12 @@ int nfs_adv __P((struct mbuf **,caddr_t *,int,int)); void nfs_nhinit __P((void)); void nfs_timer __P((void*)); u_long nfs_hash __P((nfsfh_t *,int)); -void nfsrv_slpderef __P((struct nfssvc_sock *slp)); int nfsrv_dorec __P((struct nfssvc_sock *,struct nfsd *,struct nfsrv_descript **)); -void nfsrv_cleancache __P((void)); int nfsrv_getcache __P((struct nfsrv_descript *,struct nfssvc_sock *,struct mbuf **)); -int nfs_init __P((void)); void nfsrv_updatecache __P((struct nfsrv_descript *,int,struct mbuf *)); +void nfsrv_cleancache __P((void)); int nfs_connect __P((struct nfsmount *,struct nfsreq *)); -void nfs_disconnect __P((struct nfsmount *nmp)); +void nfs_disconnect __P((struct nfsmount *)); int nfs_getattrcache __P((struct vnode *,struct vattr *)); int nfsm_strtmbuf __P((struct mbuf **,char **,char *,long)); int nfs_bioread __P((struct vnode *,struct uio *,int,struct ucred *)); @@ -531,7 +602,6 @@ int nfsm_uiotombuf __P((struct uio *,struct mbuf **,int,caddr_t *)); void nfsrv_init __P((int)); void nfs_clearcommit __P((struct mount *)); int nfsrv_errmap __P((struct nfsrv_descript *, int)); -void nfsrv_rcv __P((struct socket *so, caddr_t arg, int waitflag)); void nfsrvw_sort __P((gid_t [],int)); void nfsrv_setcred __P((struct ucred *,struct ucred *)); int nfs_writebp __P((struct buf *,int)); @@ -594,8 +664,8 @@ int nfsrv_symlink __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_write __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); - - +void nfsrv_rcv __P((struct socket *so, caddr_t arg, int waitflag)); +void nfsrv_slpderef __P((struct nfssvc_sock *slp)); #endif /* KERNEL */ #endif diff --git a/sys/nfsclient/nfsdiskless.h b/sys/nfsclient/nfsdiskless.h index 117548b..4777818 100644 --- a/sys/nfsclient/nfsdiskless.h +++ b/sys/nfsclient/nfsdiskless.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsdiskless.h 8.1 (Berkeley) 6/10/93 + * @(#)nfsdiskless.h 8.2 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_NFSDISKLESS_H_ #define _NFS_NFSDISKLESS_H_ @@ -46,8 +47,8 @@ * vnodes plus do a partial ifconfig(8) and route(8) so that the critical net * interface can communicate with the server. * The primary bootstrap is expected to fill in the appropriate fields before - * starting the kernel. Whether or not the swap area is nfs mounted is determined - * by the value in swdevt[0]. (equal to NODEV --> swap over nfs) + * starting the kernel. Whether or not the swap area is nfs mounted is + * determined by the value in swdevt[0]. (equal to NODEV --> swap over nfs) * Currently only works for AF_INET protocols. * NB: All fields are stored in net byte order to avoid hassles with * client/server byte ordering differences. diff --git a/sys/nfsclient/nfsm_subs.h b/sys/nfsclient/nfsm_subs.h index ac1a159..cd37c59 100644 --- a/sys/nfsclient/nfsm_subs.h +++ b/sys/nfsclient/nfsm_subs.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsm_subs.h 8.1 (Berkeley) 6/16/93 + * @(#)nfsm_subs.h 8.2 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_NFSM_SUBS_H_ #define _NFS_NFSM_SUBS_H_ diff --git a/sys/nfsclient/nfsmount.h b/sys/nfsclient/nfsmount.h index ea48bca..1545ada 100644 --- a/sys/nfsclient/nfsmount.h +++ b/sys/nfsclient/nfsmount.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsmount.h 8.1 (Berkeley) 6/10/93 + * @(#)nfsmount.h 8.3 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_NFSMOUNT_H_ #define _NFS_NFSMOUNT_H_ diff --git a/sys/nfsclient/nfsnode.h b/sys/nfsclient/nfsnode.h index 4408fe2..e52a3dd 100644 --- a/sys/nfsclient/nfsnode.h +++ b/sys/nfsclient/nfsnode.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsnode.h 8.4 (Berkeley) 2/13/94 + * @(#)nfsnode.h 8.9 (Berkeley) 5/14/95 * $FreeBSD$ */ + #ifndef _NFS_NFSNODE_H_ #define _NFS_NFSNODE_H_ @@ -161,26 +162,16 @@ extern vop_t **spec_nfsv2nodeop_p; * Prototypes for NFS vnode operations */ int nfs_write __P((struct vop_write_args *)); -#ifdef HAS_VOPLEASE #define nfs_lease_check ((int (*) __P((struct vop_lease_args *)))nullop) -#define nqnfs_vop_lease_check lease_check -#else -#ifdef __FreeBSD__ -#define nqnfs_lease_check nfs_lease_check -#else -#define nqnfs_lease_check lease_check -#endif -#endif -#ifdef HAS_VOPREVOKE +int nqnfs_vop_lease_check __P((struct vop_lease_args *)); #define nfs_revoke vop_revoke -#endif #define nfs_seek ((int (*) __P((struct vop_seek_args *)))nullop) int nfs_abortop __P((struct vop_abortop_args *)); int nfs_inactive __P((struct vop_inactive_args *)); int nfs_reclaim __P((struct vop_reclaim_args *)); -int nfs_lock __P((struct vop_lock_args *)); -int nfs_unlock __P((struct vop_unlock_args *)); -int nfs_islocked __P((struct vop_islocked_args *)); +#define nfs_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock) +#define nfs_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock) +#define nfs_islocked ((int (*) __P((struct vop_islocked_args *)))vop_noislocked) #define nfs_reallocblks \ ((int (*) __P((struct vop_reallocblks_args *)))eopnotsupp) @@ -190,11 +181,7 @@ int nfs_nget __P((struct mount *,nfsfh_t *,int,struct nfsnode **)); nfsuint64 *nfs_getcookie __P((struct nfsnode *, off_t, int)); void nfs_invaldir __P((struct vnode *)); -#ifdef __FreeBSD__ #define nqnfs_lease_updatetime nfs_lease_updatetime -#else -#define nqnfs_lease_updatetime lease_updatetime -#endif #endif /* KERNEL */ diff --git a/sys/nfsclient/nfsstats.h b/sys/nfsclient/nfsstats.h index db41859..73a018c 100644 --- a/sys/nfsclient/nfsstats.h +++ b/sys/nfsclient/nfsstats.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1993 + * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -33,19 +33,19 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs.h 8.1 (Berkeley) 6/10/93 + * @(#)nfs.h 8.4 (Berkeley) 5/1/95 * $FreeBSD$ */ #ifndef _NFS_NFS_H_ #define _NFS_NFS_H_ -#include <nfs/rpcv2.h> - /* * Tunable constants for nfs */ +#ifdef KERNEL + #define NFS_MAXIOVEC 34 #define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */ #define NFS_HZ (hz / nfs_ticks) /* Ticks/sec */ @@ -69,7 +69,7 @@ #define NFS_DEFRAHEAD 1 /* Def. read ahead # blocks */ #define NFS_MAXRAHEAD 4 /* Max. read ahead # blocks */ #define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */ -#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runnable */ +#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */ #define NFS_MAXGATHERDELAY 100 /* Max. write gather delay (msec) */ #ifndef NFS_GATHERDELAY #define NFS_GATHERDELAY 10 /* Default write gather delay (msec) */ @@ -89,30 +89,9 @@ /* * XXX - * sys/buf.h should be edited to change B_APPENDWRITE --> B_NEEDCOMMIT, but - * until then... - * Same goes for sys/malloc.h, which needs M_NFSDIROFF, - * M_NFSRVDESC and M_NFSBIGFH added. - * The VA_EXCLUSIVE flag should be added for va_vaflags and set for an - * exclusive create. * The B_INVAFTERWRITE flag should be set to whatever is required by the * buffer cache code to say "Invalidate the block after it is written back". */ -#ifndef B_NEEDCOMMIT -#define B_NEEDCOMMIT B_APPENDWRITE -#endif -#ifndef M_NFSRVDESC -#define M_NFSRVDESC M_TEMP -#endif -#ifndef M_NFSDIROFF -#define M_NFSDIROFF M_TEMP -#endif -#ifndef M_NFSBIGFH -#define M_NFSBIGFH M_TEMP -#endif -#ifndef VA_EXCLUSIVE -#define VA_EXCLUSIVE 0 -#endif #ifdef __FreeBSD__ #define B_INVAFTERWRITE B_NOCACHE #else @@ -120,20 +99,6 @@ #endif /* - * These ifdefs try to handle the differences between the various 4.4BSD-Lite - * based vfs interfaces. - * btw: NetBSD-current does have a VOP_LEASDE(), but I don't know how to - * differentiate between NetBSD-1.0 and NetBSD-current, so.. - * I also don't know about BSDi's 2.0 release. - */ -#if !defined(HAS_VOPLEASE) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#define HAS_VOPLEASE 1 -#endif -#if !defined(HAS_VOPREVOKE) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#define HAS_VOPREVOKE 1 -#endif - -/* * The IO_METASYNC flag should be implemented for local file systems. * (Until then, it is nothin at all.) */ @@ -164,13 +129,114 @@ #define NFS_SVCALLOC 256 #define NFS_UIDALLOC 128 +#endif /* KERNEL */ + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ + +/* + * Arguments to mount NFS + */ +#define NFS_ARGSVERSION 3 /* change when nfs_args changes */ +struct nfs_args { + int version; /* args structure version number */ + struct sockaddr *addr; /* file server address */ + int addrlen; /* length of address */ + int sotype; /* Socket type */ + int proto; /* and Protocol */ + u_char *fh; /* File handle to be mounted */ + int fhsize; /* Size, in bytes, of fh */ + int flags; /* flags */ + int wsize; /* write size in bytes */ + int rsize; /* read size in bytes */ + int readdirsize; /* readdir size in bytes */ + int timeo; /* initial timeout in .1 secs */ + int retrans; /* times to retry send */ + int maxgrouplist; /* Max. size of group list */ + int readahead; /* # of blocks to readahead */ + int leaseterm; /* Term (sec) of lease */ + int deadthresh; /* Retrans threshold */ + char *hostname; /* server's name */ +}; + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ + /* * Structures for the nfssvc(2) syscall. Not that anyone but nfsd and mount_nfs * should ever try and use it. */ struct nfsd_args { int sock; /* Socket to serve */ - caddr_t name; /* Client address for connection based sockets */ + caddr_t name; /* Client addr for connection based sockets */ int namelen; /* Length of name */ }; @@ -200,6 +266,10 @@ struct nfsd_cargs { }; /* + * XXX to allow amd to include nfs.h without nfsproto.h + */ +#ifdef NFS_NPROCS +/* * Stats structure */ struct nfsstats { @@ -237,6 +307,7 @@ struct nfsstats { int srvnqnfs_getleases; int srvvop_writes; }; +#endif /* * Flags for nfssvc() system call. @@ -267,7 +338,7 @@ struct nfsstats { * such as SIGALRM will not expect file I/O system calls to be interrupted * by them and break. */ -#if defined(KERNEL) || defined(_KERNEL) +#ifdef KERNEL struct uio; struct buf; struct vattr; struct nameidata; /* XXX */ @@ -482,6 +553,8 @@ extern int nfsd_head_flag; !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ sizeof (struct ucred))) + +int nfs_init __P((struct vfsconf *vfsp)); int nfs_reply __P((struct nfsreq *)); int nfs_getreq __P((struct nfsrv_descript *,struct nfsd *,int)); int nfs_send __P((struct socket *,struct mbuf *,struct mbuf *,struct nfsreq *)); @@ -516,14 +589,12 @@ int nfs_adv __P((struct mbuf **,caddr_t *,int,int)); void nfs_nhinit __P((void)); void nfs_timer __P((void*)); u_long nfs_hash __P((nfsfh_t *,int)); -void nfsrv_slpderef __P((struct nfssvc_sock *slp)); int nfsrv_dorec __P((struct nfssvc_sock *,struct nfsd *,struct nfsrv_descript **)); -void nfsrv_cleancache __P((void)); int nfsrv_getcache __P((struct nfsrv_descript *,struct nfssvc_sock *,struct mbuf **)); -int nfs_init __P((void)); void nfsrv_updatecache __P((struct nfsrv_descript *,int,struct mbuf *)); +void nfsrv_cleancache __P((void)); int nfs_connect __P((struct nfsmount *,struct nfsreq *)); -void nfs_disconnect __P((struct nfsmount *nmp)); +void nfs_disconnect __P((struct nfsmount *)); int nfs_getattrcache __P((struct vnode *,struct vattr *)); int nfsm_strtmbuf __P((struct mbuf **,char **,char *,long)); int nfs_bioread __P((struct vnode *,struct uio *,int,struct ucred *)); @@ -531,7 +602,6 @@ int nfsm_uiotombuf __P((struct uio *,struct mbuf **,int,caddr_t *)); void nfsrv_init __P((int)); void nfs_clearcommit __P((struct mount *)); int nfsrv_errmap __P((struct nfsrv_descript *, int)); -void nfsrv_rcv __P((struct socket *so, caddr_t arg, int waitflag)); void nfsrvw_sort __P((gid_t [],int)); void nfsrv_setcred __P((struct ucred *,struct ucred *)); int nfs_writebp __P((struct buf *,int)); @@ -594,8 +664,8 @@ int nfsrv_symlink __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_write __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); - - +void nfsrv_rcv __P((struct socket *so, caddr_t arg, int waitflag)); +void nfsrv_slpderef __P((struct nfssvc_sock *slp)); #endif /* KERNEL */ #endif diff --git a/sys/nfsserver/nfs.h b/sys/nfsserver/nfs.h index db41859..73a018c 100644 --- a/sys/nfsserver/nfs.h +++ b/sys/nfsserver/nfs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1993 + * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -33,19 +33,19 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs.h 8.1 (Berkeley) 6/10/93 + * @(#)nfs.h 8.4 (Berkeley) 5/1/95 * $FreeBSD$ */ #ifndef _NFS_NFS_H_ #define _NFS_NFS_H_ -#include <nfs/rpcv2.h> - /* * Tunable constants for nfs */ +#ifdef KERNEL + #define NFS_MAXIOVEC 34 #define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */ #define NFS_HZ (hz / nfs_ticks) /* Ticks/sec */ @@ -69,7 +69,7 @@ #define NFS_DEFRAHEAD 1 /* Def. read ahead # blocks */ #define NFS_MAXRAHEAD 4 /* Max. read ahead # blocks */ #define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */ -#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runnable */ +#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */ #define NFS_MAXGATHERDELAY 100 /* Max. write gather delay (msec) */ #ifndef NFS_GATHERDELAY #define NFS_GATHERDELAY 10 /* Default write gather delay (msec) */ @@ -89,30 +89,9 @@ /* * XXX - * sys/buf.h should be edited to change B_APPENDWRITE --> B_NEEDCOMMIT, but - * until then... - * Same goes for sys/malloc.h, which needs M_NFSDIROFF, - * M_NFSRVDESC and M_NFSBIGFH added. - * The VA_EXCLUSIVE flag should be added for va_vaflags and set for an - * exclusive create. * The B_INVAFTERWRITE flag should be set to whatever is required by the * buffer cache code to say "Invalidate the block after it is written back". */ -#ifndef B_NEEDCOMMIT -#define B_NEEDCOMMIT B_APPENDWRITE -#endif -#ifndef M_NFSRVDESC -#define M_NFSRVDESC M_TEMP -#endif -#ifndef M_NFSDIROFF -#define M_NFSDIROFF M_TEMP -#endif -#ifndef M_NFSBIGFH -#define M_NFSBIGFH M_TEMP -#endif -#ifndef VA_EXCLUSIVE -#define VA_EXCLUSIVE 0 -#endif #ifdef __FreeBSD__ #define B_INVAFTERWRITE B_NOCACHE #else @@ -120,20 +99,6 @@ #endif /* - * These ifdefs try to handle the differences between the various 4.4BSD-Lite - * based vfs interfaces. - * btw: NetBSD-current does have a VOP_LEASDE(), but I don't know how to - * differentiate between NetBSD-1.0 and NetBSD-current, so.. - * I also don't know about BSDi's 2.0 release. - */ -#if !defined(HAS_VOPLEASE) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#define HAS_VOPLEASE 1 -#endif -#if !defined(HAS_VOPREVOKE) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#define HAS_VOPREVOKE 1 -#endif - -/* * The IO_METASYNC flag should be implemented for local file systems. * (Until then, it is nothin at all.) */ @@ -164,13 +129,114 @@ #define NFS_SVCALLOC 256 #define NFS_UIDALLOC 128 +#endif /* KERNEL */ + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ + +/* + * Arguments to mount NFS + */ +#define NFS_ARGSVERSION 3 /* change when nfs_args changes */ +struct nfs_args { + int version; /* args structure version number */ + struct sockaddr *addr; /* file server address */ + int addrlen; /* length of address */ + int sotype; /* Socket type */ + int proto; /* and Protocol */ + u_char *fh; /* File handle to be mounted */ + int fhsize; /* Size, in bytes, of fh */ + int flags; /* flags */ + int wsize; /* write size in bytes */ + int rsize; /* read size in bytes */ + int readdirsize; /* readdir size in bytes */ + int timeo; /* initial timeout in .1 secs */ + int retrans; /* times to retry send */ + int maxgrouplist; /* Max. size of group list */ + int readahead; /* # of blocks to readahead */ + int leaseterm; /* Term (sec) of lease */ + int deadthresh; /* Retrans threshold */ + char *hostname; /* server's name */ +}; + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ + /* * Structures for the nfssvc(2) syscall. Not that anyone but nfsd and mount_nfs * should ever try and use it. */ struct nfsd_args { int sock; /* Socket to serve */ - caddr_t name; /* Client address for connection based sockets */ + caddr_t name; /* Client addr for connection based sockets */ int namelen; /* Length of name */ }; @@ -200,6 +266,10 @@ struct nfsd_cargs { }; /* + * XXX to allow amd to include nfs.h without nfsproto.h + */ +#ifdef NFS_NPROCS +/* * Stats structure */ struct nfsstats { @@ -237,6 +307,7 @@ struct nfsstats { int srvnqnfs_getleases; int srvvop_writes; }; +#endif /* * Flags for nfssvc() system call. @@ -267,7 +338,7 @@ struct nfsstats { * such as SIGALRM will not expect file I/O system calls to be interrupted * by them and break. */ -#if defined(KERNEL) || defined(_KERNEL) +#ifdef KERNEL struct uio; struct buf; struct vattr; struct nameidata; /* XXX */ @@ -482,6 +553,8 @@ extern int nfsd_head_flag; !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ sizeof (struct ucred))) + +int nfs_init __P((struct vfsconf *vfsp)); int nfs_reply __P((struct nfsreq *)); int nfs_getreq __P((struct nfsrv_descript *,struct nfsd *,int)); int nfs_send __P((struct socket *,struct mbuf *,struct mbuf *,struct nfsreq *)); @@ -516,14 +589,12 @@ int nfs_adv __P((struct mbuf **,caddr_t *,int,int)); void nfs_nhinit __P((void)); void nfs_timer __P((void*)); u_long nfs_hash __P((nfsfh_t *,int)); -void nfsrv_slpderef __P((struct nfssvc_sock *slp)); int nfsrv_dorec __P((struct nfssvc_sock *,struct nfsd *,struct nfsrv_descript **)); -void nfsrv_cleancache __P((void)); int nfsrv_getcache __P((struct nfsrv_descript *,struct nfssvc_sock *,struct mbuf **)); -int nfs_init __P((void)); void nfsrv_updatecache __P((struct nfsrv_descript *,int,struct mbuf *)); +void nfsrv_cleancache __P((void)); int nfs_connect __P((struct nfsmount *,struct nfsreq *)); -void nfs_disconnect __P((struct nfsmount *nmp)); +void nfs_disconnect __P((struct nfsmount *)); int nfs_getattrcache __P((struct vnode *,struct vattr *)); int nfsm_strtmbuf __P((struct mbuf **,char **,char *,long)); int nfs_bioread __P((struct vnode *,struct uio *,int,struct ucred *)); @@ -531,7 +602,6 @@ int nfsm_uiotombuf __P((struct uio *,struct mbuf **,int,caddr_t *)); void nfsrv_init __P((int)); void nfs_clearcommit __P((struct mount *)); int nfsrv_errmap __P((struct nfsrv_descript *, int)); -void nfsrv_rcv __P((struct socket *so, caddr_t arg, int waitflag)); void nfsrvw_sort __P((gid_t [],int)); void nfsrv_setcred __P((struct ucred *,struct ucred *)); int nfs_writebp __P((struct buf *,int)); @@ -594,8 +664,8 @@ int nfsrv_symlink __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_write __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); - - +void nfsrv_rcv __P((struct socket *so, caddr_t arg, int waitflag)); +void nfsrv_slpderef __P((struct nfssvc_sock *slp)); #endif /* KERNEL */ #endif diff --git a/sys/nfsserver/nfs_serv.c b/sys/nfsserver/nfs_serv.c index 3946778..28a705a 100644 --- a/sys/nfsserver/nfs_serv.c +++ b/sys/nfsserver/nfs_serv.c @@ -1723,7 +1723,7 @@ nfsrv_remove(nfsd, slp, procp, mrq) } out: if (!error) { - vnode_pager_uncache(vp); + vnode_pager_uncache(vp, procp); nqsrv_getl(nd.ni_dvp, ND_WRITE); nqsrv_getl(vp, ND_WRITE); @@ -1900,7 +1900,7 @@ out: nqsrv_getl(tdvp, ND_WRITE); if (tvp) { nqsrv_getl(tvp, ND_WRITE); - (void) vnode_pager_uncache(tvp); + (void) vnode_pager_uncache(tvp, procp); } error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); @@ -2027,11 +2027,7 @@ out: if (!error) { nqsrv_getl(vp, ND_WRITE); nqsrv_getl(xp, ND_WRITE); -#if defined(__NetBSD__) || defined(__FreeBSD__) - error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); -#else error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd); -#endif } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == nd.ni_vp) @@ -2479,7 +2475,7 @@ nfsrv_readdir(nfsd, slp, procp, mrq) int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies; int v3 = (nfsd->nd_flag & ND_NFSV3); u_quad_t frev, off, toff, verf; - u_int *cookies = NULL, *cookiep; + u_long *cookies = NULL, *cookiep; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); @@ -2520,7 +2516,7 @@ nfsrv_readdir(nfsd, slp, procp, mrq) nfsm_srvpostop_attr(getret, &at); return (0); } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, procp); MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); #ifdef __NetBSD__ ncookies = siz / (5 * NFSX_UNSIGNED); /*7 for V3, but it's an est. so*/ @@ -2538,16 +2534,12 @@ again: io.uio_rw = UIO_READ; io.uio_procp = (struct proc *)0; eofflag = 0; - VOP_LOCK(vp); -#ifndef __NetBSD__ + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp); if (cookies) { free((caddr_t)cookies, M_TEMP); cookies = NULL; } error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); -#else - error = VOP_READDIR(vp, &io, cred, &eofflag, cookies, ncookies); -#endif off = (off_t)io.uio_offset; if (!cookies && !error) error = NFSERR_PERM; @@ -2556,7 +2548,7 @@ again: if (!error) error = getret; } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, procp); if (error) { vrele(vp); free((caddr_t)rbuf, M_TEMP); @@ -2751,7 +2743,7 @@ nfsrv_readdirplus(nfsd, slp, procp, mrq) int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies; u_quad_t frev, off, toff, verf; - u_int *cookies = NULL, *cookiep; + u_long *cookies = NULL, *cookiep; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); @@ -2787,7 +2779,7 @@ nfsrv_readdirplus(nfsd, slp, procp, mrq) nfsm_srvpostop_attr(getret, &at); return (0); } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, procp); MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); #ifdef __NetBSD__ ncookies = siz / (7 * NFSX_UNSIGNED); @@ -2805,19 +2797,15 @@ again: io.uio_rw = UIO_READ; io.uio_procp = (struct proc *)0; eofflag = 0; - VOP_LOCK(vp); -#ifndef __NetBSD__ + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp); if (cookies) { free((caddr_t)cookies, M_TEMP); cookies = NULL; } error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); -#else - error = VOP_READDIR(vp, &io, cred, &eofflag, cookies, ncookies); -#endif off = (u_quad_t)io.uio_offset; getret = VOP_GETATTR(vp, &at, cred, procp); - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, procp); if (!cookies && !error) error = NFSERR_PERM; if (!error) diff --git a/sys/nfsserver/nfs_srvcache.c b/sys/nfsserver/nfs_srvcache.c index 835ec06..efff221 100644 --- a/sys/nfsserver/nfs_srvcache.c +++ b/sys/nfsserver/nfs_srvcache.c @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_srvcache.c 8.1 (Berkeley) 6/10/93 + * @(#)nfs_srvcache.c 8.3 (Berkeley) 3/30/95 * $FreeBSD$ */ diff --git a/sys/nfsserver/nfs_srvsock.c b/sys/nfsserver/nfs_srvsock.c index addd59f..ed16333 100644 --- a/sys/nfsserver/nfs_srvsock.c +++ b/sys/nfsserver/nfs_srvsock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1991, 1993 + * Copyright (c) 1989, 1991, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_socket.c 8.3 (Berkeley) 1/12/94 + * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95 * $FreeBSD$ */ @@ -1925,6 +1925,9 @@ nfs_getreq(nd, nfsd, has_header) struct mbuf *mrep, *md; register struct nfsuid *nuidp; struct timeval tvin, tvout; +#if 0 /* until encrypted keys are implemented */ + NFSKERBKEYSCHED_T keys; /* stores key schedule */ +#endif mrep = nd->nd_mrep; md = nd->nd_md; diff --git a/sys/nfsserver/nfs_srvsubs.c b/sys/nfsserver/nfs_srvsubs.c index 1feadd6..5f83bf5 100644 --- a/sys/nfsserver/nfs_srvsubs.c +++ b/sys/nfsserver/nfs_srvsubs.c @@ -100,6 +100,7 @@ enum vtype nv3tov_type[8]= { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; +int nfs_mount_type; int nfs_ticks; struct nfs_reqq nfs_reqq; @@ -1093,7 +1094,8 @@ nfsm_strtmbuf(mb, bpos, cp, siz) * Called once to initialize data structures... */ int -nfs_init() +nfs_init(vfsp) + struct vfsconf *vfsp; { register int i; @@ -1116,6 +1118,7 @@ nfs_init() printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC); printf("Try unionizing the nu_nickname and nu_flag fields\n"); } + nfs_mount_type = vfsp->vfc_typenum; nfsrtt.pos = 0; rpc_vers = txdr_unsigned(RPC_VER2); rpc_call = txdr_unsigned(RPC_CALL); @@ -1170,10 +1173,10 @@ nfs_init() * of the system can call us, if we are loadable. */ #ifndef NFS_NOSERVER - lease_check = nfs_lease_check; + lease_check_hook = nqnfs_vop_lease_check; #endif lease_updatetime = nfs_lease_updatetime; - vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */ + vfsp->vfc_refcount++; /* make us non-unloadable */ #ifdef VFS_LKM sysent[SYS_nfssvc].sy_narg = 2; sysent[SYS_nfssvc].sy_call = nfssvc; @@ -1212,7 +1215,6 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) register struct vattr *vap; register struct nfs_fattr *fp; register struct nfsnode *np; - register struct nfsnodehashhead *nhpp; register long t1; caddr_t cp2; int error = 0, rdev; @@ -1222,6 +1224,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) struct timespec mtime; struct vnode *nvp; int v3 = NFS_ISV3(vp); + struct proc *p = curproc; md = *mdp; t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; @@ -1284,7 +1287,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) * then release it here. */ if (vtyp != VREG && VOP_ISLOCKED(vp)) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); vp->v_type = vtyp; if (vp->v_type == VFIFO) { vp->v_op = fifo_nfsv2nodeop_p; @@ -1295,8 +1298,11 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) if (nvp) { /* * Discard unneeded vnode, but save its nfsnode. + * Since the nfsnode does not have a lock, its + * vnode lock has to be carried over. */ - LIST_REMOVE(np, n_hash); + nvp->v_vnlock = vp->v_vnlock; + vp->v_vnlock = NULL; nvp->v_data = vp->v_data; vp->v_data = NULL; vp->v_op = spec_vnodeop_p; @@ -1306,8 +1312,6 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) * Reinitialize aliased node. */ np->n_vnode = nvp; - nhpp = NFSNOHASH(nfs_hash(np->n_fhp, np->n_fhsize)); - LIST_INSERT_HEAD(nhpp, np, n_hash); *vpp = vp = nvp; } } @@ -1714,13 +1718,14 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) int *rdonlyp; int kerbflag; { + struct proc *p = curproc; /* XXX */ register struct mount *mp; register int i; struct ucred *credanon; int error, exflags; *vpp = (struct vnode *)0; - mp = getvfs(&fhp->fh_fsid); + mp = vfs_getvfs(&fhp->fh_fsid); if (!mp) return (ESTALE); error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); @@ -1751,7 +1756,7 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) nfsrv_object_create(*vpp); if (!lockflag) - VOP_UNLOCK(*vpp); + VOP_UNLOCK(*vpp, 0, p); return (0); } @@ -1947,3 +1952,4 @@ nfsrv_object_create(struct vnode *vp) { return vfs_object_create(vp, curproc, curproc?curproc->p_ucred:NULL, 1); } #endif /* NFS_NOSERVER */ + diff --git a/sys/nfsserver/nfs_syscalls.c b/sys/nfsserver/nfs_syscalls.c index 734fe79..24d4bd6 100644 --- a/sys/nfsserver/nfs_syscalls.c +++ b/sys/nfsserver/nfs_syscalls.c @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_syscalls.c 8.3 (Berkeley) 1/4/94 + * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 * $FreeBSD$ */ @@ -97,7 +97,6 @@ static int nfssvc_iod __P((struct proc *)); static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; - #ifndef NFS_NOSERVER int nfsd_waiting = 0; static struct nfsdrt nfsdrt; @@ -1051,6 +1050,7 @@ nfsmout: } #ifndef NFS_NOSERVER + /* * Derefence a server socket structure. If it has no more references and * is no longer valid, you can throw it away. diff --git a/sys/nfsserver/nfsm_subs.h b/sys/nfsserver/nfsm_subs.h index ac1a159..cd37c59 100644 --- a/sys/nfsserver/nfsm_subs.h +++ b/sys/nfsserver/nfsm_subs.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsm_subs.h 8.1 (Berkeley) 6/16/93 + * @(#)nfsm_subs.h 8.2 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_NFSM_SUBS_H_ #define _NFS_NFSM_SUBS_H_ diff --git a/sys/nfsserver/nfsrvcache.h b/sys/nfsserver/nfsrvcache.h index 38c9657..2cfa694 100644 --- a/sys/nfsserver/nfsrvcache.h +++ b/sys/nfsserver/nfsrvcache.h @@ -33,10 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsrvcache.h 8.1 (Berkeley) 6/10/93 + * @(#)nfsrvcache.h 8.3 (Berkeley) 3/30/95 * $FreeBSD$ */ + #ifndef _NFS_NFSRVCACHE_H_ #define _NFS_NFSRVCACHE_H_ diff --git a/sys/nfsserver/nfsrvstats.h b/sys/nfsserver/nfsrvstats.h index db41859..73a018c 100644 --- a/sys/nfsserver/nfsrvstats.h +++ b/sys/nfsserver/nfsrvstats.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1993 + * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -33,19 +33,19 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs.h 8.1 (Berkeley) 6/10/93 + * @(#)nfs.h 8.4 (Berkeley) 5/1/95 * $FreeBSD$ */ #ifndef _NFS_NFS_H_ #define _NFS_NFS_H_ -#include <nfs/rpcv2.h> - /* * Tunable constants for nfs */ +#ifdef KERNEL + #define NFS_MAXIOVEC 34 #define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */ #define NFS_HZ (hz / nfs_ticks) /* Ticks/sec */ @@ -69,7 +69,7 @@ #define NFS_DEFRAHEAD 1 /* Def. read ahead # blocks */ #define NFS_MAXRAHEAD 4 /* Max. read ahead # blocks */ #define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */ -#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runnable */ +#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */ #define NFS_MAXGATHERDELAY 100 /* Max. write gather delay (msec) */ #ifndef NFS_GATHERDELAY #define NFS_GATHERDELAY 10 /* Default write gather delay (msec) */ @@ -89,30 +89,9 @@ /* * XXX - * sys/buf.h should be edited to change B_APPENDWRITE --> B_NEEDCOMMIT, but - * until then... - * Same goes for sys/malloc.h, which needs M_NFSDIROFF, - * M_NFSRVDESC and M_NFSBIGFH added. - * The VA_EXCLUSIVE flag should be added for va_vaflags and set for an - * exclusive create. * The B_INVAFTERWRITE flag should be set to whatever is required by the * buffer cache code to say "Invalidate the block after it is written back". */ -#ifndef B_NEEDCOMMIT -#define B_NEEDCOMMIT B_APPENDWRITE -#endif -#ifndef M_NFSRVDESC -#define M_NFSRVDESC M_TEMP -#endif -#ifndef M_NFSDIROFF -#define M_NFSDIROFF M_TEMP -#endif -#ifndef M_NFSBIGFH -#define M_NFSBIGFH M_TEMP -#endif -#ifndef VA_EXCLUSIVE -#define VA_EXCLUSIVE 0 -#endif #ifdef __FreeBSD__ #define B_INVAFTERWRITE B_NOCACHE #else @@ -120,20 +99,6 @@ #endif /* - * These ifdefs try to handle the differences between the various 4.4BSD-Lite - * based vfs interfaces. - * btw: NetBSD-current does have a VOP_LEASDE(), but I don't know how to - * differentiate between NetBSD-1.0 and NetBSD-current, so.. - * I also don't know about BSDi's 2.0 release. - */ -#if !defined(HAS_VOPLEASE) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#define HAS_VOPLEASE 1 -#endif -#if !defined(HAS_VOPREVOKE) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#define HAS_VOPREVOKE 1 -#endif - -/* * The IO_METASYNC flag should be implemented for local file systems. * (Until then, it is nothin at all.) */ @@ -164,13 +129,114 @@ #define NFS_SVCALLOC 256 #define NFS_UIDALLOC 128 +#endif /* KERNEL */ + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ + +/* + * Arguments to mount NFS + */ +#define NFS_ARGSVERSION 3 /* change when nfs_args changes */ +struct nfs_args { + int version; /* args structure version number */ + struct sockaddr *addr; /* file server address */ + int addrlen; /* length of address */ + int sotype; /* Socket type */ + int proto; /* and Protocol */ + u_char *fh; /* File handle to be mounted */ + int fhsize; /* Size, in bytes, of fh */ + int flags; /* flags */ + int wsize; /* write size in bytes */ + int rsize; /* read size in bytes */ + int readdirsize; /* readdir size in bytes */ + int timeo; /* initial timeout in .1 secs */ + int retrans; /* times to retry send */ + int maxgrouplist; /* Max. size of group list */ + int readahead; /* # of blocks to readahead */ + int leaseterm; /* Term (sec) of lease */ + int deadthresh; /* Retrans threshold */ + char *hostname; /* server's name */ +}; + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ + /* * Structures for the nfssvc(2) syscall. Not that anyone but nfsd and mount_nfs * should ever try and use it. */ struct nfsd_args { int sock; /* Socket to serve */ - caddr_t name; /* Client address for connection based sockets */ + caddr_t name; /* Client addr for connection based sockets */ int namelen; /* Length of name */ }; @@ -200,6 +266,10 @@ struct nfsd_cargs { }; /* + * XXX to allow amd to include nfs.h without nfsproto.h + */ +#ifdef NFS_NPROCS +/* * Stats structure */ struct nfsstats { @@ -237,6 +307,7 @@ struct nfsstats { int srvnqnfs_getleases; int srvvop_writes; }; +#endif /* * Flags for nfssvc() system call. @@ -267,7 +338,7 @@ struct nfsstats { * such as SIGALRM will not expect file I/O system calls to be interrupted * by them and break. */ -#if defined(KERNEL) || defined(_KERNEL) +#ifdef KERNEL struct uio; struct buf; struct vattr; struct nameidata; /* XXX */ @@ -482,6 +553,8 @@ extern int nfsd_head_flag; !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ sizeof (struct ucred))) + +int nfs_init __P((struct vfsconf *vfsp)); int nfs_reply __P((struct nfsreq *)); int nfs_getreq __P((struct nfsrv_descript *,struct nfsd *,int)); int nfs_send __P((struct socket *,struct mbuf *,struct mbuf *,struct nfsreq *)); @@ -516,14 +589,12 @@ int nfs_adv __P((struct mbuf **,caddr_t *,int,int)); void nfs_nhinit __P((void)); void nfs_timer __P((void*)); u_long nfs_hash __P((nfsfh_t *,int)); -void nfsrv_slpderef __P((struct nfssvc_sock *slp)); int nfsrv_dorec __P((struct nfssvc_sock *,struct nfsd *,struct nfsrv_descript **)); -void nfsrv_cleancache __P((void)); int nfsrv_getcache __P((struct nfsrv_descript *,struct nfssvc_sock *,struct mbuf **)); -int nfs_init __P((void)); void nfsrv_updatecache __P((struct nfsrv_descript *,int,struct mbuf *)); +void nfsrv_cleancache __P((void)); int nfs_connect __P((struct nfsmount *,struct nfsreq *)); -void nfs_disconnect __P((struct nfsmount *nmp)); +void nfs_disconnect __P((struct nfsmount *)); int nfs_getattrcache __P((struct vnode *,struct vattr *)); int nfsm_strtmbuf __P((struct mbuf **,char **,char *,long)); int nfs_bioread __P((struct vnode *,struct uio *,int,struct ucred *)); @@ -531,7 +602,6 @@ int nfsm_uiotombuf __P((struct uio *,struct mbuf **,int,caddr_t *)); void nfsrv_init __P((int)); void nfs_clearcommit __P((struct mount *)); int nfsrv_errmap __P((struct nfsrv_descript *, int)); -void nfsrv_rcv __P((struct socket *so, caddr_t arg, int waitflag)); void nfsrvw_sort __P((gid_t [],int)); void nfsrv_setcred __P((struct ucred *,struct ucred *)); int nfs_writebp __P((struct buf *,int)); @@ -594,8 +664,8 @@ int nfsrv_symlink __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_write __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); - - +void nfsrv_rcv __P((struct socket *so, caddr_t arg, int waitflag)); +void nfsrv_slpderef __P((struct nfssvc_sock *slp)); #endif /* KERNEL */ #endif diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c index 3a6fed2..8c79c59 100644 --- a/sys/scsi/cd.c +++ b/sys/scsi/cd.c @@ -75,7 +75,7 @@ static d_strategy_t cdstrategy; static struct cdevsw cd_cdevsw; static struct bdevsw cd_bdevsw = { cdopen, cdclose, cdstrategy, cdioctl, /*6*/ - nodump, nopsize, 0, "cd", &cd_cdevsw, -1 }; + nodump, nopsize, D_DISK, "cd", &cd_cdevsw, -1 }; static int32_t cdstrats, cdqueues; diff --git a/sys/scsi/od.c b/sys/scsi/od.c index 7964e30..439a47e 100644 --- a/sys/scsi/od.c +++ b/sys/scsi/od.c @@ -152,7 +152,7 @@ static d_strategy_t odstrategy; static struct cdevsw od_cdevsw; static struct bdevsw od_bdevsw = { odopen, odclose, odstrategy, odioctl, /*20*/ - nodump, nopsize, 0, "od", &od_cdevsw, -1 }; + nodump, nopsize, D_DISK, "od", &od_cdevsw, -1 }; /* diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index bb310537..3162f1d 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -1,3 +1,4 @@ + /* * Written by Julian Elischer (julian@dialix.oz.au) * for TRW Financial Systems for use under the MACH(2.5) operating system. @@ -120,7 +121,7 @@ static d_strategy_t sdstrategy; static struct cdevsw sd_cdevsw; static struct bdevsw sd_bdevsw = { sdopen, sdclose, sdstrategy, sdioctl, /*4*/ - sddump, sdsize, 0, "sd", &sd_cdevsw, -1 }; + sddump, sdsize, D_DISK, "sd", &sd_cdevsw, -1 }; diff --git a/sys/scsi/st.c b/sys/scsi/st.c index d3735f3..8100f04 100644 --- a/sys/scsi/st.c +++ b/sys/scsi/st.c @@ -165,7 +165,7 @@ static d_strategy_t ststrategy; static struct cdevsw st_cdevsw; static struct bdevsw st_bdevsw = { stopen, stclose, ststrategy, stioctl, /*5*/ - nodump, nopsize, 0, "st", &st_cdevsw, -1 }; + nodump, nopsize, D_TAPE, "st", &st_cdevsw, -1 }; SCSI_DEVICE_ENTRIES(st) diff --git a/sys/sys/conf.h b/sys/sys/conf.h index fd5146c..6b8c850 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -79,6 +79,13 @@ typedef int l_start_t __P((struct tty *tp)); typedef int l_modem_t __P((struct tty *tp, int flag)); /* + * Types for d_type. + */ +#define D_TAPE 1 +#define D_DISK 2 +#define D_TTY 3 + +/* * Block device switch table */ struct bdevsw { diff --git a/sys/sys/linedisc.h b/sys/sys/linedisc.h index fd5146c..6b8c850 100644 --- a/sys/sys/linedisc.h +++ b/sys/sys/linedisc.h @@ -79,6 +79,13 @@ typedef int l_start_t __P((struct tty *tp)); typedef int l_modem_t __P((struct tty *tp, int flag)); /* + * Types for d_type. + */ +#define D_TAPE 1 +#define D_DISK 2 +#define D_TTY 3 + +/* * Block device switch table */ struct bdevsw { diff --git a/sys/sys/lkm.h b/sys/sys/lkm.h index a594786..f5ff0d9 100644 --- a/sys/sys/lkm.h +++ b/sys/sys/lkm.h @@ -222,12 +222,12 @@ struct lkm_table { sysentp \ } -#define MOD_VFS(name,vfsslot,vnodeops,vfsconf) \ +#define MOD_VFS(name,vnodeops,vfsconf) \ static struct lkm_vfs _module = { \ LM_VFS, \ LKM_VERSION, \ name, \ - vfsslot, \ + 0, \ vnodeops, \ vfsconf \ } diff --git a/sys/sys/lockf.h b/sys/sys/lockf.h index 4372980..62b3f04 100644 --- a/sys/sys/lockf.h +++ b/sys/sys/lockf.h @@ -46,15 +46,19 @@ * the inode structure. Locks are sorted by the starting byte of the lock for * efficiency. */ +TAILQ_HEAD(locklist, lockf); + struct lockf { - short lf_flags; /* Lock semantics: F_POSIX, F_FLOCK, F_WAIT */ - short lf_type; /* Lock type: F_RDLCK, F_WRLCK */ - off_t lf_start; /* The byte # of the start of the lock */ - off_t lf_end; /* The byte # of the end of the lock (-1=EOF)*/ - caddr_t lf_id; /* The id of the resource holding the lock */ - struct lockf **lf_head; /* Back pointer to the head of the lockf list */ - struct lockf *lf_next; /* A pointer to the next lock on this inode */ - struct lockf *lf_block; /* The list of blocked locks */ + short lf_flags; /* Semantics: F_POSIX, F_FLOCK, F_WAIT */ + short lf_type; /* Lock type: F_RDLCK, F_WRLCK */ + off_t lf_start; /* Byte # of the start of the lock */ + off_t lf_end; /* Byte # of the end of the lock (-1=EOF) */ + caddr_t lf_id; /* Id of the resource holding the lock */ + struct lockf **lf_head; /* Back pointer to the head of the locf list */ + struct inode *lf_inode; /* Back pointer to the inode */ + struct lockf *lf_next; /* Pointer to the next lock on this inode */ + struct locklist lf_blkhd; /* List of requests blocked on this lock */ + TAILQ_ENTRY(lockf) lf_block;/* A request waiting for a lock */ }; /* Maximum length of sleep chains to traverse to try and detect deadlock. */ diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h index 2b05483..c98dc98 100644 --- a/sys/sys/malloc.h +++ b/sys/sys/malloc.h @@ -133,7 +133,8 @@ #define M_GEOM_MOD 86 /* geometry module */ #define M_GEOM_REQ 87 /* geometry request */ #define M_GEOM_MISC 88 /* geometry misc */ -#define M_LAST 89 /* Must be last type + 1 */ +#define M_VFSCONF 89 /* vfsconf structure */ +#define M_LAST 90 /* Must be last type + 1 */ #define INITKMEMNAMES { \ "free", /* 0 M_FREE */ \ @@ -222,6 +223,7 @@ "GEOM mod", /* 86 M_GEOM_MOD */ \ "GEOM req", /* 87 M_GEOM_REQ */ \ "GEOM misc", /* 88 M_GEOM_MISC */ \ + "VFS conf", /* 89 M_VFSCONF */ \ } struct kmemstats { diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 3159f4e..90a4fde 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)mount.h 8.13 (Berkeley) 3/27/94 + * @(#)mount.h 8.21 (Berkeley) 5/20/95 * $FreeBSD$ */ @@ -41,8 +41,11 @@ #include <sys/ucred.h> #endif #include <sys/queue.h> +#include <sys/lock.h> +#include <net/radix.h> +#include <sys/socket.h> /* XXX for AF_MAX */ -typedef struct fsid { long val[2]; } fsid_t; /* file system id type */ +typedef struct fsid { int32_t val[2]; } fsid_t; /* file system id type */ /* * File identifier. @@ -60,7 +63,8 @@ struct fid { * file system statistics */ -#define MNAMELEN 90 /* length of buffer for returned name */ +#define MFSNAMELEN 16 /* length of fs type name, including null */ +#define MNAMELEN 90 /* length of buffer for returned name */ struct statfs { long f_spare2; /* placeholder */ @@ -75,13 +79,14 @@ struct statfs { uid_t f_owner; /* user that mounted the filesystem */ int f_type; /* type of filesystem (see below) */ int f_flags; /* copy of mount flags */ - long f_spare[6]; /* spare for later */ + long f_spare[2]; /* spare for later */ + char f_fstypename[MFSNAMELEN]; /* fs type name */ char f_mntonname[MNAMELEN]; /* directory on which mounted */ char f_mntfromname[MNAMELEN];/* mounted filesystem */ }; /* - * File system types. + * File system types (for backwards compat with 4.4Lite.) */ #define MOUNT_NONE 0 #define MOUNT_UFS 1 /* Fast Filesystem */ @@ -140,11 +145,11 @@ struct mount { struct vfsconf *mnt_vfc; /* configuration info */ struct vnode *mnt_vnodecovered; /* vnode we mounted on */ struct vnodelst mnt_vnodelist; /* list of vnodes this mount */ + struct lock mnt_lock; /* mount structure lock */ int mnt_flag; /* flags */ int mnt_maxsymlinklen; /* max size of short symlink */ struct statfs mnt_stat; /* cache of filesystem stats */ qaddr_t mnt_data; /* private data */ -/* struct vfsconf *mnt_vfc; */ /* configuration info */ time_t mnt_time; /* last time written*/ }; @@ -185,58 +190,109 @@ struct mount { #define MNT_VISFLAGMASK (MNT_RDONLY|MNT_SYNCHRONOUS|MNT_NOEXEC|MNT_NOSUID| \ MNT_NODEV|MNT_UNION|MNT_ASYNC|MNT_EXRDONLY|MNT_EXPORTED| \ MNT_DEFEXPORTED|MNT_EXPORTANON|MNT_EXKERB|MNT_LOCAL| \ - MNT_QUOTA|MNT_ROOTFS|MNT_USER|MNT_NOATIME) + MNT_USER|MNT_QUOTA|MNT_ROOTFS|MNT_NOATIME) /* - * filesystem control flags. - * - * MNT_MLOCK lock the mount entry so that name lookup cannot proceed - * past the mount point. This keeps the subtree stable during mounts - * and unmounts. + * External filesystem control flags. */ #define MNT_UPDATE 0x00010000 /* not a real mount, just an update */ #define MNT_DELEXPORT 0x00020000 /* delete export host lists */ #define MNT_RELOAD 0x00040000 /* reload filesystem data */ #define MNT_FORCE 0x00080000 /* force unmount or readonly change */ -#define MNT_MLOCK 0x00100000 /* lock so that subtree is stable */ -#define MNT_MWAIT 0x00200000 /* someone is waiting for lock */ -#define MNT_MPBUSY 0x00400000 /* scan of mount point in progress */ -#define MNT_MPWANT 0x00800000 /* waiting for mount point */ +/* + * Internal filesystem control flags. + * + * MNT_UNMOUNT locks the mount entry so that name lookup cannot proceed + * past the mount point. This keeps the subtree stable during mounts + * and unmounts. + */ #define MNT_UNMOUNT 0x01000000 /* unmount in progress */ -#define MNT_WANTRDWR 0x02000000 /* want upgrade to read/write */ +#define MNT_MWAIT 0x02000000 /* waiting for unmount to finish */ +#define MNT_WANTRDWR 0x04000000 /* upgrade to read/write requested */ + +/* + * Sysctl CTL_VFS definitions. + * + * Second level identifier specifies which filesystem. Second level + * identifier VFS_GENERIC returns information about all filesystems. + */ +#ifdef notyet +#define VFS_GENERIC 0 /* generic filesystem information */ +#endif +#define VFS_OVFSCONF 0 /* for backward compatibility w/ FreeBSD 2.1 */ +/* + * Third level identifiers for VFS_GENERIC are given below; third + * level identifiers for specific filesystems are given in their + * mount specific header files. + */ +#define VFS_MAXTYPENUM 1 /* int: highest defined filesystem type */ +#define VFS_CONF 2 /* struct: vfsconf for filesystem given + as next argument */ +#define VFS_VFSCONF 3 /* for backward compatibility w/ FreeBSD 2.1 */ + +/* + * Flags for various system call interfaces. + * + * waitfor flags to vfs_sync() and getfsstat() + */ +#define MNT_WAIT 1 +#define MNT_NOWAIT 2 + +/* + * Generic file handle + */ +struct fhandle { + fsid_t fh_fsid; /* File system id of mount point */ + struct fid fh_fid; /* File sys specific id */ +}; +typedef struct fhandle fhandle_t; /* - * used to get configured filesystems information + * Export arguments for local filesystem mount calls. + */ +struct export_args { + int ex_flags; /* export related flags */ + uid_t ex_root; /* mapping for root uid */ + struct ucred ex_anon; /* mapping for anonymous user */ + struct sockaddr *ex_addr; /* net address to which exported */ + int ex_addrlen; /* and the net address length */ + struct sockaddr *ex_mask; /* mask of valid bits in saddr */ + int ex_masklen; /* and the smask length */ +}; + +/* + * Filesystem configuration information. One of these exists for each + * type of filesystem supported by the kernel. These are searched at + * mount time to identify the requested filesystem. */ -#define VFS_MAXNAMELEN 32 struct vfsconf { - void *vfc_vfsops; - char vfc_name[VFS_MAXNAMELEN]; - int vfc_index; - int vfc_refcount; - int vfc_flags; + struct vfsops *vfc_vfsops; /* filesystem operations vector */ + char vfc_name[MFSNAMELEN]; /* filesystem type name */ + int vfc_typenum; /* historic filesystem type number */ + int vfc_refcount; /* number mounted of this type */ + int vfc_flags; /* permanent flags */ + struct vfsconf *vfc_next; /* next in list */ }; /* * NB: these flags refer to IMPLEMENTATION properties, not properties of * any actual mounts; i.e., it does not make sense to change the flags. */ -#define VFCF_STATIC 0x00000001 /* statically compiled into kernel */ -#define VFCF_NETWORK 0x00000002 /* may get data over the network */ -#define VFCF_READONLY 0x00000004 /* writes are not implemented */ -#define VFCF_SYNTHETIC 0x00000008 /* data does not represent real files */ -#define VFCF_LOOPBACK 0x00000010 /* aliases some other mounted FS */ -#define VFCF_UNICODE 0x00000020 /* stores file names as Unicode*/ +#define VFCF_STATIC 0x00010000 /* statically compiled into kernel */ +#define VFCF_NETWORK 0x00020000 /* may get data over the network */ +#define VFCF_READONLY 0x00040000 /* writes are not implemented */ +#define VFCF_SYNTHETIC 0x00080000 /* data does not represent real files */ +#define VFCF_LOOPBACK 0x00100000 /* aliases some other mounted FS */ +#define VFCF_UNICODE 0x00200000 /* stores file names as Unicode*/ -/* - * Operations supported on mounted file system. - */ #ifdef KERNEL -extern int doforce; /* Flag to permit forcible unmounting. */ -extern struct vfsconf void_vfsconf; -extern struct vfsconf *vfsconf[]; +extern int maxvfsconf; /* highest defined filesystem type */ +extern struct vfsconf *vfsconf; /* head of list of filesystem types */ +/* + * Operations supported on mounted file system. + */ #ifdef __STDC__ struct nameidata; struct mbuf; @@ -262,7 +318,7 @@ struct vfsops { struct mbuf *nam, struct vnode **vpp, int *exflagsp, struct ucred **credanonp)); int (*vfs_vptofh) __P((struct vnode *vp, struct fid *fhp)); - int (*vfs_init) __P((void)); + int (*vfs_init) __P((struct vfsconf *)); }; #define VFS_MOUNT(MP, PATH, DATA, NDP, P) \ @@ -290,10 +346,10 @@ struct vfsops { #fsname, \ index, \ 0, \ - flags \ + flags, \ }; \ extern struct linker_set MODVNOPS; \ - MOD_VFS(#fsname,index,&MODVNOPS,&_fs_vfsconf); \ + MOD_VFS(#fsname,&MODVNOPS,&_fs_vfsconf); \ int \ fsname ## _mod(struct lkm_table *lkmtp, int cmd, int ver) { \ DISPATCH(lkmtp, cmd, ver, lkm_nullcmd, lkm_nullcmd, lkm_nullcmd); } @@ -305,30 +361,13 @@ struct vfsops { #fsname, \ index, \ 0, \ - flags | VFCF_STATIC \ + flags | VFCF_STATIC, \ }; \ DATA_SET(vfs_set,_fs_vfsconf) #endif /* VFS_LKM */ #endif /* KERNEL */ -/* - * Flags for various system call interfaces. - * - * waitfor flags to vfs_sync() and getfsstat() - */ -#define MNT_WAIT 1 -#define MNT_NOWAIT 2 - -/* - * Generic file handle - */ -struct fhandle { - fsid_t fh_fsid; /* File system id of mount point */ - struct fid fh_fid; /* File sys specific id */ -}; -typedef struct fhandle fhandle_t; - #ifdef KERNEL #include <net/radix.h> #include <sys/socket.h> /* XXX for AF_MAX */ @@ -349,158 +388,32 @@ struct netexport { struct netcred ne_defexported; /* Default export */ struct radix_node_head *ne_rtable[AF_MAX+1]; /* Individual exports */ }; -#endif /* KERNEL */ - -/* - * Export arguments for local filesystem mount calls. - */ -struct export_args { - int ex_flags; /* export related flags */ - uid_t ex_root; /* mapping for root uid */ - struct ucred ex_anon; /* mapping for anonymous user */ - struct sockaddr *ex_addr; /* net address to which exported */ - int ex_addrlen; /* and the net address length */ - struct sockaddr *ex_mask; /* mask of valid bits in saddr */ - int ex_masklen; /* and the smask length */ -}; - -/* - * Arguments to mount UFS-based filesystems - */ -struct ufs_args { - char *fspec; /* block special device to mount */ - struct export_args export; /* network export information */ -}; -#ifdef MFS -/* - * Arguments to mount MFS - */ -struct mfs_args { - char *fspec; /* name to export for statfs */ - struct export_args export; /* if exported MFSes are supported */ - caddr_t base; /* base of file system in memory */ - u_long size; /* size of file system */ -}; -#endif /* MFS */ - -#ifdef MSDOSFS -/* - * 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 */ -}; -#endif - -#ifdef CD9660 -/* - * Arguments to mount ISO 9660 filesystems. - */ -struct iso_args { - char *fspec; /* block special device to mount */ - struct export_args export; /* network export info */ - int flags; /* mounting flags, see below */ - -}; -#define ISOFSMNT_NORRIP 0x00000001 /* disable Rock Ridge Ext.*/ -#define ISOFSMNT_GENS 0x00000002 /* enable generation numbers */ -#define ISOFSMNT_EXTATT 0x00000004 /* enable extended attributes */ -#endif /* CD9660 */ - -#ifdef NFS -/* - * Arguments to mount NFS - */ -struct nfs_args { - struct sockaddr *addr; /* file server address */ - int addrlen; /* length of address */ - int sotype; /* Socket type */ - int proto; /* and Protocol */ - u_char *fh; /* File handle to be mounted */ - int fhsize; /* Size, in bytes, of fh */ - int flags; /* flags */ - int wsize; /* write size in bytes */ - int rsize; /* read size in bytes */ - int readdirsize; /* readdir size in bytes */ - int timeo; /* initial timeout in .1 secs */ - int retrans; /* times to retry send */ - int maxgrouplist; /* Max. size of group list */ - int readahead; /* # of blocks to readahead */ - int leaseterm; /* Term (sec) of lease */ - int deadthresh; /* Retrans threshold */ - char *hostname; /* server's name */ -}; - -/* - * NFS mount option flags - */ -#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ -#define NFSMNT_WSIZE 0x00000002 /* set write size */ -#define NFSMNT_RSIZE 0x00000004 /* set read size */ -#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ -#define NFSMNT_RETRANS 0x00000010 /* set number of request retrys */ -#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ -#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ -#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ -#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ -#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ -#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ -#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ -#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ -#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ -#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ -#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ -#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ -#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ -#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ -#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ -#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ -#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ -#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ -#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ -#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ -#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ -#define NFSMNT_WANTSND 0x02000000 /* Want above */ -#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ -#define NFSMNT_WANTRCV 0x08000000 /* Want above */ -#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ -#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ -#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ -#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ -#endif /* NFS */ - -#ifdef KERNEL -extern int (*mountroot) __P((void *)); -extern struct vfsops *mountrootvfsops; +extern char *mountrootfsname; /* * exported vnode operations */ int dounmount __P((struct mount *, int, struct proc *)); -struct mount *getvfs __P((fsid_t *)); /* return vfs given fsid */ -void getnewfsid __P((struct mount *, int)); -int vflush __P((struct mount *, struct vnode *, int)); +int vfs_lock __P((struct mount *)); /* lock a vfs */ +void vfs_msync __P((struct mount *, int)); +void vfs_unlock __P((struct mount *)); /* unlock a vfs */ +int vfs_busy __P((struct mount *, int, struct simplelock *, struct proc *)); int vfs_export /* process mount export info */ __P((struct mount *, struct netexport *, struct export_args *)); struct netcred *vfs_export_lookup /* lookup host in fs export list */ __P((struct mount *, struct netexport *, struct mbuf *)); -int vfs_lock __P((struct mount *)); /* lock a vfs */ +void vfs_getnewfsid __P((struct mount *)); +struct mount *vfs_getvfs __P((fsid_t *)); /* return vfs given fsid */ int vfs_mountedon __P((struct vnode *)); /* is a vfs mounted on vp */ -int vfs_mountroot __P((void *)); /* XXX goes away? */ -void vfs_msync __P((struct mount *, int)); -void vfs_unlock __P((struct mount *)); /* unlock a vfs */ +int vfs_mountroot __P((char *)); +int vfs_rootmountalloc __P((char *, char *, struct mount **)); +void vfs_unbusy __P((struct mount *, struct proc *)); void vfs_unmountall __P((void)); -int vfs_busy __P((struct mount *)); /* mark a vfs busy */ -void vfs_unbusy __P((struct mount *)); /* mark a vfs not busy */ extern CIRCLEQ_HEAD(mntlist, mount) mountlist; /* mounted filesystem list */ -extern struct vfsops *vfssw[]; /* filesystem type table */ +extern struct simplelock mountlist_slock; -#else /* KERNEL */ +#else /* !KERNEL */ #include <sys/cdefs.h> @@ -509,7 +422,7 @@ int fstatfs __P((int, struct statfs *)); int getfh __P((const char *, fhandle_t *)); int getfsstat __P((struct statfs *, long, int)); int getmntinfo __P((struct statfs **, int)); -int mount __P((int, const char *, int, void *)); +int mount __P((const char *, const char *, int, void *)); int statfs __P((const char *, struct statfs *)); int unmount __P((const char *, int)); diff --git a/sys/sys/stat.h b/sys/sys/stat.h index 8d2a83a..cfa097f 100644 --- a/sys/sys/stat.h +++ b/sys/sys/stat.h @@ -194,9 +194,7 @@ struct stat { #endif /* !_POSIX_SOURCE */ -#ifdef KERNEL -void cvtstat __P((struct stat *, struct ostat *)); -#else /* KERNEL */ +#ifndef KERNEL #include <sys/cdefs.h> __BEGIN_DECLS @@ -214,6 +212,6 @@ int lstat __P((const char *, struct stat *)); #endif __END_DECLS -#endif /* KERNEL */ +#endif /* !KERNEL */ #endif /* !_SYS_STAT_H_ */ diff --git a/sys/sys/syscall-hide.h b/sys/sys/syscall-hide.h index d24e98e..1ca8a15 100644 --- a/sys/sys/syscall-hide.h +++ b/sys/sys/syscall-hide.h @@ -197,6 +197,7 @@ HIDE_BSD(__sysctl) HIDE_BSD(mlock) HIDE_BSD(munlock) HIDE_BSD(utrace) +HIDE_BSD(undelete) HIDE_BSD(__semctl) HIDE_BSD(semget) HIDE_BSD(semop) diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index b557187..6d7130c 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -191,6 +191,7 @@ #define SYS_mlock 203 #define SYS_munlock 204 #define SYS_utrace 205 +#define SYS_undelete 206 #define SYS___semctl 220 #define SYS_semget 221 #define SYS_semop 222 diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index f36b391..ddef56d 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -272,9 +272,6 @@ int sysctl_handle_opaque SYSCTL_HANDLER_ARGS; /* * CTL_VFS identifiers */ -#define VFS_VFSCONF 0 /* get configured filesystems */ -#define VFS_MAXID 1 /* number of items */ - #define CTL_VFS_NAMES { \ { "vfsconf", CTLTYPE_STRUCT }, \ } diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h index 7e0dd6c..ec0b4c4 100644 --- a/sys/sys/sysent.h +++ b/sys/sys/sysent.h @@ -42,6 +42,8 @@ struct sysent { /* system call table */ int sy_narg; /* number of arguments */ sy_call_t *sy_call; /* implementing function */ }; +#define SCARG(p,k) ((p)->k) /* get arg from args pointer */ + /* placeholder till we integrate rest of lite2 syscallargs changes XXX */ struct image_params; struct trapframe; diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index 973c12a..8684aaa 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -82,7 +82,7 @@ struct getpid_args { int dummy; }; struct mount_args { - int type; + char * type; char * path; int flags; caddr_t data; @@ -655,6 +655,9 @@ struct utrace_args { caddr_t addr; size_t len; }; +struct undelete_args { + char * path; +}; struct __semctl_args { int semid; int semnum; @@ -777,7 +780,7 @@ int revoke __P((struct proc *, struct revoke_args *, int [])); int symlink __P((struct proc *, struct symlink_args *, int [])); int readlink __P((struct proc *, struct readlink_args *, int [])); int execve __P((struct proc *, struct execve_args *, int [])); -mode_t umask __P((struct proc *, struct umask_args *, int [])); +int umask __P((struct proc *, struct umask_args *, int [])); int chroot __P((struct proc *, struct chroot_args *, int [])); int msync __P((struct proc *, struct msync_args *, int [])); int vfork __P((struct proc *, struct vfork_args *, int [])); @@ -876,6 +879,7 @@ int __sysctl __P((struct proc *, struct sysctl_args *, int [])); int mlock __P((struct proc *, struct mlock_args *, int [])); int munlock __P((struct proc *, struct munlock_args *, int [])); int utrace __P((struct proc *, struct utrace_args *, int [])); +int undelete __P((struct proc *, struct undelete_args *, int [])); int lkmnosys __P((struct proc *, struct nosys_args *, int [])); int __semctl __P((struct proc *, struct __semctl_args *, int [])); int semget __P((struct proc *, struct semget_args *, int [])); diff --git a/sys/sys/tty.h b/sys/sys/tty.h index c99d8e9..e44526d 100644 --- a/sys/sys/tty.h +++ b/sys/sys/tty.h @@ -72,7 +72,7 @@ struct tty { long t_cancc; /* Canonical queue statistics. */ struct clist t_outq; /* Device output queue. */ long t_outcc; /* Output queue statistics. */ - int t_line; /* Interface to device drivers. */ + u_char t_line; /* Interface to device drivers. */ dev_t t_dev; /* Device. */ int t_state; /* Device and driver (TS*) state. */ int t_flags; /* Tty flags. */ diff --git a/sys/sys/user.h b/sys/sys/user.h index 17a47df..fe407ff 100644 --- a/sys/sys/user.h +++ b/sys/sys/user.h @@ -49,7 +49,7 @@ #include <vm/vm.h> /* XXX */ #include <vm/vm_param.h> /* XXX */ #include <vm/pmap.h> /* XXX */ -#include <vm/lock.h> /* XXX */ +#include <sys/lock.h> /* XXX */ #include <vm/vm_map.h> /* XXX */ #else #include <vm/vm.h> /* XXX */ diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index e3b5a4c..f61a056 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -37,6 +37,7 @@ #ifndef _SYS_VNODE_H_ #define _SYS_VNODE_H_ +#include <sys/lock.h> #include <sys/queue.h> /* @@ -70,6 +71,13 @@ LIST_HEAD(buflists, buf); typedef int vop_t __P((void *)); struct vm_object; +/* + * Reading or writing any of these items requires holding the appropriate lock. + * v_freelist is locked by the global vnode_free_list simple lock. + * v_mntvnodes is locked by the global mntvnodes simple lock. + * v_flag, v_usecount, v_holdcount and v_writecount are + * locked by the v_interlock simple lock. + */ struct vnode { u_long v_flag; /* vnode flags (see below) */ int v_usecount; /* reference count of users */ @@ -98,6 +106,8 @@ struct vnode { int v_clen; /* length of current cluster */ int v_usage; /* Vnode usage counter */ struct vm_object *v_object; /* Place to store VM object */ + struct simplelock v_interlock; /* lock on usecount and flag */ + struct lock *v_vnlock; /* used for non-locking fs's */ enum vtagtype v_tag; /* type of underlying data */ void *v_data; /* private data for fs */ }; @@ -109,19 +119,20 @@ struct vnode { /* * Vnode flags. */ -#define VROOT 0x0001 /* root of its file system */ -#define VTEXT 0x0002 /* vnode is a pure text prototype */ -#define VSYSTEM 0x0004 /* vnode being used by kernel */ -#define VOLOCK 0x0008 /* vnode is locked waiting for an object */ -#define VOWANT 0x0010 /* a process is waiting for VOLOCK */ -#define VXLOCK 0x0100 /* vnode is locked to change underlying type */ -#define VXWANT 0x0200 /* process is waiting for vnode */ -#define VBWAIT 0x0400 /* waiting for output to complete */ -#define VALIASED 0x0800 /* vnode has an alias */ -#define VDIROP 0x1000 /* LFS: vnode is involved in a directory op */ -#define VVMIO 0x2000 /* VMIO flag */ -#define VNINACT 0x4000 /* LFS: skip ufs_inactive() in lfs_vunref */ -#define VAGE 0x8000 /* Insert vnode at head of free list */ +#define VROOT 0x00001 /* root of its file system */ +#define VTEXT 0x00002 /* vnode is a pure text prototype */ +#define VSYSTEM 0x00004 /* vnode being used by kernel */ +#define VISTTY 0x00008 /* vnode represents a tty */ +#define VXLOCK 0x00100 /* vnode is locked to change underlying type */ +#define VXWANT 0x00200 /* process is waiting for vnode */ +#define VBWAIT 0x00400 /* waiting for output to complete */ +#define VALIASED 0x00800 /* vnode has an alias */ +#define VDIROP 0x01000 /* LFS: vnode is involved in a directory op */ +#define VVMIO 0x02000 /* VMIO flag */ +#define VNINACT 0x04000 /* LFS: skip ufs_inactive() in lfs_vunref */ +#define VAGE 0x08000 /* Insert vnode at head of free list */ +#define VOLOCK 0x10000 /* vnode is locked waiting for an object */ +#define VOWANT 0x20000 /* a process is waiting for VOLOCK */ /* * Vnode attributes. A field value of VNOVAL represents a field whose value @@ -150,9 +161,10 @@ struct vattr { }; /* - * Flags for va_cflags. + * Flags for va_vaflags. */ #define VA_UTIMES_NULL 0x01 /* utimes argument was NULL */ +#define VA_EXCLUSIVE 0x02 /* exclusive create request */ /* * Flags for ioflag. @@ -199,6 +211,7 @@ extern int vttoif_tab[]; #define DOCLOSE 0x0008 /* vclean: close active files */ #define V_SAVE 0x0001 /* vinvalbuf: sync file first */ #define V_SAVEMETA 0x0002 /* vinvalbuf: leave indirect blocks */ +#define REVOKEALL 0x0001 /* vop_revoke: revoke all aliases */ #ifdef DIAGNOSTIC #define HOLDRELE(vp) holdrele(vp) @@ -208,12 +221,28 @@ extern int vttoif_tab[]; void holdrele __P((struct vnode *)); void vhold __P((struct vnode *)); +void vref __P((struct vnode *vp)); #else -#define HOLDRELE(vp) (vp)->v_holdcnt-- /* decrease buf or page ref */ #define VATTR_NULL(vap) (*(vap) = va_null) /* initialize a vattr */ -#define VHOLD(vp) (vp)->v_holdcnt++ /* increase buf or page ref */ +#define HOLDRELE(vp) holdrele(vp) /* decrease buf or page ref */ +static __inline void +holdrele(struct vnode *vp) +{ + simple_lock(&vp->v_interlock); + vp->v_holdcnt--; + simple_unlock(&vp->v_interlock); +} +#define VHOLD(vp) vhold(vp) /* increase buf or page ref */ +static __inline void +vhold(struct vnode *vp) +{ + simple_lock(&vp->v_interlock); + vp->v_holdcnt++; + simple_unlock(&vp->v_interlock); +} #define VREF(vp) vref(vp) /* increase reference */ -#endif +void vref __P((struct vnode *vp)); +#endif /* DIAGNOSTIC */ #define NULLVP ((struct vnode *)NULL) @@ -237,24 +266,20 @@ extern struct vattr va_null; /* predefined null vattr structure */ #define LEASE_READ 0x1 /* Check lease for readers */ #define LEASE_WRITE 0x2 /* Check lease for modifiers */ -extern void (*lease_check) __P((struct vnode *vp, struct proc *p, - struct ucred *ucred, int flag)); + extern void (*lease_updatetime) __P((int deltat)); #ifdef NFS #ifdef NQNFS -#define LEASE_CHECK(vp, p, cred, flag) lease_check((vp), (p), (cred), (flag)) #define LEASE_UPDATETIME(dt) lease_updatetime(dt) #else -#define LEASE_CHECK(vp, p, cred, flag) #define LEASE_UPDATETIME(dt) #endif /* NQNFS */ #else -#define LEASE_CHECK(vp, p, cred, flag) \ - do { if(lease_check) lease_check((vp), (p), (cred), (flag)); } while(0) #define LEASE_UPDATETIME(dt) \ do { if(lease_updatetime) lease_updatetime(dt); } while(0) #endif /* NFS */ + #endif /* KERNEL */ @@ -313,6 +338,10 @@ struct vnodeop_desc { */ extern struct vnodeop_desc *vnodeop_descs[]; +/* + * Interlock for scanning list of vnodes attached to a mountpoint + */ +extern struct simplelock mntvnode_slock; /* * This macro is very helpful in defining those offsets in the vdesc struct. @@ -382,6 +411,7 @@ struct componentname; struct file; struct mount; struct nameidata; +struct ostat; struct proc; struct stat; struct ucred; @@ -390,6 +420,8 @@ struct vattr; struct vnode; struct vop_bwrite_args; +extern int (*lease_check_hook) __P((struct vop_lease_args *)); + int bdevvp __P((dev_t dev, struct vnode **vpp)); /* cache_* may belong in namei.h. */ void cache_enter __P((struct vnode *dvp, struct vnode *vp, @@ -398,23 +430,28 @@ int cache_lookup __P((struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)); void cache_purge __P((struct vnode *vp)); void cache_purgevfs __P((struct mount *mp)); -struct vnode * - checkalias __P((struct vnode *vp, dev_t nvp_rdev, struct mount *mp)); +void cvtstat __P((struct stat *st, struct ostat *ost)); int getnewvnode __P((enum vtagtype tag, struct mount *mp, vop_t **vops, struct vnode **vpp)); void insmntque __P((struct vnode *vp, struct mount *mp)); +int lease_check __P((struct vop_lease_args *ap)); void vattr_null __P((struct vattr *vap)); int vcount __P((struct vnode *vp)); int vfinddev __P((dev_t dev, enum vtype type, struct vnode **vpp)); void vfs_opv_init __P((struct vnodeopv_desc **them)); -int vget __P((struct vnode *vp, int lockflag)); +int vflush __P((struct mount *mp, struct vnode *skipvp, int flags)); +int vget __P((struct vnode *vp, int lockflag, struct proc *p)); void vgone __P((struct vnode *vp)); void vgoneall __P((struct vnode *vp)); int vinvalbuf __P((struct vnode *vp, int save, struct ucred *cred, struct proc *p, int slpflag, int slptimeo)); +void vprint __P((char *label, struct vnode *vp)); +int vrecycle __P((struct vnode *vp, struct simplelock *inter_lkp, + struct proc *p)); int vn_bwrite __P((struct vop_bwrite_args *ap)); int vn_close __P((struct vnode *vp, int flags, struct ucred *cred, struct proc *p)); +int vn_lock __P((struct vnode *vp, int flags, struct proc *p)); int vn_open __P((struct nameidata *ndp, int fmode, int cmode)); int vn_rdwr __P((enum uio_rw rw, struct vnode *vp, caddr_t base, int len, off_t offset, enum uio_seg segflg, int ioflg, @@ -423,9 +460,13 @@ int vn_stat __P((struct vnode *vp, struct stat *sb, struct proc *p)); int vfs_object_create __P((struct vnode *vp, struct proc *p, struct ucred *cred, int waslocked)); int vn_writechk __P((struct vnode *vp)); -void vprint __P((char *label, struct vnode *vp)); +int vop_noislocked __P((struct vop_islocked_args *)); +int vop_nolock __P((struct vop_lock_args *)); +int vop_nounlock __P((struct vop_unlock_args *)); +int vop_revoke __P((struct vop_revoke_args *)); +struct vnode * + checkalias __P((struct vnode *vp, dev_t nvp_rdev, struct mount *mp)); void vput __P((struct vnode *vp)); -void vref __P((struct vnode *vp)); void vrele __P((struct vnode *vp)); #endif /* KERNEL */ diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index e1272ab..4787c1c 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_alloc.c 8.8 (Berkeley) 2/21/94 + * @(#)ffs_alloc.c 8.18 (Berkeley) 5/26/95 * $FreeBSD$ */ @@ -57,23 +57,23 @@ extern u_long nextgennumber; -typedef daddr_t allocfcn_t __P((struct inode *ip, int cg, daddr_t bpref, - int size)); +typedef ufs_daddr_t allocfcn_t __P((struct inode *ip, int cg, ufs_daddr_t bpref, + int size)); -static daddr_t ffs_alloccg __P((struct inode *, int, daddr_t, int)); -static daddr_t ffs_alloccgblk __P((struct fs *, struct cg *, daddr_t)); -#ifdef notyet -static daddr_t ffs_clusteralloc __P((struct inode *, int, daddr_t, int)); -#endif +static ufs_daddr_t ffs_alloccg __P((struct inode *, int, ufs_daddr_t, int)); +static ufs_daddr_t ffs_alloccgblk __P((struct fs *, struct cg *, ufs_daddr_t)); +static void ffs_clusteracct __P((struct fs *, struct cg *, ufs_daddr_t, + int)); +static ufs_daddr_t ffs_clusteralloc __P((struct inode *, int, ufs_daddr_t, + int)); static ino_t ffs_dirpref __P((struct fs *)); -static daddr_t ffs_fragextend __P((struct inode *, int, long, int, int)); +static ufs_daddr_t ffs_fragextend __P((struct inode *, int, long, int, int)); static void ffs_fserr __P((struct fs *, u_int, char *)); static u_long ffs_hashalloc __P((struct inode *, int, long, int, allocfcn_t *)); -static ino_t ffs_nodealloccg __P((struct inode *, int, daddr_t, int)); -static daddr_t ffs_mapsearch __P((struct fs *, struct cg *, daddr_t, int)); - -static void ffs_clusteracct __P((struct fs *, struct cg *, daddr_t, int)); +static ino_t ffs_nodealloccg __P((struct inode *, int, ufs_daddr_t, int)); +static ufs_daddr_t ffs_mapsearch __P((struct fs *, struct cg *, ufs_daddr_t, + int)); /* * Allocate a block in the file system. @@ -97,19 +97,18 @@ static void ffs_clusteracct __P((struct fs *, struct cg *, daddr_t, int)); int ffs_alloc(ip, lbn, bpref, size, cred, bnp) register struct inode *ip; - daddr_t lbn, bpref; + ufs_daddr_t lbn, bpref; int size; struct ucred *cred; - daddr_t *bnp; + ufs_daddr_t *bnp; { register struct fs *fs; - daddr_t bno; + ufs_daddr_t bno; int cg; #ifdef QUOTA int error; #endif - *bnp = 0; fs = ip->i_fs; #ifdef DIAGNOSTIC @@ -136,7 +135,8 @@ ffs_alloc(ip, lbn, bpref, size, cred, bnp) cg = ino_to_cg(fs, ip->i_number); else cg = dtog(fs, bpref); - bno = (daddr_t)ffs_hashalloc(ip, cg, (long)bpref, size, ffs_alloccg); + bno = (ufs_daddr_t)ffs_hashalloc(ip, cg, (long)bpref, size, + ffs_alloccg); if (bno > 0) { ip->i_blocks += btodb(size); ip->i_flag |= IN_CHANGE | IN_UPDATE; @@ -166,8 +166,8 @@ nospace: int ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) register struct inode *ip; - daddr_t lbprev; - daddr_t bpref; + ufs_daddr_t lbprev; + ufs_daddr_t bpref; int osize, nsize; struct ucred *cred; struct buf **bpp; @@ -175,7 +175,7 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) register struct fs *fs; struct buf *bp; int cg, request, error; - daddr_t bprev, bno; + ufs_daddr_t bprev, bno; *bpp = 0; fs = ip->i_fs; @@ -285,7 +285,8 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) panic("ffs_realloccg: bad optim"); /* NOTREACHED */ } - bno = (daddr_t)ffs_hashalloc(ip, cg, (long)bpref, request, ffs_alloccg); + bno = (ufs_daddr_t)ffs_hashalloc(ip, cg, (long)bpref, request, + ffs_alloccg); if (bno > 0) { bp->b_blkno = fsbtodb(fs, bno); ffs_blkfree(ip, bprev, (long)osize); @@ -331,7 +332,13 @@ nospace: * the previous block allocation will be used. */ static int doasyncfree = 1; -SYSCTL_INT(_debug, OID_AUTO, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, ""); +SYSCTL_INT(_vfs_ffs, FFS_ASYNCFREE, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, ""); + +int doreallocblks = 1; +SYSCTL_INT(_vfs_ffs, FFS_REALLOCBLKS, doreallocblks, CTLFLAG_RW, &doreallocblks, 0, ""); + +static int prtrealloc = 0; + int ffs_reallocblks(ap) struct vop_reallocblks_args /* { @@ -346,13 +353,15 @@ ffs_reallocblks(ap) struct inode *ip; struct vnode *vp; struct buf *sbp, *ebp; - daddr_t *bap, *sbap, *ebap = 0; + ufs_daddr_t *bap, *sbap, *ebap = 0; struct cluster_save *buflist; - daddr_t start_lbn, end_lbn, soff, newblk, blkno; + ufs_daddr_t start_lbn, end_lbn, soff, newblk, blkno; struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp; int i, len, start_lvl, end_lvl, pref, ssize; struct timeval tv; + if (doreallocblks == 0) + return (ENOSPC); vp = ap->a_vp; ip = VTOI(vp); fs = ip->i_fs; @@ -363,9 +372,18 @@ ffs_reallocblks(ap) start_lbn = buflist->bs_children[0]->b_lblkno; end_lbn = start_lbn + len - 1; #ifdef DIAGNOSTIC + for (i = 0; i < len; i++) + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 1"); for (i = 1; i < len; i++) if (buflist->bs_children[i]->b_lblkno != start_lbn + i) - panic("ffs_reallocblks: non-cluster"); + panic("ffs_reallocblks: non-logical cluster"); + blkno = buflist->bs_children[0]->b_blkno; + ssize = fsbtodb(fs, fs->fs_frag); + for (i = 1; i < len - 1; i++) + if (buflist->bs_children[i]->b_blkno != blkno + (i * ssize)) + panic("ffs_reallocblks: non-physical cluster %d", i); #endif /* * If the latest allocation is in a new cylinder group, assume that @@ -390,7 +408,7 @@ ffs_reallocblks(ap) brelse(sbp); return (ENOSPC); } - sbap = (daddr_t *)sbp->b_data; + sbap = (ufs_daddr_t *)sbp->b_data; soff = idp->in_off; } /* @@ -410,12 +428,12 @@ ffs_reallocblks(ap) ssize = len - (idp->in_off + 1); if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &ebp)) goto fail; - ebap = (daddr_t *)ebp->b_data; + ebap = (ufs_daddr_t *)ebp->b_data; } /* * Search the block map looking for an allocation of the desired size. */ - if ((newblk = (daddr_t)ffs_hashalloc(ip, dtog(fs, pref), (long)pref, + if ((newblk = (ufs_daddr_t)ffs_hashalloc(ip, dtog(fs, pref), (long)pref, len, ffs_clusteralloc)) == 0) goto fail; /* @@ -425,14 +443,26 @@ ffs_reallocblks(ap) * block pointers in the inode and indirect blocks associated * with the file. */ +#ifdef DEBUG + if (prtrealloc) + printf("realloc: ino %d, lbns %d-%d\n\told:", ip->i_number, + start_lbn, end_lbn); +#endif blkno = newblk; for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->fs_frag) { if (i == ssize) bap = ebap; #ifdef DIAGNOSTIC - if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap)) + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 2"); + if (dbtofsb(fs, buflist->bs_children[i]->b_blkno) != *bap) panic("ffs_reallocblks: alloc mismatch"); #endif +#ifdef DEBUG + if (prtrealloc) + printf(" %d,", *bap); +#endif *bap++ = blkno; } /* @@ -469,11 +499,28 @@ ffs_reallocblks(ap) /* * Last, free the old blocks and assign the new blocks to the buffers. */ +#ifdef DEBUG + if (prtrealloc) + printf("\n\tnew:"); +#endif for (blkno = newblk, i = 0; i < len; i++, blkno += fs->fs_frag) { ffs_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize); buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); +#ifdef DEBUG + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 3"); + if (prtrealloc) + printf(" %d,", blkno); +#endif + } +#ifdef DEBUG + if (prtrealloc) { + prtrealloc--; + printf("\n"); } +#endif return (0); fail: @@ -615,17 +662,17 @@ ffs_dirpref(fs) * fs_rotdelay milliseconds. This is to allow time for the processor to * schedule another I/O transfer. */ -daddr_t +ufs_daddr_t ffs_blkpref(ip, lbn, indx, bap) struct inode *ip; - daddr_t lbn; + ufs_daddr_t lbn; int indx; - daddr_t *bap; + ufs_daddr_t *bap; { register struct fs *fs; register int cg; int avgbfree, startcg; - daddr_t nextblk; + ufs_daddr_t nextblk; fs = ip->i_fs; if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { @@ -740,7 +787,7 @@ ffs_hashalloc(ip, cg, pref, size, allocator) * Check to see if the necessary fragments are available, and * if they are, allocate them. */ -static daddr_t +static ufs_daddr_t ffs_fragextend(ip, cg, bprev, osize, nsize) struct inode *ip; int cg; @@ -810,11 +857,11 @@ ffs_fragextend(ip, cg, bprev, osize, nsize) * Check to see if a block of the appropriate size is available, * and if it is, allocate it. */ -static daddr_t +static ufs_daddr_t ffs_alloccg(ip, cg, bpref, size) struct inode *ip; int cg; - daddr_t bpref; + ufs_daddr_t bpref; int size; { register struct fs *fs; @@ -904,13 +951,13 @@ ffs_alloccg(ip, cg, bpref, size) * Note that this routine only allocates fs_bsize blocks; these * blocks may be fragmented by the routine that allocates them. */ -static daddr_t +static ufs_daddr_t ffs_alloccgblk(fs, cgp, bpref) register struct fs *fs; register struct cg *cgp; - daddr_t bpref; + ufs_daddr_t bpref; { - daddr_t bno, blkno; + ufs_daddr_t bno, blkno; int cylno, pos, delta; short *cylbp; register int i; @@ -1016,21 +1063,22 @@ gotit: * are multiple choices in the same cylinder group. Instead we just * take the first one that we find following bpref. */ -static daddr_t +static ufs_daddr_t ffs_clusteralloc(ip, cg, bpref, len) struct inode *ip; int cg; - daddr_t bpref; + ufs_daddr_t bpref; int len; { register struct fs *fs; register struct cg *cgp; struct buf *bp; - int i, run, bno, bit, map; + int i, got, run, bno, bit, map; u_char *mapp; + int32_t *lp; fs = ip->i_fs; - if (fs->fs_cs(fs, cg).cs_nbfree < len) + if (fs->fs_maxcluster[cg] < len) return (NULL); if (bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, NOCRED, &bp)) @@ -1042,11 +1090,25 @@ ffs_clusteralloc(ip, cg, bpref, len) * Check to see if a cluster of the needed size (or bigger) is * available in this cylinder group. */ + lp = &cg_clustersum(cgp)[len]; for (i = len; i <= fs->fs_contigsumsize; i++) - if (cg_clustersum(cgp)[i] > 0) + if (*lp++ > 0) break; - if (i > fs->fs_contigsumsize) + if (i > fs->fs_contigsumsize) { + /* + * This is the first time looking for a cluster in this + * cylinder group. Update the cluster summary information + * to reflect the true maximum sized cluster so that + * future cluster allocation requests can avoid reading + * the cylinder group map only to find no clusters. + */ + lp = &cg_clustersum(cgp)[len - 1]; + for (i = len - 1; i > 0; i--) + if (*lp-- > 0) + break; + fs->fs_maxcluster[cg] = i; goto fail; + } /* * Search the cluster map to find a big enough cluster. * We take the first one that we find, even if it is larger @@ -1065,7 +1127,7 @@ ffs_clusteralloc(ip, cg, bpref, len) mapp = &cg_clustersfree(cgp)[bpref / NBBY]; map = *mapp++; bit = 1 << (bpref % NBBY); - for (run = 0, i = bpref; i < cgp->cg_nclusterblks; i++) { + for (run = 0, got = bpref; got < cgp->cg_nclusterblks; got++) { if ((map & bit) == 0) { run = 0; } else { @@ -1073,22 +1135,27 @@ ffs_clusteralloc(ip, cg, bpref, len) if (run == len) break; } - if ((i & (NBBY - 1)) != (NBBY - 1)) { + if ((got & (NBBY - 1)) != (NBBY - 1)) { bit <<= 1; } else { map = *mapp++; bit = 1; } } - if (i == cgp->cg_nclusterblks) + if (got == cgp->cg_nclusterblks) goto fail; /* * Allocate the cluster that we have found. */ - bno = cg * fs->fs_fpg + blkstofrags(fs, i - run + 1); + for (i = 1; i <= len; i++) + if (!ffs_isblock(fs, cg_blksfree(cgp), got - run + i)) + panic("ffs_clusteralloc: map mismatch"); + bno = cg * fs->fs_fpg + blkstofrags(fs, got - run + 1); + if (dtog(fs, bno) != cg) + panic("ffs_clusteralloc: allocated out of group"); len = blkstofrags(fs, len); for (i = 0; i < len; i += fs->fs_frag) - if (ffs_alloccgblk(fs, cgp, bno + i) != bno + i) + if ((got = ffs_alloccgblk(fs, cgp, bno + i)) != bno + i) panic("ffs_clusteralloc: lost block"); bdwrite(bp); return (bno); @@ -1112,7 +1179,7 @@ static ino_t ffs_nodealloccg(ip, cg, ipref, mode) struct inode *ip; int cg; - daddr_t ipref; + ufs_daddr_t ipref; int mode; { register struct fs *fs; @@ -1191,13 +1258,13 @@ gotit: void ffs_blkfree(ip, bno, size) register struct inode *ip; - daddr_t bno; + ufs_daddr_t bno; long size; { register struct fs *fs; register struct cg *cgp; struct buf *bp; - daddr_t blkno; + ufs_daddr_t blkno; int i, error, cg, blk, frags, bbase; fs = ip->i_fs; @@ -1288,6 +1355,56 @@ ffs_blkfree(ip, bno, size) bdwrite(bp); } +#ifdef DIAGNOSTIC +/* + * Verify allocation of a block or fragment. Returns true if block or + * fragment is allocated, false if it is free. + */ +ffs_checkblk(ip, bno, size) + struct inode *ip; + ufs_daddr_t bno; + long size; +{ + struct fs *fs; + struct cg *cgp; + struct buf *bp; + int i, error, frags, free; + + fs = ip->i_fs; + if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) { + printf("bsize = %d, size = %d, fs = %s\n", + fs->fs_bsize, size, fs->fs_fsmnt); + panic("checkblk: bad size"); + } + if ((u_int)bno >= fs->fs_size) + panic("checkblk: bad block %d", bno); + error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, dtog(fs, bno))), + (int)fs->fs_cgsize, NOCRED, &bp); + if (error) { + brelse(bp); + return; + } + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp)) { + brelse(bp); + return; + } + bno = dtogd(fs, bno); + if (size == fs->fs_bsize) { + free = ffs_isblock(fs, cg_blksfree(cgp), fragstoblks(fs, bno)); + } else { + frags = numfrags(fs, size); + for (free = 0, i = 0; i < frags; i++) + if (isset(cg_blksfree(cgp), bno + i)) + free++; + if (free != 0 && free != frags) + panic("checkblk: partially free fragment"); + } + brelse(bp); + return (!free); +} +#endif /* DIAGNOSTIC */ + /* * Free an inode. * @@ -1355,14 +1472,14 @@ ffs_vfree(ap) * It is a panic if a request is made to find a block if none are * available. */ -static daddr_t +static ufs_daddr_t ffs_mapsearch(fs, cgp, bpref, allocsiz) register struct fs *fs; register struct cg *cgp; - daddr_t bpref; + ufs_daddr_t bpref; int allocsiz; { - daddr_t bno; + ufs_daddr_t bno; int start, len, loc, i; int blk, field, subfield, pos; @@ -1423,10 +1540,11 @@ static void ffs_clusteracct(fs, cgp, blkno, cnt) struct fs *fs; struct cg *cgp; - daddr_t blkno; + ufs_daddr_t blkno; int cnt; { - long *sump; + int32_t *sump; + int32_t *lp; u_char *freemapp, *mapp; int i, start, end, forw, back, map, bit; @@ -1495,6 +1613,14 @@ ffs_clusteracct(fs, cgp, blkno, cnt) sump[back] -= cnt; if (forw > 0) sump[forw] -= cnt; + /* + * Update cluster summary information. + */ + lp = &sump[fs->fs_contigsumsize]; + for (i = fs->fs_contigsumsize; i > 0; i--) + if (*lp-- > 0) + break; + fs->fs_maxcluster[cgp->cg_cgx] = i; } /* diff --git a/sys/ufs/ffs/ffs_balloc.c b/sys/ufs/ffs/ffs_balloc.c index 4d382fa..5d7d798 100644 --- a/sys/ufs/ffs/ffs_balloc.c +++ b/sys/ufs/ffs/ffs_balloc.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93 + * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95 * $FreeBSD$ */ @@ -56,27 +56,27 @@ * the inode and the logical block number in a file. */ int -ffs_balloc(ip, bn, size, cred, bpp, flags) +ffs_balloc(ip, lbn, size, cred, bpp, flags) register struct inode *ip; - register daddr_t bn; + register ufs_daddr_t lbn; int size; struct ucred *cred; struct buf **bpp; int flags; { register struct fs *fs; - register daddr_t nb; + register ufs_daddr_t nb; struct buf *bp, *nbp; struct vnode *vp = ITOV(ip); struct indir indirs[NIADDR + 2]; - daddr_t newb, lbn, *bap, pref; - int osize, nsize, num, i, error; + ufs_daddr_t newb, *bap, pref; + int deallocated, osize, nsize, num, i, error; + ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; *bpp = NULL; - if (bn < 0) + if (lbn < 0) return (EFBIG); fs = ip->i_fs; - lbn = bn; /* * If the next write will extend the file into a new block, @@ -84,7 +84,7 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) * this fragment has to be extended to be a full block. */ nb = lblkno(fs, ip->i_size); - if (nb < NDADDR && nb < bn) { + if (nb < NDADDR && nb < lbn) { osize = blksize(fs, ip, nb); if (osize < fs->fs_bsize && osize > 0) { error = ffs_realloccg(ip, nb, @@ -104,10 +104,10 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) /* * The first NDADDR blocks are direct blocks */ - if (bn < NDADDR) { - nb = ip->i_db[bn]; - if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) { - error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp); + if (lbn < NDADDR) { + nb = ip->i_db[lbn]; + if (nb != 0 && ip->i_size >= (lbn + 1) * fs->fs_bsize) { + error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp); if (error) { brelse(bp); return (error); @@ -123,35 +123,35 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) osize = fragroundup(fs, blkoff(fs, ip->i_size)); nsize = fragroundup(fs, size); if (nsize <= osize) { - error = bread(vp, bn, osize, NOCRED, &bp); + error = bread(vp, lbn, osize, NOCRED, &bp); if (error) { brelse(bp); return (error); } bp->b_blkno = fsbtodb(fs, nb); } else { - error = ffs_realloccg(ip, bn, - ffs_blkpref(ip, bn, (int)bn, &ip->i_db[0]), - osize, nsize, cred, &bp); + error = ffs_realloccg(ip, lbn, + ffs_blkpref(ip, lbn, (int)lbn, + &ip->i_db[0]), osize, nsize, cred, &bp); if (error) return (error); } } else { - if (ip->i_size < (bn + 1) * fs->fs_bsize) + if (ip->i_size < (lbn + 1) * fs->fs_bsize) nsize = fragroundup(fs, size); else nsize = fs->fs_bsize; - error = ffs_alloc(ip, bn, - ffs_blkpref(ip, bn, (int)bn, &ip->i_db[0]), + error = ffs_alloc(ip, lbn, + ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]), nsize, cred, &newb); if (error) return (error); - bp = getblk(vp, bn, nsize, 0, 0); + bp = getblk(vp, lbn, nsize, 0, 0); bp->b_blkno = fsbtodb(fs, newb); if (flags & B_CLRBUF) vfs_bio_clrbuf(bp); } - ip->i_db[bn] = dbtofsb(fs, bp->b_blkno); + ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno); ip->i_flag |= IN_CHANGE | IN_UPDATE; *bpp = bp; return (0); @@ -160,8 +160,7 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) * Determine the number of levels of indirection. */ pref = 0; - error = ufs_getlbns(vp, bn, indirs, &num); - if (error) + if (error = ufs_getlbns(vp, lbn, indirs, &num)) return(error); #ifdef DIAGNOSTIC if (num < 1) @@ -172,26 +171,26 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) */ --num; nb = ip->i_ib[indirs[0].in_off]; + allocib = NULL; + allocblk = allociblk; if (nb == 0) { - pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); - error = ffs_alloc(ip, lbn, pref, - (int)fs->fs_bsize, cred, &newb); - if (error) + pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); + if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, + cred, &newb)) return (error); nb = newb; + *allocblk++ = nb; bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0); - bp->b_blkno = fsbtodb(fs, newb); + bp->b_blkno = fsbtodb(fs, nb); vfs_bio_clrbuf(bp); /* * Write synchronously so that indirect blocks * never point at garbage. */ - error = bwrite(bp); - if (error) { - ffs_blkfree(ip, nb, fs->fs_bsize); - return (error); - } - ip->i_ib[indirs[0].in_off] = newb; + if (error = bwrite(bp)) + goto fail; + allocib = &ip->i_ib[indirs[0].in_off]; + *allocib = nb; ip->i_flag |= IN_CHANGE | IN_UPDATE; } /* @@ -202,9 +201,9 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp); if (error) { brelse(bp); - return (error); + goto fail; } - bap = (daddr_t *)bp->b_data; + bap = (ufs_daddr_t *)bp->b_data; nb = bap[indirs[i].in_off]; if (i == num) break; @@ -214,14 +213,14 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) continue; } if (pref == 0) - pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); - error = - ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb); - if (error) { + pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); + if (error = + ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) { brelse(bp); - return (error); + goto fail; } nb = newb; + *allocblk++ = nb; nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); vfs_bio_clrbuf(nbp); @@ -229,11 +228,9 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) * Write synchronously so that indirect blocks * never point at garbage. */ - error = bwrite(nbp); - if (error) { - ffs_blkfree(ip, nb, fs->fs_bsize); + if (error = bwrite(nbp)) { brelse(bp); - return (error); + goto fail; } bap[indirs[i - 1].in_off] = nb; /* @@ -255,9 +252,10 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) lbn, pref, (int)fs->fs_bsize, cred, &newb); if (error) { brelse(bp); - return (error); + goto fail; } nb = newb; + *allocblk++ = nb; nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); if (flags & B_CLRBUF) @@ -280,7 +278,7 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); if (error) { brelse(nbp); - return (error); + goto fail; } } else { nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); @@ -288,4 +286,26 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) } *bpp = nbp; return (0); +fail: + /* + * If we have failed part way through block allocation, we + * have to deallocate any indirect blocks that we have allocated. + */ + for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { + ffs_blkfree(ip, *blkp, fs->fs_bsize); + deallocated += fs->fs_bsize; + } + if (allocib != NULL) + *allocib = 0; + if (deallocated) { +#ifdef QUOTA + /* + * Restore user's disk quota because allocation failed. + */ + (void) chkdq(ip, (long)-btodb(deallocated), cred, FORCE); +#endif + ip->i_blocks -= btodb(deallocated); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } + return (error); } diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index c0ef7c4..f168d01 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -30,13 +30,31 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_extern.h 8.3 (Berkeley) 4/16/94 + * @(#)ffs_extern.h 8.6 (Berkeley) 3/30/95 * $FreeBSD$ */ #ifndef _UFS_FFS_EXTERN_H #define _UFS_FFS_EXTERN_H +/* + * Sysctl values for the fast filesystem. + */ +#define FFS_CLUSTERREAD 1 /* cluster reading enabled */ +#define FFS_CLUSTERWRITE 2 /* cluster writing enabled */ +#define FFS_REALLOCBLKS 3 /* block reallocation enabled */ +#define FFS_ASYNCFREE 4 /* asynchronous block freeing enabled */ +#define FFS_MAXID 5 /* number of valid ffs ids */ + +#define FFS_NAMES { \ + { 0, 0 }, \ + { "doclusterread", CTLTYPE_INT }, \ + { "doclusterwrite", CTLTYPE_INT }, \ + { "doreallocblks", CTLTYPE_INT }, \ + { "doasyncfree", CTLTYPE_INT }, \ +} + +struct buf; struct fid; struct fs; struct inode; @@ -44,29 +62,28 @@ struct mbuf; struct mount; struct statfs; struct vnode; +struct mbuf; int ffs_alloc __P((struct inode *, - daddr_t, daddr_t, int, struct ucred *, daddr_t *)); + ufs_daddr_t, ufs_daddr_t, int, struct ucred *, ufs_daddr_t *)); int ffs_balloc __P((struct inode *, - daddr_t, int, struct ucred *, struct buf **, int)); + ufs_daddr_t, int, struct ucred *, struct buf **, int)); int ffs_blkatoff __P((struct vop_blkatoff_args *)); -void ffs_blkfree __P((struct inode *, daddr_t, long)); -daddr_t ffs_blkpref __P((struct inode *, daddr_t, int, daddr_t *)); +void ffs_blkfree __P((struct inode *, ufs_daddr_t, long)); +ufs_daddr_t ffs_blkpref __P((struct inode *, ufs_daddr_t, int, ufs_daddr_t *)); int ffs_bmap __P((struct vop_bmap_args *)); -void ffs_clrblock __P((struct fs *, u_char *, daddr_t)); +void ffs_clrblock __P((struct fs *, u_char *, ufs_daddr_t)); int ffs_fhtovp __P((struct mount *, struct fid *, struct mbuf *, struct vnode **, int *, struct ucred **)); -int ffs_flushfiles __P((struct mount *, int, struct proc *)); -void ffs_fragacct __P((struct fs *, int, long [], int)); -int ffs_init __P((void)); -int ffs_isblock __P((struct fs *, u_char *, daddr_t)); +void ffs_fragacct __P((struct fs *, int, int32_t [], int)); +int ffs_isblock __P((struct fs *, u_char *, ufs_daddr_t)); int ffs_mountfs __P((struct vnode *, struct mount *, struct proc *)); int ffs_mountroot __P((void)); int ffs_reallocblks __P((struct vop_reallocblks_args *)); int ffs_realloccg __P((struct inode *, - daddr_t, daddr_t, int, int, struct ucred *, struct buf **)); + ufs_daddr_t, ufs_daddr_t, int, int, struct ucred *, struct buf **)); int ffs_reclaim __P((struct vop_reclaim_args *)); -void ffs_setblock __P((struct fs *, u_char *, daddr_t)); +void ffs_setblock __P((struct fs *, u_char *, ufs_daddr_t)); int ffs_statfs __P((struct mount *, struct statfs *, struct proc *)); int ffs_sync __P((struct mount *, int, struct ucred *, struct proc *)); int ffs_truncate __P((struct vop_truncate_args *)); diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c index ba3e82a..f7af3f3 100644 --- a/sys/ufs/ffs/ffs_inode.c +++ b/sys/ufs/ffs/ffs_inode.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_inode.c 8.5 (Berkeley) 12/30/93 + * @(#)ffs_inode.c 8.13 (Berkeley) 4/21/95 * $FreeBSD$ */ @@ -59,14 +59,8 @@ #include <ufs/ffs/fs.h> #include <ufs/ffs/ffs_extern.h> -static int ffs_indirtrunc __P((struct inode *, daddr_t, daddr_t, daddr_t, int, - long *)); - -int -ffs_init() -{ - return (ufs_init()); -} +static int ffs_indirtrunc __P((struct inode *, ufs_daddr_t, ufs_daddr_t, + ufs_daddr_t, int, long *)); /* * Update the access, modified, and inode change times as specified by the @@ -115,15 +109,15 @@ ffs_update(ap) */ tv_sec = time.tv_sec; if (ip->i_flag & IN_ACCESS) - ip->i_atime.tv_sec = + ip->i_atime = (ap->a_access == &time ? tv_sec : ap->a_access->tv_sec); if (ip->i_flag & IN_UPDATE) { - ip->i_mtime.tv_sec = + ip->i_mtime = (ap->a_modify == &time ? tv_sec : ap->a_modify->tv_sec); ip->i_modrev++; } if (ip->i_flag & IN_CHANGE) - ip->i_ctime.tv_sec = tv_sec; + ip->i_ctime = tv_sec; ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); fs = ip->i_fs; /* @@ -169,10 +163,10 @@ ffs_truncate(ap) } */ *ap; { register struct vnode *ovp = ap->a_vp; - register daddr_t lastblock; + ufs_daddr_t lastblock; register struct inode *oip; - daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR]; - daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR]; + ufs_daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR]; + ufs_daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR]; off_t length = ap->a_length; register struct fs *fs; struct buf *bp; @@ -185,8 +179,10 @@ ffs_truncate(ap) oip = VTOI(ovp); fs = oip->i_fs; - if (length < 0 || length > fs->fs_maxfilesize) + if (length < 0) return (EINVAL); + if (length > fs->fs_maxfilesize) + return (EFBIG); tv = time; if (ovp->v_type == VLNK && (oip->i_size < ovp->v_mount->mnt_maxsymlinklen || oip->i_din.di_blocks == 0)) { @@ -220,12 +216,12 @@ ffs_truncate(ap) aflags = B_CLRBUF; if (ap->a_flags & IO_SYNC) aflags |= B_SYNC; - vnode_pager_setsize(ovp, length); error = ffs_balloc(oip, lbn, offset + 1, ap->a_cred, &bp, aflags); if (error) return (error); oip->i_size = length; + vnode_pager_setsize(ovp, length); if (aflags & B_SYNC) bwrite(bp); else if (ovp->v_mount->mnt_flag & MNT_ASYNC) @@ -264,6 +260,7 @@ ffs_truncate(ap) else bawrite(bp); } + vnode_pager_setsize(ovp, length); /* * Calculate index into inode's block list of * last direct and indirect blocks (if any) @@ -413,17 +410,17 @@ done: static int ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) register struct inode *ip; - daddr_t lbn, lastbn; - daddr_t dbn; + ufs_daddr_t lbn, lastbn; + ufs_daddr_t dbn; int level; long *countp; { register int i; struct buf *bp; register struct fs *fs = ip->i_fs; - register daddr_t *bap; + register ufs_daddr_t *bap; struct vnode *vp; - daddr_t *copy = NULL, nb, nlbn, last; + ufs_daddr_t *copy = NULL, nb, nlbn, last; long blkcount, factor; int nblocks, blocksreleased = 0; int error = 0, allerror = 0; @@ -466,12 +463,12 @@ ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) return (error); } - bap = (daddr_t *)bp->b_data; + bap = (ufs_daddr_t *)bp->b_data; if (lastbn != -1) { - MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); + MALLOC(copy, ufs_daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); bzero((caddr_t)&bap[last + 1], - (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); + (u_int)(NINDIR(fs) - (last + 1)) * sizeof (ufs_daddr_t)); if ((vp->v_mount->mnt_flag & MNT_ASYNC) == 0) { error = bwrite(bp); if (error) @@ -491,9 +488,8 @@ ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) if (nb == 0) continue; if (level > SINGLE) { - error = ffs_indirtrunc(ip, nlbn, - fsbtodb(fs, nb), (daddr_t)-1, level - 1, &blkcount); - if (error) + if (error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb), + (ufs_daddr_t)-1, level - 1, &blkcount)) allerror = error; blocksreleased += blkcount; } diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c index 1cb9f3f..629a228 100644 --- a/sys/ufs/ffs/ffs_subr.c +++ b/sys/ufs/ffs/ffs_subr.c @@ -30,22 +30,26 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_subr.c 8.2 (Berkeley) 9/21/93 + * @(#)ffs_subr.c 8.5 (Berkeley) 3/21/95 * $FreeBSD$ */ #include <sys/param.h> -#include <ufs/ffs/fs.h> -#ifdef KERNEL +#ifndef KERNEL +#include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> +#else #include "opt_ddb.h" #include <sys/systm.h> #include <sys/vnode.h> -#include <ufs/ffs/ffs_extern.h> #include <sys/buf.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> +#include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> +#include <ufs/ffs/ffs_extern.h> /* * Return buffer with the contents of block "offset" from the beginning of @@ -64,7 +68,7 @@ ffs_blkatoff(ap) struct inode *ip; register struct fs *fs; struct buf *bp; - daddr_t lbn; + ufs_daddr_t lbn; int bsize, error; ip = VTOI(ap->a_vp); @@ -93,7 +97,7 @@ void ffs_fragacct(fs, fragmap, fraglist, cnt) struct fs *fs; int fragmap; - long fraglist[]; + int32_t fraglist[]; int cnt; { int inblk; @@ -127,7 +131,7 @@ ffs_checkoverlap(bp, ip) struct inode *ip; { register struct buf *ebp, *ep; - register daddr_t start, last; + register ufs_daddr_t start, last; struct vnode *vp; ebp = &buf[nbuf]; @@ -137,7 +141,8 @@ ffs_checkoverlap(bp, ip) if (ep == bp || (ep->b_flags & B_INVAL) || ep->b_vp == NULLVP) continue; - if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0, NULL, NULL)) + if (VOP_BMAP(ep->b_vp, (ufs_daddr_t)0, &vp, (ufs_daddr_t)0, + NULL)) continue; if (vp != ip->i_devvp) continue; @@ -163,7 +168,7 @@ int ffs_isblock(fs, cp, h) struct fs *fs; unsigned char *cp; - daddr_t h; + ufs_daddr_t h; { unsigned char mask; @@ -191,7 +196,7 @@ void ffs_clrblock(fs, cp, h) struct fs *fs; u_char *cp; - daddr_t h; + ufs_daddr_t h; { switch ((int)fs->fs_frag) { @@ -219,7 +224,7 @@ void ffs_setblock(fs, cp, h) struct fs *fs; unsigned char *cp; - daddr_t h; + ufs_daddr_t h; { switch ((int)fs->fs_frag) { diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 4b86cb0..c8b8959 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_vfsops.c 8.8 (Berkeley) 4/18/94 + * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95 * $FreeBSD$ */ @@ -72,8 +72,9 @@ static int ffs_sbupdate __P((struct ufsmount *, int)); static int ffs_reload __P((struct mount *,struct ucred *,struct proc *)); static int ffs_oldfscompat __P((struct fs *)); -static int ffs_mount __P((struct mount *, - char *, caddr_t, struct nameidata *, struct proc *)); +static int ffs_mount __P((struct mount *, char *, caddr_t, + struct nameidata *, struct proc *)); +static int ffs_init __P((struct vfsconf *)); struct vfsops ufs_vfsops = { ffs_mount, @@ -93,7 +94,6 @@ VFS_SET(ufs_vfsops, ufs, MOUNT_UFS, 0); extern u_long nextgennumber; - /* * ffs_mount * @@ -133,7 +133,7 @@ extern u_long nextgennumber; */ static int ffs_mount( mp, path, data, ndp, p) - register struct mount *mp; /* mount struct pointer*/ + struct mount *mp; /* mount struct pointer*/ char *path; /* path to mount point*/ caddr_t data; /* arguments to FS specific mount*/ struct nameidata *ndp; /* mount point credentials*/ @@ -159,13 +159,10 @@ ffs_mount( mp, path, data, ndp, p) */ /* Get vnode for root device*/ - if( bdevvp( rootdev, &rootvp)) - panic("ffs_mountroot: can't setup bdevvp for root"); - - /* - * FS specific handling - */ - mp->mnt_flag |= MNT_RDONLY; /* XXX globally applicable?*/ + if ((err = bdevvp( rootdev, &rootvp))) { + printf("ffs_mountroot: can't setup bdevvp for root"); + return (err); + } /* * Attempt mount @@ -202,12 +199,7 @@ ffs_mount( mp, path, data, ndp, p) flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; - if (vfs_busy(mp)) { - err = EBUSY; - goto error_1; - } err = ffs_flushfiles(mp, flags, p); - vfs_unbusy(mp); } if (!err && (mp->mnt_flag & MNT_RELOAD)) err = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); @@ -341,7 +333,6 @@ success: return( err); } - /* * Reload all incore data for a filesystem (used after running fsck on * the root filesystem and finding things to fix). The filesystem must @@ -365,8 +356,10 @@ ffs_reload(mp, cred, p) struct inode *ip; struct csum *space; struct buf *bp; - struct fs *fs; + struct fs *fs, *newfs; + struct partinfo dpart; int i, blks, size, error; + int32_t *lp; if ((mp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); @@ -379,24 +372,33 @@ ffs_reload(mp, cred, p) /* * Step 2: re-read superblock from disk. */ - error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp); - if (error) + if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) + size = DEV_BSIZE; + else + size = dpart.disklab->d_secsize; + if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp)) return (error); - fs = (struct fs *)bp->b_data; - fs->fs_fmod = 0; - if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || - fs->fs_bsize < sizeof(struct fs)) { - brelse(bp); - return (EIO); /* XXX needs translation */ + newfs = (struct fs *)bp->b_data; + if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE || + newfs->fs_bsize < sizeof(struct fs)) { + brelse(bp); + return (EIO); /* XXX needs translation */ } fs = VFSTOUFS(mp)->um_fs; - bcopy(&fs->fs_csp[0], &((struct fs *)bp->b_data)->fs_csp[0], - sizeof(fs->fs_csp)); - bcopy(bp->b_data, fs, (u_int)fs->fs_sbsize); + /* + * Copy pointer fields back into superblock before copying in XXX + * new superblock. These should really be in the ufsmount. XXX + * Note that important parameters (eg fs_ncg) are unchanged. + */ + bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp)); + newfs->fs_maxcluster = fs->fs_maxcluster; + bcopy(newfs, fs, (u_int)fs->fs_sbsize); if (fs->fs_sbsize < SBSIZE) bp->b_flags |= B_INVAL; brelse(bp); + mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; ffs_oldfscompat(fs); + /* * Step 3: re-read summary information from disk. */ @@ -413,21 +415,36 @@ ffs_reload(mp, cred, p) bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size); brelse(bp); } + /* + * We no longer know anything about clusters per cylinder group. + */ + if (fs->fs_contigsumsize > 0) { + lp = fs->fs_maxcluster; + for (i = 0; i < fs->fs_ncg; i++) + *lp++ = fs->fs_contigsumsize; + } + loop: + simple_lock(&mntvnode_slock); for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { + if (vp->v_mount != mp) { + simple_unlock(&mntvnode_slock); + goto loop; + } nvp = vp->v_mntvnodes.le_next; /* * Step 4: invalidate all inactive vnodes. */ - if (vp->v_usecount == 0) { - vgone(vp); - continue; - } + if (vrecycle(vp, &mntvnode_slock, p)) + goto loop; /* * Step 5: invalidate all cached file data. */ - if (vget(vp, 1)) + simple_lock(&vp->v_interlock); + simple_unlock(&mntvnode_slock); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) { goto loop; + } if (vinvalbuf(vp, 0, cred, p, 0, 0)) panic("ffs_reload: dirty2"); /* @@ -445,9 +462,9 @@ loop: ino_to_fsbo(fs, ip->i_number)); brelse(bp); vput(vp); - if (vp->v_mount != mp) - goto loop; + simple_lock(&mntvnode_slock); } + simple_unlock(&mntvnode_slock); return (0); } @@ -463,15 +480,18 @@ ffs_mountfs(devvp, mp, p) register struct ufsmount *ump; struct buf *bp; register struct fs *fs; - dev_t dev = devvp->v_rdev; + dev_t dev; struct partinfo dpart; caddr_t base, space; - int havepart = 0, blks; - int error, i, size; - int ronly; + int error, i, blks, size, ronly; + int32_t *lp; + struct ucred *cred; + u_int64_t maxfilesize; /* XXX */ u_int strsize; int ncount; + dev = devvp->v_rdev; + cred = p ? p->p_ucred : NOCRED; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use @@ -486,25 +506,21 @@ ffs_mountfs(devvp, mp, p) ncount -= 1; if (ncount > 1 && devvp != rootvp) return (EBUSY); - error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); - if (error) + if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); if (error) return (error); - if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) + if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) size = DEV_BSIZE; - else { - havepart = 1; + else size = dpart.disklab->d_secsize; - } bp = NULL; ump = NULL; - error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp); - if (error) + if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, cred, &bp)) goto out; fs = (struct fs *)bp->b_data; if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || @@ -522,6 +538,11 @@ ffs_mountfs(devvp, mp, p) goto out; } } + /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */ + if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) { + error = EROFS; /* needs translation */ + goto out; + } ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); bzero((caddr_t)ump, sizeof *ump); ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, @@ -537,16 +558,17 @@ ffs_mountfs(devvp, mp, p) fs->fs_fmod = 1; fs->fs_clean = 0; } - blks = howmany(fs->fs_cssize, fs->fs_fsize); - base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT, - M_WAITOK); + size = fs->fs_cssize; + blks = howmany(size, fs->fs_fsize); + if (fs->fs_contigsumsize > 0) + size += fs->fs_ncg * sizeof(int32_t); + base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK); for (i = 0; i < blks; i += fs->fs_frag) { size = fs->fs_bsize; if (i + fs->fs_frag > blks) size = (blks - i) * fs->fs_fsize; - error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, - NOCRED, &bp); - if (error) { + if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, + cred, &bp)) { free(base, M_UFSMNT); goto out; } @@ -556,11 +578,15 @@ ffs_mountfs(devvp, mp, p) brelse(bp); bp = NULL; } + if (fs->fs_contigsumsize > 0) { + fs->fs_maxcluster = lp = (int32_t *)space; + for (i = 0; i < fs->fs_ncg; i++) + *lp++ = fs->fs_contigsumsize; + } mp->mnt_data = (qaddr_t)ump; mp->mnt_stat.f_fsid.val[0] = (long)dev; - mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; + mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; - mp->mnt_flag |= MNT_LOCAL; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; @@ -589,8 +615,15 @@ ffs_mountfs(devvp, mp, p) */ mp->mnt_time = fs->fs_time; } - if (ronly == 0) - ffs_sbupdate(ump, MNT_WAIT); + + ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */ + maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1; /* XXX */ + if (fs->fs_maxfilesize > maxfilesize) /* XXX */ + fs->fs_maxfilesize = maxfilesize; /* XXX */ + if (ronly == 0) { + fs->fs_clean = 0; + (void) ffs_sbupdate(ump, MNT_WAIT); + } /* * Only VMIO the backing device if the backing device is a real * block device. This excludes the original MFS implementation. @@ -604,7 +637,7 @@ ffs_mountfs(devvp, mp, p) out: if (bp) brelse(bp); - (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); + (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); if (ump) { free(ump->um_fs, M_UFSMNT); free(ump, M_UFSMNT); @@ -630,7 +663,8 @@ ffs_oldfscompat(fs) if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ #if 0 int i; /* XXX */ - quad_t sizepb = fs->fs_bsize; /* XXX */ + u_int64_t sizepb = fs->fs_bsize; /* XXX */ + /* XXX */ fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ for (i = 0; i < NIADDR; i++) { /* XXX */ sizepb *= NINDIR(fs); /* XXX */ @@ -655,7 +689,7 @@ ffs_unmount(mp, mntflags, p) { register struct ufsmount *ump; register struct fs *fs; - int error, flags, ronly; + int error, flags; flags = 0; if (mntflags & MNT_FORCE) { @@ -666,18 +700,21 @@ ffs_unmount(mp, mntflags, p) return (error); ump = VFSTOUFS(mp); fs = ump->um_fs; - ronly = fs->fs_ronly; - if (!ronly) { + if (fs->fs_ronly == 0) { fs->fs_clean = 1; - ffs_sbupdate(ump, MNT_WAIT); + error = ffs_sbupdate(ump, MNT_WAIT); + if (error) { + fs->fs_clean = 0; + return (error); + } } ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; - VOP_LOCK(ump->um_devvp); - vnode_pager_uncache(ump->um_devvp); - VOP_UNLOCK(ump->um_devvp); + vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p); + vnode_pager_uncache(ump->um_devvp, p); + VOP_UNLOCK(ump->um_devvp, 0, p); - error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, + error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, NOCRED, p); vrele(ump->um_devvp); @@ -686,7 +723,6 @@ ffs_unmount(mp, mntflags, p) free(fs, M_UFSMNT); free(ump, M_UFSMNT); mp->mnt_data = (qaddr_t)0; - mp->mnt_flag &= ~MNT_LOCAL; return (error); } @@ -702,8 +738,6 @@ ffs_flushfiles(mp, flags, p) register struct ufsmount *ump; int error; - if (!doforce) - flags &= ~FORCECLOSE; ump = VFSTOUFS(mp); #ifdef QUOTA if (mp->mnt_flag & MNT_QUOTA) { @@ -742,7 +776,6 @@ ffs_statfs(mp, sbp, p) fs = ump->um_fs; if (fs->fs_magic != FS_MAGIC) panic("ffs_statfs"); - sbp->f_type = MOUNT_UFS; sbp->f_bsize = fs->fs_fsize; sbp->f_iosize = fs->fs_bsize; sbp->f_blocks = fs->fs_dsize; @@ -752,6 +785,7 @@ ffs_statfs(mp, sbp, p) sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; sbp->f_ffree = fs->fs_cstotal.cs_nifree; if (sbp != &mp->mnt_stat) { + sbp->f_type = mp->mnt_vfc->vfc_typenum; bcopy((caddr_t)mp->mnt_stat.f_mntonname, (caddr_t)&sbp->f_mntonname[0], MNAMELEN); bcopy((caddr_t)mp->mnt_stat.f_mntfromname, @@ -774,31 +808,22 @@ ffs_sync(mp, waitfor, cred, p) struct ucred *cred; struct proc *p; { - register struct vnode *vp, *nvp; - register struct inode *ip; - register struct ufsmount *ump = VFSTOUFS(mp); - register struct fs *fs; + struct vnode *nvp, *vp; + struct inode *ip; + struct ufsmount *ump = VFSTOUFS(mp); + struct fs *fs; struct timeval tv; int error, allerror = 0; fs = ump->um_fs; - /* - * Write back modified superblock. - * Consistency check that the superblock - * is still in the buffer cache. - */ - if (fs->fs_fmod != 0) { - if (fs->fs_ronly != 0) { /* XXX */ - printf("fs = %s\n", fs->fs_fsmnt); - panic("update: rofs mod"); - } - fs->fs_fmod = 0; - fs->fs_time = time.tv_sec; - allerror = ffs_sbupdate(ump, waitfor); + if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */ + printf("fs = %s\n", fs->fs_fsmnt); + panic("update: rofs mod"); } /* * Write back each (modified) inode. */ + simple_lock(&mntvnode_slock); loop: for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { /* @@ -807,27 +832,40 @@ loop: */ if (vp->v_mount != mp) goto loop; + simple_lock(&vp->v_interlock); nvp = vp->v_mntvnodes.le_next; - if (VOP_ISLOCKED(vp)) - continue; ip = VTOI(vp); - if ((((ip->i_flag & - (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0)) && - vp->v_dirtyblkhd.lh_first == NULL) + if (((ip->i_flag & + (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) && + vp->v_dirtyblkhd.lh_first == NULL) { + simple_unlock(&vp->v_interlock); continue; + } if (vp->v_type != VCHR) { - if (vget(vp, 1)) - goto loop; - error = VOP_FSYNC(vp, cred, waitfor, p); - if (error) + simple_unlock(&mntvnode_slock); + error = + vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); + if (error) { + simple_lock(&mntvnode_slock); + if (error == ENOENT) + goto loop; + continue; + } + if (error = VOP_FSYNC(vp, cred, waitfor, p)) allerror = error; - vput(vp); + VOP_UNLOCK(vp, 0, p); + vrele(vp); + simple_lock(&mntvnode_slock); } else { + simple_unlock(&mntvnode_slock); + simple_unlock(&vp->v_interlock); tv = time; /* VOP_UPDATE(vp, &tv, &tv, waitfor == MNT_WAIT); */ VOP_UPDATE(vp, &tv, &tv, 0); + simple_lock(&mntvnode_slock); } } + simple_unlock(&mntvnode_slock); /* * Force stale file system control information to be flushed. */ @@ -837,6 +875,15 @@ loop: #ifdef QUOTA qsync(mp); #endif + /* + * Write back modified superblock. + */ + if (fs->fs_fmod != 0) { + fs->fs_fmod = 0; + fs->fs_time = time.tv_sec; + if (error = ffs_sbupdate(ump, waitfor)) + allerror = error; + } return (allerror); } @@ -854,8 +901,8 @@ ffs_vget(mp, ino, vpp) ino_t ino; struct vnode **vpp; { - register struct fs *fs; - register struct inode *ip; + struct fs *fs; + struct inode *ip; struct ufsmount *ump; struct buf *bp; struct vnode *vp; @@ -903,6 +950,7 @@ restart: return (error); } bzero((caddr_t)ip, sizeof(struct inode)); + lockinit(&ip->i_lock, PINOD, "inode", 0, 0); vp->v_data = ip; ip->i_vnode = vp; ip->i_fs = fs = ump->um_fs; @@ -1035,6 +1083,17 @@ ffs_vptofh(vp, fhp) } /* + * Initialize the filesystem; just use ufs_init. + */ +static int +ffs_init(vfsp) + struct vfsconf *vfsp; +{ + + return (ufs_init(vfsp)); +} + +/* * Write a superblock and associated information back to disk. */ static int @@ -1042,21 +1101,15 @@ ffs_sbupdate(mp, waitfor) struct ufsmount *mp; int waitfor; { - register struct fs *fs = mp->um_fs; + register struct fs *dfs, *fs = mp->um_fs; register struct buf *bp; int blks; caddr_t space; - int i, size, error = 0; + int i, size, error, allerror = 0; - bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); - bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); - /* Restore compatibility to old file systems. XXX */ - if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ - ((struct fs *)bp->b_data)->fs_nrpos = -1; /* XXX */ - if (waitfor == MNT_WAIT) - error = bwrite(bp); - else - bawrite(bp); + /* + * First write back the summary information. + */ blks = howmany(fs->fs_cssize, fs->fs_fsize); space = (caddr_t)fs->fs_csp[0]; for (i = 0; i < blks; i += fs->fs_frag) { @@ -1067,10 +1120,37 @@ ffs_sbupdate(mp, waitfor) size, 0, 0); bcopy(space, bp->b_data, (u_int)size); space += size; - if (waitfor == MNT_WAIT) - error = bwrite(bp); - else + if (waitfor != MNT_WAIT) bawrite(bp); + else if (error = bwrite(bp)) + allerror = error; } - return (error); + /* + * Now write back the superblock itself. If any errors occurred + * up to this point, then fail so that the superblock avoids + * being written out as clean. + */ + if (allerror) + return (allerror); + bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); + bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); + /* Restore compatibility to old file systems. XXX */ + dfs = (struct fs *)bp->b_data; /* XXX */ + if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ + dfs->fs_nrpos = -1; /* XXX */ + if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ + int32_t *lp, tmp; /* XXX */ + /* XXX */ + lp = (int32_t *)&dfs->fs_qbmask; /* XXX */ + tmp = lp[4]; /* XXX */ + for (i = 4; i > 0; i--) /* XXX */ + lp[i] = lp[i-1]; /* XXX */ + lp[0] = tmp; /* XXX */ + } /* XXX */ + dfs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */ + if (waitfor != MNT_WAIT) + bawrite(bp); + else if (error = bwrite(bp)) + allerror = error; + return (allerror); } diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index c3f750b..ddce646 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_vnops.c 8.7 (Berkeley) 2/3/94 + * @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95 * $FreeBSD$ */ @@ -62,6 +62,7 @@ #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/dir.h> +#include <ufs/ufs/ufsmount.h> #include <ufs/ufs/ufs_extern.h> #include <ufs/ffs/fs.h> @@ -78,6 +79,7 @@ static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { { &vop_default_desc, (vop_t *)vn_default_error }, { &vop_lookup_desc, (vop_t *)ufs_lookup }, /* lookup */ { &vop_create_desc, (vop_t *)ufs_create }, /* create */ + { &vop_whiteout_desc, (vop_t *)ufs_whiteout }, /* whiteout */ { &vop_mknod_desc, (vop_t *)ufs_mknod }, /* mknod */ { &vop_open_desc, (vop_t *)ufs_open }, /* open */ { &vop_close_desc, (vop_t *)ufs_close }, /* close */ @@ -86,8 +88,10 @@ static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { { &vop_setattr_desc, (vop_t *)ufs_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)ffs_read }, /* read */ { &vop_write_desc, (vop_t *)ffs_write }, /* write */ + { &vop_lease_desc, (vop_t *)ufs_lease_check }, /* lease */ { &vop_ioctl_desc, (vop_t *)ufs_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)ufs_select }, /* select */ + { &vop_revoke_desc, (vop_t *)ufs_revoke }, /* revoke */ { &vop_mmap_desc, (vop_t *)ufs_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)ffs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)ufs_seek }, /* seek */ @@ -101,7 +105,7 @@ static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { { &vop_readlink_desc, (vop_t *)ufs_readlink }, /* readlink */ { &vop_abortop_desc, (vop_t *)ufs_abortop }, /* abortop */ { &vop_inactive_desc, (vop_t *)ufs_inactive }, /* inactive */ - { &vop_reclaim_desc, (vop_t *)ufs_reclaim }, /* reclaim */ + { &vop_reclaim_desc, (vop_t *)ffs_reclaim }, /* reclaim */ { &vop_lock_desc, (vop_t *)ufs_lock }, /* lock */ { &vop_unlock_desc, (vop_t *)ufs_unlock }, /* unlock */ { &vop_bmap_desc, (vop_t *)ufs_bmap }, /* bmap */ @@ -136,8 +140,10 @@ static struct vnodeopv_entry_desc ffs_specop_entries[] = { { &vop_setattr_desc, (vop_t *)ufs_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)ufsspec_read }, /* read */ { &vop_write_desc, (vop_t *)ufsspec_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 *)ffs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)spec_seek }, /* seek */ @@ -151,7 +157,7 @@ static struct vnodeopv_entry_desc ffs_specop_entries[] = { { &vop_readlink_desc, (vop_t *)spec_readlink }, /* readlink */ { &vop_abortop_desc, (vop_t *)spec_abortop }, /* abortop */ { &vop_inactive_desc, (vop_t *)ufs_inactive }, /* inactive */ - { &vop_reclaim_desc, (vop_t *)ufs_reclaim }, /* reclaim */ + { &vop_reclaim_desc, (vop_t *)ffs_reclaim }, /* reclaim */ { &vop_lock_desc, (vop_t *)ufs_lock }, /* lock */ { &vop_unlock_desc, (vop_t *)ufs_unlock }, /* unlock */ { &vop_bmap_desc, (vop_t *)spec_bmap }, /* bmap */ @@ -186,8 +192,10 @@ static struct vnodeopv_entry_desc ffs_fifoop_entries[] = { { &vop_setattr_desc, (vop_t *)ufs_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)ufsfifo_read }, /* read */ { &vop_write_desc, (vop_t *)ufsfifo_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 *)ffs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)fifo_seek }, /* seek */ @@ -201,7 +209,7 @@ static struct vnodeopv_entry_desc ffs_fifoop_entries[] = { { &vop_readlink_desc, (vop_t *)fifo_readlink }, /* readlink */ { &vop_abortop_desc, (vop_t *)fifo_abortop }, /* abortop */ { &vop_inactive_desc, (vop_t *)ufs_inactive }, /* inactive */ - { &vop_reclaim_desc, (vop_t *)ufs_reclaim }, /* reclaim */ + { &vop_reclaim_desc, (vop_t *)ffs_reclaim }, /* reclaim */ { &vop_lock_desc, (vop_t *)ufs_lock }, /* lock */ { &vop_unlock_desc, (vop_t *)ufs_unlock }, /* unlock */ { &vop_bmap_desc, (vop_t *)fifo_bmap }, /* bmap */ @@ -226,20 +234,16 @@ VNODEOP_SET(ffs_vnodeop_opv_desc); VNODEOP_SET(ffs_specop_opv_desc); VNODEOP_SET(ffs_fifoop_opv_desc); -#ifdef DEBUG /* * Enabling cluster read/write operations. */ -#include <sys/sysctl.h> int doclusterread = 1; -SYSCTL_INT(_debug, 11, doclusterread, CTLFLAG_RW, &doclusterread, 0, ""); int doclusterwrite = 1; -SYSCTL_INT(_debug, 12, doclusterwrite, CTLFLAG_RW, &doclusterwrite, 0, ""); -#else -/* XXX for ufs_readwrite */ -#define doclusterread 1 -#define doclusterwrite 1 -#endif + +#include <sys/sysctl.h> +SYSCTL_NODE(_vfs_ffs, MOUNT_UFS, ffs, CTLFLAG_RW, 0, "FFS"); +SYSCTL_INT(_vfs_ffs, FFS_CLUSTERREAD, doclusterread, CTLFLAG_RW, &doclusterread, 0, ""); +SYSCTL_INT(_vfs_ffs, FFS_CLUSTERWRITE, doclusterwrite, CTLFLAG_RW, &doclusterwrite, 0, ""); #include <ufs/ufs/ufs_readwrite.c> @@ -320,3 +324,24 @@ loop: tv = time; return (VOP_UPDATE(ap->a_vp, &tv, &tv, ap->a_waitfor == MNT_WAIT)); } + +/* + * Reclaim an inode so that it can be used for other purposes. + */ +int +ffs_reclaim(ap) + struct vop_reclaim_args /* { + struct vnode *a_vp; + struct proc *a_p; + } */ *ap; +{ + register struct vnode *vp = ap->a_vp; + int error; + + if (error = ufs_reclaim(vp, ap->a_p)) + return (error); + FREE(vp->v_data, VFSTOUFS(vp->v_mount)->um_devvp->v_tag == VT_MFS ? + M_MFSNODE : M_FFSNODE); + vp->v_data = NULL; + return (0); +} diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h index 16862c4..02720da 100644 --- a/sys/ufs/ffs/fs.h +++ b/sys/ufs/ffs/fs.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)fs.h 8.7 (Berkeley) 4/19/94 + * @(#)fs.h 8.13 (Berkeley) 3/21/95 * $FreeBSD$ */ @@ -65,8 +65,8 @@ #define SBSIZE 8192 #define BBOFF ((off_t)(0)) #define SBOFF ((off_t)(BBOFF + BBSIZE)) -#define BBLOCK ((daddr_t)(0)) -#define SBLOCK ((daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE)) +#define BBLOCK ((ufs_daddr_t)(0)) +#define SBLOCK ((ufs_daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE)) /* * Addresses stored in inodes are capable of addressing fragments @@ -102,12 +102,18 @@ * The path name on which the file system is mounted is maintained * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in * the super block for this name. + */ +#define MAXMNTLEN 512 + +/* * The limit on the amount of summary information per file system * is defined by MAXCSBUFS. It is currently parameterized for a - * maximum of two million cylinders. + * size of 128 bytes (2 million cylinder groups on machines with + * 32-bit pointers, and 1 million on 64-bit machines). One pointer + * is taken away to point to an array of cluster sizes that is + * computed as cylinder groups are inspected. */ -#define MAXMNTLEN 512 -#define MAXCSBUFS 32 +#define MAXCSBUFS ((128 / sizeof(void *)) - 1) /* * A summary of contiguous blocks of various sizes is maintained @@ -142,103 +148,105 @@ * the ``fs_cs'' macro to work (see below). */ struct csum { - long cs_ndir; /* number of directories */ - long cs_nbfree; /* number of free blocks */ - long cs_nifree; /* number of free inodes */ - long cs_nffree; /* number of free frags */ + int32_t cs_ndir; /* number of directories */ + int32_t cs_nbfree; /* number of free blocks */ + int32_t cs_nifree; /* number of free inodes */ + int32_t cs_nffree; /* number of free frags */ }; /* - * Super block for a file system. + * Super block for an FFS file system. */ struct fs { - struct fs *fs_link; /* linked list of file systems */ - struct fs *fs_rlink; /* used for incore super blocks */ - daddr_t fs_sblkno; /* addr of super-block in filesys */ - daddr_t fs_cblkno; /* offset of cyl-block in filesys */ - daddr_t fs_iblkno; /* offset of inode-blocks in filesys */ - daddr_t fs_dblkno; /* offset of first data after cg */ - long fs_cgoffset; /* cylinder group offset in cylinder */ - long fs_cgmask; /* used to calc mod fs_ntrak */ - time_t fs_time; /* last time written */ - long fs_size; /* number of blocks in fs */ - long fs_dsize; /* number of data blocks in fs */ - long fs_ncg; /* number of cylinder groups */ - long fs_bsize; /* size of basic blocks in fs */ - long fs_fsize; /* size of frag blocks in fs */ - long fs_frag; /* number of frags in a block in fs */ + int32_t fs_firstfield; /* historic file system linked list, */ + int32_t fs_unused_1; /* used for incore super blocks */ + ufs_daddr_t fs_sblkno; /* addr of super-block in filesys */ + ufs_daddr_t fs_cblkno; /* offset of cyl-block in filesys */ + ufs_daddr_t fs_iblkno; /* offset of inode-blocks in filesys */ + ufs_daddr_t fs_dblkno; /* offset of first data after cg */ + int32_t fs_cgoffset; /* cylinder group offset in cylinder */ + int32_t fs_cgmask; /* used to calc mod fs_ntrak */ + time_t fs_time; /* last time written */ + int32_t fs_size; /* number of blocks in fs */ + int32_t fs_dsize; /* number of data blocks in fs */ + int32_t fs_ncg; /* number of cylinder groups */ + int32_t fs_bsize; /* size of basic blocks in fs */ + int32_t fs_fsize; /* size of frag blocks in fs */ + int32_t fs_frag; /* number of frags in a block in fs */ /* these are configuration parameters */ - long fs_minfree; /* minimum percentage of free blocks */ - long fs_rotdelay; /* num of ms for optimal next block */ - long fs_rps; /* disk revolutions per second */ + int32_t fs_minfree; /* minimum percentage of free blocks */ + int32_t fs_rotdelay; /* num of ms for optimal next block */ + int32_t fs_rps; /* disk revolutions per second */ /* these fields can be computed from the others */ - long fs_bmask; /* ``blkoff'' calc of blk offsets */ - long fs_fmask; /* ``fragoff'' calc of frag offsets */ - long fs_bshift; /* ``lblkno'' calc of logical blkno */ - long fs_fshift; /* ``numfrags'' calc number of frags */ + int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */ + int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */ + int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */ + int32_t fs_fshift; /* ``numfrags'' calc number of frags */ /* these are configuration parameters */ - long fs_maxcontig; /* max number of contiguous blks */ - long fs_maxbpg; /* max number of blks per cyl group */ + int32_t fs_maxcontig; /* max number of contiguous blks */ + int32_t fs_maxbpg; /* max number of blks per cyl group */ /* these fields can be computed from the others */ - long fs_fragshift; /* block to frag shift */ - long fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ - long fs_sbsize; /* actual size of super block */ - long fs_csmask; /* csum block offset */ - long fs_csshift; /* csum block number */ - long fs_nindir; /* value of NINDIR */ - long fs_inopb; /* value of INOPB */ - long fs_nspf; /* value of NSPF */ + int32_t fs_fragshift; /* block to frag shift */ + int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ + int32_t fs_sbsize; /* actual size of super block */ + int32_t fs_csmask; /* csum block offset */ + int32_t fs_csshift; /* csum block number */ + int32_t fs_nindir; /* value of NINDIR */ + int32_t fs_inopb; /* value of INOPB */ + int32_t fs_nspf; /* value of NSPF */ /* yet another configuration parameter */ - long fs_optim; /* optimization preference, see below */ + int32_t fs_optim; /* optimization preference, see below */ /* these fields are derived from the hardware */ - long fs_npsect; /* # sectors/track including spares */ - long fs_interleave; /* hardware sector interleave */ - long fs_trackskew; /* sector 0 skew, per track */ - long fs_headswitch; /* head switch time, usec */ - long fs_trkseek; /* track-to-track seek, usec */ + int32_t fs_npsect; /* # sectors/track including spares */ + int32_t fs_interleave; /* hardware sector interleave */ + int32_t fs_trackskew; /* sector 0 skew, per track */ + int32_t fs_headswitch; /* head switch time, usec */ + int32_t fs_trkseek; /* track-to-track seek, usec */ /* sizes determined by number of cylinder groups and their sizes */ - daddr_t fs_csaddr; /* blk addr of cyl grp summary area */ - long fs_cssize; /* size of cyl grp summary area */ - long fs_cgsize; /* cylinder group size */ + ufs_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */ + int32_t fs_cssize; /* size of cyl grp summary area */ + int32_t fs_cgsize; /* cylinder group size */ /* these fields are derived from the hardware */ - long fs_ntrak; /* tracks per cylinder */ - long fs_nsect; /* sectors per track */ - long fs_spc; /* sectors per cylinder */ + int32_t fs_ntrak; /* tracks per cylinder */ + int32_t fs_nsect; /* sectors per track */ + int32_t fs_spc; /* sectors per cylinder */ /* this comes from the disk driver partitioning */ - long fs_ncyl; /* cylinders in file system */ + int32_t fs_ncyl; /* cylinders in file system */ /* these fields can be computed from the others */ - long fs_cpg; /* cylinders per group */ - long fs_ipg; /* inodes per group */ - long fs_fpg; /* blocks per group * fs_frag */ + int32_t fs_cpg; /* cylinders per group */ + int32_t fs_ipg; /* inodes per group */ + int32_t fs_fpg; /* blocks per group * fs_frag */ /* this data must be re-computed after crashes */ struct csum fs_cstotal; /* cylinder summary information */ /* these fields are cleared at mount time */ - char fs_fmod; /* super block modified flag */ - char fs_clean; /* file system is clean flag */ - char fs_ronly; /* mounted read-only flag */ - char fs_flags; /* currently unused flag */ - char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ + int8_t fs_fmod; /* super block modified flag */ + int8_t fs_clean; /* file system is clean flag */ + int8_t fs_ronly; /* mounted read-only flag */ + int8_t fs_flags; /* currently unused flag */ + u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ /* these fields retain the current block allocation info */ - long fs_cgrotor; /* last cg searched */ + int32_t fs_cgrotor; /* last cg searched */ struct csum *fs_csp[MAXCSBUFS];/* list of fs_cs info buffers */ - long fs_cpc; /* cyl per cycle in postbl */ - short fs_opostbl[16][8]; /* old rotation block list head */ - long fs_sparecon[50]; /* reserved for future constants */ - long fs_contigsumsize; /* size of cluster summary array */ - long fs_maxsymlinklen; /* max length of an internal symlink */ - long fs_inodefmt; /* format of on-disk inodes */ - u_quad_t fs_maxfilesize; /* maximum representable file size */ - quad_t fs_qbmask; /* ~fs_bmask - for use with quad size */ - quad_t fs_qfmask; /* ~fs_fmask - for use with quad size */ - long fs_state; /* validate fs_clean field */ - long fs_postblformat; /* format of positional layout tables */ - long fs_nrpos; /* number of rotational positions */ - long fs_postbloff; /* (short) rotation block list head */ - long fs_rotbloff; /* (u_char) blocks for each rotation */ - long fs_magic; /* magic number */ - u_char fs_space[1]; /* list of blocks for each rotation */ + int32_t *fs_maxcluster; /* max cluster in each cyl group */ + int32_t fs_cpc; /* cyl per cycle in postbl */ + int16_t fs_opostbl[16][8]; /* old rotation block list head */ + int32_t fs_sparecon[50]; /* reserved for future constants */ + int32_t fs_contigsumsize; /* size of cluster summary array */ + int32_t fs_maxsymlinklen; /* max length of an internal symlink */ + int32_t fs_inodefmt; /* format of on-disk inodes */ + u_int64_t fs_maxfilesize; /* maximum representable file size */ + int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */ + int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */ + int32_t fs_state; /* validate fs_clean field */ + int32_t fs_postblformat; /* format of positional layout tables */ + int32_t fs_nrpos; /* number of rotational positions */ + int32_t fs_postbloff; /* (u_int16) rotation block list head */ + int32_t fs_rotbloff; /* (u_int8) blocks for each rotation */ + int32_t fs_magic; /* magic number */ + u_int8_t fs_space[1]; /* list of blocks for each rotation */ /* actually longer */ }; + /* * Filesystem identification */ @@ -263,11 +271,12 @@ struct fs { #define fs_postbl(fs, cylno) \ (((fs)->fs_postblformat == FS_42POSTBLFMT) \ ? ((fs)->fs_opostbl[cylno]) \ - : ((short *)((char *)(fs) + (fs)->fs_postbloff) + (cylno) * (fs)->fs_nrpos)) + : ((int16_t *)((u_int8_t *)(fs) + \ + (fs)->fs_postbloff) + (cylno) * (fs)->fs_nrpos)) #define fs_rotbl(fs) \ (((fs)->fs_postblformat == FS_42POSTBLFMT) \ ? ((fs)->fs_space) \ - : ((u_char *)((char *)(fs) + (fs)->fs_rotbloff))) + : ((u_int8_t *)((u_int8_t *)(fs) + (fs)->fs_rotbloff))) /* * The size of a cylinder group is calculated by CGSIZE. The maximum size @@ -276,13 +285,13 @@ struct fs { * cylinder group and the (struct cg) size. */ #define CGSIZE(fs) \ - /* base cg */ (sizeof(struct cg) + sizeof(long) + \ - /* blktot size */ (fs)->fs_cpg * sizeof(long) + \ - /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof(short) + \ + /* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \ + /* blktot size */ (fs)->fs_cpg * sizeof(int32_t) + \ + /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof(int16_t) + \ /* inode map */ howmany((fs)->fs_ipg, NBBY) + \ /* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY) +\ /* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \ - /* cluster sum */ (fs)->fs_contigsumsize * sizeof(long) + \ + /* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \ /* cluster map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPB(fs), NBBY))) /* @@ -297,79 +306,81 @@ struct fs { * Cylinder group block for a file system. */ #define CG_MAGIC 0x090255 -struct cg { - struct cg *cg_link; /* linked list of cyl groups */ - long cg_magic; /* magic number */ - time_t cg_time; /* time last written */ - long cg_cgx; /* we are the cgx'th cylinder group */ - short cg_ncyl; /* number of cyl's this cg */ - short cg_niblk; /* number of inode blocks this cg */ - long cg_ndblk; /* number of data blocks this cg */ +struct cg { + int32_t cg_firstfield; /* historic cyl groups linked list */ + int32_t cg_magic; /* magic number */ + time_t cg_time; /* time last written */ + int32_t cg_cgx; /* we are the cgx'th cylinder group */ + int16_t cg_ncyl; /* number of cyl's this cg */ + int16_t cg_niblk; /* number of inode blocks this cg */ + int32_t cg_ndblk; /* number of data blocks this cg */ struct csum cg_cs; /* cylinder summary information */ - long cg_rotor; /* position of last used block */ - long cg_frotor; /* position of last used frag */ - long cg_irotor; /* position of last used inode */ - long cg_frsum[MAXFRAG]; /* counts of available frags */ - long cg_btotoff; /* (long) block totals per cylinder */ - long cg_boff; /* (short) free block positions */ - long cg_iusedoff; /* (char) used inode map */ - long cg_freeoff; /* (u_char) free block map */ - long cg_nextfreeoff; /* (u_char) next available space */ - long cg_clustersumoff; /* (long) counts of avail clusters */ - long cg_clusteroff; /* (char) free cluster map */ - long cg_nclusterblks; /* number of clusters this cg */ - long cg_sparecon[13]; /* reserved for future use */ - u_char cg_space[1]; /* space for cylinder group maps */ + int32_t cg_rotor; /* position of last used block */ + int32_t cg_frotor; /* position of last used frag */ + int32_t cg_irotor; /* position of last used inode */ + int32_t cg_frsum[MAXFRAG]; /* counts of available frags */ + int32_t cg_btotoff; /* (int32) block totals per cylinder */ + int32_t cg_boff; /* (u_int16) free block positions */ + int32_t cg_iusedoff; /* (u_int8) used inode map */ + int32_t cg_freeoff; /* (u_int8) free block map */ + int32_t cg_nextfreeoff; /* (u_int8) next available space */ + int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */ + int32_t cg_clusteroff; /* (u_int8) free cluster map */ + int32_t cg_nclusterblks; /* number of clusters this cg */ + int32_t cg_sparecon[13]; /* reserved for future use */ + u_int8_t cg_space[1]; /* space for cylinder group maps */ /* actually longer */ }; + /* * Macros for access to cylinder group array structures */ #define cg_blktot(cgp) \ (((cgp)->cg_magic != CG_MAGIC) \ ? (((struct ocg *)(cgp))->cg_btot) \ - : ((long *)((char *)(cgp) + (cgp)->cg_btotoff))) + : ((int32_t *)((u_int8_t *)(cgp) + (cgp)->cg_btotoff))) #define cg_blks(fs, cgp, cylno) \ (((cgp)->cg_magic != CG_MAGIC) \ ? (((struct ocg *)(cgp))->cg_b[cylno]) \ - : ((short *)((char *)(cgp) + (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos)) + : ((int16_t *)((u_int8_t *)(cgp) + \ + (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos)) #define cg_inosused(cgp) \ (((cgp)->cg_magic != CG_MAGIC) \ ? (((struct ocg *)(cgp))->cg_iused) \ - : ((char *)((char *)(cgp) + (cgp)->cg_iusedoff))) + : ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_iusedoff))) #define cg_blksfree(cgp) \ (((cgp)->cg_magic != CG_MAGIC) \ ? (((struct ocg *)(cgp))->cg_free) \ - : ((u_char *)((char *)(cgp) + (cgp)->cg_freeoff))) + : ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_freeoff))) #define cg_chkmagic(cgp) \ ((cgp)->cg_magic == CG_MAGIC || ((struct ocg *)(cgp))->cg_magic == CG_MAGIC) #define cg_clustersfree(cgp) \ - ((u_char *)((char *)(cgp) + (cgp)->cg_clusteroff)) + ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_clusteroff)) #define cg_clustersum(cgp) \ - ((long *)((char *)(cgp) + (cgp)->cg_clustersumoff)) + ((int32_t *)((u_int8_t *)(cgp) + (cgp)->cg_clustersumoff)) /* * The following structure is defined * for compatibility with old file systems. */ -struct ocg { - struct ocg *cg_link; /* linked list of cyl groups */ - struct ocg *cg_rlink; /* used for incore cyl groups */ - time_t cg_time; /* time last written */ - long cg_cgx; /* we are the cgx'th cylinder group */ - short cg_ncyl; /* number of cyl's this cg */ - short cg_niblk; /* number of inode blocks this cg */ - long cg_ndblk; /* number of data blocks this cg */ +struct ocg { + int32_t cg_firstfield; /* historic linked list of cyl groups */ + int32_t cg_unused_1; /* used for incore cyl groups */ + time_t cg_time; /* time last written */ + int32_t cg_cgx; /* we are the cgx'th cylinder group */ + int16_t cg_ncyl; /* number of cyl's this cg */ + int16_t cg_niblk; /* number of inode blocks this cg */ + int32_t cg_ndblk; /* number of data blocks this cg */ struct csum cg_cs; /* cylinder summary information */ - long cg_rotor; /* position of last used block */ - long cg_frotor; /* position of last used frag */ - long cg_irotor; /* position of last used inode */ - long cg_frsum[8]; /* counts of available frags */ - long cg_btot[32]; /* block totals per cylinder */ - short cg_b[32][8]; /* positions of free blocks */ - char cg_iused[256]; /* used inode map */ - long cg_magic; /* magic number */ - u_char cg_free[1]; /* free block map */ + int32_t cg_rotor; /* position of last used block */ + int32_t cg_frotor; /* position of last used frag */ + int32_t cg_irotor; /* position of last used inode */ + int32_t cg_frsum[8]; /* counts of available frags */ + int32_t cg_btot[32]; /* block totals per cylinder */ + int16_t cg_b[32][8]; /* positions of free blocks */ + u_int8_t cg_iused[256]; /* used inode map */ + int32_t cg_magic; /* magic number */ + u_int8_t cg_free[1]; /* free block map */ /* actually longer */ }; @@ -384,7 +395,7 @@ struct ocg { * Cylinder group macros to locate things in cylinder groups. * They calc file system addresses of cylinder group data structures. */ -#define cgbase(fs, c) ((daddr_t)((fs)->fs_fpg * (c))) +#define cgbase(fs, c) ((ufs_daddr_t)((fs)->fs_fpg * (c))) #define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */ #define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */ #define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */ @@ -400,7 +411,7 @@ struct ocg { */ #define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg) #define ino_to_fsba(fs, x) \ - ((daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \ + ((ufs_daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \ (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs)))))) #define ino_to_fsbo(fs, x) ((x) % INOPB(fs)) @@ -457,7 +468,7 @@ struct ocg { /* * Determine the number of available frags given a - * percentage to hold in reserve + * percentage to hold in reserve. */ #define freespace(fs, percentreserved) \ (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \ @@ -476,19 +487,20 @@ struct ocg { : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) /* - * Number of disk sectors per block; assumes DEV_BSIZE byte sector size. + * Number of disk sectors per block/fragment; assumes DEV_BSIZE byte + * sector size. */ #define NSPB(fs) ((fs)->fs_nspf << (fs)->fs_fragshift) #define NSPF(fs) ((fs)->fs_nspf) /* - * INOPB is the number of inodes in a secondary storage block. + * Number of inodes in a secondary storage block/fragment. */ #define INOPB(fs) ((fs)->fs_inopb) #define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift) /* - * NINDIR is the number of indirects in a file system block. + * Number of indirects in a file system block. */ #define NINDIR(fs) ((fs)->fs_nindir) diff --git a/sys/ufs/lfs/lfs_subr.c b/sys/ufs/lfs/lfs_subr.c index 7cd938b..737d2c5 100644 --- a/sys/ufs/lfs/lfs_subr.c +++ b/sys/ufs/lfs/lfs_subr.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)lfs_subr.c 8.2 (Berkeley) 9/21/93 + * @(#)lfs_subr.c 8.4 (Berkeley) 5/8/95 * $FreeBSD$ */ @@ -65,13 +65,13 @@ lfs_blkatoff(ap) register struct lfs *fs; struct inode *ip; struct buf *bp; - daddr_t lbn; + ufs_daddr_t lbn; int bsize, error; ip = VTOI(ap->a_vp); fs = ip->i_lfs; lbn = lblkno(fs, ap->a_offset); - bsize = blksize(fs); + bsize = blksize(fs, ip, lbn); *ap->a_bpp = NULL; if (error = bread(ap->a_vp, lbn, bsize, NOCRED, &bp)) { @@ -112,7 +112,8 @@ lfs_seglock(fs, flags) sp = fs->lfs_sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / - sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); + sizeof(ufs_daddr_t) + 1) * sizeof(struct buf *), + M_SEGMENT, M_WAITOK); sp->seg_flags = flags; sp->vp = NULL; (void) lfs_initseg(fs); diff --git a/sys/ufs/lfs/lfs_syscalls.c b/sys/ufs/lfs/lfs_syscalls.c index 01e63e2..6ec1d9e 100644 --- a/sys/ufs/lfs/lfs_syscalls.c +++ b/sys/ufs/lfs/lfs_syscalls.c @@ -115,7 +115,7 @@ lfs_markv(p, uap, retval) if (error = copyin(uap->fsidp, &fsid, sizeof(fsid_t))) return (error); - if ((mntp = getvfs(&fsid)) == NULL) + if ((mntp = vfs_getvfs(&fsid)) == NULL) return (EINVAL); cnt = uap->blkcnt; @@ -286,7 +286,7 @@ lfs_bmapv(p, uap, retval) if (error = copyin(uap->fsidp, &fsid, sizeof(fsid_t))) return (error); - if ((mntp = getvfs(&fsid)) == NULL) + if ((mntp = vfs_getvfs(&fsid)) == NULL) return (EINVAL); cnt = uap->blkcnt; @@ -347,7 +347,7 @@ lfs_segclean(p, uap, retval) if (error = copyin(uap->fsidp, &fsid, sizeof(fsid_t))) return (error); - if ((mntp = getvfs(&fsid)) == NULL) + if ((mntp = vfs_getvfs(&fsid)) == NULL) return (EINVAL); fs = VFSTOUFS(mntp)->um_lfs; @@ -413,14 +413,14 @@ lfs_segwait(p, uap, retval) if (fsid == (fsid_t)-1) addr = &lfs_allclean_wakeup; else { - if ((mntp = getvfs(&fsid)) == NULL) + if ((mntp = vfs_getvfs(&fsid)) == NULL) return (EINVAL); addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; } #else if (error = copyin(uap->fsidp, &fsid, sizeof(fsid_t))) return (error); - if ((mntp = getvfs(&fsid)) == NULL) + if ((mntp = vfs_getvfs(&fsid)) == NULL) addr = &lfs_allclean_wakeup; else addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; diff --git a/sys/ufs/mfs/mfs_extern.h b/sys/ufs/mfs/mfs_extern.h index e2bd561..1556659 100644 --- a/sys/ufs/mfs/mfs_extern.h +++ b/sys/ufs/mfs/mfs_extern.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)mfs_extern.h 8.1 (Berkeley) 6/11/93 + * @(#)mfs_extern.h 8.4 (Berkeley) 3/30/95 * $FreeBSD$ */ @@ -44,4 +44,6 @@ void mfs_doio __P((struct buf *bp, caddr_t base)); int mfs_mountfs __P((struct vnode *, struct mount *, struct proc *)); int mfs_mountroot __P((void)); +#define mfs_revoke vop_revoke + #endif /* !_UFS_MFS_MFS_EXTERN_H_ */ diff --git a/sys/ufs/mfs/mfs_vfsops.c b/sys/ufs/mfs/mfs_vfsops.c index 372d9db..3847603 100644 --- a/sys/ufs/mfs/mfs_vfsops.c +++ b/sys/ufs/mfs/mfs_vfsops.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)mfs_vfsops.c 8.4 (Berkeley) 4/16/94 + * @(#)mfs_vfsops.c 8.11 (Berkeley) 6/19/95 * $FreeBSD$ */ @@ -84,7 +84,7 @@ static int mfs_mount __P((struct mount *mp, static int mfs_start __P((struct mount *mp, int flags, struct proc *p)); static int mfs_statfs __P((struct mount *mp, struct statfs *sbp, struct proc *p)); -static int mfs_init __P((void)); +static int mfs_init __P((struct vfsconf *)); /* * mfs vfs operations. @@ -230,8 +230,8 @@ mfs_mount(mp, path, data, ndp, p) struct vnode *devvp; struct mfs_args args; struct ufsmount *ump; - register struct fs *fs; - register struct mfsnode *mfsp; + struct fs *fs; + struct mfsnode *mfsp; u_int size; int flags, err; @@ -282,8 +282,10 @@ mfs_mount(mp, path, data, ndp, p) /* Get vnode for root device*/ - if( bdevvp( rootdev, &rootvp)) - panic("mfs_mountroot: can't setup bdevvp for rootdev"); + if (error = bdevvp( rootdev, &rootvp)) { + printf("mfs_mountroot: can't setup bdevvp for rootdev"); + return (error); + } /* * FS specific handling @@ -342,12 +344,7 @@ mfs_mount(mp, path, data, ndp, p) flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; - if (vfs_busy(mp)) { - err = EBUSY; - goto error_1; - } err = ffs_flushfiles(mp, flags, p); - vfs_unbusy(mp); if (err) goto error_1; } @@ -503,7 +500,7 @@ mfs_statfs(mp, sbp, p) int error; error = ffs_statfs(mp, sbp, p); - sbp->f_type = MOUNT_MFS; + sbp->f_type = mp->mnt_vfc->vfc_typenum; return (error); } @@ -511,7 +508,8 @@ mfs_statfs(mp, sbp, p) * Memory based filesystem initialization. */ static int -mfs_init() +mfs_init(vfsp) + struct vfsconf *vfsp; { return (0); } diff --git a/sys/ufs/mfs/mfs_vnops.c b/sys/ufs/mfs/mfs_vnops.c index 29eae7d..75ccd85 100644 --- a/sys/ufs/mfs/mfs_vnops.c +++ b/sys/ufs/mfs/mfs_vnops.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)mfs_vnops.c 8.3 (Berkeley) 9/21/93 + * @(#)mfs_vnops.c 8.11 (Berkeley) 5/22/95 * $FreeBSD$ */ @@ -51,12 +51,6 @@ #include <ufs/mfs/mfsiom.h> #include <ufs/mfs/mfs_extern.h> -#if !defined(hp300) && !defined(i386) && !defined(mips) && !defined(sparc) && !defined(luna68k) -static int mfsmap_want; /* 1 => need kernel I/O resources */ -struct map mfsmap[MFS_MAPSIZE]; -extern char mfsiobuf[]; -#endif - static int mfs_badop __P((void)); static int mfs_bmap __P((struct vop_bmap_args *)); static int mfs_close __P((struct vop_close_args *)); @@ -84,6 +78,7 @@ static struct vnodeopv_entry_desc mfs_vnodeop_entries[] = { { &vop_write_desc, (vop_t *)mfs_write }, /* write */ { &vop_ioctl_desc, (vop_t *)mfs_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)mfs_select }, /* select */ + { &vop_revoke_desc, (vop_t *)mfs_revoke }, /* revoke */ { &vop_mmap_desc, (vop_t *)mfs_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)spec_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)mfs_seek }, /* seek */ @@ -227,9 +222,9 @@ static int mfs_bmap(ap) struct vop_bmap_args /* { struct vnode *a_vp; - daddr_t a_bn; + ufs_daddr_t a_bn; struct vnode **a_vpp; - daddr_t *a_bnp; + ufs_daddr_t *a_bnp; int *a_runp; } */ *ap; { @@ -300,13 +295,16 @@ static int mfs_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { - register struct mfsnode *mfsp = VTOMFS(ap->a_vp); + struct vnode *vp = ap->a_vp; + struct mfsnode *mfsp = VTOMFS(vp); if (!TAILQ_EMPTY(&mfsp->buf_queue)) panic("mfs_inactive: not inactive (next buffer %p)", TAILQ_FIRST(&mfsp->buf_queue)); + VOP_UNLOCK(vp, 0, ap->a_p); return (0); } @@ -319,9 +317,10 @@ mfs_reclaim(ap) struct vnode *a_vp; } */ *ap; { + register struct vnode *vp = ap->a_vp; - FREE(ap->a_vp->v_data, M_MFSNODE); - ap->a_vp->v_data = NULL; + FREE(vp->v_data, M_MFSNODE); + vp->v_data = NULL; return (0); } @@ -351,4 +350,3 @@ mfs_badop() panic("mfs_badop called"); /* NOTREACHED */ } - diff --git a/sys/ufs/mfs/mfsnode.h b/sys/ufs/mfs/mfsnode.h index 29fbd33..403d473 100644 --- a/sys/ufs/mfs/mfsnode.h +++ b/sys/ufs/mfs/mfsnode.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)mfsnode.h 8.2 (Berkeley) 8/11/93 + * @(#)mfsnode.h 8.3 (Berkeley) 5/19/95 * $FreeBSD$ */ @@ -78,9 +78,9 @@ struct mfsnode { #define mfs_readdir ((int (*) __P((struct vop_readdir_args *)))mfs_badop) #define mfs_readlink ((int (*) __P((struct vop_readlink_args *)))mfs_badop) #define mfs_abortop ((int (*) __P((struct vop_abortop_args *)))mfs_badop) -#define mfs_lock ((int (*) __P((struct vop_lock_args *)))nullop) -#define mfs_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) -#define mfs_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) +#define mfs_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock) +#define mfs_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock) +#define mfs_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked) #define mfs_pathconf ((int (*) __P((struct vop_pathconf_args *)))mfs_badop) #define mfs_advlock ((int (*) __P((struct vop_advlock_args *)))mfs_badop) #define mfs_blkatoff ((int (*) __P((struct vop_blkatoff_args *)))mfs_badop) diff --git a/sys/ufs/ufs/dinode.h b/sys/ufs/ufs/dinode.h index c2fd5bd..461a6c0 100644 --- a/sys/ufs/ufs/dinode.h +++ b/sys/ufs/ufs/dinode.h @@ -51,32 +51,46 @@ #define ROOTINO ((ino_t)2) /* + * The Whiteout inode# is a dummy non-zero inode number which will + * never be allocated to a real file. It is used as a place holder + * in the directory entry which has been tagged as a DT_W entry. + * See the comments about ROOTINO above. + */ +#define WINO ((ino_t)1) + +/* * A dinode contains all the meta-data associated with a UFS file. - * This structure defines the on-disk format of a dinode. + * This structure defines the on-disk format of a dinode. Since + * this structure describes an on-disk structure, all its fields + * are defined by types with precise widths. */ +/* typedef int32_t ufs_daddr_t; */ #define NDADDR 12 /* Direct addresses in inode. */ #define NIADDR 3 /* Indirect addresses in inode. */ struct dinode { - u_short di_mode; /* 0: IFMT and permissions. */ - short di_nlink; /* 2: File link count. */ + u_int16_t di_mode; /* 0: IFMT, permissions; see below. */ + int16_t di_nlink; /* 2: File link count. */ union { - u_short oldids[2]; /* 4: Ffs: old user and group ids. */ - ino_t inumber; /* 4: Lfs: inode number. */ + u_int16_t oldids[2]; /* 4: Ffs: old user and group ids. */ + int32_t inumber; /* 4: Lfs: inode number. */ } di_u; - u_quad_t di_size; /* 8: File byte count. */ - struct timespec di_atime; /* 16: Last access time. */ - struct timespec di_mtime; /* 24: Last modified time. */ - struct timespec di_ctime; /* 32: Last inode change time. */ - daddr_t di_db[NDADDR]; /* 40: Direct disk blocks. */ - daddr_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */ - u_long di_flags; /* 100: Status flags (chflags). */ - long di_blocks; /* 104: Blocks actually held. */ - long di_gen; /* 108: Generation number. */ - u_long di_uid; /* 112: File owner. */ - u_long di_gid; /* 116: File group. */ - long di_spare[2]; /* 120: Reserved; currently unused */ + u_int64_t di_size; /* 8: File byte count. */ + int32_t di_atime; /* 16: Last access time. */ + int32_t di_atimensec; /* 20: Last access time. */ + int32_t di_mtime; /* 24: Last modified time. */ + int32_t di_mtimensec; /* 28: Last modified time. */ + int32_t di_ctime; /* 32: Last inode change time. */ + int32_t di_ctimensec; /* 36: Last inode change time. */ + ufs_daddr_t di_db[NDADDR]; /* 40: Direct disk blocks. */ + ufs_daddr_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */ + u_int32_t di_flags; /* 100: Status flags (chflags). */ + int32_t di_blocks; /* 104: Blocks actually held. */ + int32_t di_gen; /* 108: Generation number. */ + u_int32_t di_uid; /* 112: File owner. */ + u_int32_t di_gid; /* 116: File group. */ + int32_t di_spare[2]; /* 120: Reserved; currently unused */ }; /* @@ -91,9 +105,9 @@ struct dinode { #define di_ouid di_u.oldids[0] #define di_rdev di_db[0] #define di_shortlink di_db -#define MAXSYMLINKLEN ((NDADDR + NIADDR) * sizeof(daddr_t)) +#define MAXSYMLINKLEN ((NDADDR + NIADDR) * sizeof(ufs_daddr_t)) -/* File modes. */ +/* File permissions. */ #define IEXEC 0000100 /* Executable. */ #define IWRITE 0000200 /* Writeable. */ #define IREAD 0000400 /* Readable. */ @@ -110,5 +124,6 @@ struct dinode { #define IFREG 0100000 /* Regular file. */ #define IFLNK 0120000 /* Symbolic link. */ #define IFSOCK 0140000 /* UNIX domain socket. */ +#define IFWHT 0160000 /* Whiteout. */ #endif diff --git a/sys/ufs/ufs/dir.h b/sys/ufs/ufs/dir.h index 3a3ceb8..0c8680e 100644 --- a/sys/ufs/ufs/dir.h +++ b/sys/ufs/ufs/dir.h @@ -43,6 +43,17 @@ #define _UFS_UFS_DIR_H_ /* + * Theoretically, directories can be more than 2Gb in length, however, in + * practice this seems unlikely. So, we define the type doff_t as a 32-bit + * quantity to keep down the cost of doing lookup on a 32-bit machine. + */ +#define doff_t int32_t + +#ifdef notused +#define MAXDIRSIZE (0x7fffffff) +#endif + +/* * A directory consists of some number of blocks of DIRBLKSIZ * bytes, where DIRBLKSIZ is chosen such that it can be transferred * to disk in a single atomic operation (e.g. 512 bytes on most machines). @@ -71,11 +82,11 @@ #define MAXNAMLEN 255 struct direct { - u_long d_ino; /* inode number of entry */ - u_short d_reclen; /* length of this record */ - u_char d_type; /* file type, see below */ - u_char d_namlen; /* length of string in d_name */ - char d_name[MAXNAMLEN + 1]; /* name with length <= MAXNAMLEN */ + u_int32_t d_ino; /* inode number of entry */ + u_int16_t d_reclen; /* length of this record */ + u_int8_t d_type; /* file type, see below */ + u_int8_t d_namlen; /* length of string in d_name */ + char d_name[MAXNAMLEN + 1];/* name with length <= MAXNAMLEN */ }; /* @@ -89,6 +100,7 @@ struct direct { #define DT_REG 8 #define DT_LNK 10 #define DT_SOCK 12 +#define DT_WHT 14 /* * Convert between stat structure types and directory types. @@ -118,34 +130,33 @@ struct direct { #define NEWDIRFMT 0 /* - * Template for manipulating directories. - * Should use struct direct's, but the name field - * is MAXNAMLEN - 1, and this just won't do. + * Template for manipulating directories. Should use struct direct's, + * but the name field is MAXNAMLEN - 1, and this just won't do. */ struct dirtemplate { - u_long dot_ino; - short dot_reclen; - u_char dot_type; - u_char dot_namlen; - char dot_name[4]; /* must be multiple of 4 */ - u_long dotdot_ino; - short dotdot_reclen; - u_char dotdot_type; - u_char dotdot_namlen; - char dotdot_name[4]; /* ditto */ + u_int32_t dot_ino; + int16_t dot_reclen; + u_int8_t dot_type; + u_int8_t dot_namlen; + char dot_name[4]; /* must be multiple of 4 */ + u_int32_t dotdot_ino; + int16_t dotdot_reclen; + u_int8_t dotdot_type; + u_int8_t dotdot_namlen; + char dotdot_name[4]; /* ditto */ }; /* * This is the old format of directories, sanz type element. */ struct odirtemplate { - u_long dot_ino; - short dot_reclen; - u_short dot_namlen; - char dot_name[4]; /* must be multiple of 4 */ - u_long dotdot_ino; - short dotdot_reclen; - u_short dotdot_namlen; - char dotdot_name[4]; /* ditto */ + u_int32_t dot_ino; + int16_t dot_reclen; + u_int16_t dot_namlen; + char dot_name[4]; /* must be multiple of 4 */ + u_int32_t dotdot_ino; + int16_t dotdot_reclen; + u_int16_t dotdot_namlen; + char dotdot_name[4]; /* ditto */ }; #endif /* !_DIR_H_ */ diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h index dc19d34..438471f 100644 --- a/sys/ufs/ufs/inode.h +++ b/sys/ufs/ufs/inode.h @@ -35,42 +35,33 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)inode.h 8.4 (Berkeley) 1/21/94 + * @(#)inode.h 8.9 (Berkeley) 5/14/95 * $FreeBSD$ */ #ifndef _UFS_UFS_INODE_H_ #define _UFS_UFS_INODE_H_ +#include <ufs/ufs/dir.h> #include <ufs/ufs/dinode.h> /* - * Theoretically, directories can be more than 2Gb in length, however, in - * practice this seems unlikely. So, we define the type doff_t as a long - * to keep down the cost of doing lookup on a 32-bit machine. If you are - * porting to a 64-bit architecture, you should make doff_t the same as off_t. - */ -#define doff_t long - -/* - * The inode is used to describe each active (or recently active) - * file in the UFS filesystem. It is composed of two types of - * information. The first part is the information that is needed - * only while the file is active (such as the identity of the file - * and linkage to speed its lookup). The second part is the - * permanent meta-data associated with the file which is read - * in from the permanent dinode from long term storage when the - * file becomes active, and is put back when the file is no longer - * being used. + * The inode is used to describe each active (or recently active) file in the + * UFS filesystem. It is composed of two types of information. The first part + * is the information that is needed only while the file is active (such as + * the identity of the file and linkage to speed its lookup). The second part + * is the permanent meta-data associated with the file which is read in + * from the permanent dinode from long term storage when the file becomes + * active, and is put back when the file is no longer being used. */ struct inode { - struct inode *i_next; /* Hash chain forward. */ - struct inode **i_prev; /* Hash chain back. */ - struct vnode *i_vnode; /* Vnode associated with this inode. */ - struct vnode *i_devvp; /* Vnode for block I/O. */ - u_long i_flag; /* I* flags. */ - dev_t i_dev; /* Device associated with the inode. */ - ino_t i_number; /* The identity of the inode. */ + LIST_ENTRY(inode) i_hash;/* Hash chain. */ + struct vnode *i_vnode;/* Vnode associated with this inode. */ + struct vnode *i_devvp;/* Vnode for block I/O. */ + u_int32_t i_flag; /* flags, see below */ + dev_t i_dev; /* Device associated with the inode. */ + ino_t i_number; /* The identity of the inode. */ + union { /* Associated filesystem. */ struct fs *fs; /* FFS */ struct lfs *lfs; /* LFS */ @@ -79,22 +70,21 @@ struct inode { #define i_fs inode_u.fs #define i_lfs inode_u.lfs #define i_e2fs inode_u.e2fs - struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ - u_quad_t i_modrev; /* Revision level for lease. */ - struct lockf *i_lockf; /* Head of byte-level lock list. */ - pid_t i_lockholder; /* DEBUG: holder of inode lock. */ - pid_t i_lockwaiter; /* DEBUG: latest blocked for inode lock. */ + struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ + u_quad_t i_modrev; /* Revision level for NFS lease. */ + struct lockf *i_lockf;/* Head of byte-level lock list. */ + struct lock i_lock; /* Inode lock. */ /* * Side effects; used during directory lookup. */ - long i_count; /* Size of free slot in directory. */ - doff_t i_endoff; /* End of useful stuff in directory. */ - 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. */ - u_long i_reclen; /* Size of found directory entry. */ - int i_lockcount; /* Process lock count (recursion) */ - long i_spare[10]; /* Spares to round up to 128 bytes. */ + int32_t i_count; /* Size of free slot in directory. */ + doff_t i_endoff; /* End of useful stuff in directory. */ + 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. */ + u_int32_t i_reclen; /* Size of found directory entry. */ + int i_lockcount; /* Process lock count (recursion) */ + int i_spare[10]; /* XXX spare storage (for ext2fs) */ /* * The on-disk dinode itself. */ @@ -102,8 +92,10 @@ struct inode { }; #define i_atime i_din.di_atime +#define i_atimensec i_din.di_atimensec #define i_blocks i_din.di_blocks #define i_ctime i_din.di_ctime +#define i_ctimensec i_din.di_ctimensec #define i_db i_din.di_db #define i_flags i_din.di_flags #define i_gen i_din.di_gen @@ -111,6 +103,7 @@ struct inode { #define i_ib i_din.di_ib #define i_mode i_din.di_mode #define i_mtime i_din.di_mtime +#define i_mtimensec i_din.di_mtimensec #define i_nlink i_din.di_nlink #define i_rdev i_din.di_rdev #define i_shortlink i_din.di_shortlink @@ -120,15 +113,12 @@ struct inode { /* These flags are kept in i_flag. */ #define IN_ACCESS 0x0001 /* Access time update request. */ #define IN_CHANGE 0x0002 /* Inode change time update request. */ -#define IN_EXLOCK 0x0004 /* File has exclusive lock. */ -#define IN_LOCKED 0x0008 /* Inode lock. */ -#define IN_LWAIT 0x0010 /* Process waiting on file lock. */ -#define IN_MODIFIED 0x0020 /* Inode has been modified. */ -#define IN_RENAME 0x0040 /* Inode is being renamed. */ -#define IN_SHLOCK 0x0080 /* File has shared lock. */ -#define IN_UPDATE 0x0100 /* Modification time update request. */ -#define IN_WANTED 0x0200 /* Inode is wanted by a process. */ -#define IN_RECURSE 0x0400 /* Recursion expected */ +#define IN_UPDATE 0x0004 /* Modification time update request. */ +#define IN_MODIFIED 0x0008 /* Inode has been modified. */ +#define IN_RENAME 0x0010 /* Inode is being renamed. */ +#define IN_SHLOCK 0x0020 /* File has shared lock. */ +#define IN_EXLOCK 0x0040 /* File has exclusive lock. */ +#define IN_RECURSE 0x0080 /* Recursion expected */ #ifdef KERNEL /* @@ -136,7 +126,7 @@ struct inode { * ufs_getlbns and used by truncate and bmap code. */ struct indir { - daddr_t in_lbn; /* Logical block number. */ + ufs_daddr_t in_lbn; /* Logical block number. */ int in_off; /* Offset in buffer. */ int in_exists; /* Flag if the block exists. */ }; @@ -155,25 +145,25 @@ struct indir { if ((ip)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) { \ (ip)->i_flag |= IN_MODIFIED; \ if ((ip)->i_flag & IN_ACCESS) \ - (ip)->i_atime.tv_sec \ + (ip)->i_atime \ = ((t1) == &time ? tv_sec : (t1)->tv_sec); \ if ((ip)->i_flag & IN_UPDATE) { \ - (ip)->i_mtime.tv_sec \ + (ip)->i_mtime \ = ((t2) == &time ? tv_sec : (t2)->tv_sec); \ (ip)->i_modrev++; \ } \ if ((ip)->i_flag & IN_CHANGE) \ - (ip)->i_ctime.tv_sec = tv_sec; \ + (ip)->i_ctime = tv_sec; \ (ip)->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); \ } \ } /* This overlays the fid structure (see mount.h). */ struct ufid { - u_short ufid_len; /* Length of structure. */ - u_short ufid_pad; /* Force long alignment. */ - ino_t ufid_ino; /* File number (ino). */ - long ufid_gen; /* Generation number. */ + u_int16_t ufid_len; /* Length of structure. */ + u_int16_t ufid_pad; /* Force 32-bit alignment. */ + ino_t ufid_ino; /* File number (ino). */ + int32_t ufid_gen; /* Generation number. */ }; #endif /* KERNEL */ diff --git a/sys/ufs/ufs/quota.h b/sys/ufs/ufs/quota.h index e780865..7b9ff40 100644 --- a/sys/ufs/ufs/quota.h +++ b/sys/ufs/ufs/quota.h @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)quota.h 8.1 (Berkeley) 6/11/93 + * @(#)quota.h 8.3 (Berkeley) 8/19/94 * $FreeBSD$ */ @@ -49,8 +49,8 @@ * failure). The timer is started when the user crosses their soft limit, it * is reset when they go below their soft limit. */ -#define MAX_IQ_TIME (7*24*60*60) /* 1 week */ -#define MAX_DQ_TIME (7*24*60*60) /* 1 week */ +#define MAX_IQ_TIME (7*24*60*60) /* seconds in 1 week */ +#define MAX_DQ_TIME (7*24*60*60) /* seconds in 1 week */ /* * The following constants define the usage of the quota file array in the @@ -97,15 +97,15 @@ * the vnode for each quota file (a pointer is retained in the ufsmount * structure). */ -struct dqblk { - u_long dqb_bhardlimit; /* absolute limit on disk blks alloc */ - u_long dqb_bsoftlimit; /* preferred limit on disk blks */ - u_long dqb_curblocks; /* current block count */ - u_long dqb_ihardlimit; /* maximum # allocated inodes + 1 */ - u_long dqb_isoftlimit; /* preferred inode limit */ - u_long dqb_curinodes; /* current # allocated inodes */ - time_t dqb_btime; /* time limit for excessive disk use */ - time_t dqb_itime; /* time limit for excessive files */ +struct dqblk { + u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ + u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */ + u_int32_t dqb_curblocks; /* current block count */ + u_int32_t dqb_ihardlimit; /* maximum # allocated inodes + 1 */ + u_int32_t dqb_isoftlimit; /* preferred inode limit */ + u_int32_t dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive files */ }; /* @@ -114,14 +114,14 @@ struct dqblk { * filesystem for the current user or group. A cache is kept of recently * used entries. */ -struct dquot { - struct dquot *dq_forw, **dq_back; /* hash list */ - struct dquot *dq_freef, **dq_freeb; /* free list */ - short dq_flags; /* flags, see below */ - short dq_cnt; /* count of active references */ - short dq_spare; /* unused spare padding */ - short dq_type; /* quota type of this dquot */ - u_long dq_id; /* identifier this applies to */ +struct dquot { + LIST_ENTRY(dquot) dq_hash; /* hash list */ + TAILQ_ENTRY(dquot) dq_freelist; /* free list */ + u_int16_t dq_flags; /* flags, see below */ + u_int16_t dq_cnt; /* count of active references */ + u_int16_t dq_spare; /* unused spare padding */ + u_int16_t dq_type; /* quota type of this dquot */ + u_int32_t dq_id; /* identifier this applies to */ struct ufsmount *dq_ump; /* filesystem that this is taken from */ struct dqblk dq_dqb; /* actual usage & quotas */ }; @@ -147,11 +147,11 @@ struct dquot { #define dq_itime dq_dqb.dqb_itime /* - * If the system has never checked for a quota for this file, then it is set - * to NODQUOT. Once a write attempt is made the inode pointer is set to - * reference a dquot structure. + * If the system has never checked for a quota for this file, then it is + * set to NODQUOT. Once a write attempt is made the inode pointer is set + * to reference a dquot structure. */ -#define NODQUOT ((struct dquot *) 0) +#define NODQUOT NULL /* * Flags to chkdq() and chkiq() diff --git a/sys/ufs/ufs/ufs_bmap.c b/sys/ufs/ufs/ufs_bmap.c index e17b5b7..aef2b83 100644 --- a/sys/ufs/ufs/ufs_bmap.c +++ b/sys/ufs/ufs/ufs_bmap.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ufs_bmap.c 8.6 (Berkeley) 1/21/94 + * @(#)ufs_bmap.c 8.7 (Berkeley) 3/21/95 * $FreeBSD$ */ @@ -63,9 +63,9 @@ int ufs_bmap(ap) struct vop_bmap_args /* { struct vnode *a_vp; - daddr_t a_bn; + ufs_daddr_t a_bn; struct vnode **a_vpp; - daddr_t *a_bnp; + ufs_daddr_t *a_bnp; int *a_runp; int *a_runb; } */ *ap; @@ -100,8 +100,8 @@ ufs_bmap(ap) int ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb) struct vnode *vp; - register daddr_t bn; - daddr_t *bnp; + ufs_daddr_t bn; + ufs_daddr_t *bnp; struct indir *ap; int *nump; int *runp; @@ -113,7 +113,7 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb) struct mount *mp; struct vnode *devvp; struct indir a[NIADDR+1], *xap; - daddr_t daddr; + ufs_daddr_t daddr; long metalbn; int error, maxrun = 0, num; @@ -209,12 +209,13 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb) } } - daddr = ((daddr_t *)bp->b_data)[xap->in_off]; + daddr = ((ufs_daddr_t *)bp->b_data)[xap->in_off]; if (num == 1 && daddr && runp) { for (bn = xap->in_off + 1; bn < MNINDIR(ump) && *runp < maxrun && - is_sequential(ump, ((daddr_t *)bp->b_data)[bn - 1], - ((daddr_t *)bp->b_data)[bn]); + is_sequential(ump, + ((ufs_daddr_t *)bp->b_data)[bn - 1], + ((ufs_daddr_t *)bp->b_data)[bn]); ++bn, ++*runp); bn = xap->in_off; if (runb && bn) { @@ -245,7 +246,7 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb) int ufs_getlbns(vp, bn, ap, nump) struct vnode *vp; - register daddr_t bn; + ufs_daddr_t bn; struct indir *ap; int *nump; { diff --git a/sys/ufs/ufs/ufs_extern.h b/sys/ufs/ufs/ufs_extern.h index 4c114d9..a450e92 100644 --- a/sys/ufs/ufs/ufs_extern.h +++ b/sys/ufs/ufs/ufs_extern.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ufs_extern.h 8.3 (Berkeley) 4/16/94 + * @(#)ufs_extern.h 8.10 (Berkeley) 5/14/95 * $FreeBSD$ */ @@ -49,8 +49,8 @@ struct proc; struct ucred; struct uio; struct vattr; +struct vfsconf; struct vnode; -struct ufs_args; int ufs_abortop __P((struct vop_abortop_args *)); int ufs_access __P((struct vop_access_args *)); @@ -71,7 +71,7 @@ int ufs_dirremove __P((struct vnode *, struct componentname*)); int ufs_dirrewrite __P((struct inode *, struct inode *, struct componentname *)); int ufs_getattr __P((struct vop_getattr_args *)); -int ufs_getlbns __P((struct vnode *, daddr_t, struct indir *, int *)); +int ufs_getlbns __P((struct vnode *, ufs_daddr_t, struct indir *, int *)); struct vnode * ufs_ihashget __P((dev_t, ino_t)); void ufs_ihashinit __P((void)); @@ -80,9 +80,14 @@ struct vnode * ufs_ihashlookup __P((dev_t, ino_t)); void ufs_ihashrem __P((struct inode *)); int ufs_inactive __P((struct vop_inactive_args *)); -int ufs_init __P((void)); +int ufs_init __P((struct vfsconf *)); int ufs_ioctl __P((struct vop_ioctl_args *)); int ufs_islocked __P((struct vop_islocked_args *)); +#ifdef NFS +#define ufs_lease_check lease_check +#else +#define ufs_lease_check ((int (*) __P((struct vop_lease_args *)))nullop) +#endif int ufs_link __P((struct vop_link_args *)); int ufs_lock __P((struct vop_lock_args *)); int ufs_lookup __P((struct vop_lookup_args *)); @@ -95,9 +100,10 @@ int ufs_pathconf __P((struct vop_pathconf_args *)); int ufs_print __P((struct vop_print_args *)); int ufs_readdir __P((struct vop_readdir_args *)); int ufs_readlink __P((struct vop_readlink_args *)); -int ufs_reclaim __P((struct vop_reclaim_args *)); +int ufs_reclaim __P((struct vnode *, struct proc *)); int ufs_remove __P((struct vop_remove_args *)); int ufs_rename __P((struct vop_rename_args *)); +#define ufs_revoke vop_revoke int ufs_rmdir __P((struct vop_rmdir_args *)); int ufs_root __P((struct mount *, struct vnode **)); int ufs_seek __P((struct vop_seek_args *)); @@ -108,6 +114,7 @@ int ufs_strategy __P((struct vop_strategy_args *)); int ufs_symlink __P((struct vop_symlink_args *)); int ufs_unlock __P((struct vop_unlock_args *)); int ufs_vinit __P((struct mount *, vop_t **, vop_t **, struct vnode **)); +int ufs_whiteout __P((struct vop_whiteout_args *)); int ufsspec_close __P((struct vop_close_args *)); int ufsspec_read __P((struct vop_read_args *)); int ufsspec_write __P((struct vop_write_args *)); diff --git a/sys/ufs/ufs/ufs_ihash.c b/sys/ufs/ufs/ufs_ihash.c index a51af00..ea83308 100644 --- a/sys/ufs/ufs/ufs_ihash.c +++ b/sys/ufs/ufs/ufs_ihash.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1982, 1986, 1989, 1991, 1993 + * Copyright (c) 1982, 1986, 1989, 1991, 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. * - * @(#)ufs_ihash.c 8.4 (Berkeley) 12/30/93 + * @(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95 * $FreeBSD$ */ @@ -47,9 +47,10 @@ /* * Structures associated with inode cacheing. */ -struct inode **ihashtbl; +LIST_HEAD(ihashhead, inode) *ihashtbl; u_long ihash; /* size of hash table - 1 */ -#define INOHASH(device, inum) (((device) + (inum)) & ihash) +#define INOHASH(device, inum) (&ihashtbl[((device) + (inum)) & ihash]) +struct simplelock ufs_ihash_slock; /* * Initialize inode hash table. @@ -59,6 +60,7 @@ ufs_ihashinit() { ihashtbl = hashinit(desiredvnodes, M_UFSMNT, &ihash); + simple_lock_init(&ufs_ihash_slock); } /* @@ -66,19 +68,21 @@ ufs_ihashinit() * to it. If it is in core, return it, even if it is locked. */ struct vnode * -ufs_ihashlookup(device, inum) - dev_t device; +ufs_ihashlookup(dev, inum) + dev_t dev; ino_t inum; { - register struct inode *ip; + struct inode *ip; - for (ip = ihashtbl[INOHASH(device, inum)];; ip = ip->i_next) { - if (ip == NULL) - return (NULL); - if (inum == ip->i_number && device == ip->i_dev) - return (ITOV(ip)); - } - /* NOTREACHED */ + simple_lock(&ufs_ihash_slock); + for (ip = INOHASH(dev, inum)->lh_first; ip; ip = ip->i_hash.le_next) + if (inum == ip->i_number && dev == ip->i_dev) + break; + simple_unlock(&ufs_ihash_slock); + + if (ip) + return (ITOV(ip)); + return (NULLVP); } /* @@ -86,36 +90,28 @@ ufs_ihashlookup(device, inum) * to it. If it is in core, but locked, wait for it. */ struct vnode * -ufs_ihashget(device, inum) - dev_t device; +ufs_ihashget(dev, inum) + dev_t dev; ino_t inum; { - register struct inode *ip; + struct proc *p = curproc; /* XXX */ + struct inode *ip; struct vnode *vp; - for (;;) - for (ip = ihashtbl[INOHASH(device, inum)];; ip = ip->i_next) { - if (ip == NULL) - return (NULL); - if (inum == ip->i_number && device == ip->i_dev) { - if (ip->i_flag & IN_LOCKED) { - if( curproc->p_pid != ip->i_lockholder) { - ip->i_flag |= IN_WANTED; - (void) tsleep(ip, PINOD, "uihget", 0); - break; - } else if (ip->i_flag & IN_RECURSE) { - ip->i_lockcount++; - } else { - panic("ufs_ihashget: recursive lock not expected -- pid %d\n", ip->i_lockholder); - } - } - vp = ITOV(ip); - if (!vget(vp, 1)) - return (vp); - break; - } +loop: + simple_lock(&ufs_ihash_slock); + for (ip = INOHASH(dev, inum)->lh_first; ip; ip = ip->i_hash.le_next) { + if (inum == ip->i_number && dev == ip->i_dev) { + vp = ITOV(ip); + simple_lock(&vp->v_interlock); + simple_unlock(&ufs_ihash_slock); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) + goto loop; + return (vp); } - /* NOTREACHED */ + } + simple_unlock(&ufs_ihash_slock); + return (NULL); } /* @@ -125,26 +121,16 @@ void ufs_ihashins(ip) struct inode *ip; { - struct inode **ipp, *iq; + struct proc *p = curproc; /* XXX */ + struct ihashhead *ipp; - ipp = &ihashtbl[INOHASH(ip->i_dev, ip->i_number)]; - iq = *ipp; - if (iq) - iq->i_prev = &ip->i_next; - ip->i_next = iq; - ip->i_prev = ipp; - *ipp = ip; - if ((ip->i_flag & IN_LOCKED) && - ((ip->i_flag & IN_RECURSE) == 0 || - (!curproc || (curproc && (ip->i_lockholder != curproc->p_pid))))) - panic("ufs_ihashins: already locked"); - if (curproc) { - ip->i_lockcount += 1; - ip->i_lockholder = curproc->p_pid; - } else { - ip->i_lockholder = -1; - } - ip->i_flag |= IN_LOCKED; + /* lock the inode, then put it on the appropriate hash list */ + lockmgr(&ip->i_lock, LK_EXCLUSIVE, (struct simplelock *)0, p); + + simple_lock(&ufs_ihash_slock); + ipp = INOHASH(ip->i_dev, ip->i_number); + LIST_INSERT_HEAD(ipp, ip, i_hash); + simple_unlock(&ufs_ihash_slock); } /* @@ -152,16 +138,13 @@ ufs_ihashins(ip) */ void ufs_ihashrem(ip) - register struct inode *ip; + struct inode *ip; { - register struct inode *iq; - - iq = ip->i_next; - if (iq) - iq->i_prev = ip->i_prev; - *ip->i_prev = iq; + simple_lock(&ufs_ihash_slock); + LIST_REMOVE(ip, i_hash); #ifdef DIAGNOSTIC - ip->i_next = NULL; - ip->i_prev = NULL; + ip->i_hash.le_next = NULL; + ip->i_hash.le_prev = NULL; #endif + simple_unlock(&ufs_ihash_slock); } diff --git a/sys/ufs/ufs/ufs_inode.c b/sys/ufs/ufs/ufs_inode.c index 45616bb..dd59142 100644 --- a/sys/ufs/ufs/ufs_inode.c +++ b/sys/ufs/ufs/ufs_inode.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1991, 1993 + * Copyright (c) 1991, 1993, 1995 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ufs_inode.c 8.4 (Berkeley) 1/21/94 + * @(#)ufs_inode.c 8.9 (Berkeley) 5/14/95 * $FreeBSD$ */ @@ -57,24 +57,6 @@ u_long nextgennumber; /* Next generation number to assign. */ int prtactive = 0; /* 1 => print out reclaim of active vnodes */ -int -ufs_init() -{ - static int first = 1; - - if (!first) - return (0); - first = 0; - -#ifdef DIAGNOSTIC - if ((sizeof(struct inode) - 1) & sizeof(struct inode)) - printf("ufs_init: bad size %d\n", sizeof(struct inode)); -#endif - ufs_ihashinit(); - dqinit(); - return (0); -} - /* * Last reference to an inode. If necessary, write or delete it. */ @@ -82,39 +64,29 @@ int ufs_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { - register struct vnode *vp = ap->a_vp; - register struct inode *ip = VTOI(vp); + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + struct proc *p = ap->a_p; struct timeval tv; - int mode, error; + int mode, error = 0; if (prtactive && vp->v_usecount != 0) vprint("ufs_inactive: pushing active", vp); - /* Get rid of inodes related to stale file handles. */ - if (ip->i_mode == 0) { - if ((vp->v_flag & VXLOCK) == 0) - vgone(vp); - return (0); - } - - error = 0; -#ifdef DIAGNOSTIC - if (VOP_ISLOCKED(vp)) - panic("ufs_inactive: locked inode"); - if (curproc) - ip->i_lockholder = curproc->p_pid; - else - ip->i_lockholder = -1; -#endif - ip->i_flag |= IN_LOCKED; + /* + * Ignore inodes related to stale file handles. + */ + if (ip->i_mode == 0) + goto out; if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { #ifdef QUOTA if (!getinoquota(ip)) (void)chkiq(ip, -1, NOCRED, 0); #endif - error = VOP_TRUNCATE(vp, (off_t)0, 0, NOCRED, NULL); + error = VOP_TRUNCATE(vp, (off_t)0, 0, NOCRED, p); ip->i_rdev = 0; mode = ip->i_mode; ip->i_mode = 0; @@ -125,13 +97,14 @@ ufs_inactive(ap) tv = time; VOP_UPDATE(vp, &tv, &tv, 0); } - VOP_UNLOCK(vp); +out: + 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->i_mode == 0) - vgone(vp); + if (ip->i_mode == 0) + vrecycle(vp, (struct simplelock *)0, p); return (error); } @@ -139,14 +112,11 @@ ufs_inactive(ap) * Reclaim an inode so that it can be used for other purposes. */ int -ufs_reclaim(ap) - struct vop_reclaim_args /* { - struct vnode *a_vp; - } */ *ap; +ufs_reclaim(vp, p) + struct vnode *vp; + struct proc *p; { - register struct vnode *vp = ap->a_vp; register struct inode *ip; - int type; #ifdef QUOTA int i; #endif @@ -174,23 +144,5 @@ ufs_reclaim(ap) } } #endif - switch (vp->v_mount->mnt_stat.f_type) { - case MOUNT_EXT2FS: - type = M_FFSNODE; - break; - case MOUNT_UFS: - type = M_FFSNODE; - break; - case MOUNT_MFS: - type = M_MFSNODE; - break; - case MOUNT_LFS: - type = M_LFSNODE; - break; - default: - panic("ufs_reclaim: not ufs file"); - } - FREE(vp->v_data, type); - vp->v_data = NULL; return (0); } diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c index 4b99584..38fe929 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ufs_lookup.c 8.6 (Berkeley) 4/1/94 + * @(#)ufs_lookup.c 8.15 (Berkeley) 6/16/95 * $FreeBSD$ */ @@ -128,6 +128,7 @@ ufs_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; slotoffset = -1; @@ -175,14 +176,14 @@ ufs_lookup(ap) VREF(vdp); error = 0; } else if (flags & ISDOTDOT) { - VOP_UNLOCK(pdp); - error = vget(vdp, 1); + VOP_UNLOCK(pdp, 0, p); + error = vget(vdp, LK_EXCLUSIVE, p); if (!error && lockparent && (flags & ISLASTCN)) - error = VOP_LOCK(pdp); + error = vn_lock(pdp, LK_EXCLUSIVE, p); } else { - error = vget(vdp, 1); + error = vget(vdp, LK_EXCLUSIVE, p); if (!lockparent || error || !(flags & ISLASTCN)) - VOP_UNLOCK(pdp); + VOP_UNLOCK(pdp, 0, p); } /* * Check that the capability number did not change @@ -193,10 +194,9 @@ ufs_lookup(ap) return (0); vput(vdp); if (lockparent && pdp != vdp && (flags & ISLASTCN)) - VOP_UNLOCK(pdp); + VOP_UNLOCK(pdp, 0, p); } - error = VOP_LOCK(pdp); - if (error) + if (error = vn_lock(pdp, LK_EXCLUSIVE, p)) return (error); vdp = pdp; dp = VTOI(pdp); @@ -337,6 +337,17 @@ searchloop: * reclen in ndp->ni_ufs area, and release * directory buffer. */ + if (vdp->v_mount->mnt_maxsymlinklen > 0 && + ep->d_type == DT_WHT) { + slotstatus = FOUND; + slotoffset = dp->i_offset; + slotsize = ep->d_reclen; + dp->i_reclen = slotsize; + enduseful = dp->i_size; + ap->a_cnp->cn_flags |= ISWHITEOUT; + numdirpasses--; + goto notfound; + } dp->i_ino = ep->d_ino; dp->i_reclen = ep->d_reclen; brelse(bp); @@ -349,7 +360,7 @@ searchloop: if (ep->d_ino) enduseful = dp->i_offset; } -/* notfound: */ +notfound: /* * If we started in the middle of the directory and failed * to find our target, we must check the beginning as well. @@ -367,7 +378,10 @@ searchloop: * directory has not been removed, then can consider * allowing file to be created. */ - if ((nameiop == CREATE || nameiop == RENAME) && + if ((nameiop == CREATE || nameiop == RENAME || + (nameiop == DELETE && + (ap->a_cnp->cn_flags & DOWHITEOUT) && + (ap->a_cnp->cn_flags & ISWHITEOUT))) && (flags & ISLASTCN) && dp->i_nlink != 0) { /* * Access for write is interpreted as allowing @@ -389,6 +403,12 @@ searchloop: dp->i_offset = roundup2(dp->i_size, DIRBLKSIZ); dp->i_count = 0; enduseful = dp->i_offset; + } else if (nameiop == DELETE) { + dp->i_offset = slotoffset; + if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) + dp->i_count = 0; + else + dp->i_count = dp->i_offset - prevoff; } else { dp->i_offset = slotoffset; dp->i_count = slotsize; @@ -412,7 +432,7 @@ searchloop: */ cnp->cn_flags |= SAVENAME; if (!lockparent) - VOP_UNLOCK(vdp); + VOP_UNLOCK(vdp, 0, p); return (EJUSTRETURN); } /* @@ -484,13 +504,14 @@ found: if ((dp->i_mode & ISVTX) && cred->cr_uid != 0 && cred->cr_uid != dp->i_uid && + tdp->v_type != VLNK && VTOI(tdp)->i_uid != cred->cr_uid) { vput(tdp); return (EPERM); } *vpp = tdp; if (!lockparent) - VOP_UNLOCK(vdp); + VOP_UNLOCK(vdp, 0, p); return (0); } @@ -500,10 +521,8 @@ found: * Must get inode of directory entry to verify it's a * regular file, or empty directory. */ - if (nameiop == RENAME && wantparent && - (flags & ISLASTCN)) { - error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc); - if (error) + if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) { + if (error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) return (error); /* * Careful about locking second inode. @@ -517,7 +536,7 @@ found: *vpp = tdp; cnp->cn_flags |= SAVENAME; if (!lockparent) - VOP_UNLOCK(vdp); + VOP_UNLOCK(vdp, 0, p); return (0); } @@ -542,14 +561,13 @@ found: */ pdp = vdp; if (flags & ISDOTDOT) { - VOP_UNLOCK(pdp); /* race to get the inode */ - error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); - if (error) { - VOP_LOCK(pdp); + VOP_UNLOCK(pdp, 0, p); /* race to get the inode */ + if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) { + vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p); return (error); } if (lockparent && (flags & ISLASTCN) && - (error = VOP_LOCK(pdp))) { + (error = vn_lock(pdp, LK_EXCLUSIVE, p))) { vput(tdp); return (error); } @@ -562,7 +580,7 @@ found: if (error) return (error); if (!lockparent || !(flags & ISLASTCN)) - VOP_UNLOCK(pdp); + VOP_UNLOCK(pdp, 0, p); *vpp = tdp; } @@ -621,6 +639,8 @@ ufs_dirbadentry(dp, ep, entryoffsetinblock) printf("First bad\n"); goto bad; } + if (ep->d_ino == 0) + return (0); for (i = 0; i < namlen; i++) if (ep->d_name[i] == '\0') { /*return (1); */ @@ -629,9 +649,9 @@ ufs_dirbadentry(dp, ep, entryoffsetinblock) } if (ep->d_name[i]) goto bad; - return (ep->d_name[i]); + return (0); bad: - return(1); + return (1); } /* @@ -648,15 +668,8 @@ ufs_direnter(ip, dvp, cnp) struct vnode *dvp; register struct componentname *cnp; { - register struct direct *ep, *nep; register struct inode *dp; - struct buf *bp; struct direct newdir; - struct iovec aiov; - struct uio auio; - u_int dsize; - int error, loc, newentrysize, spacefree; - char *dirbuf; #ifdef DIAGNOSTIC if ((cnp->cn_flags & SAVENAME) == 0) @@ -676,7 +689,33 @@ ufs_direnter(ip, dvp, cnp) newdir.d_type = tmp; } # endif } - newentrysize = DIRSIZ(OFSFMT(dvp), &newdir); + return (ufs_direnter2(dvp, &newdir, cnp->cn_cred, cnp->cn_proc)); +} + +/* + * Common entry point for directory entry removal used by ufs_direnter + * and ufs_whiteout + */ +int +ufs_direnter2(dvp, dirp, cr, p) + struct vnode *dvp; + struct direct *dirp; + struct ucred *cr; + struct proc *p; +{ + int newentrysize; + struct inode *dp; + struct buf *bp; + struct iovec aiov; + struct uio auio; + u_int dsize; + struct direct *ep, *nep; + int error, loc, spacefree; + char *dirbuf; + + dp = VTOI(dvp); + newentrysize = DIRSIZ(OFSFMT(dvp), dirp); + if (dp->i_count == 0) { /* * If dp->i_count is 0, then namei could find no @@ -685,22 +724,22 @@ ufs_direnter(ip, dvp, cnp) * new entry into a fresh block. */ if (dp->i_offset & (DIRBLKSIZ - 1)) - panic("ufs_direnter: newblk"); + panic("ufs_direnter2: newblk"); auio.uio_offset = dp->i_offset; - newdir.d_reclen = DIRBLKSIZ; + dirp->d_reclen = DIRBLKSIZ; auio.uio_resid = newentrysize; aiov.iov_len = newentrysize; - aiov.iov_base = (caddr_t)&newdir; + aiov.iov_base = (caddr_t)dirp; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_rw = UIO_WRITE; auio.uio_segflg = UIO_SYSSPACE; auio.uio_procp = (struct proc *)0; - error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred); + error = VOP_WRITE(dvp, &auio, IO_SYNC, cr); if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) /* XXX should grow with balloc() */ - panic("ufs_direnter: frag size"); + panic("ufs_direnter2: frag size"); else if (!error) { dp->i_size = roundup2(dp->i_size, DIRBLKSIZ); dp->i_flag |= IN_CHANGE; @@ -761,18 +800,20 @@ ufs_direnter(ip, dvp, cnp) * Update the pointer fields in the previous entry (if any), * copy in the new entry, and write out the block. */ - if (ep->d_ino == 0) { + if (ep->d_ino == 0 || + (ep->d_ino == WINO && + bcmp(ep->d_name, dirp->d_name, dirp->d_namlen) == 0)) { if (spacefree + dsize < newentrysize) - panic("ufs_direnter: compact1"); - newdir.d_reclen = spacefree + dsize; + panic("ufs_direnter2: compact1"); + dirp->d_reclen = spacefree + dsize; } else { if (spacefree < newentrysize) - panic("ufs_direnter: compact2"); - newdir.d_reclen = spacefree; + panic("ufs_direnter2: compact2"); + dirp->d_reclen = spacefree; ep->d_reclen = dsize; ep = (struct direct *)((char *)ep + dsize); } - bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize); + bcopy((caddr_t)dirp, (caddr_t)ep, (u_int)newentrysize); if (dvp->v_mount->mnt_flag & MNT_ASYNC) { bdwrite(bp); @@ -782,8 +823,7 @@ ufs_direnter(ip, dvp, cnp) } dp->i_flag |= IN_CHANGE | IN_UPDATE; if (!error && dp->i_endoff && dp->i_endoff < dp->i_size) - error = VOP_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, - cnp->cn_cred, cnp->cn_proc); + error = VOP_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, cr, p); return (error); } @@ -810,6 +850,21 @@ ufs_dirremove(dvp, cnp) int error; dp = VTOI(dvp); + + if (cnp->cn_flags & DOWHITEOUT) { + /* + * Whiteout entry: set d_ino to WINO. + */ + if (error = + VOP_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) + return (error); + ep->d_ino = WINO; + ep->d_type = DT_WHT; + error = VOP_BWRITE(bp); + dp->i_flag |= IN_CHANGE | IN_UPDATE; + return (error); + } + if (dp->i_count == 0) { /* * First entry in block: set d_ino to zero. @@ -906,7 +961,7 @@ ufs_dirempty(ip, parentino, cred) if (dp->d_reclen == 0) return (0); /* skip empty entries */ - if (dp->d_ino == 0) + if (dp->d_ino == 0 || dp->d_ino == WINO) continue; /* accept only "." and ".." */ # if (BYTE_ORDER == LITTLE_ENDIAN) diff --git a/sys/ufs/ufs/ufs_quota.c b/sys/ufs/ufs/ufs_quota.c index 88d659d..6d69a98 100644 --- a/sys/ufs/ufs/ufs_quota.c +++ b/sys/ufs/ufs/ufs_quota.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1982, 1986, 1990, 1993 + * Copyright (c) 1982, 1986, 1990, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ufs_quota.c 8.2 (Berkeley) 12/30/93 + * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 * $FreeBSD$ */ @@ -379,8 +379,8 @@ quotaon(p, mp, type, fname) register int type; caddr_t fname; { - register struct ufsmount *ump = VFSTOUFS(mp); - register struct vnode *vp, **vpp; + struct ufsmount *ump = VFSTOUFS(mp); + struct vnode *vp, **vpp; struct vnode *nextvp; struct dquot *dq; int error; @@ -392,15 +392,11 @@ quotaon(p, mp, type, fname) if (error) return (error); vp = nd.ni_vp; - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); if (vp->v_type != VREG) { (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p); return (EACCES); } - if (vfs_busy(mp)) { - (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p); - return (EBUSY); - } if (*vpp != vp) quotaoff(p, mp, type); ump->um_qflags[type] |= QTF_OPENING; @@ -432,7 +428,7 @@ again: nextvp = vp->v_mntvnodes.le_next; if (vp->v_writecount == 0) continue; - if (vget(vp, 1)) + if (vget(vp, LK_EXCLUSIVE, p)) goto again; error = getinoquota(VTOI(vp)); if (error) { @@ -446,7 +442,6 @@ again: ump->um_qflags[type] &= ~QTF_OPENING; if (error) quotaoff(p, mp, type); - vfs_unbusy(mp); return (error); } @@ -459,15 +454,13 @@ quotaoff(p, mp, type) struct mount *mp; register int type; { - register struct vnode *vp; + struct vnode *vp; struct vnode *qvp, *nextvp; struct ufsmount *ump = VFSTOUFS(mp); - register struct dquot *dq; - register struct inode *ip; + struct dquot *dq; + struct inode *ip; int error; - if ((mp->mnt_flag & MNT_MPBUSY) == 0) - panic("quotaoff: not busy"); if ((qvp = ump->um_quotas[type]) == NULLVP) return (0); ump->um_qflags[type] |= QTF_CLOSING; @@ -478,7 +471,7 @@ quotaoff(p, mp, type) again: for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) { nextvp = vp->v_mntvnodes.le_next; - if (vget(vp, 1)) + if (vget(vp, LK_EXCLUSIVE, p)) goto again; ip = VTOI(vp); dq = ip->i_dquot[type]; @@ -641,16 +634,15 @@ qsync(mp) struct mount *mp; { struct ufsmount *ump = VFSTOUFS(mp); - register struct vnode *vp, *nextvp; - register struct dquot *dq; - register int i; + struct proc *p = curproc; /* XXX */ + struct vnode *vp, *nextvp; + struct dquot *dq; + int i, error; /* * Check if the mount point has any quotas. * If not, simply return. */ - if ((mp->mnt_flag & MNT_MPBUSY) == 0) - panic("qsync: not busy"); for (i = 0; i < MAXQUOTAS; i++) if (ump->um_quotas[i] != NULLVP) break; @@ -660,36 +652,48 @@ qsync(mp) * Search vnodes associated with this mount point, * synchronizing any modified dquot structures. */ + simple_lock(&mntvnode_slock); again: for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) { + if (vp->v_mount != mp) + goto again; nextvp = vp->v_mntvnodes.le_next; - if (VOP_ISLOCKED(vp)) + simple_lock(&vp->v_interlock); + simple_unlock(&mntvnode_slock); + error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); + if (error) { + simple_lock(&mntvnode_slock); + if (error == ENOENT) + goto again; continue; - if (vget(vp, 1)) - goto again; + } for (i = 0; i < MAXQUOTAS; i++) { dq = VTOI(vp)->i_dquot[i]; if (dq != NODQUOT && (dq->dq_flags & DQ_MOD)) dqsync(vp, dq); } vput(vp); - if (vp->v_mntvnodes.le_next != nextvp || vp->v_mount != mp) + simple_lock(&mntvnode_slock); + if (vp->v_mntvnodes.le_next != nextvp) goto again; } + simple_unlock(&mntvnode_slock); return (0); } /* * Code pertaining to management of the in-core dquot data structures. */ -static struct dquot **dqhashtbl; +#define DQHASH(dqvp, id) \ + (&dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash]) +static LIST_HEAD(dqhash, dquot) *dqhashtbl; static u_long dqhash; /* * Dquot free list. */ #define DQUOTINC 5 /* minimum free dquots desired */ -static struct dquot *dqfreel, **dqback = &dqfreel; +TAILQ_HEAD(dqfreelist, dquot) dqfreelist; static long numdquot, desireddquot = DQUOTINC; /* @@ -700,6 +704,7 @@ dqinit() { dqhashtbl = hashinit(desiredvnodes, M_DQUOT, &dqhash); + TAILQ_INIT(&dqfreelist); } /* @@ -714,8 +719,10 @@ dqget(vp, id, ump, type, dqp) register int type; struct dquot **dqp; { - register struct dquot *dq, *dp, **dpp; - register struct vnode *dqvp; + struct proc *p = curproc; /* XXX */ + struct dquot *dq; + struct dqhash *dqh; + struct vnode *dqvp; struct iovec aiov; struct uio auio; int error; @@ -728,8 +735,8 @@ dqget(vp, id, ump, type, dqp) /* * Check the cache first. */ - dpp = &dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash]; - for (dq = *dpp; dq; dq = dq->dq_forw) { + dqh = DQHASH(dqvp, id); + for (dq = dqh->lh_first; dq; dq = dq->dq_hash.le_next) { if (dq->dq_id != id || dq->dq_ump->um_quotas[dq->dq_type] != dqvp) continue; @@ -737,13 +744,8 @@ dqget(vp, id, ump, type, dqp) * Cache hit with no references. Take * the structure off the free list. */ - if (dq->dq_cnt == 0) { - if ((dp = dq->dq_freef) != NODQUOT) - dp->dq_freeb = dq->dq_freeb; - else - dqback = dq->dq_freeb; - *dq->dq_freeb = dp; - } + if (dq->dq_cnt == 0) + TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); DQREF(dq); *dqp = dq; return (0); @@ -751,43 +753,30 @@ dqget(vp, id, ump, type, dqp) /* * Not in cache, allocate a new one. */ - if (dqfreel == NODQUOT && numdquot < MAXQUOTAS * desiredvnodes) + if (dqfreelist.tqh_first == NODQUOT && + numdquot < MAXQUOTAS * desiredvnodes) desireddquot += DQUOTINC; if (numdquot < desireddquot) { dq = (struct dquot *)malloc(sizeof *dq, M_DQUOT, M_WAITOK); bzero((char *)dq, sizeof *dq); numdquot++; } else { - if ((dq = dqfreel) == NULL) { + if ((dq = dqfreelist.tqh_first) == NULL) { tablefull("dquot"); *dqp = NODQUOT; return (EUSERS); } if (dq->dq_cnt || (dq->dq_flags & DQ_MOD)) panic("free dquot isn't"); - if ((dp = dq->dq_freef) != NODQUOT) - dp->dq_freeb = &dqfreel; - else - dqback = &dqfreel; - dqfreel = dp; - dq->dq_freef = NULL; - dq->dq_freeb = NULL; - dp = dq->dq_forw; - if (dp) - dp->dq_back = dq->dq_back; - *dq->dq_back = dp; + TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); + LIST_REMOVE(dq, dq_hash); } /* * Initialize the contents of the dquot structure. */ if (vp != dqvp) - VOP_LOCK(dqvp); - dp = *dpp; - if (dp) - dp->dq_back = &dq->dq_forw; - dq->dq_forw = dp; - dq->dq_back = dpp; - *dpp = dq; + vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY, p); + LIST_INSERT_HEAD(dqh, dq, dq_hash); DQREF(dq); dq->dq_flags = DQ_LOCK; dq->dq_id = id; @@ -806,7 +795,7 @@ dqget(vp, id, ump, type, dqp) if (auio.uio_resid == sizeof(struct dqblk) && error == 0) bzero((caddr_t)&dq->dq_dqb, sizeof(struct dqblk)); if (vp != dqvp) - VOP_UNLOCK(dqvp); + VOP_UNLOCK(dqvp, 0, p); if (dq->dq_flags & DQ_WANT) wakeup((caddr_t)dq); dq->dq_flags = 0; @@ -815,12 +804,7 @@ dqget(vp, id, ump, type, dqp) * quota structure and reflect problem to caller. */ if (error) { - dp = dq->dq_forw; - if (dp) - dp->dq_back = dq->dq_back; - *dq->dq_back = dp; - dq->dq_forw = NULL; - dq->dq_back = NULL; + LIST_REMOVE(dq, dq_hash); dqrele(vp, dq); *dqp = NODQUOT; return (error); @@ -874,15 +858,7 @@ dqrele(vp, dq) (void) dqsync(vp, dq); if (--dq->dq_cnt > 0) return; - if (dqfreel != NODQUOT) { - *dqback = dq; - dq->dq_freeb = dqback; - } else { - dqfreel = dq; - dq->dq_freeb = &dqfreel; - } - dq->dq_freef = NODQUOT; - dqback = &dq->dq_freef; + TAILQ_INSERT_TAIL(&dqfreelist, dq, dq_freelist); } /* @@ -891,8 +867,9 @@ dqrele(vp, dq) static int dqsync(vp, dq) struct vnode *vp; - register struct dquot *dq; + struct dquot *dq; { + struct proc *p = curproc; /* XXX */ struct vnode *dqvp; struct iovec aiov; struct uio auio; @@ -905,13 +882,13 @@ dqsync(vp, dq) if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP) panic("dqsync: file"); if (vp != dqvp) - VOP_LOCK(dqvp); + vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY, p); while (dq->dq_flags & DQ_LOCK) { dq->dq_flags |= DQ_WANT; (void) tsleep((caddr_t)dq, PINOD+2, "dqsync", 0); if ((dq->dq_flags & DQ_MOD) == 0) { if (vp != dqvp) - VOP_UNLOCK(dqvp); + VOP_UNLOCK(dqvp, 0, p); return (0); } } @@ -932,7 +909,7 @@ dqsync(vp, dq) wakeup((caddr_t)dq); dq->dq_flags &= ~(DQ_MOD|DQ_LOCK|DQ_WANT); if (vp != dqvp) - VOP_UNLOCK(dqvp); + VOP_UNLOCK(dqvp, 0, p); return (error); } @@ -943,26 +920,22 @@ static void dqflush(vp) register struct vnode *vp; { - register struct dquot *dq, *dp, **dpp, *nextdq; + register struct dquot *dq, *nextdq; + struct dqhash *dqh; /* * Move all dquot's that used to refer to this quota * file off their hash chains (they will eventually * fall off the head of the free list and be re-used). */ - for (dpp = &dqhashtbl[dqhash]; dpp >= dqhashtbl; dpp--) { - for (dq = *dpp; dq; dq = nextdq) { - nextdq = dq->dq_forw; + for (dqh = &dqhashtbl[dqhash]; dqh >= dqhashtbl; dqh--) { + for (dq = dqh->lh_first; dq; dq = nextdq) { + nextdq = dq->dq_hash.le_next; if (dq->dq_ump->um_quotas[dq->dq_type] != vp) continue; if (dq->dq_cnt) panic("dqflush: stray dquot"); - dp = dq->dq_forw; - if (dp) - dp->dq_back = dq->dq_back; - *dq->dq_back = dp; - dq->dq_forw = NULL; - dq->dq_back = NULL; + LIST_REMOVE(dq, dq_hash); dq->dq_ump = (struct ufsmount *)0; } } diff --git a/sys/ufs/ufs/ufs_readwrite.c b/sys/ufs/ufs/ufs_readwrite.c index 99497e6..c83ba17 100644 --- a/sys/ufs/ufs/ufs_readwrite.c +++ b/sys/ufs/ufs/ufs_readwrite.c @@ -30,12 +30,12 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ufs_readwrite.c 8.7 (Berkeley) 1/21/94 + * @(#)ufs_readwrite.c 8.11 (Berkeley) 5/8/95 * $FreeBSD$ */ #ifdef LFS_READWRITE -#define BLKSIZE(a, b, c) blksize(a) +#define BLKSIZE(a, b, c) blksize(a, b, c) #define FS struct lfs #define I_FS i_lfs #define READ lfs_read @@ -75,7 +75,7 @@ READ(ap) register struct uio *uio; register FS *fs; struct buf *bp; - daddr_t lbn, nextlbn; + ufs_daddr_t lbn, nextlbn; off_t bytesinfile; long size, xfersize, blkoffset; int error; @@ -99,7 +99,7 @@ READ(ap) panic("%s: type %d", READ_S, vp->v_type); #endif fs = ip->I_FS; - if ((u_quad_t)uio->uio_offset > fs->fs_maxfilesize) + if ((u_int64_t)uio->uio_offset > fs->fs_maxfilesize) return (EFBIG); for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) { @@ -189,7 +189,7 @@ WRITE(ap) register FS *fs; struct buf *bp; struct proc *p; - daddr_t lbn; + ufs_daddr_t lbn; off_t osize; int blkoffset, error, flags, ioflag, resid, size, xfersize; struct timeval tv; @@ -223,7 +223,7 @@ WRITE(ap) fs = ip->I_FS; if (uio->uio_offset < 0 || - (u_quad_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize) + (u_int64_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize) return (EFBIG); /* * Maybe this should be above the vnode op call, but so long as @@ -253,7 +253,7 @@ WRITE(ap) #ifdef LFS_READWRITE (void)lfs_check(vp, lbn); - error = lfs_balloc(vp, xfersize, lbn, &bp); + error = lfs_balloc(vp, blkoffset, xfersize, lbn, &bp); #else if (fs->fs_bsize > xfersize) flags |= B_CLRBUF; diff --git a/sys/ufs/ufs/ufs_vfsops.c b/sys/ufs/ufs/ufs_vfsops.c index 7ae2a27..a0d6af5 100644 --- a/sys/ufs/ufs/ufs_vfsops.c +++ b/sys/ufs/ufs/ufs_vfsops.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ufs_vfsops.c 8.4 (Berkeley) 4/16/94 + * @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95 * $FreeBSD$ */ @@ -57,11 +57,6 @@ #include <ufs/ufs/ufs_extern.h> /* - * Flag to permit forcible unmounting. - */ -int doforce = 1; - -/* * Make a filesystem operational. * Nothing to do at the moment. */ @@ -129,40 +124,61 @@ ufs_quotactl(mp, cmds, uid, arg, p) type = cmds & SUBCMDMASK; if ((u_int)type >= MAXQUOTAS) return (EINVAL); + if (vfs_busy(mp, LK_NOWAIT, 0, p)) + return (0); switch (cmd) { case Q_QUOTAON: - return (quotaon(p, mp, type, arg)); + error = quotaon(p, mp, type, arg); + break; case Q_QUOTAOFF: - if (vfs_busy(mp)) - return (0); error = quotaoff(p, mp, type); - vfs_unbusy(mp); - return (error); + break; case Q_SETQUOTA: - return (setquota(mp, uid, type, arg)); + error = setquota(mp, uid, type, arg); + break; case Q_SETUSE: - return (setuse(mp, uid, type, arg)); + error = setuse(mp, uid, type, arg); + break; case Q_GETQUOTA: - return (getquota(mp, uid, type, arg)); + error = getquota(mp, uid, type, arg); + break; case Q_SYNC: - if (vfs_busy(mp)) - return (0); error = qsync(mp); - vfs_unbusy(mp); - return (error); + break; default: - return (EINVAL); + error = EINVAL; + break; } - /* NOTREACHED */ + vfs_unbusy(mp, p); + return (error); +#endif +} + +/* + * Initial UFS filesystems, done only once. + */ +int +ufs_init(vfsp) + struct vfsconf *vfsp; +{ + static int done; + + if (done) + return (0); + done = 1; + ufs_ihashinit(); +#ifdef QUOTA + dqinit(); #endif + return (0); } /* diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index edc022f..66527c1 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1982, 1986, 1989, 1993 + * Copyright (c) 1982, 1986, 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ufs_vnops.c 8.10 (Berkeley) 4/1/94 + * @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95 * $FreeBSD$ */ @@ -80,8 +80,8 @@ static int ufs_chown #endif /* EXT2FS */ union _qcvt { - quad_t qcvt; - long val[2]; + int64_t qcvt; + int32_t val[2]; }; #define SETHIGH(q, h) { \ union _qcvt tmp; \ @@ -204,8 +204,10 @@ ufs_close(ap) register struct vnode *vp = ap->a_vp; register struct inode *ip = VTOI(vp); - if (vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED)) + simple_lock(&vp->v_interlock); + if (vp->v_usecount > 1) ITIMES(ip, &time, &time); + simple_unlock(&vp->v_interlock); return (0); } @@ -317,9 +319,12 @@ ufs_getattr(ap) vap->va_gid = ip->i_gid; vap->va_rdev = (dev_t)ip->i_rdev; vap->va_size = ip->i_din.di_size; - vap->va_atime = ip->i_atime; - vap->va_mtime = ip->i_mtime; - vap->va_ctime = ip->i_ctime; + vap->va_atime.tv_sec = ip->i_atime; + vap->va_atime.tv_nsec = ip->i_atimensec; + vap->va_mtime.tv_sec = ip->i_mtime; + vap->va_mtime.tv_nsec = ip->i_mtimensec; + vap->va_ctime.tv_sec = ip->i_ctime; + vap->va_ctime.tv_nsec = ip->i_ctimensec; vap->va_flags = ip->i_flags; vap->va_gen = ip->i_gen; /* this doesn't belong here */ @@ -329,7 +334,7 @@ ufs_getattr(ap) vap->va_blocksize = MAXBSIZE; else vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; - vap->va_bytes = dbtob(ip->i_blocks); + vap->va_bytes = dbtob((u_quad_t)ip->i_blocks); vap->va_type = vp->v_type; vap->va_filerev = ip->i_modrev; return (0); @@ -376,7 +381,8 @@ ufs_setattr(ap) return (EPERM); ip->i_flags = vap->va_flags; } else { - if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) + if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND) || + (vap->va_flags & UF_SETTABLE) != vap->va_flags) return (EPERM); ip->i_flags &= SF_SETTABLE; ip->i_flags |= (vap->va_flags & UF_SETTABLE); @@ -393,8 +399,7 @@ ufs_setattr(ap) if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); - error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p); - if (error) + if (error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p)) return (error); } if (vap->va_size != VNOVAL) { @@ -412,8 +417,7 @@ ufs_setattr(ap) return (EROFS); break; } - error = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p); - if (error) + if (error = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p)) return (error); } ip = VTOI(vp); @@ -711,6 +715,7 @@ ufs_link(ap) struct vnode *vp = ap->a_vp; struct vnode *tdvp = ap->a_tdvp; struct componentname *cnp = ap->a_cnp; + struct proc *p = cnp->cn_proc; struct inode *ip; struct timeval tv; int error; @@ -719,12 +724,12 @@ ufs_link(ap) if ((cnp->cn_flags & HASBUF) == 0) panic("ufs_link: no name"); #endif - if (vp->v_mount != tdvp->v_mount) { + if (tdvp->v_mount != vp->v_mount) { VOP_ABORTOP(tdvp, cnp); error = EXDEV; goto out2; } - if (vp != tdvp && (error = VOP_LOCK(vp))) { + if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) { VOP_ABORTOP(tdvp, cnp); goto out2; } @@ -761,13 +766,69 @@ ufs_link(ap) } FREE(cnp->cn_pnbuf, M_NAMEI); out1: - if (vp != tdvp) - VOP_UNLOCK(vp); + if (tdvp != vp) + VOP_UNLOCK(vp, 0, p); out2: vput(tdvp); return (error); } +/* + * whiteout vnode call + */ +int +ufs_whiteout(ap) + struct vop_whiteout_args /* { + struct vnode *a_dvp; + struct componentname *a_cnp; + int a_flags; + } */ *ap; +{ + struct vnode *dvp = ap->a_dvp; + struct componentname *cnp = ap->a_cnp; + struct direct newdir; + int error = 0; + + switch (ap->a_flags) { + case LOOKUP: + /* 4.4 format directories support whiteout operations */ + if (dvp->v_mount->mnt_maxsymlinklen > 0) + return (0); + return (EOPNOTSUPP); + + case CREATE: + /* create a new directory whiteout */ +#ifdef DIAGNOSTIC + if ((cnp->cn_flags & SAVENAME) == 0) + panic("ufs_whiteout: missing name"); + if (dvp->v_mount->mnt_maxsymlinklen <= 0) + panic("ufs_whiteout: old format filesystem"); +#endif + + newdir.d_ino = WINO; + newdir.d_namlen = cnp->cn_namelen; + bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1); + newdir.d_type = DT_WHT; + error = ufs_direnter2(dvp, &newdir, cnp->cn_cred, cnp->cn_proc); + break; + + case DELETE: + /* remove an existing directory whiteout */ +#ifdef DIAGNOSTIC + if (dvp->v_mount->mnt_maxsymlinklen <= 0) + panic("ufs_whiteout: old format filesystem"); +#endif + + cnp->cn_flags &= ~DOWHITEOUT; + error = ufs_dirremove(dvp, cnp); + break; + } + if (cnp->cn_flags & HASBUF) { + FREE(cnp->cn_pnbuf, M_NAMEI); + cnp->cn_flags &= ~HASBUF; + } + return (error); +} /* * Rename system call. @@ -810,6 +871,7 @@ ufs_rename(ap) struct vnode *fdvp = ap->a_fdvp; struct componentname *tcnp = ap->a_tcnp; struct componentname *fcnp = ap->a_fcnp; + struct proc *p = fcnp->cn_proc; struct inode *ip, *xp, *dp; struct dirtemplate dirbuf; struct timeval tv; @@ -899,13 +961,12 @@ abortit: } return (VOP_REMOVE(fdvp, fvp, fcnp)); } - error = VOP_LOCK(fvp); - if (error) + if (error = vn_lock(fvp, LK_EXCLUSIVE, p)) goto abortit; dp = VTOI(fdvp); ip = VTOI(fvp); if ((ip->i_flags & (IMMUTABLE | APPEND)) || (dp->i_flags & APPEND)) { - VOP_UNLOCK(fvp); + VOP_UNLOCK(fvp, 0, p); error = EPERM; goto abortit; } @@ -916,7 +977,7 @@ abortit: if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || dp == ip || (fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT || (ip->i_flag & IN_RENAME)) { - VOP_UNLOCK(fvp); + VOP_UNLOCK(fvp, 0, p); error = EINVAL; goto abortit; } @@ -944,9 +1005,8 @@ abortit: ip->i_nlink++; ip->i_flag |= IN_CHANGE; tv = time; - error = VOP_UPDATE(fvp, &tv, &tv, 1); - if (error) { - VOP_UNLOCK(fvp); + if (error = VOP_UPDATE(fvp, &tv, &tv, 1)) { + VOP_UNLOCK(fvp, 0, p); goto bad; } @@ -961,7 +1021,7 @@ abortit: * call to checkpath(). */ error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc); - VOP_UNLOCK(fvp); + VOP_UNLOCK(fvp, 0, p); if (oldparent != dp->i_number) newparent = dp->i_number; if (doingdirectory && newparent) { @@ -1235,7 +1295,9 @@ bad: vput(ITOV(xp)); vput(ITOV(dp)); out: - if (VOP_LOCK(fvp) == 0) { + if (doingdirectory) + ip->i_flag &= ~IN_RENAME; + if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) { ip->i_nlink--; ip->i_flag |= IN_CHANGE; ip->i_flag &= ~IN_RENAME; @@ -1314,6 +1376,8 @@ ufs_mkdir(ap) ip->i_mode = dmode; tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ ip->i_nlink = 2; + if (cnp->cn_flags & ISWHITEOUT) + ip->i_flags |= UF_OPAQUE; tv = time; error = VOP_UPDATE(tvp, &tv, &tv, 1); @@ -1545,13 +1609,15 @@ ufs_readdir(ap) struct vnode *a_vp; struct uio *a_uio; struct ucred *a_cred; - int *a_ncookies; - u_int **cookies; + int *a_eofflag; + int *ncookies; + u_long **a_cookies; } */ *ap; { register struct uio *uio = ap->a_uio; + int error; + size_t count, lost; off_t off; - int count, lost, error; if (ap->a_ncookies != NULL) /* @@ -1561,10 +1627,11 @@ ufs_readdir(ap) uio->uio_offset &= ~(DIRBLKSIZ - 1); off = uio->uio_offset; count = uio->uio_resid; - count &= ~(DIRBLKSIZ - 1); - lost = uio->uio_resid - count; - if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) + /* Make sure we don't return partial entries. */ + count -= (uio->uio_offset + count) & (DIRBLKSIZ -1); + if (count <= 0) return (EINVAL); + lost = uio->uio_resid - count; uio->uio_resid = count; uio->uio_iov->iov_len = count; # if (BYTE_ORDER == LITTLE_ENDIAN) @@ -1614,8 +1681,8 @@ ufs_readdir(ap) struct dirent* dpEnd; struct dirent* dp; int ncookies; - u_int *cookies; - u_int *cookiep; + u_long *cookies; + u_long *cookiep; if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) panic("ufs_readdir: unexpected uio from NFS server"); @@ -1626,20 +1693,20 @@ ufs_readdir(ap) dp < dpEnd; dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) ncookies++; - MALLOC(cookies, u_int *, ncookies * sizeof(u_int), - M_TEMP, M_WAITOK); + MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP, + M_WAITOK); for (dp = dpStart, cookiep = cookies; dp < dpEnd; dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { off += dp->d_reclen; - *cookiep++ = (u_int) off; + *cookiep++ = (u_long) off; } *ap->a_ncookies = ncookies; *ap->a_cookies = cookies; } + uio->uio_resid += lost; if (ap->a_eofflag) *ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset; - uio->uio_resid += lost; return (error); } @@ -1691,95 +1758,31 @@ int ufs_lock(ap) struct vop_lock_args /* { struct vnode *a_vp; + int a_flags; + struct proc *a_p; } */ *ap; { - struct proc *p = curproc; - register struct vnode *vp = ap->a_vp; - register struct inode *ip; - -start: - while (vp->v_flag & VXLOCK) { - vp->v_flag |= VXWANT; - (void) tsleep((caddr_t)vp, PINOD, "ufslk1", 0); - } - if (vp->v_tag == VT_NON) - return (ENOENT); - ip = VTOI(vp); - if (ip->i_flag & IN_LOCKED) { - if (p->p_pid == ip->i_lockholder) { - if( (ip->i_flag & IN_RECURSE) == 0) - panic("ufs_lock: recursive lock not expected, pid: %d\n", - ip->i_lockholder); - } else { - ip->i_flag |= IN_WANTED; -#ifdef DIAGNOSTIC - if (p) - ip->i_lockwaiter = p->p_pid; - else - ip->i_lockwaiter = -1; -#endif - (void) tsleep((caddr_t)ip, PINOD, "ufslk2", 0); - goto start; - } - } -#ifdef DIAGNOSTIC - ip->i_lockwaiter = 0; - if (((ip->i_flag & IN_RECURSE) == 0) && (ip->i_lockholder != 0)) - panic("lockholder (%d) != 0", ip->i_lockholder); - if (p && p->p_pid == 0) - printf("locking by process 0\n"); -#endif - - if ((ip->i_flag & IN_RECURSE) == 0) - ip->i_lockcount = 1; - else - ++ip->i_lockcount; + struct vnode *vp = ap->a_vp; - if (p) - ip->i_lockholder = p->p_pid; - else - ip->i_lockholder = -1; - ip->i_flag |= IN_LOCKED; - return (0); + return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, &vp->v_interlock, + ap->a_p)); } /* - * Unlock an inode. If WANT bit is on, wakeup. + * Unlock an inode. */ -int lockcount = 90; int ufs_unlock(ap) struct vop_unlock_args /* { struct vnode *a_vp; + int a_flags; + struct proc *a_p; } */ *ap; { - register struct inode *ip = VTOI(ap->a_vp); - -#ifdef DIAGNOSTIC - struct proc *p = curproc; + struct vnode *vp = ap->a_vp; - if ((ip->i_flag & IN_LOCKED) == 0) { - vprint("ufs_unlock: unlocked inode", ap->a_vp); - panic("ufs_unlock NOT LOCKED"); - } - if (p && p->p_pid != ip->i_lockholder && p->p_pid > -1 && - ip->i_lockholder > -1 && lockcount++ < 100) - panic("unlocker (%d) != lock holder (%d)", - p->p_pid, ip->i_lockholder); -#endif - if (--ip->i_lockcount > 0) { - if ((ip->i_flag & IN_RECURSE) == 0) - panic("ufs_unlock: recursive lock prematurely released, pid=%d\n", - ip->i_lockholder); - return (0); - } - ip->i_lockholder = 0; - ip->i_flag &= ~(IN_LOCKED|IN_RECURSE); - if (ip->i_flag & IN_WANTED) { - ip->i_flag &= ~IN_WANTED; - wakeup((caddr_t)ip); - } - return (0); + return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE, + &vp->v_interlock, ap->a_p)); } /* @@ -1792,9 +1795,7 @@ ufs_islocked(ap) } */ *ap; { - if (VTOI(ap->a_vp)->i_flag & IN_LOCKED) - return (1); - return (0); + return (lockstatus(&VTOI(ap->a_vp)->i_lock)); } /* @@ -1850,14 +1851,11 @@ ufs_print(ap) printf("tag VT_UFS, ino %ld, on dev %d, %d", ip->i_number, major(ip->i_dev), minor(ip->i_dev)); +#ifdef FIFO if (vp->v_type == VFIFO) fifo_printinfo(vp); - printf("%s\n", (ip->i_flag & IN_LOCKED) ? " (LOCKED)" : ""); - if (ip->i_lockholder == 0) - return (0); - printf("\towner pid %lu", (u_long)ip->i_lockholder); - if (ip->i_lockwaiter) - printf(" waiting pid %lu", (u_long)ip->i_lockwaiter); +#endif /* FIFO */ + lockmgr_printinfo(&ip->i_lock); printf("\n"); return (0); } @@ -1916,10 +1914,13 @@ ufsspec_close(ap) struct proc *a_p; } */ *ap; { - register struct inode *ip = VTOI(ap->a_vp); + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); - if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED)) + simple_lock(&vp->v_interlock); + if (ap->a_vp->v_usecount > 1) ITIMES(ip, &time, &time); + simple_unlock(&vp->v_interlock); return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap)); } @@ -1975,10 +1976,13 @@ ufsfifo_close(ap) struct proc *a_p; } */ *ap; { - register struct inode *ip = VTOI(ap->a_vp); + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); - if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED)) + simple_lock(&vp->v_interlock); + if (ap->a_vp->v_usecount > 1) ITIMES(ip, &time, &time); + simple_unlock(&vp->v_interlock); return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap)); } @@ -2061,9 +2065,9 @@ ufs_vinit(mntp, specops, fifoops, vpp) if (nvp) { /* * Discard unneeded vnode, but save its inode. + * Note that the lock is carried over in the inode + * to the replacement vnode. */ - ufs_ihashrem(ip); - VOP_UNLOCK(vp); nvp->v_data = vp->v_data; vp->v_data = NULL; vp->v_op = spec_vnodeop_p; @@ -2074,7 +2078,6 @@ ufs_vinit(mntp, specops, fifoops, vpp) */ vp = nvp; ip->i_vnode = vp; - ufs_ihashins(ip); } break; case VFIFO: @@ -2149,6 +2152,9 @@ ufs_makeinode(mode, dvp, vpp, cnp) suser(cnp->cn_cred, NULL)) ip->i_mode &= ~ISGID; + if (cnp->cn_flags & ISWHITEOUT) + ip->i_flags |= UF_OPAQUE; + /* * Make sure inode goes to disk before directory entry. */ diff --git a/sys/ufs/ufs/ufsmount.h b/sys/ufs/ufs/ufsmount.h index d7b7b28..87041a6 100644 --- a/sys/ufs/ufs/ufsmount.h +++ b/sys/ufs/ufs/ufsmount.h @@ -30,13 +30,34 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ufsmount.h 8.2 (Berkeley) 1/12/94 + * @(#)ufsmount.h 8.6 (Berkeley) 3/30/95 * $FreeBSD$ */ #ifndef _UFS_UFS_UFSMOUNT_H_ #define _UFS_UFS_UFSMOUNT_H_ +/* + * Arguments to mount UFS-based filesystems + */ +struct ufs_args { + char *fspec; /* block special device to mount */ + struct export_args export; /* network export information */ +}; + +#ifdef MFS +/* + * Arguments to mount MFS + */ +struct mfs_args { + char *fspec; /* name to export for statfs */ + struct export_args export; /* if exported MFSes are supported */ + caddr_t base; /* base of file system in memory */ + u_long size; /* size of file system */ +}; +#endif /* MFS */ + +#ifdef KERNEL struct buf; struct inode; struct nameidata; @@ -51,6 +72,7 @@ struct ufsmount { struct mount *um_mountp; /* filesystem vfs structure */ dev_t um_dev; /* device mounted */ struct vnode *um_devvp; /* block device mounted vnode */ + union { /* pointer to superblock */ struct lfs *lfs; /* LFS */ struct fs *fs; /* FFS */ @@ -60,6 +82,7 @@ struct ufsmount { #define um_lfs ufsmount_u.lfs #define um_e2fs ufsmount_u.e2fs #define um_e2fsb ufsmount_u.e2fs->s_es + struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */ struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */ u_long um_nindir; /* indirect ptrs per block */ @@ -69,7 +92,9 @@ struct ufsmount { time_t um_itime[MAXQUOTAS]; /* inode quota time limit */ char um_qflags[MAXQUOTAS]; /* quota specific flags */ struct netexport um_export; /* export information */ + int64_t um_savedmaxfilesize; /* XXX - limit maxfilesize */ }; + /* * Flags describing the state of quotas. */ @@ -83,8 +108,9 @@ struct ufsmount { * Macros to access file system parameters in the ufsmount structure. * Used by ufs_bmap. */ -#define blkptrtodb(ump, b) ((b) << (ump)->um_bptrtodb) -#define is_sequential(ump, a, b) ((b) == (a) + ump->um_seqinc) -#define MNINDIR(ump) ((ump)->um_nindir) +#define MNINDIR(ump) ((ump)->um_nindir) +#define blkptrtodb(ump, b) ((b) << (ump)->um_bptrtodb) +#define is_sequential(ump, a, b) ((b) == (a) + ump->um_seqinc) +#endif /* KERNEL */ #endif diff --git a/sys/vm/vm.h b/sys/vm/vm.h index 1fd2745..a87c435 100644 --- a/sys/vm/vm.h +++ b/sys/vm/vm.h @@ -70,4 +70,15 @@ struct vm_page; typedef struct vm_page *vm_page_t; #endif +/* + * MACH VM locking type mappings to kernel types + */ +#include <sys/lock.h> +typedef struct simplelock simple_lock_data_t; +typedef struct simplelock *simple_lock_t; +#if 0 +typedef struct lock lock_data_t; +typedef struct lock *lock_t; +#endif + #endif /* VM_H */ diff --git a/sys/vm/vm_extern.h b/sys/vm/vm_extern.h index fa734de..e9ecd30 100644 --- a/sys/vm/vm_extern.h +++ b/sys/vm/vm_extern.h @@ -91,7 +91,7 @@ struct vmspace *vmspace_fork __P((struct vmspace *)); void vmspace_free __P((struct vmspace *)); void vnode_pager_setsize __P((struct vnode *, vm_ooffset_t)); void vnode_pager_umount __P((struct mount *)); -void vnode_pager_uncache __P((struct vnode *)); +void vnode_pager_uncache __P((struct vnode *, struct proc *)); void vslock __P((caddr_t, u_int)); void vsunlock __P((caddr_t, u_int, int)); void vm_object_print __P((/* db_expr_t */ int, boolean_t, /* db_expr_t */ int, diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index 74fb29a..236e255 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -86,7 +86,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_object.h> @@ -146,6 +146,7 @@ vm_fault(map, vaddr, fault_type, change_wiring) vm_page_t marray[VM_FAULT_READ]; int hardfault = 0; struct vnode *vp = NULL; + struct proc *p = curproc; /* XXX */ cnt.v_vm_faults++; /* needs lock XXX */ /* @@ -175,7 +176,7 @@ vm_fault(map, vaddr, fault_type, change_wiring) vm_object_pip_wakeup(first_object); \ } \ UNLOCK_MAP; \ - if (vp != NULL) VOP_UNLOCK(vp); \ + if (vp != NULL) VOP_UNLOCK(vp, 0, p); \ } #define UNLOCK_AND_DEALLOCATE { \ diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c index 25290e6..84197ea 100644 --- a/sys/vm/vm_glue.c +++ b/sys/vm/vm_glue.c @@ -79,7 +79,7 @@ #include <vm/vm_param.h> #include <vm/vm_inherit.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_page.h> @@ -424,9 +424,11 @@ retry: vm_map_reference(&vm->vm_map); /* * do not swapout a process that is waiting for VM - * datastructures there is a possible deadlock. + * data structures there is a possible deadlock. */ - if (!lock_try_write(&vm->vm_map.lock)) { + if (lockmgr(&vm->vm_map.lock, + LK_EXCLUSIVE | LK_NOWAIT, + (void *)0, curproc)) { vm_map_deallocate(&vm->vm_map); vmspace_free(vm); continue; diff --git a/sys/vm/vm_init.c b/sys/vm/vm_init.c index de14867..1d9b1f9 100644 --- a/sys/vm/vm_init.c +++ b/sys/vm/vm_init.c @@ -76,7 +76,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_object.h> #include <vm/vm_page.h> #include <vm/vm_map.h> diff --git a/sys/vm/vm_kern.c b/sys/vm/vm_kern.c index 5d8c00d..51d71b4 100644 --- a/sys/vm/vm_kern.c +++ b/sys/vm/vm_kern.c @@ -80,7 +80,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_object.h> diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index bc3bea9..53fd164 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -80,7 +80,7 @@ #include <vm/vm_param.h> #include <vm/vm_prot.h> #include <vm/vm_inherit.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_page.h> @@ -283,9 +283,9 @@ vm_map_create(pmap, min, max, pageable) if (kmem_map == NULL) { result = kmap_free; - kmap_free = (vm_map_t) result->header.next; if (result == NULL) panic("vm_map_create: out of maps"); + kmap_free = (vm_map_t) result->header.next; } else MALLOC(result, vm_map_t, sizeof(struct vm_map), M_VMMAP, M_WAITOK); @@ -317,7 +317,8 @@ vm_map_init(map, min, max, pageable) map->first_free = &map->header; map->hint = &map->header; map->timestamp = 0; - lock_init(&map->lock, TRUE); + lockinit(&map->lock, PVM, "thrd_sleep", 0, 0); + simple_lock_init(&map->ref_lock); } /* @@ -486,7 +487,7 @@ vm_map_deallocate(map) * Lock the map, to wait out all other references to it. */ - vm_map_lock(map); + vm_map_lock_drain_interlock(map); (void) vm_map_delete(map, map->min_offset, map->max_offset); --map->ref_count; if( map->ref_count != 0) { @@ -495,6 +496,9 @@ vm_map_deallocate(map) } pmap_destroy(map->pmap); + + vm_map_unlock(map); + FREE(map, M_VMMAP); } @@ -1367,7 +1371,7 @@ vm_map_user_pageable(map, start, end, new_pageable) * becomes completely unwired, unwire its physical pages and * mappings. */ - lock_set_recursive(&map->lock); + vm_map_set_recursive(map); entry = start_entry; while ((entry != &map->header) && (entry->start < end)) { @@ -1381,7 +1385,7 @@ vm_map_user_pageable(map, start, end, new_pageable) entry = entry->next; } vm_map_simplify_entry(map, start_entry); - lock_clear_recursive(&map->lock); + vm_map_clear_recursive(map); } else { /* @@ -1438,25 +1442,35 @@ vm_map_user_pageable(map, start, end, new_pageable) entry->eflags |= MAP_ENTRY_USER_WIRED; /* First we need to allow map modifications */ - lock_set_recursive(&map->lock); - lock_write_to_read(&map->lock); + vm_map_set_recursive(map); + if (lockmgr(&map->lock, LK_EXCLUPGRADE, + (void *)0, curproc)) { + entry->wired_count--; + entry->eflags &= ~MAP_ENTRY_USER_WIRED; + vm_map_clear_recursive(map); + vm_map_unlock(map); + + (void) vm_map_user_pageable(map, start, entry->start, TRUE); + return rv; + } + + rv = vm_fault_user_wire(map, entry->start, entry->end); if (rv) { entry->wired_count--; entry->eflags &= ~MAP_ENTRY_USER_WIRED; - lock_clear_recursive(&map->lock); + vm_map_clear_recursive(map); vm_map_unlock(map); (void) vm_map_user_pageable(map, start, entry->start, TRUE); return rv; } - lock_clear_recursive(&map->lock); - vm_map_unlock(map); - vm_map_lock(map); + vm_map_clear_recursive(map); + lockmgr(&map->lock, LK_DOWNGRADE, (void *)0, curproc); goto rescan; } @@ -1536,7 +1550,7 @@ vm_map_pageable(map, start, end, new_pageable) * becomes completely unwired, unwire its physical pages and * mappings. */ - lock_set_recursive(&map->lock); + vm_map_set_recursive(map); entry = start_entry; while ((entry != &map->header) && (entry->start < end)) { @@ -1549,7 +1563,7 @@ vm_map_pageable(map, start, end, new_pageable) entry = entry->next; } vm_map_simplify_entry(map, start_entry); - lock_clear_recursive(&map->lock); + vm_map_clear_recursive(map); } else { /* * Wiring. We must do this in two passes: @@ -1655,8 +1669,8 @@ vm_map_pageable(map, start, end, new_pageable) if (vm_map_pmap(map) == kernel_pmap) { vm_map_unlock(map); /* trust me ... */ } else { - lock_set_recursive(&map->lock); - lock_write_to_read(&map->lock); + vm_map_set_recursive(map); + lockmgr(&map->lock, LK_DOWNGRADE, (void*)0, curproc); } rv = 0; @@ -1686,7 +1700,7 @@ vm_map_pageable(map, start, end, new_pageable) if (vm_map_pmap(map) == kernel_pmap) { vm_map_lock(map); } else { - lock_clear_recursive(&map->lock); + vm_map_clear_recursive(map); } if (rv) { vm_map_unlock(map); @@ -2379,7 +2393,8 @@ RetryLookup:; * object. */ - if (lock_read_to_write(&share_map->lock)) { + if (lockmgr(&share_map->lock, LK_EXCLUPGRADE, + (void *)0, curproc)) { if (share_map != map) vm_map_unlock_read(map); goto RetryLookup; @@ -2391,7 +2406,8 @@ RetryLookup:; entry->eflags &= ~MAP_ENTRY_NEEDS_COPY; - lock_write_to_read(&share_map->lock); + lockmgr(&share_map->lock, LK_DOWNGRADE, + (void *)0, curproc); } else { /* * We're attempting to read a copy-on-write page -- @@ -2406,7 +2422,8 @@ RetryLookup:; */ if (entry->object.vm_object == NULL) { - if (lock_read_to_write(&share_map->lock)) { + if (lockmgr(&share_map->lock, LK_EXCLUPGRADE, + (void *)0, curproc)) { if (share_map != map) vm_map_unlock_read(map); goto RetryLookup; @@ -2414,7 +2431,7 @@ RetryLookup:; entry->object.vm_object = vm_object_allocate(OBJT_DEFAULT, OFF_TO_IDX(entry->end - entry->start)); entry->offset = 0; - lock_write_to_read(&share_map->lock); + lockmgr(&share_map->lock, LK_DOWNGRADE, (void *)0, curproc); } if (entry->object.vm_object != NULL) diff --git a/sys/vm/vm_map.h b/sys/vm/vm_map.h index 8f46b8d..1c55c57 100644 --- a/sys/vm/vm_map.h +++ b/sys/vm/vm_map.h @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from: @(#)vm_map.h 8.3 (Berkeley) 3/15/94 + * @(#)vm_map.h 8.9 (Berkeley) 5/17/95 * * * Copyright (c) 1987, 1990 Carnegie-Mellon University. @@ -105,14 +105,6 @@ struct vm_map_entry { union vm_map_object object; /* object I point to */ vm_ooffset_t offset; /* offset into object */ u_char eflags; /* map entry flags */ -#if 0 - u_char is_a_map:1, /* Is "object" a map? */ - is_sub_map:1, /* Is "object" a submap? */ - copy_on_write:1, /* is data copy-on-write */ - needs_copy:1, /* does object need to be copied */ - nofault:1, /* should never fault */ - user_wired:1; /* wired by user */ -#endif /* Only in task maps: */ vm_prot_t protection; /* protection code */ vm_prot_t max_protection; /* maximum protection */ @@ -135,12 +127,13 @@ struct vm_map_entry { */ struct vm_map { struct pmap *pmap; /* Physical map */ - lock_data_t lock; /* Lock for map data */ + struct lock lock; /* Lock for map data */ struct vm_map_entry header; /* List of entries */ int nentries; /* Number of entries */ vm_size_t size; /* virtual size */ boolean_t is_main_map; /* Am I a main map? */ int ref_count; /* Reference count */ + simple_lock_data_t ref_lock; /* Lock for ref_count field */ vm_map_entry_t hint; /* hint for quick lookups */ vm_map_entry_t first_free; /* First free space hint */ boolean_t entries_pageable; /* map entries pageable?? */ @@ -195,14 +188,42 @@ typedef struct { * Perform locking on the data portion of a map. */ +#include <sys/proc.h> /* XXX for curproc and p_pid */ + +#define vm_map_lock_drain_interlock(map) { \ + lockmgr(&(map)->lock, LK_DRAIN|LK_INTERLOCK, \ + &(map)->ref_lock, curproc); \ + (map)->timestamp++; \ +} +#ifdef DIAGNOSTIC #define vm_map_lock(map) { \ - lock_write(&(map)->lock); \ + if (lockmgr(&(map)->lock, LK_EXCLUSIVE, (void *)0, curproc) != 0) { \ + panic("vm_map_lock: failed to get lock"); \ + } \ (map)->timestamp++; \ } -#define vm_map_unlock(map) lock_write_done(&(map)->lock) -#define vm_map_lock_read(map) lock_read(&(map)->lock) -#define vm_map_unlock_read(map) lock_read_done(&(map)->lock) - +#else +#define vm_map_lock(map) { \ + lockmgr(&(map)->lock, LK_EXCLUSIVE, (void *)0, curproc); \ + (map)->timestamp++; \ +} +#endif /* DIAGNOSTIC */ +#define vm_map_unlock(map) \ + lockmgr(&(map)->lock, LK_RELEASE, (void *)0, curproc) +#define vm_map_lock_read(map) \ + lockmgr(&(map)->lock, LK_SHARED, (void *)0, curproc) +#define vm_map_unlock_read(map) \ + lockmgr(&(map)->lock, LK_RELEASE, (void *)0, curproc) +#define vm_map_set_recursive(map) { \ + simple_lock(&(map)->lock.lk_interlock); \ + (map)->lock.lk_flags |= LK_CANRECURSE; \ + simple_unlock(&(map)->lock.lk_interlock); \ +} +#define vm_map_clear_recursive(map) { \ + simple_lock(&(map)->lock.lk_interlock); \ + (map)->lock.lk_flags &= ~LK_CANRECURSE; \ + simple_unlock(&(map)->lock.lk_interlock); \ +} /* * Functions implemented as macros */ diff --git a/sys/vm/vm_meter.c b/sys/vm/vm_meter.c index f36e138..c511ae7 100644 --- a/sys/vm/vm_meter.c +++ b/sys/vm/vm_meter.c @@ -45,7 +45,7 @@ #include <vm/vm_extern.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_object.h> diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index f751e14..d86feb2 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -65,7 +65,7 @@ #include <vm/vm_param.h> #include <vm/vm_prot.h> #include <vm/vm_inherit.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_object.h> diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index ebd29f1..e429711 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -81,7 +81,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/vm_object.h> @@ -130,6 +130,7 @@ int vm_object_cache_max; struct object_q vm_object_cached_list; static int vm_object_cached; struct object_q vm_object_list; +struct simplelock vm_object_list_lock; static long vm_object_count; vm_object_t kernel_object; vm_object_t kmem_object; @@ -182,6 +183,7 @@ vm_object_init() { TAILQ_INIT(&vm_object_cached_list); TAILQ_INIT(&vm_object_list); + simple_lock_init(&vm_object_list_lock); vm_object_count = 0; vm_object_cache_max = 84; @@ -388,16 +390,18 @@ vm_object_terminate(object) */ if (object->type == OBJT_VNODE) { struct vnode *vp = object->handle; + struct proc *p = curproc; /* XXX */ int waslocked; waslocked = VOP_ISLOCKED(vp); if (!waslocked) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); vm_object_page_clean(object, 0, 0, TRUE, FALSE); vinvalbuf(vp, V_SAVE, NOCRED, NULL, 0, 0); if (!waslocked) - VOP_UNLOCK(vp); - } + VOP_UNLOCK(vp, 0, p); + } + /* * Now free the pages. For internal objects, this also removes them * from paging queues. @@ -415,8 +419,10 @@ vm_object_terminate(object) */ vm_pager_deallocate(object); + simple_lock(&vm_object_list_lock); TAILQ_REMOVE(&vm_object_list, object, object_list); vm_object_count--; + simple_unlock(&vm_object_list_lock); wakeup(object); @@ -458,6 +464,7 @@ vm_object_page_clean(object, start, end, syncio, lockflag) vm_page_t maf[vm_pageout_page_count]; vm_page_t mab[vm_pageout_page_count]; vm_page_t ma[vm_pageout_page_count]; + struct proc *pproc = curproc; /* XXX */ if (object->type != OBJT_VNODE || (object->flags & OBJ_MIGHTBEDIRTY) == 0) @@ -466,7 +473,7 @@ vm_object_page_clean(object, start, end, syncio, lockflag) vp = object->handle; if (lockflag) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, pproc); object->flags |= OBJ_CLEANING; tstart = start; @@ -584,7 +591,7 @@ rescan: VOP_FSYNC(vp, NULL, syncio, curproc); if (lockflag) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, pproc); object->flags &= ~OBJ_CLEANING; return; } diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index d106301..41cf3a3 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -77,7 +77,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_kern.h> #include <vm/vm_object.h> #include <vm/vm_page.h> diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index 2054471..d1f2537 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -87,7 +87,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_prot.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/vm_object.h> #include <vm/vm_page.h> #include <vm/vm_map.h> @@ -505,7 +505,7 @@ vm_pageout_map_deactivate_pages(map, desired) vm_object_t obj, bigobj; vm_map_reference(map); - if (!lock_try_write(&map->lock)) { + if (lockmgr(&map->lock, LK_EXCLUSIVE | LK_NOWAIT, (void *)0, curproc)) { vm_map_deallocate(map); return; } @@ -669,7 +669,9 @@ rescan0: if (object->type == OBJT_VNODE) { vp = object->handle; - if (VOP_ISLOCKED(vp) || vget(vp, 1)) { + if (VOP_ISLOCKED(vp) || + vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, + curproc)) { if ((m->queue == PQ_INACTIVE) && (m->hold_count == 0) && (m->busy == 0) && diff --git a/sys/vm/vm_unix.c b/sys/vm/vm_unix.c index 4a69ee7..2d2372e 100644 --- a/sys/vm/vm_unix.c +++ b/sys/vm/vm_unix.c @@ -52,7 +52,7 @@ #include <vm/vm.h> #include <vm/vm_param.h> -#include <vm/lock.h> +#include <sys/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <vm/swap_pager.h> diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index bf6a1c9..12e2f8c 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -329,6 +329,7 @@ void vnode_pager_umount(mp) register struct mount *mp; { + struct proc *p = curproc; /* XXX */ struct vnode *vp, *nvp; loop: @@ -347,9 +348,9 @@ loop: nvp = vp->v_mntvnodes.le_next; if (vp->v_object != NULL) { - VOP_LOCK(vp); - vnode_pager_uncache(vp); - VOP_UNLOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + vnode_pager_uncache(vp, p); + VOP_UNLOCK(vp, 0, p); } } } @@ -364,8 +365,9 @@ loop: * re-locking the vnode. */ void -vnode_pager_uncache(vp) +vnode_pager_uncache(vp, p) struct vnode *vp; + struct proc *p; { vm_object_t object; @@ -383,10 +385,10 @@ vnode_pager_uncache(vp) * VBLK devices... */ if (vp->v_type != VBLK) - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, p); pager_cache(object, FALSE); if (vp->v_type != VBLK) - VOP_LOCK(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); return; } @@ -968,11 +970,13 @@ struct vnode * vnode_pager_lock(object) vm_object_t object; { + struct proc *p = curproc; /* XXX */ + for (; object != NULL; object = object->backing_object) { if (object->type != OBJT_VNODE) continue; - VOP_LOCK(object->handle); + vn_lock(object->handle, LK_EXCLUSIVE | LK_RETRY, p); return object->handle; } return NULL; |