X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/6cb69bbe7a74db9e0c7038e4de6063dfd863394a..655da94564f7a532b437699be6af925d975ad125:/usr/src/sys/ufs/ffs/ufs_vnops.c diff --git a/usr/src/sys/ufs/ffs/ufs_vnops.c b/usr/src/sys/ufs/ffs/ufs_vnops.c index d70847ad16..4757e49740 100644 --- a/usr/src/sys/ufs/ffs/ufs_vnops.c +++ b/usr/src/sys/ufs/ffs/ufs_vnops.c @@ -2,221 +2,40 @@ * Copyright (c) 1982, 1986, 1989 Regents of the University of California. * All rights reserved. * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * %sccs.include.redist.c% * - * @(#)ufs_vnops.c 7.41 (Berkeley) %G% + * @(#)ufs_vnops.c 7.63 (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 "../ufs/quota.h" -#include "../ufs/inode.h" -#include "../ufs/fs.h" +#include "fifo.h" +#include "malloc.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(); - -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 */ -}; - -int spec_lookup(), - spec_open(), - ufsspec_read(), - ufsspec_write(), - spec_strategy(), - spec_bmap(), - spec_ioctl(), - spec_select(), - ufsspec_close(), - 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 */ -}; - -#ifdef FIFO -int fifo_lookup(), - fifo_open(), - ufsfifo_read(), - ufsfifo_write(), - fifo_bmap(), - fifo_ioctl(), - fifo_select(), - ufsfifo_close(), - fifo_print(), - 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 */ -}; -#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; @@ -231,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; @@ -268,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); @@ -283,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); @@ -300,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; @@ -350,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); @@ -398,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; @@ -419,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) @@ -429,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; @@ -440,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; @@ -460,28 +285,29 @@ 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); - ip->i_mode &= ~07777; if (cred->cr_uid) { - if (vp->v_type != VDIR) - mode &= ~ISVTX; - if (!groupmember(ip->i_gid, cred)) - mode &= ~ISGID; + if (vp->v_type != VDIR && (mode & ISVTX)) + return (EFTYPE); + if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) + return (EPERM); } + ip->i_mode &= ~07777; ip->i_mode |= mode & 07777; ip->i_flag |= ICHG; if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0) - xrele(vp); + (void) vnode_pager_uncache(vp); return (0); } @@ -489,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; @@ -515,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; @@ -607,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) @@ -658,16 +487,19 @@ 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; daddr_t lbn, bn; u_long osize; - int i, n, on, flags; - int count, size, resid, error = 0; + 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) @@ -692,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; @@ -715,12 +547,12 @@ ufs_write(vp, uio, ioflag, cred) if (error = balloc(ip, lbn, (int)(on + n), &bp, flags)) break; bn = bp->b_blkno; - if (uio->uio_offset + n > ip->i_size) + if (uio->uio_offset + n > ip->i_size) { ip->i_size = uio->uio_offset + n; + vnode_pager_setsize(vp, ip->i_size); + } size = blksize(fs, ip, lbn); - count = howmany(size, CLBYTES); - for (i = 0; i < count; i++) - munhash(ip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); + (void) vnode_pager_uncache(vp); n = MIN(n, size - bp->b_resid); error = uiomove(bp->b_un.b_addr + on, n, uio); if (ioflag & IO_SYNC) @@ -739,29 +571,36 @@ ufs_write(vp, uio, ioflag, cred) uio->uio_offset -= resid - uio->uio_resid; uio->uio_resid = resid; } + if (!error && (ioflag & IO_SYNC)) + error = iupdat(ip, &time, &time, 1); return (error); } /* 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); } /* @@ -770,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); @@ -783,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)); @@ -817,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; @@ -841,27 +683,33 @@ 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; +#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); - if (ip->i_nlink == LINK_MAX - 1) { - error = EMLINK; - goto out; - } ip->i_nlink++; ip->i_flag |= ICHG; error = iupdat(ip, &time, &time, 1); if (!error) error = direnter(ip, ndp); -out: 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; @@ -893,28 +741,52 @@ out: * 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)) { - IUNLOCK(ip); - ufs_abortop(fndp); - ufs_abortop(tndp); + 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) + vput(tndp->ni_vp); + VOP_ABORTOP(fndp); + vrele(fndp->ni_dvp); + vput(fndp->ni_vp); return (EINVAL); } ip->i_flag |= IRENAME; @@ -956,23 +828,22 @@ 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 = 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"); + 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 @@ -990,12 +861,24 @@ ufs_rename(fndp, tndp) * parent we don't fool with the link count. */ if (doingdirectory && newparent) { + if ((unsigned short)dp->i_nlink >= LINK_MAX) { + error = EMLINK; + goto bad; + } dp->i_nlink++; dp->i_flag |= ICHG; - error = iupdat(dp, &time, &time, 1); + 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"); @@ -1017,11 +900,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) || @@ -1040,6 +921,16 @@ ufs_rename(fndp, tndp) } if (error = dirrewrite(dp, ip, tndp)) goto bad; + /* + * If the target directory is in the same + * directory as the source directory, + * decrement the link count on the parent + * of the target directory. + */ + if (doingdirectory && !newparent) { + dp->i_nlink--; + dp->i_flag |= ICHG; + } vput(ITOV(dp)); /* * Adjust the link count of the target to @@ -1065,16 +956,23 @@ ufs_rename(fndp, tndp) /* * 3) Unlink the source. */ - 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"); + (void) lookup(fndp, p); if (fndp->ni_vp != NULL) { xp = VTOI(fndp->ni_vp); dp = VTOI(fndp->ni_dvp); } else { - if (fndp->ni_dvp != NULL) - vput(fndp->ni_dvp); - xp = NULL; - dp = NULL; + /* + * From name has disappeared. + */ + if (doingdirectory) + panic("rename: lost dir entry"); + vrele(ITOV(ip)); + return (0); } /* * Ensure that the directory entry still exists and has not @@ -1102,7 +1000,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] != '.' || @@ -1115,7 +1013,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)); } } @@ -1156,9 +1055,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; @@ -1167,18 +1067,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); } @@ -1188,6 +1096,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); @@ -1208,7 +1117,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 "." @@ -1218,32 +1128,27 @@ 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; goto bad; } - if (DIRBLKSIZ > dp->i_fs->fs_fsize) + if (DIRBLKSIZ > dp->i_fs->fs_fsize) { panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ - else + } else { ip->i_size = DIRBLKSIZ; + ip->i_flag |= ICHG; + } /* * Directory all set up, now * install the entry for it in * the parent directory. */ - error = direnter(ip, ndp); - dp = NULL; - if (error) { - 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: /* @@ -1257,16 +1162,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; @@ -1328,10 +1234,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; @@ -1340,7 +1247,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); } @@ -1386,23 +1294,16 @@ ufs_readlink(vp, uiop, cred) /* * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually - * done. Iff ni_vp/ni_dvp not null and locked, unlock. + * done. If a buffer has been saved in anticipation of a CREATE, delete it. */ +/* ARGSUSED */ ufs_abortop(ndp) - register struct nameidata *ndp; + struct nameidata *ndp; { - if (ndp->ni_dvp) { - if (VOP_ISLOCKED(ndp->ni_dvp)) - VOP_UNLOCK(ndp->ni_dvp); - vrele(ndp->ni_dvp); - } - if (ndp->ni_vp) { - if (VOP_ISLOCKED(ndp->ni_vp)) - VOP_UNLOCK(ndp->ni_vp); - vrele(ndp->ni_vp); - } - return; + if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF) + FREE(ndp->ni_pnbuf, M_NAMEI); + return (0); } /* @@ -1583,16 +1484,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 @@ -1635,21 +1537,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; @@ -1662,6 +1565,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; @@ -1670,6 +1577,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); } @@ -1679,6 +1587,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); @@ -1698,10 +1607,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); @@ -1710,10 +1620,218 @@ 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); return (error); } + +/* + * Advisory record locking support + */ +ufs_advlock(vp, id, op, fl, flags) + struct vnode *vp; + caddr_t id; + int op; + register struct flock *fl; + int flags; +{ + register struct inode *ip = VTOI(vp); + register struct lockf *lock; + off_t start, end; + int error; + + /* + * Avoid the common case of unlocking when inode has no locks. + */ + if (ip->i_lockf == (struct lockf *)0) { + if (op != F_SETLK) { + fl->l_type = F_UNLCK; + return (0); + } + } + /* + * Convert the flock structure into a start and end. + */ + switch (fl->l_whence) { + + case SEEK_SET: + case SEEK_CUR: + /* + * Caller is responsible for adding any necessary offset + * when SEEK_CUR is used. + */ + start = fl->l_start; + break; + + case SEEK_END: + start = ip->i_size + fl->l_start; + break; + + default: + return (EINVAL); + } + if (start < 0) + return (EINVAL); + if (fl->l_len == 0) + end = -1; + else + end = start + fl->l_len - 1; + /* + * Create the lockf structure + */ + MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK); + lock->lf_start = start; + lock->lf_end = end; + lock->lf_id = id; + lock->lf_inode = ip; + lock->lf_type = fl->l_type; + lock->lf_next = (struct lockf *)0; + lock->lf_block = (struct lockf *)0; + lock->lf_flags = flags; + /* + * Do the requested operation. + */ + switch(op) { + case F_SETLK: + return (lf_setlock(lock)); + + case F_UNLCK: + error = lf_clearlock(lock); + FREE(lock, M_LOCKF); + return (error); + + case F_GETLK: + error = lf_getlock(lock, fl); + FREE(lock, M_LOCKF); + return (error); + + default: + free(lock, M_LOCKF); + return (EINVAL); + } + /* NOTREACHED */ +} + +/* + * Global vfs data structures for ufs + */ +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 */ +}; + +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 */ +}; + +#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 */ + +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, +};