123405Smckusick /* 237737Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337737Smckusick * All rights reserved. 423405Smckusick * 544539Sbostic * %sccs.include.redist.c% 637737Smckusick * 7*51134Sbostic * @(#)lfs_vnops.c 7.65 (Berkeley) 09/17/91 823405Smckusick */ 937Sbill 1017101Sbloom #include "param.h" 1117101Sbloom #include "systm.h" 1247571Skarels #include "namei.h" 1347571Skarels #include "resourcevar.h" 1417101Sbloom #include "kernel.h" 1517101Sbloom #include "file.h" 1617101Sbloom #include "stat.h" 1717101Sbloom #include "buf.h" 1817101Sbloom #include "proc.h" 1937737Smckusick #include "conf.h" 2017101Sbloom #include "mount.h" 2137737Smckusick #include "vnode.h" 2240653Smckusick #include "specdev.h" 2348039Smckusick #include "fifo.h" 2446207Smckusick #include "malloc.h" 2537Sbill 2647571Skarels #include "lockf.h" 2747571Skarels #include "quota.h" 2847571Skarels #include "inode.h" 2949737Smckusick #include "dir.h" 30*51134Sbostic #include "lfs.h" 3147571Skarels 32*51134Sbostic static int chmod1 __P((struct vnode *, int, struct proc *)); 33*51134Sbostic static int chown1 __P((struct vnode *, uid_t, gid_t, struct proc *)); 34*51134Sbostic static int maknode __P((int, struct nameidata *, struct inode **)); 35*51134Sbostic 369167Ssam /* 3737737Smckusick * Create a regular file 389167Ssam */ 39*51134Sbostic lfs_create(ndp, vap, p) 4037737Smckusick struct nameidata *ndp; 4137737Smckusick struct vattr *vap; 4248039Smckusick struct proc *p; 436254Sroot { 4437737Smckusick struct inode *ip; 4537737Smckusick int error; 466254Sroot 4737737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 4837737Smckusick return (error); 4937737Smckusick ndp->ni_vp = ITOV(ip); 5037737Smckusick return (0); 516254Sroot } 526254Sroot 5337Sbill /* 5437737Smckusick * Mknod vnode call 556254Sroot */ 5637737Smckusick /* ARGSUSED */ 57*51134Sbostic lfs_mknod(ndp, vap, cred, p) 5837737Smckusick struct nameidata *ndp; 5937737Smckusick struct ucred *cred; 6037737Smckusick struct vattr *vap; 6148039Smckusick struct proc *p; 626254Sroot { 6339435Smckusick register struct vnode *vp; 6437737Smckusick struct inode *ip; 6537737Smckusick int error; 666254Sroot 6737737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 6837737Smckusick return (error); 6940290Smckusick ip->i_flag |= IACC|IUPD|ICHG; 7040290Smckusick if (vap->va_rdev != VNOVAL) { 7137737Smckusick /* 7237737Smckusick * Want to be able to use this to make badblock 7337737Smckusick * inodes, so don't truncate the dev number. 7437737Smckusick */ 7539608Smckusick ip->i_rdev = vap->va_rdev; 7612756Ssam } 7737737Smckusick /* 7837737Smckusick * Remove inode so that it will be reloaded by iget and 7937737Smckusick * checked to see if it is an alias of an existing entry 8037737Smckusick * in the inode cache. 8137737Smckusick */ 8240290Smckusick vp = ITOV(ip); 8340290Smckusick vput(vp); 8439435Smckusick vp->v_type = VNON; 8539435Smckusick vgone(vp); 8637737Smckusick return (0); 876254Sroot } 886254Sroot 896254Sroot /* 9037737Smckusick * Close called 9137737Smckusick * 9237737Smckusick * Update the times on the inode. 936254Sroot */ 9437737Smckusick /* ARGSUSED */ 95*51134Sbostic lfs_close(vp, fflag, cred, p) 9637737Smckusick struct vnode *vp; 9737737Smckusick int fflag; 9837737Smckusick struct ucred *cred; 9948039Smckusick struct proc *p; 1006254Sroot { 10137737Smckusick register struct inode *ip = VTOI(vp); 1026254Sroot 10339815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 10437737Smckusick ITIMES(ip, &time, &time); 10537737Smckusick return (0); 1066254Sroot } 1076254Sroot 10841312Smckusick /* 10941312Smckusick * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 11041312Smckusick * The mode is shifted to select the owner/group/other fields. The 11141312Smckusick * super user is granted all permissions. 11241312Smckusick */ 113*51134Sbostic lfs_access(vp, mode, cred, p) 11437737Smckusick struct vnode *vp; 11541312Smckusick register int mode; 11637737Smckusick struct ucred *cred; 11748039Smckusick struct proc *p; 1186254Sroot { 11941312Smckusick register struct inode *ip = VTOI(vp); 12041312Smckusick register gid_t *gp; 12141312Smckusick int i, error; 1226254Sroot 12341312Smckusick #ifdef DIAGNOSTIC 12441312Smckusick if (!VOP_ISLOCKED(vp)) { 12541312Smckusick vprint("ufs_access: not locked", vp); 12641312Smckusick panic("ufs_access: not locked"); 12741312Smckusick } 12841312Smckusick #endif 12941312Smckusick #ifdef QUOTA 13041312Smckusick if (mode & VWRITE) { 13141312Smckusick switch (vp->v_type) { 13241312Smckusick case VREG: case VDIR: case VLNK: 13341312Smckusick if (error = getinoquota(ip)) 13441312Smckusick return (error); 13541312Smckusick } 13641312Smckusick } 13741312Smckusick #endif /* QUOTA */ 13841312Smckusick /* 13941312Smckusick * If you're the super-user, you always get access. 14041312Smckusick */ 14141312Smckusick if (cred->cr_uid == 0) 14241312Smckusick return (0); 14341312Smckusick /* 14441312Smckusick * Access check is based on only one of owner, group, public. 14541312Smckusick * If not owner, then check group. If not a member of the 14641312Smckusick * group, then check public access. 14741312Smckusick */ 14841312Smckusick if (cred->cr_uid != ip->i_uid) { 14941312Smckusick mode >>= 3; 15041312Smckusick gp = cred->cr_groups; 15141312Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 15241312Smckusick if (ip->i_gid == *gp) 15341312Smckusick goto found; 15441312Smckusick mode >>= 3; 15541312Smckusick found: 15641312Smckusick ; 15741312Smckusick } 15841312Smckusick if ((ip->i_mode & mode) != 0) 15941312Smckusick return (0); 16041312Smckusick return (EACCES); 1616254Sroot } 1626254Sroot 16337737Smckusick /* ARGSUSED */ 164*51134Sbostic lfs_getattr(vp, vap, cred, p) 16537737Smckusick struct vnode *vp; 16637737Smckusick register struct vattr *vap; 16737737Smckusick struct ucred *cred; 16848039Smckusick struct proc *p; 1696254Sroot { 17037737Smckusick register struct inode *ip = VTOI(vp); 1716254Sroot 17237737Smckusick ITIMES(ip, &time, &time); 1736254Sroot /* 17437737Smckusick * Copy from inode table 1756254Sroot */ 17637737Smckusick vap->va_fsid = ip->i_dev; 17737737Smckusick vap->va_fileid = ip->i_number; 17837737Smckusick vap->va_mode = ip->i_mode & ~IFMT; 17937737Smckusick vap->va_nlink = ip->i_nlink; 18037737Smckusick vap->va_uid = ip->i_uid; 18137737Smckusick vap->va_gid = ip->i_gid; 18237737Smckusick vap->va_rdev = (dev_t)ip->i_rdev; 18341312Smckusick #ifdef tahoe 18441312Smckusick vap->va_size = ip->i_size; 18541312Smckusick vap->va_size_rsv = 0; 18641312Smckusick #else 18740641Smckusick vap->va_qsize = ip->i_din.di_qsize; 18841312Smckusick #endif 18937737Smckusick vap->va_atime.tv_sec = ip->i_atime; 19038578Smckusick vap->va_atime.tv_usec = 0; 19137737Smckusick vap->va_mtime.tv_sec = ip->i_mtime; 19238578Smckusick vap->va_mtime.tv_usec = 0; 19337737Smckusick vap->va_ctime.tv_sec = ip->i_ctime; 19438578Smckusick vap->va_ctime.tv_usec = 0; 19538254Smckusick vap->va_flags = ip->i_flags; 19638254Smckusick vap->va_gen = ip->i_gen; 19737737Smckusick /* this doesn't belong here */ 19837737Smckusick if (vp->v_type == VBLK) 19937737Smckusick vap->va_blocksize = BLKDEV_IOSIZE; 20037737Smckusick else if (vp->v_type == VCHR) 20137737Smckusick vap->va_blocksize = MAXBSIZE; 2027142Smckusick else 20337737Smckusick vap->va_blocksize = ip->i_fs->fs_bsize; 20438657Smckusick vap->va_bytes = dbtob(ip->i_blocks); 20540641Smckusick vap->va_bytes_rsv = 0; 20637737Smckusick vap->va_type = vp->v_type; 20737737Smckusick return (0); 2086254Sroot } 2096254Sroot 2106254Sroot /* 21137737Smckusick * Set attribute vnode op. called from several syscalls 2126254Sroot */ 213*51134Sbostic lfs_setattr(vp, vap, cred, p) 21437737Smckusick register struct vnode *vp; 21537737Smckusick register struct vattr *vap; 21637737Smckusick register struct ucred *cred; 21748039Smckusick struct proc *p; 2186254Sroot { 21937737Smckusick register struct inode *ip = VTOI(vp); 22037737Smckusick int error = 0; 2216254Sroot 22237737Smckusick /* 22337737Smckusick * Check for unsetable attributes. 22437737Smckusick */ 22537737Smckusick if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 22637737Smckusick (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 22737737Smckusick (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 22838254Smckusick ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 22937737Smckusick return (EINVAL); 23016540Ssam } 23137737Smckusick /* 23237737Smckusick * Go through the fields and update iff not VNOVAL. 23337737Smckusick */ 23437737Smckusick if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL) 23547571Skarels if (error = chown1(vp, vap->va_uid, vap->va_gid, p)) 23637737Smckusick return (error); 23737737Smckusick if (vap->va_size != VNOVAL) { 23837737Smckusick if (vp->v_type == VDIR) 23937737Smckusick return (EISDIR); 24039674Smckusick if (error = itrunc(ip, vap->va_size, 0)) /* XXX IO_SYNC? */ 24137737Smckusick return (error); 24213878Ssam } 24337737Smckusick if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 24437773Smckusick if (cred->cr_uid != ip->i_uid && 24547571Skarels (error = suser(cred, &p->p_acflag))) 24637773Smckusick return (error); 24737737Smckusick if (vap->va_atime.tv_sec != VNOVAL) 24837737Smckusick ip->i_flag |= IACC; 24937737Smckusick if (vap->va_mtime.tv_sec != VNOVAL) 25037737Smckusick ip->i_flag |= IUPD; 25137737Smckusick ip->i_flag |= ICHG; 25237737Smckusick if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1)) 25337737Smckusick return (error); 2546254Sroot } 25537737Smckusick if (vap->va_mode != (u_short)VNOVAL) 25647571Skarels error = chmod1(vp, (int)vap->va_mode, p); 25738254Smckusick if (vap->va_flags != VNOVAL) { 25838254Smckusick if (cred->cr_uid != ip->i_uid && 25947571Skarels (error = suser(cred, &p->p_acflag))) 26038254Smckusick return (error); 26138254Smckusick if (cred->cr_uid == 0) { 26238254Smckusick ip->i_flags = vap->va_flags; 26338254Smckusick } else { 26438254Smckusick ip->i_flags &= 0xffff0000; 26538254Smckusick ip->i_flags |= (vap->va_flags & 0xffff); 26638254Smckusick } 26738254Smckusick ip->i_flag |= ICHG; 26838254Smckusick } 26937737Smckusick return (error); 2706254Sroot } 2716254Sroot 2726254Sroot /* 2739167Ssam * Change the mode on a file. 2749167Ssam * Inode must be locked before calling. 2759167Ssam */ 276*51134Sbostic static int 27747571Skarels chmod1(vp, mode, p) 27837737Smckusick register struct vnode *vp; 2797701Ssam register int mode; 28047571Skarels struct proc *p; 2817701Ssam { 28247571Skarels register struct ucred *cred = p->p_ucred; 28337737Smckusick register struct inode *ip = VTOI(vp); 28437773Smckusick int error; 2857868Sroot 28637773Smckusick if (cred->cr_uid != ip->i_uid && 28747571Skarels (error = suser(cred, &p->p_acflag))) 28837773Smckusick return (error); 28937737Smckusick if (cred->cr_uid) { 29046206Smckusick if (vp->v_type != VDIR && (mode & ISVTX)) 29145783Sbostic return (EFTYPE); 29246206Smckusick if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) 29345783Sbostic return (EPERM); 2947439Sroot } 29545783Sbostic ip->i_mode &= ~07777; 29637737Smckusick ip->i_mode |= mode & 07777; 2976254Sroot ip->i_flag |= ICHG; 29837737Smckusick if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0) 29945722Smckusick (void) vnode_pager_uncache(vp); 30021015Smckusick return (0); 3015992Swnj } 3025992Swnj 3039167Ssam /* 3047701Ssam * Perform chown operation on inode ip; 3057701Ssam * inode must be locked prior to call. 3067701Ssam */ 307*51134Sbostic static int 30847571Skarels chown1(vp, uid, gid, p) 30937737Smckusick register struct vnode *vp; 31037737Smckusick uid_t uid; 31137737Smckusick gid_t gid; 31247571Skarels struct proc *p; 3137701Ssam { 31437737Smckusick register struct inode *ip = VTOI(vp); 31547571Skarels register struct ucred *cred = p->p_ucred; 31641312Smckusick uid_t ouid; 31741312Smckusick gid_t ogid; 31841312Smckusick int error = 0; 3197701Ssam #ifdef QUOTA 32041312Smckusick register int i; 32141312Smckusick long change; 32211811Ssam #endif 3237701Ssam 32437737Smckusick if (uid == (u_short)VNOVAL) 32511811Ssam uid = ip->i_uid; 32637737Smckusick if (gid == (u_short)VNOVAL) 32711811Ssam gid = ip->i_gid; 32836614Sbostic /* 32936614Sbostic * If we don't own the file, are trying to change the owner 33036614Sbostic * of the file, or are not a member of the target group, 33136614Sbostic * the caller must be superuser or the call fails. 33236614Sbostic */ 33337737Smckusick if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid || 33437737Smckusick !groupmember((gid_t)gid, cred)) && 33547571Skarels (error = suser(cred, &p->p_acflag))) 33637737Smckusick return (error); 33741312Smckusick ouid = ip->i_uid; 33841312Smckusick ogid = ip->i_gid; 33911811Ssam #ifdef QUOTA 34041312Smckusick if (error = getinoquota(ip)) 34141312Smckusick return (error); 34241312Smckusick if (ouid == uid) { 34341312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 34441312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 34541312Smckusick } 34641312Smckusick if (ogid == gid) { 34741312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 34841312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 34941312Smckusick } 35041312Smckusick change = ip->i_blocks; 35141312Smckusick (void) chkdq(ip, -change, cred, CHOWN); 35241312Smckusick (void) chkiq(ip, -1, cred, CHOWN); 35341312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 35441312Smckusick dqrele(vp, ip->i_dquot[i]); 35541312Smckusick ip->i_dquot[i] = NODQUOT; 35641312Smckusick } 3577482Skre #endif 35811811Ssam ip->i_uid = uid; 35911811Ssam ip->i_gid = gid; 3607701Ssam #ifdef QUOTA 36141312Smckusick if ((error = getinoquota(ip)) == 0) { 36241312Smckusick if (ouid == uid) { 36341312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 36441312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 36541312Smckusick } 36641312Smckusick if (ogid == gid) { 36741312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 36841312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 36941312Smckusick } 37041312Smckusick if ((error = chkdq(ip, change, cred, CHOWN)) == 0) { 37141312Smckusick if ((error = chkiq(ip, 1, cred, CHOWN)) == 0) 37241927Smckusick goto good; 37341312Smckusick else 37441312Smckusick (void) chkdq(ip, -change, cred, CHOWN|FORCE); 37541312Smckusick } 37641312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 37741312Smckusick dqrele(vp, ip->i_dquot[i]); 37841312Smckusick ip->i_dquot[i] = NODQUOT; 37941312Smckusick } 38041312Smckusick } 38141312Smckusick ip->i_uid = ouid; 38241312Smckusick ip->i_gid = ogid; 38341312Smckusick if (getinoquota(ip) == 0) { 38441312Smckusick if (ouid == uid) { 38541312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 38641312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 38741312Smckusick } 38841312Smckusick if (ogid == gid) { 38941312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 39041312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 39141312Smckusick } 39241927Smckusick (void) chkdq(ip, change, cred, FORCE|CHOWN); 39341927Smckusick (void) chkiq(ip, 1, cred, FORCE|CHOWN); 39442440Smckusick (void) getinoquota(ip); 39541312Smckusick } 39642440Smckusick return (error); 39741927Smckusick good: 39842440Smckusick if (getinoquota(ip)) 39942440Smckusick panic("chown: lost quota"); 40042440Smckusick #endif /* QUOTA */ 40141312Smckusick if (ouid != uid || ogid != gid) 40241312Smckusick ip->i_flag |= ICHG; 40341312Smckusick if (ouid != uid && cred->cr_uid != 0) 40441312Smckusick ip->i_mode &= ~ISUID; 40541312Smckusick if (ogid != gid && cred->cr_uid != 0) 40641312Smckusick ip->i_mode &= ~ISGID; 40712646Ssam return (0); 40837Sbill } 40937Sbill 41039608Smckusick /* 41139608Smckusick * Vnode op for reading. 41239608Smckusick */ 41337737Smckusick /* ARGSUSED */ 414*51134Sbostic lfs_read(vp, uio, ioflag, cred) 41539608Smckusick struct vnode *vp; 41639608Smckusick register struct uio *uio; 41739608Smckusick int ioflag; 41839608Smckusick struct ucred *cred; 41939608Smckusick { 42039608Smckusick register struct inode *ip = VTOI(vp); 42139608Smckusick register struct fs *fs; 42239608Smckusick struct buf *bp; 42339608Smckusick daddr_t lbn, bn, rablock; 42439896Smckusick int size, diff, error = 0; 42539608Smckusick long n, on, type; 42639608Smckusick 42748039Smckusick #ifdef DIAGNOSTIC 42839608Smckusick if (uio->uio_rw != UIO_READ) 42939608Smckusick panic("ufs_read mode"); 43039608Smckusick type = ip->i_mode & IFMT; 43139608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 43239608Smckusick panic("ufs_read type"); 43348039Smckusick #endif 43439608Smckusick if (uio->uio_resid == 0) 43539608Smckusick return (0); 43639608Smckusick if (uio->uio_offset < 0) 43739608Smckusick return (EINVAL); 43839608Smckusick ip->i_flag |= IACC; 43939608Smckusick fs = ip->i_fs; 44039608Smckusick do { 44139608Smckusick lbn = lblkno(fs, uio->uio_offset); 44239608Smckusick on = blkoff(fs, uio->uio_offset); 44339608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 44439608Smckusick diff = ip->i_size - uio->uio_offset; 44539608Smckusick if (diff <= 0) 44639608Smckusick return (0); 44739608Smckusick if (diff < n) 44839608Smckusick n = diff; 44939608Smckusick size = blksize(fs, ip, lbn); 45039674Smckusick rablock = lbn + 1; 45139896Smckusick if (vp->v_lastr + 1 == lbn && 45239896Smckusick lblktosize(fs, rablock) < ip->i_size) 45339896Smckusick error = breada(ITOV(ip), lbn, size, rablock, 45439896Smckusick blksize(fs, ip, rablock), NOCRED, &bp); 45539608Smckusick else 45639674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 45739815Smckusick vp->v_lastr = lbn; 45839608Smckusick n = MIN(n, size - bp->b_resid); 45939608Smckusick if (error) { 46039608Smckusick brelse(bp); 46139608Smckusick return (error); 46239608Smckusick } 46339608Smckusick error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 46439608Smckusick if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size) 46539608Smckusick bp->b_flags |= B_AGE; 46639608Smckusick brelse(bp); 46739608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 46839608Smckusick return (error); 46939608Smckusick } 47039608Smckusick 47139608Smckusick /* 47239608Smckusick * Vnode op for writing. 47339608Smckusick */ 474*51134Sbostic lfs_write(vp, uio, ioflag, cred) 47539608Smckusick register struct vnode *vp; 47639608Smckusick struct uio *uio; 47739608Smckusick int ioflag; 47839608Smckusick struct ucred *cred; 47939608Smckusick { 48048039Smckusick struct proc *p = uio->uio_procp; 48139608Smckusick register struct inode *ip = VTOI(vp); 48239608Smckusick register struct fs *fs; 48339608Smckusick struct buf *bp; 48439608Smckusick daddr_t lbn, bn; 48539608Smckusick u_long osize; 48645722Smckusick int n, on, flags; 48745722Smckusick int size, resid, error = 0; 48839608Smckusick 48948039Smckusick #ifdef DIAGNOSTIC 49039608Smckusick if (uio->uio_rw != UIO_WRITE) 49139608Smckusick panic("ufs_write mode"); 49248039Smckusick #endif 49339608Smckusick switch (vp->v_type) { 49439608Smckusick case VREG: 49539608Smckusick if (ioflag & IO_APPEND) 49639608Smckusick uio->uio_offset = ip->i_size; 49739608Smckusick /* fall through */ 49839608Smckusick case VLNK: 49939608Smckusick break; 50039608Smckusick 50139608Smckusick case VDIR: 50239608Smckusick if ((ioflag & IO_SYNC) == 0) 50339608Smckusick panic("ufs_write nonsync dir write"); 50439608Smckusick break; 50539608Smckusick 50639608Smckusick default: 50739608Smckusick panic("ufs_write type"); 50839608Smckusick } 50939608Smckusick if (uio->uio_offset < 0) 51039608Smckusick return (EINVAL); 51139608Smckusick if (uio->uio_resid == 0) 51239608Smckusick return (0); 51339608Smckusick /* 51439608Smckusick * Maybe this should be above the vnode op call, but so long as 51539608Smckusick * file servers have no limits, i don't think it matters 51639608Smckusick */ 51749679Smckusick if (vp->v_type == VREG && p && 51839608Smckusick uio->uio_offset + uio->uio_resid > 51947571Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 52047571Skarels psignal(p, SIGXFSZ); 52139608Smckusick return (EFBIG); 52239608Smckusick } 52339608Smckusick resid = uio->uio_resid; 52439608Smckusick osize = ip->i_size; 52539608Smckusick fs = ip->i_fs; 52639674Smckusick flags = 0; 52739674Smckusick if (ioflag & IO_SYNC) 52839674Smckusick flags = B_SYNC; 52939608Smckusick do { 53039608Smckusick lbn = lblkno(fs, uio->uio_offset); 53139608Smckusick on = blkoff(fs, uio->uio_offset); 53239608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 53339608Smckusick if (n < fs->fs_bsize) 53439674Smckusick flags |= B_CLRBUF; 53539608Smckusick else 53639674Smckusick flags &= ~B_CLRBUF; 53739674Smckusick if (error = balloc(ip, lbn, (int)(on + n), &bp, flags)) 53839608Smckusick break; 53939674Smckusick bn = bp->b_blkno; 54045722Smckusick if (uio->uio_offset + n > ip->i_size) { 54139608Smckusick ip->i_size = uio->uio_offset + n; 54245722Smckusick vnode_pager_setsize(vp, ip->i_size); 54345722Smckusick } 54439608Smckusick size = blksize(fs, ip, lbn); 54545722Smckusick (void) vnode_pager_uncache(vp); 54639608Smckusick n = MIN(n, size - bp->b_resid); 54739608Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 54839608Smckusick if (ioflag & IO_SYNC) 54939608Smckusick (void) bwrite(bp); 55039608Smckusick else if (n + on == fs->fs_bsize) { 55139608Smckusick bp->b_flags |= B_AGE; 55239608Smckusick bawrite(bp); 55339608Smckusick } else 55439608Smckusick bdwrite(bp); 55539608Smckusick ip->i_flag |= IUPD|ICHG; 55639608Smckusick if (cred->cr_uid != 0) 55739608Smckusick ip->i_mode &= ~(ISUID|ISGID); 55839608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 55939608Smckusick if (error && (ioflag & IO_UNIT)) { 56039674Smckusick (void) itrunc(ip, osize, ioflag & IO_SYNC); 56139608Smckusick uio->uio_offset -= resid - uio->uio_resid; 56239608Smckusick uio->uio_resid = resid; 56339608Smckusick } 56442493Smckusick if (!error && (ioflag & IO_SYNC)) 56542493Smckusick error = iupdat(ip, &time, &time, 1); 56639608Smckusick return (error); 56739608Smckusick } 56839608Smckusick 56939608Smckusick /* ARGSUSED */ 570*51134Sbostic lfs_ioctl(vp, com, data, fflag, cred, p) 57137737Smckusick struct vnode *vp; 57237737Smckusick int com; 57337737Smckusick caddr_t data; 57437737Smckusick int fflag; 57537737Smckusick struct ucred *cred; 57648039Smckusick struct proc *p; 57711811Ssam { 57811811Ssam 57937737Smckusick return (ENOTTY); 58011811Ssam } 58111811Ssam 58237737Smckusick /* ARGSUSED */ 583*51134Sbostic lfs_select(vp, which, fflags, cred, p) 58437737Smckusick struct vnode *vp; 58540290Smckusick int which, fflags; 58637737Smckusick struct ucred *cred; 58748039Smckusick struct proc *p; 58837737Smckusick { 58937737Smckusick 59048039Smckusick /* 59148039Smckusick * We should really check to see if I/O is possible. 59248039Smckusick */ 59348039Smckusick return (1); 59437737Smckusick } 59537737Smckusick 5969167Ssam /* 59737737Smckusick * Mmap a file 59837737Smckusick * 59937737Smckusick * NB Currently unsupported. 6009167Ssam */ 60137737Smckusick /* ARGSUSED */ 602*51134Sbostic lfs_mmap(vp, fflags, cred, p) 60337737Smckusick struct vnode *vp; 60437737Smckusick int fflags; 60537737Smckusick struct ucred *cred; 60648039Smckusick struct proc *p; 60737Sbill { 60837Sbill 60937737Smckusick return (EINVAL); 61037Sbill } 6117535Sroot 6129167Ssam /* 61337737Smckusick * Synch an open file. 6149167Ssam */ 61537737Smckusick /* ARGSUSED */ 616*51134Sbostic lfs_fsync(vp, fflags, cred, waitfor, p) 61737737Smckusick struct vnode *vp; 61837737Smckusick int fflags; 61937737Smckusick struct ucred *cred; 62039597Smckusick int waitfor; 62148039Smckusick struct proc *p; 6227701Ssam { 62339597Smckusick struct inode *ip = VTOI(vp); 6247701Ssam 62548039Smckusick if (fflags & FWRITE) 62637737Smckusick ip->i_flag |= ICHG; 62739674Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 62839674Smckusick return (iupdat(ip, &time, &time, waitfor == MNT_WAIT)); 6297701Ssam } 6307701Ssam 6319167Ssam /* 63237737Smckusick * Seek on a file 63337737Smckusick * 63437737Smckusick * Nothing to do, so just return. 6359167Ssam */ 63637737Smckusick /* ARGSUSED */ 637*51134Sbostic lfs_seek(vp, oldoff, newoff, cred) 63837737Smckusick struct vnode *vp; 63937737Smckusick off_t oldoff, newoff; 64037737Smckusick struct ucred *cred; 6417701Ssam { 6427701Ssam 64337737Smckusick return (0); 64437737Smckusick } 64537737Smckusick 64637737Smckusick /* 64737737Smckusick * ufs remove 64837737Smckusick * Hard to avoid races here, especially 64937737Smckusick * in unlinking directories. 65037737Smckusick */ 651*51134Sbostic lfs_remove(ndp, p) 65237737Smckusick struct nameidata *ndp; 65348039Smckusick struct proc *p; 65437737Smckusick { 65537737Smckusick register struct inode *ip, *dp; 65637737Smckusick int error; 65737737Smckusick 65837737Smckusick ip = VTOI(ndp->ni_vp); 65937737Smckusick dp = VTOI(ndp->ni_dvp); 66037737Smckusick error = dirremove(ndp); 66137737Smckusick if (!error) { 66237737Smckusick ip->i_nlink--; 66337737Smckusick ip->i_flag |= ICHG; 6647701Ssam } 66537737Smckusick if (dp == ip) 66637737Smckusick vrele(ITOV(ip)); 66737737Smckusick else 66837737Smckusick iput(ip); 66937737Smckusick iput(dp); 67037737Smckusick return (error); 6717701Ssam } 6727701Ssam 6739167Ssam /* 67437737Smckusick * link vnode call 6759167Ssam */ 676*51134Sbostic lfs_link(vp, ndp, p) 67737737Smckusick register struct vnode *vp; 67837737Smckusick register struct nameidata *ndp; 67948039Smckusick struct proc *p; 6809167Ssam { 68137737Smckusick register struct inode *ip = VTOI(vp); 68237737Smckusick int error; 6839167Ssam 68449737Smckusick #ifdef DIANOSTIC 68549737Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) 68649737Smckusick panic("ufs_link: no name"); 68749737Smckusick #endif 68849737Smckusick if ((unsigned short)ip->i_nlink >= LINK_MAX) { 68949737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 69046251Smckusick return (EMLINK); 69149737Smckusick } 69237737Smckusick if (ndp->ni_dvp != vp) 69337737Smckusick ILOCK(ip); 69437737Smckusick ip->i_nlink++; 69537737Smckusick ip->i_flag |= ICHG; 69637737Smckusick error = iupdat(ip, &time, &time, 1); 69737737Smckusick if (!error) 69837737Smckusick error = direnter(ip, ndp); 69937737Smckusick if (ndp->ni_dvp != vp) 70037737Smckusick IUNLOCK(ip); 70149737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 70247219Smckusick vput(ndp->ni_dvp); 70337737Smckusick if (error) { 70437737Smckusick ip->i_nlink--; 70530598Smckusick ip->i_flag |= ICHG; 70637737Smckusick } 70737737Smckusick return (error); 7089167Ssam } 7099167Ssam 7109167Ssam /* 7119167Ssam * Rename system call. 7129167Ssam * rename("foo", "bar"); 7139167Ssam * is essentially 7149167Ssam * unlink("bar"); 7159167Ssam * link("foo", "bar"); 7169167Ssam * unlink("foo"); 7179167Ssam * but ``atomically''. Can't do full commit without saving state in the 7189167Ssam * inode on disk which isn't feasible at this time. Best we can do is 7199167Ssam * always guarantee the target exists. 7209167Ssam * 7219167Ssam * Basic algorithm is: 7229167Ssam * 7239167Ssam * 1) Bump link count on source while we're linking it to the 72437737Smckusick * target. This also ensure the inode won't be deleted out 72516776Smckusick * from underneath us while we work (it may be truncated by 72616776Smckusick * a concurrent `trunc' or `open' for creation). 7279167Ssam * 2) Link source to destination. If destination already exists, 7289167Ssam * delete it first. 72916776Smckusick * 3) Unlink source reference to inode if still around. If a 73016776Smckusick * directory was moved and the parent of the destination 7319167Ssam * is different from the source, patch the ".." entry in the 7329167Ssam * directory. 7339167Ssam */ 734*51134Sbostic lfs_rename(fndp, tndp, p) 73537737Smckusick register struct nameidata *fndp, *tndp; 73648039Smckusick struct proc *p; 7377701Ssam { 7389167Ssam register struct inode *ip, *xp, *dp; 73916776Smckusick struct dirtemplate dirbuf; 74016776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 74110051Ssam int error = 0; 7427701Ssam 74349737Smckusick #ifdef DIANOSTIC 74449737Smckusick if ((tndp->ni_nameiop & HASBUF) == 0 || 74549737Smckusick (fndp->ni_nameiop & HASBUF) == 0) 74649737Smckusick panic("ufs_rename: no name"); 74749737Smckusick #endif 74837737Smckusick dp = VTOI(fndp->ni_dvp); 74937737Smckusick ip = VTOI(fndp->ni_vp); 75049737Smckusick /* 75149737Smckusick * Check if just deleting a link name. 75249737Smckusick */ 75349737Smckusick if (fndp->ni_vp == tndp->ni_vp) { 75449737Smckusick VOP_ABORTOP(tndp); 75549737Smckusick vput(tndp->ni_dvp); 75649737Smckusick vput(tndp->ni_vp); 75749737Smckusick vrele(fndp->ni_dvp); 75849737Smckusick if ((ip->i_mode&IFMT) == IFDIR) { 75949737Smckusick VOP_ABORTOP(fndp); 76049737Smckusick vrele(fndp->ni_vp); 76149737Smckusick return (EINVAL); 76249737Smckusick } 76349737Smckusick doingdirectory = 0; 76449737Smckusick goto unlinkit; 76549737Smckusick } 76637737Smckusick ILOCK(ip); 7679167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 7689167Ssam /* 76911641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 7709167Ssam */ 77149737Smckusick if ((fndp->ni_namelen == 1 && fndp->ni_ptr[0] == '.') || 77249737Smckusick dp == ip || fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { 77342466Smckusick VOP_ABORTOP(tndp); 77442466Smckusick vput(tndp->ni_dvp); 77542466Smckusick if (tndp->ni_vp) 77642466Smckusick vput(tndp->ni_vp); 77742466Smckusick VOP_ABORTOP(fndp); 77842466Smckusick vrele(fndp->ni_dvp); 77942466Smckusick vput(fndp->ni_vp); 78037737Smckusick return (EINVAL); 7819167Ssam } 78216776Smckusick ip->i_flag |= IRENAME; 7839167Ssam oldparent = dp->i_number; 7849167Ssam doingdirectory++; 7859167Ssam } 78637737Smckusick vrele(fndp->ni_dvp); 7879167Ssam 7889167Ssam /* 7899167Ssam * 1) Bump link count while we're moving stuff 7909167Ssam * around. If we crash somewhere before 7919167Ssam * completing our work, the link count 7929167Ssam * may be wrong, but correctable. 7939167Ssam */ 7949167Ssam ip->i_nlink++; 7959167Ssam ip->i_flag |= ICHG; 79637737Smckusick error = iupdat(ip, &time, &time, 1); 79716664Smckusick IUNLOCK(ip); 7989167Ssam 7999167Ssam /* 8009167Ssam * When the target exists, both the directory 80137737Smckusick * and target vnodes are returned locked. 8029167Ssam */ 80337737Smckusick dp = VTOI(tndp->ni_dvp); 80437737Smckusick xp = NULL; 80537737Smckusick if (tndp->ni_vp) 80637737Smckusick xp = VTOI(tndp->ni_vp); 8079167Ssam /* 80811641Ssam * If ".." must be changed (ie the directory gets a new 80912816Smckusick * parent) then the source directory must not be in the 81012816Smckusick * directory heirarchy above the target, as this would 81112816Smckusick * orphan everything below the source directory. Also 81212816Smckusick * the user must have write permission in the source so 81312816Smckusick * as to be able to change "..". We must repeat the call 81412816Smckusick * to namei, as the parent directory is unlocked by the 81512816Smckusick * call to checkpath(). 81611641Ssam */ 81716776Smckusick if (oldparent != dp->i_number) 81816776Smckusick newparent = dp->i_number; 81916776Smckusick if (doingdirectory && newparent) { 82041466Smckusick VOP_LOCK(fndp->ni_vp); 82148039Smckusick error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred, p); 82241466Smckusick VOP_UNLOCK(fndp->ni_vp); 82341466Smckusick if (error) 82412816Smckusick goto bad; 82549737Smckusick if (xp != NULL) 82649737Smckusick iput(xp); 82749737Smckusick if (error = checkpath(ip, dp, tndp->ni_cred)) 82849737Smckusick goto out; 82949737Smckusick if ((tndp->ni_nameiop & SAVESTART) == 0) 83049737Smckusick panic("ufs_rename: lost to startdir"); 83149737Smckusick if (error = lookup(tndp, p)) 83249737Smckusick goto out; 83349737Smckusick dp = VTOI(tndp->ni_dvp); 83449737Smckusick xp = NULL; 83549737Smckusick if (tndp->ni_vp) 83649737Smckusick xp = VTOI(tndp->ni_vp); 83712816Smckusick } 83811641Ssam /* 8399167Ssam * 2) If target doesn't exist, link the target 8409167Ssam * to the source and unlink the source. 8419167Ssam * Otherwise, rewrite the target directory 8429167Ssam * entry to reference the source inode and 8439167Ssam * expunge the original entry's existence. 8449167Ssam */ 8459167Ssam if (xp == NULL) { 84637737Smckusick if (dp->i_dev != ip->i_dev) 84737737Smckusick panic("rename: EXDEV"); 8489167Ssam /* 84916776Smckusick * Account for ".." in new directory. 85016776Smckusick * When source and destination have the same 85116776Smckusick * parent we don't fool with the link count. 8529167Ssam */ 85316776Smckusick if (doingdirectory && newparent) { 85446251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 85546251Smckusick error = EMLINK; 85646251Smckusick goto bad; 85746251Smckusick } 8589167Ssam dp->i_nlink++; 8599167Ssam dp->i_flag |= ICHG; 86046251Smckusick if (error = iupdat(dp, &time, &time, 1)) 86146251Smckusick goto bad; 8629167Ssam } 86347219Smckusick if (error = direnter(ip, tndp)) { 86447219Smckusick if (doingdirectory && newparent) { 86547219Smckusick dp->i_nlink--; 86647219Smckusick dp->i_flag |= ICHG; 86747219Smckusick (void) iupdat(dp, &time, &time, 1); 86847219Smckusick } 86947219Smckusick goto bad; 87047219Smckusick } 87147234Smckusick iput(dp); 8729167Ssam } else { 87337737Smckusick if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 87437737Smckusick panic("rename: EXDEV"); 8759167Ssam /* 87610590Ssam * Short circuit rename(foo, foo). 87710590Ssam */ 87810590Ssam if (xp->i_number == ip->i_number) 87937737Smckusick panic("rename: same file"); 88010590Ssam /* 88124433Sbloom * If the parent directory is "sticky", then the user must 88224433Sbloom * own the parent directory, or the destination of the rename, 88324433Sbloom * otherwise the destination may not be changed (except by 88424433Sbloom * root). This implements append-only directories. 88524433Sbloom */ 88637737Smckusick if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 && 88737737Smckusick tndp->ni_cred->cr_uid != dp->i_uid && 88837737Smckusick xp->i_uid != tndp->ni_cred->cr_uid) { 88924433Sbloom error = EPERM; 89024433Sbloom goto bad; 89124433Sbloom } 89224433Sbloom /* 89349737Smckusick * Target must be empty if a directory and have no links 89449737Smckusick * to it. Also, ensure source and target are compatible 89549737Smckusick * (both directories, or both not directories). 8969167Ssam */ 8979167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 89837737Smckusick if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 89937737Smckusick xp->i_nlink > 2) { 90010051Ssam error = ENOTEMPTY; 9019167Ssam goto bad; 9029167Ssam } 9039167Ssam if (!doingdirectory) { 90410051Ssam error = ENOTDIR; 9059167Ssam goto bad; 9069167Ssam } 90737737Smckusick cache_purge(ITOV(dp)); 9089167Ssam } else if (doingdirectory) { 90910051Ssam error = EISDIR; 9109167Ssam goto bad; 9119167Ssam } 91237737Smckusick if (error = dirrewrite(dp, ip, tndp)) 91337737Smckusick goto bad; 91445354Smckusick /* 91545354Smckusick * If the target directory is in the same 91645354Smckusick * directory as the source directory, 91745354Smckusick * decrement the link count on the parent 91845354Smckusick * of the target directory. 91945354Smckusick */ 92045354Smckusick if (doingdirectory && !newparent) { 92145354Smckusick dp->i_nlink--; 92245354Smckusick dp->i_flag |= ICHG; 92345354Smckusick } 92437737Smckusick vput(ITOV(dp)); 9259167Ssam /* 92610051Ssam * Adjust the link count of the target to 92710051Ssam * reflect the dirrewrite above. If this is 92810051Ssam * a directory it is empty and there are 92910051Ssam * no links to it, so we can squash the inode and 93010051Ssam * any space associated with it. We disallowed 93110051Ssam * renaming over top of a directory with links to 93216776Smckusick * it above, as the remaining link would point to 93316776Smckusick * a directory without "." or ".." entries. 9349167Ssam */ 93510051Ssam xp->i_nlink--; 9369167Ssam if (doingdirectory) { 93710051Ssam if (--xp->i_nlink != 0) 93810051Ssam panic("rename: linked directory"); 93939674Smckusick error = itrunc(xp, (u_long)0, IO_SYNC); 94010051Ssam } 9419167Ssam xp->i_flag |= ICHG; 94238398Smckusick iput(xp); 94310246Ssam xp = NULL; 9449167Ssam } 9459167Ssam 9469167Ssam /* 9479167Ssam * 3) Unlink the source. 9489167Ssam */ 94949737Smckusick unlinkit: 95049737Smckusick fndp->ni_nameiop &= ~MODMASK; 95149737Smckusick fndp->ni_nameiop |= LOCKPARENT | LOCKLEAF; 95249737Smckusick if ((fndp->ni_nameiop & SAVESTART) == 0) 95349737Smckusick panic("ufs_rename: lost from startdir"); 95449737Smckusick (void) lookup(fndp, p); 95537737Smckusick if (fndp->ni_vp != NULL) { 95637737Smckusick xp = VTOI(fndp->ni_vp); 95737737Smckusick dp = VTOI(fndp->ni_dvp); 95837737Smckusick } else { 95946250Smckusick /* 96046250Smckusick * From name has disappeared. 96146250Smckusick */ 96246250Smckusick if (doingdirectory) 96346250Smckusick panic("rename: lost dir entry"); 96446250Smckusick vrele(ITOV(ip)); 96546250Smckusick return (0); 96637737Smckusick } 9679167Ssam /* 96837737Smckusick * Ensure that the directory entry still exists and has not 96916776Smckusick * changed while the new name has been entered. If the source is 97016776Smckusick * a file then the entry may have been unlinked or renamed. In 97116776Smckusick * either case there is no further work to be done. If the source 97216776Smckusick * is a directory then it cannot have been rmdir'ed; its link 97316776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 97437737Smckusick * The IRENAME flag ensures that it cannot be moved by another 97516776Smckusick * rename. 9769167Ssam */ 97717758Smckusick if (xp != ip) { 97816776Smckusick if (doingdirectory) 97917758Smckusick panic("rename: lost dir entry"); 98016776Smckusick } else { 9819167Ssam /* 98216776Smckusick * If the source is a directory with a 98316776Smckusick * new parent, the link count of the old 98416776Smckusick * parent directory must be decremented 98516776Smckusick * and ".." set to point to the new parent. 9869167Ssam */ 98716776Smckusick if (doingdirectory && newparent) { 9889167Ssam dp->i_nlink--; 9899167Ssam dp->i_flag |= ICHG; 99039597Smckusick error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, 99137737Smckusick sizeof (struct dirtemplate), (off_t)0, 99239597Smckusick UIO_SYSSPACE, IO_NODELOCKED, 99348039Smckusick tndp->ni_cred, (int *)0, (struct proc *)0); 99416776Smckusick if (error == 0) { 99516776Smckusick if (dirbuf.dotdot_namlen != 2 || 99616776Smckusick dirbuf.dotdot_name[0] != '.' || 99716776Smckusick dirbuf.dotdot_name[1] != '.') { 99839610Smckusick dirbad(xp, 12, "rename: mangled dir"); 99916776Smckusick } else { 100016776Smckusick dirbuf.dotdot_ino = newparent; 100139597Smckusick (void) vn_rdwr(UIO_WRITE, ITOV(xp), 100216776Smckusick (caddr_t)&dirbuf, 100316776Smckusick sizeof (struct dirtemplate), 100437740Smckusick (off_t)0, UIO_SYSSPACE, 100539597Smckusick IO_NODELOCKED|IO_SYNC, 100648039Smckusick tndp->ni_cred, (int *)0, 100748039Smckusick (struct proc *)0); 100837737Smckusick cache_purge(ITOV(dp)); 100916776Smckusick } 101016776Smckusick } 10119167Ssam } 101237737Smckusick error = dirremove(fndp); 101337737Smckusick if (!error) { 101416776Smckusick xp->i_nlink--; 101516776Smckusick xp->i_flag |= ICHG; 10169167Ssam } 101716776Smckusick xp->i_flag &= ~IRENAME; 10189167Ssam } 10199167Ssam if (dp) 102037737Smckusick vput(ITOV(dp)); 102116776Smckusick if (xp) 102237737Smckusick vput(ITOV(xp)); 102337737Smckusick vrele(ITOV(ip)); 102437737Smckusick return (error); 10259167Ssam 10269167Ssam bad: 10279167Ssam if (xp) 102837737Smckusick vput(ITOV(xp)); 102937737Smckusick vput(ITOV(dp)); 10309167Ssam out: 10319167Ssam ip->i_nlink--; 10329167Ssam ip->i_flag |= ICHG; 103337737Smckusick vrele(ITOV(ip)); 103437737Smckusick return (error); 10357701Ssam } 10367701Ssam 10377535Sroot /* 103812756Ssam * A virgin directory (no blushing please). 103912756Ssam */ 104012756Ssam struct dirtemplate mastertemplate = { 104112756Ssam 0, 12, 1, ".", 104212756Ssam 0, DIRBLKSIZ - 12, 2, ".." 104312756Ssam }; 104412756Ssam 104512756Ssam /* 104612756Ssam * Mkdir system call 104712756Ssam */ 1048*51134Sbostic lfs_mkdir(ndp, vap, p) 104937737Smckusick struct nameidata *ndp; 105037737Smckusick struct vattr *vap; 105148039Smckusick struct proc *p; 105212756Ssam { 105312756Ssam register struct inode *ip, *dp; 105437737Smckusick struct inode *tip; 105537737Smckusick struct vnode *dvp; 105612756Ssam struct dirtemplate dirtemplate; 105737737Smckusick int error; 105837737Smckusick int dmode; 105912756Ssam 106049737Smckusick #ifdef DIANOSTIC 106149737Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) 106249737Smckusick panic("ufs_mkdir: no name"); 106349737Smckusick #endif 106437737Smckusick dvp = ndp->ni_dvp; 106537737Smckusick dp = VTOI(dvp); 106646251Smckusick if ((unsigned short)dp->i_nlink >= LINK_MAX) { 106749737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 106846251Smckusick iput(dp); 106946251Smckusick return (EMLINK); 107046251Smckusick } 107137737Smckusick dmode = vap->va_mode&0777; 107237737Smckusick dmode |= IFDIR; 107312756Ssam /* 107449737Smckusick * Must simulate part of maknode here to acquire the inode, but 107549737Smckusick * not have it entered in the parent directory. The entry is made 107649737Smckusick * later after writing "." and ".." entries. 107712756Ssam */ 107841312Smckusick if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) { 107949737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 108012756Ssam iput(dp); 108137737Smckusick return (error); 108212756Ssam } 108337737Smckusick ip = tip; 108441312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 108541312Smckusick ip->i_gid = dp->i_gid; 108612756Ssam #ifdef QUOTA 108741312Smckusick if ((error = getinoquota(ip)) || 108841312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 108949737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 109041312Smckusick ifree(ip, ip->i_number, dmode); 109141312Smckusick iput(ip); 109241312Smckusick iput(dp); 109341312Smckusick return (error); 109441312Smckusick } 109512756Ssam #endif 109612756Ssam ip->i_flag |= IACC|IUPD|ICHG; 109737737Smckusick ip->i_mode = dmode; 109837737Smckusick ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */ 109912756Ssam ip->i_nlink = 2; 110037737Smckusick error = iupdat(ip, &time, &time, 1); 110112756Ssam 110212756Ssam /* 110312756Ssam * Bump link count in parent directory 110412756Ssam * to reflect work done below. Should 110512756Ssam * be done before reference is created 110612756Ssam * so reparation is possible if we crash. 110712756Ssam */ 110812756Ssam dp->i_nlink++; 110912756Ssam dp->i_flag |= ICHG; 111047219Smckusick if (error = iupdat(dp, &time, &time, 1)) 111147219Smckusick goto bad; 111212756Ssam 111312756Ssam /* 111412756Ssam * Initialize directory with "." 111512756Ssam * and ".." from static template. 111612756Ssam */ 111712756Ssam dirtemplate = mastertemplate; 111812756Ssam dirtemplate.dot_ino = ip->i_number; 111912756Ssam dirtemplate.dotdot_ino = dp->i_number; 112039597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, 112148039Smckusick sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 112248039Smckusick IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0, (struct proc *)0); 112337737Smckusick if (error) { 112412756Ssam dp->i_nlink--; 112512756Ssam dp->i_flag |= ICHG; 112612756Ssam goto bad; 112712756Ssam } 112843288Smckusick if (DIRBLKSIZ > dp->i_fs->fs_fsize) { 112937737Smckusick panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ 113043288Smckusick } else { 113118103Smckusick ip->i_size = DIRBLKSIZ; 113243288Smckusick ip->i_flag |= ICHG; 113343288Smckusick } 113412756Ssam /* 113512756Ssam * Directory all set up, now 113612756Ssam * install the entry for it in 113712756Ssam * the parent directory. 113812756Ssam */ 113947219Smckusick if (error = direnter(ip, ndp)) { 114047657Smckusick dp->i_nlink--; 114147657Smckusick dp->i_flag |= ICHG; 114212756Ssam } 114312756Ssam bad: 114412756Ssam /* 114512756Ssam * No need to do an explicit itrunc here, 114637737Smckusick * vrele will do this for us because we set 114712756Ssam * the link count to 0. 114812756Ssam */ 114937737Smckusick if (error) { 115012756Ssam ip->i_nlink = 0; 115112756Ssam ip->i_flag |= ICHG; 115238144Smckusick iput(ip); 115338144Smckusick } else 115438144Smckusick ndp->ni_vp = ITOV(ip); 115549737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 115647219Smckusick iput(dp); 115737737Smckusick return (error); 115812756Ssam } 115912756Ssam 116012756Ssam /* 116112756Ssam * Rmdir system call. 116212756Ssam */ 1163*51134Sbostic lfs_rmdir(ndp, p) 116437737Smckusick register struct nameidata *ndp; 116548039Smckusick struct proc *p; 116612756Ssam { 116712756Ssam register struct inode *ip, *dp; 116837737Smckusick int error = 0; 116912756Ssam 117037737Smckusick ip = VTOI(ndp->ni_vp); 117137737Smckusick dp = VTOI(ndp->ni_dvp); 117212756Ssam /* 117312756Ssam * No rmdir "." please. 117412756Ssam */ 117512756Ssam if (dp == ip) { 117637737Smckusick vrele(ITOV(dp)); 117712756Ssam iput(ip); 117837737Smckusick return (EINVAL); 117912756Ssam } 118012756Ssam /* 118112756Ssam * Verify the directory is empty (and valid). 118212756Ssam * (Rmdir ".." won't be valid since 118312756Ssam * ".." will contain a reference to 118412756Ssam * the current directory and thus be 118512756Ssam * non-empty.) 118612756Ssam */ 118737737Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) { 118837737Smckusick error = ENOTEMPTY; 118912756Ssam goto out; 119012756Ssam } 119112756Ssam /* 119212756Ssam * Delete reference to directory before purging 119312756Ssam * inode. If we crash in between, the directory 119412756Ssam * will be reattached to lost+found, 119512756Ssam */ 119637737Smckusick if (error = dirremove(ndp)) 119712756Ssam goto out; 119812756Ssam dp->i_nlink--; 119912756Ssam dp->i_flag |= ICHG; 120037737Smckusick cache_purge(ITOV(dp)); 120112756Ssam iput(dp); 120237737Smckusick ndp->ni_dvp = NULL; 120312756Ssam /* 120412756Ssam * Truncate inode. The only stuff left 120512756Ssam * in the directory is "." and "..". The 120612756Ssam * "." reference is inconsequential since 120712756Ssam * we're quashing it. The ".." reference 120812756Ssam * has already been adjusted above. We've 120912756Ssam * removed the "." reference and the reference 121012756Ssam * in the parent directory, but there may be 121112756Ssam * other hard links so decrement by 2 and 121212756Ssam * worry about them later. 121312756Ssam */ 121412756Ssam ip->i_nlink -= 2; 121539674Smckusick error = itrunc(ip, (u_long)0, IO_SYNC); 121637737Smckusick cache_purge(ITOV(ip)); 121712756Ssam out: 121837737Smckusick if (ndp->ni_dvp) 121912756Ssam iput(dp); 122012756Ssam iput(ip); 122137737Smckusick return (error); 122212756Ssam } 122312756Ssam 122437737Smckusick /* 122537737Smckusick * symlink -- make a symbolic link 122637737Smckusick */ 1227*51134Sbostic lfs_symlink(ndp, vap, target, p) 122837737Smckusick struct nameidata *ndp; 122937737Smckusick struct vattr *vap; 123037737Smckusick char *target; 123148039Smckusick struct proc *p; 123212756Ssam { 123337737Smckusick struct inode *ip; 123437737Smckusick int error; 123512756Ssam 123637737Smckusick error = maknode(IFLNK | vap->va_mode, ndp, &ip); 123737737Smckusick if (error) 123837737Smckusick return (error); 123939597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, 124048039Smckusick UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0, 124148039Smckusick (struct proc *)0); 124237737Smckusick iput(ip); 124337737Smckusick return (error); 124437737Smckusick } 124537737Smckusick 124637737Smckusick /* 124737737Smckusick * Vnode op for read and write 124837737Smckusick */ 1249*51134Sbostic lfs_readdir(vp, uio, cred, eofflagp) 125037737Smckusick struct vnode *vp; 125137737Smckusick register struct uio *uio; 125237737Smckusick struct ucred *cred; 125340345Smckusick int *eofflagp; 125437737Smckusick { 125539597Smckusick int count, lost, error; 125637737Smckusick 125737737Smckusick count = uio->uio_resid; 125837737Smckusick count &= ~(DIRBLKSIZ - 1); 125939597Smckusick lost = uio->uio_resid - count; 126039597Smckusick if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) 126137737Smckusick return (EINVAL); 126237737Smckusick uio->uio_resid = count; 126337737Smckusick uio->uio_iov->iov_len = count; 126439597Smckusick error = ufs_read(vp, uio, 0, cred); 126539597Smckusick uio->uio_resid += lost; 126640345Smckusick if ((VTOI(vp)->i_size - uio->uio_offset) <= 0) 126740345Smckusick *eofflagp = 1; 126840345Smckusick else 126940345Smckusick *eofflagp = 0; 127037737Smckusick return (error); 127137737Smckusick } 127237737Smckusick 127337737Smckusick /* 127437737Smckusick * Return target name of a symbolic link 127537737Smckusick */ 1276*51134Sbostic lfs_readlink(vp, uiop, cred) 127737737Smckusick struct vnode *vp; 127837737Smckusick struct uio *uiop; 127937737Smckusick struct ucred *cred; 128037737Smckusick { 128137737Smckusick 128239597Smckusick return (ufs_read(vp, uiop, 0, cred)); 128337737Smckusick } 128437737Smckusick 128537737Smckusick /* 128637737Smckusick * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 128749737Smckusick * done. If a buffer has been saved in anticipation of a CREATE, delete it. 128837737Smckusick */ 128942466Smckusick /* ARGSUSED */ 1290*51134Sbostic lfs_abortop(ndp) 129142466Smckusick struct nameidata *ndp; 129237737Smckusick { 129337737Smckusick 129449737Smckusick if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF) 129549737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 129642466Smckusick return (0); 129712756Ssam } 129812756Ssam 129939909Smckusick /* 130039909Smckusick * Lock an inode. 130139909Smckusick */ 1302*51134Sbostic lfs_lock(vp) 130337737Smckusick struct vnode *vp; 130437737Smckusick { 130537737Smckusick register struct inode *ip = VTOI(vp); 130637737Smckusick 130737737Smckusick ILOCK(ip); 130837737Smckusick return (0); 130937737Smckusick } 131037737Smckusick 131139909Smckusick /* 131239909Smckusick * Unlock an inode. 131339909Smckusick */ 1314*51134Sbostic lfs_unlock(vp) 131537737Smckusick struct vnode *vp; 131637737Smckusick { 131737737Smckusick register struct inode *ip = VTOI(vp); 131837737Smckusick 131937737Smckusick if (!(ip->i_flag & ILOCKED)) 132037737Smckusick panic("ufs_unlock NOT LOCKED"); 132137737Smckusick IUNLOCK(ip); 132237737Smckusick return (0); 132337737Smckusick } 132437737Smckusick 132512756Ssam /* 132639909Smckusick * Check for a locked inode. 132739909Smckusick */ 1328*51134Sbostic lfs_islocked(vp) 132939909Smckusick struct vnode *vp; 133039909Smckusick { 133139909Smckusick 133239909Smckusick if (VTOI(vp)->i_flag & ILOCKED) 133339909Smckusick return (1); 133439909Smckusick return (0); 133539909Smckusick } 133639909Smckusick 133739909Smckusick /* 133837737Smckusick * Get access to bmap 133912756Ssam */ 1340*51134Sbostic lfs_bmap(vp, bn, vpp, bnp) 134137737Smckusick struct vnode *vp; 134237737Smckusick daddr_t bn; 134337737Smckusick struct vnode **vpp; 134437737Smckusick daddr_t *bnp; 134512756Ssam { 134637737Smckusick struct inode *ip = VTOI(vp); 134712756Ssam 134837737Smckusick if (vpp != NULL) 134937737Smckusick *vpp = ip->i_devvp; 135037737Smckusick if (bnp == NULL) 135137737Smckusick return (0); 135241538Smckusick return (bmap(ip, bn, bnp)); 135312756Ssam } 135437737Smckusick 135537737Smckusick /* 135641538Smckusick * Calculate the logical to physical mapping if not done already, 135741538Smckusick * then call the device strategy routine. 135837737Smckusick */ 135941538Smckusick int checkoverlap = 0; 136039674Smckusick 1361*51134Sbostic lfs_strategy(bp) 136237737Smckusick register struct buf *bp; 136337737Smckusick { 136439674Smckusick register struct inode *ip = VTOI(bp->b_vp); 136539674Smckusick struct vnode *vp; 136639674Smckusick int error; 136739674Smckusick 136839674Smckusick if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR) 136939674Smckusick panic("ufs_strategy: spec"); 137039674Smckusick if (bp->b_blkno == bp->b_lblkno) { 137139674Smckusick if (error = bmap(ip, bp->b_lblkno, &bp->b_blkno)) 137239674Smckusick return (error); 137339896Smckusick if ((long)bp->b_blkno == -1) 137439674Smckusick clrbuf(bp); 137539674Smckusick } 137639896Smckusick if ((long)bp->b_blkno == -1) { 137739896Smckusick biodone(bp); 137839674Smckusick return (0); 137939896Smckusick } 138041538Smckusick #ifdef DIAGNOSTIC 138139674Smckusick if (checkoverlap) { 138241538Smckusick register struct buf *ep; 138341538Smckusick struct buf *ebp; 138441538Smckusick daddr_t start, last; 138541538Smckusick 138639674Smckusick ebp = &buf[nbuf]; 138739674Smckusick start = bp->b_blkno; 138839674Smckusick last = start + btodb(bp->b_bcount) - 1; 138939674Smckusick for (ep = buf; ep < ebp; ep++) { 139039674Smckusick if (ep == bp || (ep->b_flags & B_INVAL) || 139141396Smckusick ep->b_vp == NULLVP) 139239674Smckusick continue; 139339674Smckusick if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0)) 139439674Smckusick continue; 139539674Smckusick if (vp != ip->i_devvp) 139639674Smckusick continue; 139739674Smckusick /* look for overlap */ 139839674Smckusick if (ep->b_bcount == 0 || ep->b_blkno > last || 139939674Smckusick ep->b_blkno + btodb(ep->b_bcount) <= start) 140039674Smckusick continue; 140139896Smckusick vprint("Disk overlap", vp); 140239896Smckusick printf("\tstart %d, end %d overlap start %d, end %d\n", 140339896Smckusick start, last, ep->b_blkno, 140439896Smckusick ep->b_blkno + btodb(ep->b_bcount) - 1); 140541538Smckusick panic("Disk buffer overlap"); 140639674Smckusick } 140739674Smckusick } 140841538Smckusick #endif /* DIAGNOSTIC */ 140939674Smckusick vp = ip->i_devvp; 141039674Smckusick bp->b_dev = vp->v_rdev; 141149762Smckusick (*(vp->v_op->vop_strategy))(bp); 141237737Smckusick return (0); 141337737Smckusick } 141437737Smckusick 141537737Smckusick /* 141639674Smckusick * Print out the contents of an inode. 141739674Smckusick */ 1418*51134Sbostic lfs_print(vp) 141939674Smckusick struct vnode *vp; 142039674Smckusick { 142139674Smckusick register struct inode *ip = VTOI(vp); 142239674Smckusick 142340293Smckusick printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number, 142440293Smckusick major(ip->i_dev), minor(ip->i_dev)); 142540293Smckusick #ifdef FIFO 142640293Smckusick if (vp->v_type == VFIFO) 142740293Smckusick fifo_printinfo(vp); 142840293Smckusick #endif /* FIFO */ 142940293Smckusick printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : ""); 143039900Smckusick if (ip->i_spare0 == 0) 143139900Smckusick return; 143239900Smckusick printf("\towner pid %d", ip->i_spare0); 143339900Smckusick if (ip->i_spare1) 143439900Smckusick printf(" waiting pid %d", ip->i_spare1); 143539900Smckusick printf("\n"); 143639674Smckusick } 143739674Smckusick 143839674Smckusick /* 143949452Smckusick * Allocate a new inode. 144037737Smckusick */ 1441*51134Sbostic static int 144237737Smckusick maknode(mode, ndp, ipp) 144337737Smckusick int mode; 144437737Smckusick register struct nameidata *ndp; 144537737Smckusick struct inode **ipp; 144637737Smckusick { 144737737Smckusick register struct inode *ip; 144837737Smckusick struct inode *tip; 144937737Smckusick register struct inode *pdir = VTOI(ndp->ni_dvp); 145037737Smckusick ino_t ipref; 145137737Smckusick int error; 145237737Smckusick 145349737Smckusick #ifdef DIANOSTIC 145449737Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) 145549737Smckusick panic("maknode: no name"); 145649737Smckusick #endif 145737737Smckusick *ipp = 0; 145841312Smckusick if ((mode & IFMT) == 0) 145941312Smckusick mode |= IFREG; 146037737Smckusick if ((mode & IFMT) == IFDIR) 146137737Smckusick ipref = dirpref(pdir->i_fs); 146237737Smckusick else 146337737Smckusick ipref = pdir->i_number; 146441312Smckusick if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) { 146549737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 146637737Smckusick iput(pdir); 146737737Smckusick return (error); 146837737Smckusick } 146937737Smckusick ip = tip; 147041312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 147141312Smckusick ip->i_gid = pdir->i_gid; 147237737Smckusick #ifdef QUOTA 147341312Smckusick if ((error = getinoquota(ip)) || 147441312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 147549737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 147641312Smckusick ifree(ip, ip->i_number, mode); 147741312Smckusick iput(ip); 147841312Smckusick iput(pdir); 147941312Smckusick return (error); 148041312Smckusick } 148137737Smckusick #endif 148237737Smckusick ip->i_flag |= IACC|IUPD|ICHG; 148337737Smckusick ip->i_mode = mode; 148437737Smckusick ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */ 148537737Smckusick ip->i_nlink = 1; 148637737Smckusick if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) && 148737737Smckusick suser(ndp->ni_cred, NULL)) 148837737Smckusick ip->i_mode &= ~ISGID; 148937737Smckusick 149037737Smckusick /* 149137737Smckusick * Make sure inode goes to disk before directory entry. 149237737Smckusick */ 149341312Smckusick if (error = iupdat(ip, &time, &time, 1)) 149441312Smckusick goto bad; 149547219Smckusick if (error = direnter(ip, ndp)) 149641312Smckusick goto bad; 149749737Smckusick if ((ndp->ni_nameiop & SAVESTART) == 0) 149849737Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 149947219Smckusick iput(pdir); 150037737Smckusick *ipp = ip; 150137737Smckusick return (0); 150241312Smckusick 150341312Smckusick bad: 150441312Smckusick /* 150541312Smckusick * Write error occurred trying to update the inode 150641312Smckusick * or the directory so must deallocate the inode. 150741312Smckusick */ 150849737Smckusick free(ndp->ni_pnbuf, M_NAMEI); 150947219Smckusick iput(pdir); 151041312Smckusick ip->i_nlink = 0; 151141312Smckusick ip->i_flag |= ICHG; 151241312Smckusick iput(ip); 151341312Smckusick return (error); 151437737Smckusick } 151546207Smckusick 151646207Smckusick /* 151746207Smckusick * Advisory record locking support 151846207Smckusick */ 1519*51134Sbostic lfs_advlock(vp, id, op, fl, flags) 152046207Smckusick struct vnode *vp; 152146207Smckusick caddr_t id; 152246207Smckusick int op; 152346207Smckusick register struct flock *fl; 152446207Smckusick int flags; 152546207Smckusick { 152646207Smckusick register struct inode *ip = VTOI(vp); 152746207Smckusick register struct lockf *lock; 152846207Smckusick off_t start, end; 152946207Smckusick int error; 153046207Smckusick 153146207Smckusick /* 153246207Smckusick * Avoid the common case of unlocking when inode has no locks. 153346207Smckusick */ 153446207Smckusick if (ip->i_lockf == (struct lockf *)0) { 153546207Smckusick if (op != F_SETLK) { 153646207Smckusick fl->l_type = F_UNLCK; 153746207Smckusick return (0); 153846207Smckusick } 153946207Smckusick } 154046207Smckusick /* 154146207Smckusick * Convert the flock structure into a start and end. 154246207Smckusick */ 154346207Smckusick switch (fl->l_whence) { 154446207Smckusick 154546207Smckusick case SEEK_SET: 154646207Smckusick case SEEK_CUR: 154746207Smckusick /* 154846207Smckusick * Caller is responsible for adding any necessary offset 154946207Smckusick * when SEEK_CUR is used. 155046207Smckusick */ 155146207Smckusick start = fl->l_start; 155246207Smckusick break; 155346207Smckusick 155446207Smckusick case SEEK_END: 155546207Smckusick start = ip->i_size + fl->l_start; 155646207Smckusick break; 155746207Smckusick 155846207Smckusick default: 155946207Smckusick return (EINVAL); 156046207Smckusick } 156146207Smckusick if (start < 0) 156246207Smckusick return (EINVAL); 156346207Smckusick if (fl->l_len == 0) 156446207Smckusick end = -1; 156546207Smckusick else 156646507Smckusick end = start + fl->l_len - 1; 156746207Smckusick /* 156846207Smckusick * Create the lockf structure 156946207Smckusick */ 157046207Smckusick MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK); 157146207Smckusick lock->lf_start = start; 157246207Smckusick lock->lf_end = end; 157346207Smckusick lock->lf_id = id; 157446207Smckusick lock->lf_inode = ip; 157546207Smckusick lock->lf_type = fl->l_type; 157646207Smckusick lock->lf_next = (struct lockf *)0; 157746207Smckusick lock->lf_block = (struct lockf *)0; 157846207Smckusick lock->lf_flags = flags; 157946207Smckusick /* 158046207Smckusick * Do the requested operation. 158146207Smckusick */ 158246207Smckusick switch(op) { 158346207Smckusick case F_SETLK: 158446679Smckusick return (lf_setlock(lock)); 158546207Smckusick 158646207Smckusick case F_UNLCK: 158746679Smckusick error = lf_clearlock(lock); 158846679Smckusick FREE(lock, M_LOCKF); 158946679Smckusick return (error); 159046207Smckusick 159146207Smckusick case F_GETLK: 159246679Smckusick error = lf_getlock(lock, fl); 159346679Smckusick FREE(lock, M_LOCKF); 159446679Smckusick return (error); 159546207Smckusick 159646207Smckusick default: 159746207Smckusick free(lock, M_LOCKF); 159846207Smckusick return (EINVAL); 159946207Smckusick } 160046207Smckusick /* NOTREACHED */ 160146207Smckusick } 160248039Smckusick 160348039Smckusick /* 1604*51134Sbostic * Global vfs data structures for lfs 160548039Smckusick */ 1606*51134Sbostic struct vnodeops lfs_vnodeops = { 160748039Smckusick ufs_lookup, /* lookup */ 160848039Smckusick ufs_create, /* create */ 160948039Smckusick ufs_mknod, /* mknod */ 161048039Smckusick ufs_open, /* open */ 161148039Smckusick ufs_close, /* close */ 161248039Smckusick ufs_access, /* access */ 161348039Smckusick ufs_getattr, /* getattr */ 161448039Smckusick ufs_setattr, /* setattr */ 161548039Smckusick ufs_read, /* read */ 161648039Smckusick ufs_write, /* write */ 161748039Smckusick ufs_ioctl, /* ioctl */ 161848039Smckusick ufs_select, /* select */ 161948039Smckusick ufs_mmap, /* mmap */ 162048039Smckusick ufs_fsync, /* fsync */ 162148039Smckusick ufs_seek, /* seek */ 162248039Smckusick ufs_remove, /* remove */ 162348039Smckusick ufs_link, /* link */ 162448039Smckusick ufs_rename, /* rename */ 162548039Smckusick ufs_mkdir, /* mkdir */ 162648039Smckusick ufs_rmdir, /* rmdir */ 162748039Smckusick ufs_symlink, /* symlink */ 162848039Smckusick ufs_readdir, /* readdir */ 162948039Smckusick ufs_readlink, /* readlink */ 163048039Smckusick ufs_abortop, /* abortop */ 163148039Smckusick ufs_inactive, /* inactive */ 163248039Smckusick ufs_reclaim, /* reclaim */ 163348039Smckusick ufs_lock, /* lock */ 163448039Smckusick ufs_unlock, /* unlock */ 163548039Smckusick ufs_bmap, /* bmap */ 163648039Smckusick ufs_strategy, /* strategy */ 163748039Smckusick ufs_print, /* print */ 163848039Smckusick ufs_islocked, /* islocked */ 163948039Smckusick ufs_advlock, /* advlock */ 164048039Smckusick }; 1641