X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/10bae9ee1aeaee13e63c4615fa45369e4e6acb84..5e03b55dcb52583818730cc2f1aa8a6e352e4c1f:/usr/src/sys/ufs/ffs/ffs_vnops.c diff --git a/usr/src/sys/ufs/ffs/ffs_vnops.c b/usr/src/sys/ufs/ffs/ffs_vnops.c index febfef1792..873773cacd 100644 --- a/usr/src/sys/ufs/ffs/ffs_vnops.c +++ b/usr/src/sys/ufs/ffs/ffs_vnops.c @@ -4,218 +4,38 @@ * * %sccs.include.redist.c% * - * @(#)ffs_vnops.c 7.54 (Berkeley) %G% + * @(#)ffs_vnops.c 7.64.1.1 (Berkeley) %G% */ #include "param.h" #include "systm.h" -#include "user.h" +#include "namei.h" +#include "resourcevar.h" #include "kernel.h" #include "file.h" #include "stat.h" #include "buf.h" #include "proc.h" -#include "socket.h" -#include "socketvar.h" #include "conf.h" #include "mount.h" #include "vnode.h" #include "specdev.h" -#include "fcntl.h" +#include "fifo.h" #include "malloc.h" -#include "../ufs/lockf.h" -#include "../ufs/quota.h" -#include "../ufs/inode.h" -#include "../ufs/fs.h" -/* - * Global vfs data structures for ufs - */ - -int ufs_lookup(), - ufs_create(), - ufs_mknod(), - ufs_open(), - ufs_close(), - ufs_access(), - ufs_getattr(), - ufs_setattr(), - ufs_read(), - ufs_write(), - ufs_ioctl(), - ufs_select(), - ufs_mmap(), - ufs_fsync(), - ufs_seek(), - ufs_remove(), - ufs_link(), - ufs_rename(), - ufs_mkdir(), - ufs_rmdir(), - ufs_symlink(), - ufs_readdir(), - ufs_readlink(), - ufs_abortop(), - ufs_inactive(), - ufs_reclaim(), - ufs_lock(), - ufs_unlock(), - ufs_bmap(), - ufs_strategy(), - ufs_print(), - ufs_islocked(), - ufs_advlock(); - -struct vnodeops ufs_vnodeops = { - ufs_lookup, /* lookup */ - ufs_create, /* create */ - ufs_mknod, /* mknod */ - ufs_open, /* open */ - ufs_close, /* close */ - ufs_access, /* access */ - ufs_getattr, /* getattr */ - ufs_setattr, /* setattr */ - ufs_read, /* read */ - ufs_write, /* write */ - ufs_ioctl, /* ioctl */ - ufs_select, /* select */ - ufs_mmap, /* mmap */ - ufs_fsync, /* fsync */ - ufs_seek, /* seek */ - ufs_remove, /* remove */ - ufs_link, /* link */ - ufs_rename, /* rename */ - ufs_mkdir, /* mkdir */ - ufs_rmdir, /* rmdir */ - ufs_symlink, /* symlink */ - ufs_readdir, /* readdir */ - ufs_readlink, /* readlink */ - ufs_abortop, /* abortop */ - ufs_inactive, /* inactive */ - ufs_reclaim, /* reclaim */ - ufs_lock, /* lock */ - ufs_unlock, /* unlock */ - ufs_bmap, /* bmap */ - ufs_strategy, /* strategy */ - ufs_print, /* print */ - ufs_islocked, /* islocked */ - ufs_advlock, /* advlock */ -}; - -int spec_lookup(), - spec_open(), - ufsspec_read(), - ufsspec_write(), - spec_strategy(), - spec_bmap(), - spec_ioctl(), - spec_select(), - ufsspec_close(), - spec_advlock(), - spec_badop(), - spec_nullop(); - -struct vnodeops spec_inodeops = { - spec_lookup, /* lookup */ - spec_badop, /* create */ - spec_badop, /* mknod */ - spec_open, /* open */ - ufsspec_close, /* close */ - ufs_access, /* access */ - ufs_getattr, /* getattr */ - ufs_setattr, /* setattr */ - ufsspec_read, /* read */ - ufsspec_write, /* write */ - spec_ioctl, /* ioctl */ - spec_select, /* select */ - spec_badop, /* mmap */ - spec_nullop, /* fsync */ - spec_badop, /* seek */ - spec_badop, /* remove */ - spec_badop, /* link */ - spec_badop, /* rename */ - spec_badop, /* mkdir */ - spec_badop, /* rmdir */ - spec_badop, /* symlink */ - spec_badop, /* readdir */ - spec_badop, /* readlink */ - spec_badop, /* abortop */ - ufs_inactive, /* inactive */ - ufs_reclaim, /* reclaim */ - ufs_lock, /* lock */ - ufs_unlock, /* unlock */ - spec_bmap, /* bmap */ - spec_strategy, /* strategy */ - ufs_print, /* print */ - ufs_islocked, /* islocked */ - spec_advlock, /* advlock */ -}; - -#ifdef FIFO -int fifo_lookup(), - fifo_open(), - ufsfifo_read(), - ufsfifo_write(), - fifo_bmap(), - fifo_ioctl(), - fifo_select(), - ufsfifo_close(), - fifo_print(), - fifo_advlock(), - fifo_badop(), - fifo_nullop(); - -struct vnodeops fifo_inodeops = { - fifo_lookup, /* lookup */ - fifo_badop, /* create */ - fifo_badop, /* mknod */ - fifo_open, /* open */ - ufsfifo_close, /* close */ - ufs_access, /* access */ - ufs_getattr, /* getattr */ - ufs_setattr, /* setattr */ - ufsfifo_read, /* read */ - ufsfifo_write, /* write */ - fifo_ioctl, /* ioctl */ - fifo_select, /* select */ - fifo_badop, /* mmap */ - fifo_nullop, /* fsync */ - fifo_badop, /* seek */ - fifo_badop, /* remove */ - fifo_badop, /* link */ - fifo_badop, /* rename */ - fifo_badop, /* mkdir */ - fifo_badop, /* rmdir */ - fifo_badop, /* symlink */ - fifo_badop, /* readdir */ - fifo_badop, /* readlink */ - fifo_badop, /* abortop */ - ufs_inactive, /* inactive */ - ufs_reclaim, /* reclaim */ - ufs_lock, /* lock */ - ufs_unlock, /* unlock */ - fifo_bmap, /* bmap */ - fifo_badop, /* strategy */ - ufs_print, /* print */ - ufs_islocked, /* islocked */ - fifo_advlock, /* advlock */ -}; -#endif /* FIFO */ - -enum vtype iftovt_tab[16] = { - VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, - VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, -}; -int vttoif_tab[9] = { - 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT, -}; +#include "lockf.h" +#include "quota.h" +#include "inode.h" +#include "dir.h" +#include "fs.h" /* * Create a regular file */ -ufs_create(ndp, vap) +ufs_create(ndp, vap, p) struct nameidata *ndp; struct vattr *vap; + struct proc *p; { struct inode *ip; int error; @@ -230,10 +50,11 @@ ufs_create(ndp, vap) * Mknod vnode call */ /* ARGSUSED */ -ufs_mknod(ndp, vap, cred) +ufs_mknod(ndp, vap, cred, p) struct nameidata *ndp; struct ucred *cred; struct vattr *vap; + struct proc *p; { register struct vnode *vp; struct inode *ip; @@ -267,10 +88,11 @@ ufs_mknod(ndp, vap, cred) * Nothing to do. */ /* ARGSUSED */ -ufs_open(vp, mode, cred) +ufs_open(vp, mode, cred, p) struct vnode *vp; int mode; struct ucred *cred; + struct proc *p; { return (0); @@ -282,10 +104,11 @@ ufs_open(vp, mode, cred) * Update the times on the inode. */ /* ARGSUSED */ -ufs_close(vp, fflag, cred) +ufs_close(vp, fflag, cred, p) struct vnode *vp; int fflag; struct ucred *cred; + struct proc *p; { register struct inode *ip = VTOI(vp); @@ -299,10 +122,11 @@ ufs_close(vp, fflag, cred) * The mode is shifted to select the owner/group/other fields. The * super user is granted all permissions. */ -ufs_access(vp, mode, cred) +ufs_access(vp, mode, cred, p) struct vnode *vp; register int mode; struct ucred *cred; + struct proc *p; { register struct inode *ip = VTOI(vp); register gid_t *gp; @@ -349,10 +173,11 @@ found: } /* ARGSUSED */ -ufs_getattr(vp, vap, cred) +ufs_getattr(vp, vap, cred, p) struct vnode *vp; register struct vattr *vap; struct ucred *cred; + struct proc *p; { register struct inode *ip = VTOI(vp); @@ -397,10 +222,11 @@ ufs_getattr(vp, vap, cred) /* * Set attribute vnode op. called from several syscalls */ -ufs_setattr(vp, vap, cred) +ufs_setattr(vp, vap, cred, p) register struct vnode *vp; register struct vattr *vap; register struct ucred *cred; + struct proc *p; { register struct inode *ip = VTOI(vp); int error = 0; @@ -418,7 +244,7 @@ ufs_setattr(vp, vap, cred) * Go through the fields and update iff not VNOVAL. */ if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL) - if (error = chown1(vp, vap->va_uid, vap->va_gid, cred)) + if (error = chown1(vp, vap->va_uid, vap->va_gid, p)) return (error); if (vap->va_size != VNOVAL) { if (vp->v_type == VDIR) @@ -428,7 +254,7 @@ ufs_setattr(vp, vap, cred) } if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { if (cred->cr_uid != ip->i_uid && - (error = suser(cred, &u.u_acflag))) + (error = suser(cred, &p->p_acflag))) return (error); if (vap->va_atime.tv_sec != VNOVAL) ip->i_flag |= IACC; @@ -439,10 +265,10 @@ ufs_setattr(vp, vap, cred) return (error); } if (vap->va_mode != (u_short)VNOVAL) - error = chmod1(vp, (int)vap->va_mode, cred); + error = chmod1(vp, (int)vap->va_mode, p); if (vap->va_flags != VNOVAL) { if (cred->cr_uid != ip->i_uid && - (error = suser(cred, &u.u_acflag))) + (error = suser(cred, &p->p_acflag))) return (error); if (cred->cr_uid == 0) { ip->i_flags = vap->va_flags; @@ -459,16 +285,17 @@ ufs_setattr(vp, vap, cred) * Change the mode on a file. * Inode must be locked before calling. */ -chmod1(vp, mode, cred) +chmod1(vp, mode, p) register struct vnode *vp; register int mode; - struct ucred *cred; + struct proc *p; { + register struct ucred *cred = p->p_ucred; register struct inode *ip = VTOI(vp); int error; if (cred->cr_uid != ip->i_uid && - (error = suser(cred, &u.u_acflag))) + (error = suser(cred, &p->p_acflag))) return (error); if (cred->cr_uid) { if (vp->v_type != VDIR && (mode & ISVTX)) @@ -488,13 +315,14 @@ chmod1(vp, mode, cred) * Perform chown operation on inode ip; * inode must be locked prior to call. */ -chown1(vp, uid, gid, cred) +chown1(vp, uid, gid, p) register struct vnode *vp; uid_t uid; gid_t gid; - struct ucred *cred; + struct proc *p; { register struct inode *ip = VTOI(vp); + register struct ucred *cred = p->p_ucred; uid_t ouid; gid_t ogid; int error = 0; @@ -514,7 +342,7 @@ chown1(vp, uid, gid, cred) */ if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid || !groupmember((gid_t)gid, cred)) && - (error = suser(cred, &u.u_acflag))) + (error = suser(cred, &p->p_acflag))) return (error); ouid = ip->i_uid; ogid = ip->i_gid; @@ -606,11 +434,13 @@ ufs_read(vp, uio, ioflag, cred) int size, diff, error = 0; long n, on, type; +#ifdef DIAGNOSTIC if (uio->uio_rw != UIO_READ) panic("ufs_read mode"); type = ip->i_mode & IFMT; if (type != IFDIR && type != IFREG && type != IFLNK) panic("ufs_read type"); +#endif if (uio->uio_resid == 0) return (0); if (uio->uio_offset < 0) @@ -657,6 +487,7 @@ ufs_write(vp, uio, ioflag, cred) int ioflag; struct ucred *cred; { + struct proc *p = uio->uio_procp; register struct inode *ip = VTOI(vp); register struct fs *fs; struct buf *bp; @@ -665,8 +496,10 @@ ufs_write(vp, uio, ioflag, cred) int n, on, flags; int size, resid, error = 0; +#ifdef DIAGNOSTIC if (uio->uio_rw != UIO_WRITE) panic("ufs_write mode"); +#endif switch (vp->v_type) { case VREG: if (ioflag & IO_APPEND) @@ -691,10 +524,10 @@ ufs_write(vp, uio, ioflag, cred) * Maybe this should be above the vnode op call, but so long as * file servers have no limits, i don't think it matters */ - if (vp->v_type == VREG && + if (vp->v_type == VREG && p && uio->uio_offset + uio->uio_resid > - u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { - psignal(u.u_procp, SIGXFSZ); + p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { + psignal(p, SIGXFSZ); return (EFBIG); } resid = uio->uio_resid; @@ -744,25 +577,30 @@ ufs_write(vp, uio, ioflag, cred) } /* ARGSUSED */ -ufs_ioctl(vp, com, data, fflag, cred) +ufs_ioctl(vp, com, data, fflag, cred, p) struct vnode *vp; int com; caddr_t data; int fflag; struct ucred *cred; + struct proc *p; { return (ENOTTY); } /* ARGSUSED */ -ufs_select(vp, which, fflags, cred) +ufs_select(vp, which, fflags, cred, p) struct vnode *vp; int which, fflags; struct ucred *cred; + struct proc *p; { - return (1); /* XXX */ + /* + * We should really check to see if I/O is possible. + */ + return (1); } /* @@ -771,10 +609,11 @@ ufs_select(vp, which, fflags, cred) * NB Currently unsupported. */ /* ARGSUSED */ -ufs_mmap(vp, fflags, cred) +ufs_mmap(vp, fflags, cred, p) struct vnode *vp; int fflags; struct ucred *cred; + struct proc *p; { return (EINVAL); @@ -784,15 +623,16 @@ ufs_mmap(vp, fflags, cred) * Synch an open file. */ /* ARGSUSED */ -ufs_fsync(vp, fflags, cred, waitfor) +ufs_fsync(vp, fflags, cred, waitfor, p) struct vnode *vp; int fflags; struct ucred *cred; int waitfor; + struct proc *p; { struct inode *ip = VTOI(vp); - if (fflags&FWRITE) + if (fflags & FWRITE) ip->i_flag |= ICHG; vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); return (iupdat(ip, &time, &time, waitfor == MNT_WAIT)); @@ -818,8 +658,9 @@ ufs_seek(vp, oldoff, newoff, cred) * Hard to avoid races here, especially * in unlinking directories. */ -ufs_remove(ndp) +ufs_remove(ndp, p) struct nameidata *ndp; + struct proc *p; { register struct inode *ip, *dp; int error; @@ -842,15 +683,22 @@ ufs_remove(ndp) /* * link vnode call */ -ufs_link(vp, ndp) +ufs_link(vp, ndp, p) register struct vnode *vp; register struct nameidata *ndp; + struct proc *p; { register struct inode *ip = VTOI(vp); int error; - if ((unsigned short)ip->i_nlink >= LINK_MAX) +#ifdef DIANOSTIC + if ((ndp->ni_nameiop & HASBUF) == 0) + panic("ufs_link: no name"); +#endif + if ((unsigned short)ip->i_nlink >= LINK_MAX) { + free(ndp->ni_pnbuf, M_NAMEI); return (EMLINK); + } if (ndp->ni_dvp != vp) ILOCK(ip); ip->i_nlink++; @@ -860,6 +708,8 @@ ufs_link(vp, ndp) error = direnter(ip, ndp); if (ndp->ni_dvp != vp) IUNLOCK(ip); + FREE(ndp->ni_pnbuf, M_NAMEI); + vput(ndp->ni_dvp); if (error) { ip->i_nlink--; ip->i_flag |= ICHG; @@ -891,25 +741,45 @@ ufs_link(vp, ndp) * is different from the source, patch the ".." entry in the * directory. */ -ufs_rename(fndp, tndp) +ufs_rename(fndp, tndp, p) register struct nameidata *fndp, *tndp; + struct proc *p; { register struct inode *ip, *xp, *dp; struct dirtemplate dirbuf; int doingdirectory = 0, oldparent = 0, newparent = 0; int error = 0; +#ifdef DIANOSTIC + if ((tndp->ni_nameiop & HASBUF) == 0 || + (fndp->ni_nameiop & HASBUF) == 0) + panic("ufs_rename: no name"); +#endif dp = VTOI(fndp->ni_dvp); ip = VTOI(fndp->ni_vp); + /* + * Check if just deleting a link name. + */ + if (fndp->ni_vp == tndp->ni_vp) { + VOP_ABORTOP(tndp); + vput(tndp->ni_dvp); + vput(tndp->ni_vp); + vrele(fndp->ni_dvp); + if ((ip->i_mode&IFMT) == IFDIR) { + VOP_ABORTOP(fndp); + vrele(fndp->ni_vp); + return (EINVAL); + } + doingdirectory = 0; + goto unlinkit; + } ILOCK(ip); if ((ip->i_mode&IFMT) == IFDIR) { - register struct direct *d = &fndp->ni_dent; - /* * Avoid ".", "..", and aliases of "." for obvious reasons. */ - if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip || - fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { + if ((fndp->ni_namelen == 1 && fndp->ni_ptr[0] == '.') || + dp == ip || fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { VOP_ABORTOP(tndp); vput(tndp->ni_dvp); if (tndp->ni_vp) @@ -958,24 +828,23 @@ ufs_rename(fndp, tndp) newparent = dp->i_number; if (doingdirectory && newparent) { VOP_LOCK(fndp->ni_vp); - error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred); + error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred, p); VOP_UNLOCK(fndp->ni_vp); if (error) goto bad; - tndp->ni_nameiop &= ~(MODMASK | OPMASK); - tndp->ni_nameiop |= RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; - do { - dp = VTOI(tndp->ni_dvp); - if (xp != NULL) - iput(xp); - if (error = checkpath(ip, dp, tndp->ni_cred)) - goto out; - if (error = namei(tndp)) - goto out; - xp = NULL; - if (tndp->ni_vp) - xp = VTOI(tndp->ni_vp); - } while (dp != VTOI(tndp->ni_dvp)); + if (xp != NULL) + iput(xp); + if (error = checkpath(ip, dp, tndp->ni_cred)) + goto out; + if ((tndp->ni_nameiop & SAVESTART) == 0) + panic("ufs_rename: lost to startdir"); + p->p_spare[1]--; + if (error = lookup(tndp, p)) + goto out; + dp = VTOI(tndp->ni_dvp); + xp = NULL; + if (tndp->ni_vp) + xp = VTOI(tndp->ni_vp); } /* * 2) If target doesn't exist, link the target @@ -1002,8 +871,15 @@ ufs_rename(fndp, tndp) if (error = iupdat(dp, &time, &time, 1)) goto bad; } - if (error = direnter(ip, tndp)) - goto out; + if (error = direnter(ip, tndp)) { + if (doingdirectory && newparent) { + dp->i_nlink--; + dp->i_flag |= ICHG; + (void) iupdat(dp, &time, &time, 1); + } + goto bad; + } + iput(dp); } else { if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) panic("rename: EXDEV"); @@ -1025,11 +901,9 @@ ufs_rename(fndp, tndp) goto bad; } /* - * Target must be empty if a directory - * and have no links to it. - * Also, insure source and target are - * compatible (both directories, or both - * not directories). + * Target must be empty if a directory and have no links + * to it. Also, ensure source and target are compatible + * (both directories, or both not directories). */ if ((xp->i_mode&IFMT) == IFDIR) { if (!dirempty(xp, dp->i_number, tndp->ni_cred) || @@ -1083,9 +957,13 @@ ufs_rename(fndp, tndp) /* * 3) Unlink the source. */ - fndp->ni_nameiop &= ~(MODMASK | OPMASK); - fndp->ni_nameiop |= DELETE | LOCKPARENT | LOCKLEAF; - (void)namei(fndp); +unlinkit: + fndp->ni_nameiop &= ~MODMASK; + fndp->ni_nameiop |= LOCKPARENT | LOCKLEAF; + if ((fndp->ni_nameiop & SAVESTART) == 0) + panic("ufs_rename: lost from startdir"); + p->p_spare[1]--; + (void) lookup(fndp, p); if (fndp->ni_vp != NULL) { xp = VTOI(fndp->ni_vp); dp = VTOI(fndp->ni_dvp); @@ -1124,7 +1002,7 @@ ufs_rename(fndp, tndp) error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, IO_NODELOCKED, - tndp->ni_cred, (int *)0); + tndp->ni_cred, (int *)0, (struct proc *)0); if (error == 0) { if (dirbuf.dotdot_namlen != 2 || dirbuf.dotdot_name[0] != '.' || @@ -1137,7 +1015,8 @@ ufs_rename(fndp, tndp) sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_SYNC, - tndp->ni_cred, (int *)0); + tndp->ni_cred, (int *)0, + (struct proc *)0); cache_purge(ITOV(dp)); } } @@ -1178,9 +1057,10 @@ struct dirtemplate mastertemplate = { /* * Mkdir system call */ -ufs_mkdir(ndp, vap) +ufs_mkdir(ndp, vap, p) struct nameidata *ndp; struct vattr *vap; + struct proc *p; { register struct inode *ip, *dp; struct inode *tip; @@ -1189,22 +1069,26 @@ ufs_mkdir(ndp, vap) int error; int dmode; +#ifdef DIANOSTIC + if ((ndp->ni_nameiop & HASBUF) == 0) + panic("ufs_mkdir: no name"); +#endif dvp = ndp->ni_dvp; dp = VTOI(dvp); if ((unsigned short)dp->i_nlink >= LINK_MAX) { + free(ndp->ni_pnbuf, M_NAMEI); iput(dp); return (EMLINK); } dmode = vap->va_mode&0777; dmode |= IFDIR; /* - * Must simulate part of maknode here - * in order to acquire the inode, but - * not have it entered in the parent - * directory. The entry is made later - * after writing "." and ".." entries out. + * Must simulate part of maknode here to acquire the inode, but + * not have it entered in the parent directory. The entry is made + * later after writing "." and ".." entries. */ if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) { + free(ndp->ni_pnbuf, M_NAMEI); iput(dp); return (error); } @@ -1214,6 +1098,7 @@ ufs_mkdir(ndp, vap) #ifdef QUOTA if ((error = getinoquota(ip)) || (error = chkiq(ip, 1, ndp->ni_cred, 0))) { + free(ndp->ni_pnbuf, M_NAMEI); ifree(ip, ip->i_number, dmode); iput(ip); iput(dp); @@ -1234,7 +1119,8 @@ ufs_mkdir(ndp, vap) */ dp->i_nlink++; dp->i_flag |= ICHG; - error = iupdat(dp, &time, &time, 1); + if (error = iupdat(dp, &time, &time, 1)) + goto bad; /* * Initialize directory with "." @@ -1244,8 +1130,8 @@ ufs_mkdir(ndp, vap) dirtemplate.dot_ino = ip->i_number; dirtemplate.dotdot_ino = dp->i_number; error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, - sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, - IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0); + sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, + IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0, (struct proc *)0); if (error) { dp->i_nlink--; dp->i_flag |= ICHG; @@ -1262,17 +1148,9 @@ ufs_mkdir(ndp, vap) * install the entry for it in * the parent directory. */ - error = direnter(ip, ndp); - dp = NULL; - if (error) { - ndp->ni_nameiop &= ~(MODMASK | OPMASK); - ndp->ni_nameiop |= LOOKUP | NOCACHE; - error = namei(ndp); - if (!error) { - dp = VTOI(ndp->ni_vp); - dp->i_nlink--; - dp->i_flag |= ICHG; - } + if (error = direnter(ip, ndp)) { + dp->i_nlink--; + dp->i_flag |= ICHG; } bad: /* @@ -1286,16 +1164,17 @@ bad: iput(ip); } else ndp->ni_vp = ITOV(ip); - if (dp) - iput(dp); + FREE(ndp->ni_pnbuf, M_NAMEI); + iput(dp); return (error); } /* * Rmdir system call. */ -ufs_rmdir(ndp) +ufs_rmdir(ndp, p) register struct nameidata *ndp; + struct proc *p; { register struct inode *ip, *dp; int error = 0; @@ -1357,10 +1236,11 @@ out: /* * symlink -- make a symbolic link */ -ufs_symlink(ndp, vap, target) +ufs_symlink(ndp, vap, target, p) struct nameidata *ndp; struct vattr *vap; char *target; + struct proc *p; { struct inode *ip; int error; @@ -1369,7 +1249,8 @@ ufs_symlink(ndp, vap, target) if (error) return (error); error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, - UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0); + UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0, + (struct proc *)0); iput(ip); return (error); } @@ -1415,13 +1296,15 @@ ufs_readlink(vp, uiop, cred) /* * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually - * done. Nothing to do at the moment. + * done. If a buffer has been saved in anticipation of a CREATE, delete it. */ /* ARGSUSED */ ufs_abortop(ndp) struct nameidata *ndp; { + if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF) + FREE(ndp->ni_pnbuf, M_NAMEI); return (0); } @@ -1537,7 +1420,7 @@ ufs_strategy(bp) #endif /* DIAGNOSTIC */ vp = ip->i_devvp; bp->b_dev = vp->v_rdev; - (*(vp->v_op->vn_strategy))(bp); + (*(vp->v_op->vop_strategy))(bp); return (0); } @@ -1603,16 +1486,17 @@ ufsspec_write(vp, uio, ioflag, cred) * * Update the times on the inode then do device close. */ -ufsspec_close(vp, fflag, cred) +ufsspec_close(vp, fflag, cred, p) struct vnode *vp; int fflag; struct ucred *cred; + struct proc *p; { register struct inode *ip = VTOI(vp); if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) ITIMES(ip, &time, &time); - return (spec_close(vp, fflag, cred)); + return (spec_close(vp, fflag, cred, p)); } #ifdef FIFO @@ -1655,21 +1539,22 @@ ufsfifo_write(vp, uio, ioflag, cred) * * Update the times on the inode then do device close. */ -ufsfifo_close(vp, fflag, cred) +ufsfifo_close(vp, fflag, cred, p) struct vnode *vp; int fflag; struct ucred *cred; + struct proc *p; { register struct inode *ip = VTOI(vp); if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) ITIMES(ip, &time, &time); - return (fifo_close(vp, fflag, cred)); + return (fifo_close(vp, fflag, cred, p)); } #endif /* FIFO */ /* - * Make a new file. + * Allocate a new inode. */ maknode(mode, ndp, ipp) int mode; @@ -1682,6 +1567,10 @@ maknode(mode, ndp, ipp) ino_t ipref; int error; +#ifdef DIANOSTIC + if ((ndp->ni_nameiop & HASBUF) == 0) + panic("maknode: no name"); +#endif *ipp = 0; if ((mode & IFMT) == 0) mode |= IFREG; @@ -1690,6 +1579,7 @@ maknode(mode, ndp, ipp) else ipref = pdir->i_number; if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) { + free(ndp->ni_pnbuf, M_NAMEI); iput(pdir); return (error); } @@ -1699,6 +1589,7 @@ maknode(mode, ndp, ipp) #ifdef QUOTA if ((error = getinoquota(ip)) || (error = chkiq(ip, 1, ndp->ni_cred, 0))) { + free(ndp->ni_pnbuf, M_NAMEI); ifree(ip, ip->i_number, mode); iput(ip); iput(pdir); @@ -1718,10 +1609,11 @@ maknode(mode, ndp, ipp) */ if (error = iupdat(ip, &time, &time, 1)) goto bad; - if (error = direnter(ip, ndp)) { - pdir = NULL; + if (error = direnter(ip, ndp)) goto bad; - } + if ((ndp->ni_nameiop & SAVESTART) == 0) + FREE(ndp->ni_pnbuf, M_NAMEI); + iput(pdir); *ipp = ip; return (0); @@ -1730,8 +1622,8 @@ bad: * Write error occurred trying to update the inode * or the directory so must deallocate the inode. */ - if (pdir) - iput(pdir); + free(ndp->ni_pnbuf, M_NAMEI); + iput(pdir); ip->i_nlink = 0; ip->i_flag |= ICHG; iput(ip); @@ -1806,13 +1698,17 @@ ufs_advlock(vp, id, op, fl, flags) */ switch(op) { case F_SETLK: - return (ufs_setlock(lock)); + return (lf_setlock(lock)); case F_UNLCK: - return (ufs_advunlock(lock)); + error = lf_clearlock(lock); + FREE(lock, M_LOCKF); + return (error); case F_GETLK: - return (ufs_advgetlock(lock, fl)); + error = lf_getlock(lock, fl); + FREE(lock, M_LOCKF); + return (error); default: free(lock, M_LOCKF); @@ -1822,166 +1718,122 @@ ufs_advlock(vp, id, op, fl, flags) } /* - * This variable controls the maximum number of processes that will - * be checked in doing deadlock detection. - */ -int maxlockdepth = MAXDEPTH; - -/* - * Set a byte-range lock. - */ -ufs_setlock(lock) - register struct lockf *lock; -{ - register struct inode *ip = lock->lf_inode; - register struct lockf *block; - static char lockstr[] = "lockf"; - int priority, error; - -#ifdef LOCKF_DEBUG - if (lockf_debug & 4) - lf_print("ufs_setlock", lock); -#endif /* LOCKF_DEBUG */ - - /* - * Set the priority - */ - priority = PLOCK; - if ((lock->lf_type & F_WRLCK) == 0) - priority += 4; - priority |= PCATCH; - /* - * Scan lock list for this file looking for locks that would block us. - */ - while (block = lf_getblock(lock)) { - /* - * Free the structure and return if nonblocking. - */ - if ((lock->lf_flags & F_WAIT) == 0) { - free(lock, M_LOCKF); - return (EAGAIN); - } - /* - * We are blocked. Since flock style locks cover - * the whole file, there is no chance for deadlock. - * For byte-range locks we must check for deadlock. - * - * Deadlock detection is done by looking through the - * wait channels to see if there are any cycles that - * involve us. MAXDEPTH is set just to make sure we - * do not go off into neverland. - */ - if ((lock->lf_flags & F_POSIX) && - (block->lf_flags & F_POSIX)) { - register struct proc *wproc; - register struct lockf *waitblock; - int i = 0; - - /* The block is waiting on something */ - wproc = (struct proc *)block->lf_id; - while (wproc->p_wchan && - (wproc->p_wmesg == lockstr) && - (i++ < maxlockdepth)) { - waitblock = (struct lockf *)wproc->p_wchan; - /* Get the owner of the blocking lock */ - waitblock = waitblock->lf_next; - if ((waitblock->lf_flags & F_POSIX) == 0) - break; - wproc = (struct proc *)waitblock->lf_id; - if (wproc == (struct proc *)lock->lf_id) { - free(lock, M_LOCKF); - return (EDEADLK); - } - } - } - /* - * Add our lock to the blocked - * list and sleep until we're free. - */ -#ifdef LOCKF_DEBUG - if (lockf_debug & 4) - lf_print("ufs_advlock: blocking on", block); -#endif /* LOCKF_DEBUG */ - /* - * Remember who blocked us (for deadlock detection) - */ - lock->lf_next = block; - lf_addblock(block, lock); - if (error = tsleep((caddr_t *)lock, priority, lockstr, 0)) { - free(lock, M_LOCKF); - return (error); - } - } - /* - * No blocks!! Add the lock. Note that addlock will - * downgrade or upgrade any overlapping locks this - * process already owns. - */ - lf_addlock(lock); -#ifdef LOCKF_DEBUG - if (lockf_debug & 4) { - lf_print("ufs_advlock: got the lock", lock); - lf_printlist(lock); - } -#endif /* LOCKF_DEBUG */ - return (0); -} - -/* - * Remove a byte-range lock on an inode. + * Global vfs data structures for ufs */ -ufs_advunlock(lock) - struct lockf *lock; -{ - struct lockf *blocklist; +struct vnodeops ufs_vnodeops = { + ufs_lookup, /* lookup */ + ufs_create, /* create */ + ufs_mknod, /* mknod */ + ufs_open, /* open */ + ufs_close, /* close */ + ufs_access, /* access */ + ufs_getattr, /* getattr */ + ufs_setattr, /* setattr */ + ufs_read, /* read */ + ufs_write, /* write */ + ufs_ioctl, /* ioctl */ + ufs_select, /* select */ + ufs_mmap, /* mmap */ + ufs_fsync, /* fsync */ + ufs_seek, /* seek */ + ufs_remove, /* remove */ + ufs_link, /* link */ + ufs_rename, /* rename */ + ufs_mkdir, /* mkdir */ + ufs_rmdir, /* rmdir */ + ufs_symlink, /* symlink */ + ufs_readdir, /* readdir */ + ufs_readlink, /* readlink */ + ufs_abortop, /* abortop */ + ufs_inactive, /* inactive */ + ufs_reclaim, /* reclaim */ + ufs_lock, /* lock */ + ufs_unlock, /* unlock */ + ufs_bmap, /* bmap */ + ufs_strategy, /* strategy */ + ufs_print, /* print */ + ufs_islocked, /* islocked */ + ufs_advlock, /* advlock */ +}; - if (lock->lf_inode->i_lockf == (struct lockf *)0) - return (0); -#ifdef LOCKF_DEBUG - if (lockf_debug & 4) - lf_print("ufs_advunlock", lock); -#endif /* LOCKF_DEBUG */ - /* - * Generally, find the lock (or an overlap to that lock) - * and remove it (or shrink it), then wakeup anyone we can. - */ - blocklist = lf_remove(lock); -#ifdef LOCKF_DEBUG - lf_printlist(lock); -#endif /* LOCKF_DEBUG */ - FREE(lock, M_LOCKF); - lf_wakelock(blocklist); - return (0); -} +struct vnodeops spec_inodeops = { + spec_lookup, /* lookup */ + spec_create, /* create */ + spec_mknod, /* mknod */ + spec_open, /* open */ + ufsspec_close, /* close */ + ufs_access, /* access */ + ufs_getattr, /* getattr */ + ufs_setattr, /* setattr */ + ufsspec_read, /* read */ + ufsspec_write, /* write */ + spec_ioctl, /* ioctl */ + spec_select, /* select */ + spec_mmap, /* mmap */ + spec_fsync, /* fsync */ + spec_seek, /* seek */ + spec_remove, /* remove */ + spec_link, /* link */ + spec_rename, /* rename */ + spec_mkdir, /* mkdir */ + spec_rmdir, /* rmdir */ + spec_symlink, /* symlink */ + spec_readdir, /* readdir */ + spec_readlink, /* readlink */ + spec_abortop, /* abortop */ + ufs_inactive, /* inactive */ + ufs_reclaim, /* reclaim */ + ufs_lock, /* lock */ + ufs_unlock, /* unlock */ + spec_bmap, /* bmap */ + spec_strategy, /* strategy */ + ufs_print, /* print */ + ufs_islocked, /* islocked */ + spec_advlock, /* advlock */ +}; -/* - * Return the blocking pid - */ -ufs_advgetlock(lock, fl) - register struct lockf *lock; - register struct flock *fl; -{ - register struct lockf *block; - off_t start, end; +#ifdef FIFO +struct vnodeops fifo_inodeops = { + fifo_lookup, /* lookup */ + fifo_create, /* create */ + fifo_mknod, /* mknod */ + fifo_open, /* open */ + ufsfifo_close, /* close */ + ufs_access, /* access */ + ufs_getattr, /* getattr */ + ufs_setattr, /* setattr */ + ufsfifo_read, /* read */ + ufsfifo_write, /* write */ + fifo_ioctl, /* ioctl */ + fifo_select, /* select */ + fifo_mmap, /* mmap */ + fifo_fsync, /* fsync */ + fifo_seek, /* seek */ + fifo_remove, /* remove */ + fifo_link, /* link */ + fifo_rename, /* rename */ + fifo_mkdir, /* mkdir */ + fifo_rmdir, /* rmdir */ + fifo_symlink, /* symlink */ + fifo_readdir, /* readdir */ + fifo_readlink, /* readlink */ + fifo_abortop, /* abortop */ + ufs_inactive, /* inactive */ + ufs_reclaim, /* reclaim */ + ufs_lock, /* lock */ + ufs_unlock, /* unlock */ + fifo_bmap, /* bmap */ + fifo_strategy, /* strategy */ + ufs_print, /* print */ + ufs_islocked, /* islocked */ + fifo_advlock, /* advlock */ +}; +#endif /* FIFO */ -#ifdef LOCKF_DEBUG - if (lockf_debug & 4) - lf_print("ufs_advgetlock", lock); -#endif /* LOCKF_DEBUG */ - - if (block = lf_getblock(lock)) { - fl->l_type = block->lf_type; - fl->l_whence = SEEK_SET; - fl->l_start = block->lf_start; - if (block->lf_end == -1) - fl->l_len = 0; - else - fl->l_len = block->lf_end - block->lf_start + 1; - if (block->lf_flags & F_POSIX) - fl->l_pid = ((struct proc *)(block->lf_id))->p_pid; - else - fl->l_pid = -1; - } - FREE(lock, M_LOCKF); - return (0); -} +enum vtype iftovt_tab[16] = { + VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, + VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, +}; +int vttoif_tab[9] = { + 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT, +};