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*46207Smckusick * @(#)lfs_vnops.c 7.50 (Berkeley) 02/01/91 823405Smckusick */ 937Sbill 1017101Sbloom #include "param.h" 1117101Sbloom #include "systm.h" 1217101Sbloom #include "user.h" 1317101Sbloom #include "kernel.h" 1417101Sbloom #include "file.h" 1517101Sbloom #include "stat.h" 1617101Sbloom #include "buf.h" 1717101Sbloom #include "proc.h" 1817101Sbloom #include "socket.h" 1917101Sbloom #include "socketvar.h" 2037737Smckusick #include "conf.h" 2117101Sbloom #include "mount.h" 2237737Smckusick #include "vnode.h" 2340653Smckusick #include "specdev.h" 24*46207Smckusick #include "fcntl.h" 25*46207Smckusick #include "malloc.h" 26*46207Smckusick #include "../ufs/lockf.h" 2741312Smckusick #include "../ufs/quota.h" 2837737Smckusick #include "../ufs/inode.h" 2937737Smckusick #include "../ufs/fs.h" 3037Sbill 319167Ssam /* 3237737Smckusick * Global vfs data structures for ufs 339167Ssam */ 346254Sroot 3537737Smckusick int ufs_lookup(), 3637737Smckusick ufs_create(), 3737737Smckusick ufs_mknod(), 3837737Smckusick ufs_open(), 3937737Smckusick ufs_close(), 4037737Smckusick ufs_access(), 4137737Smckusick ufs_getattr(), 4237737Smckusick ufs_setattr(), 4337737Smckusick ufs_read(), 4437737Smckusick ufs_write(), 4537737Smckusick ufs_ioctl(), 4637737Smckusick ufs_select(), 4737737Smckusick ufs_mmap(), 4837737Smckusick ufs_fsync(), 4937737Smckusick ufs_seek(), 5037737Smckusick ufs_remove(), 5137737Smckusick ufs_link(), 5237737Smckusick ufs_rename(), 5337737Smckusick ufs_mkdir(), 5437737Smckusick ufs_rmdir(), 5537737Smckusick ufs_symlink(), 5637737Smckusick ufs_readdir(), 5737737Smckusick ufs_readlink(), 5837737Smckusick ufs_abortop(), 5937737Smckusick ufs_inactive(), 6039391Smckusick ufs_reclaim(), 6137737Smckusick ufs_lock(), 6237737Smckusick ufs_unlock(), 6337737Smckusick ufs_bmap(), 6439674Smckusick ufs_strategy(), 6539909Smckusick ufs_print(), 66*46207Smckusick ufs_islocked(), 67*46207Smckusick ufs_advlock(); 686254Sroot 6937737Smckusick struct vnodeops ufs_vnodeops = { 7039674Smckusick ufs_lookup, /* lookup */ 7139674Smckusick ufs_create, /* create */ 7239674Smckusick ufs_mknod, /* mknod */ 7339674Smckusick ufs_open, /* open */ 7439674Smckusick ufs_close, /* close */ 7539674Smckusick ufs_access, /* access */ 7639674Smckusick ufs_getattr, /* getattr */ 7739674Smckusick ufs_setattr, /* setattr */ 7839674Smckusick ufs_read, /* read */ 7939674Smckusick ufs_write, /* write */ 8039674Smckusick ufs_ioctl, /* ioctl */ 8139674Smckusick ufs_select, /* select */ 8239674Smckusick ufs_mmap, /* mmap */ 8339674Smckusick ufs_fsync, /* fsync */ 8439674Smckusick ufs_seek, /* seek */ 8539674Smckusick ufs_remove, /* remove */ 8639674Smckusick ufs_link, /* link */ 8739674Smckusick ufs_rename, /* rename */ 8839674Smckusick ufs_mkdir, /* mkdir */ 8939674Smckusick ufs_rmdir, /* rmdir */ 9039674Smckusick ufs_symlink, /* symlink */ 9139674Smckusick ufs_readdir, /* readdir */ 9239674Smckusick ufs_readlink, /* readlink */ 9339674Smckusick ufs_abortop, /* abortop */ 9439674Smckusick ufs_inactive, /* inactive */ 9539674Smckusick ufs_reclaim, /* reclaim */ 9639674Smckusick ufs_lock, /* lock */ 9739674Smckusick ufs_unlock, /* unlock */ 9839674Smckusick ufs_bmap, /* bmap */ 9939674Smckusick ufs_strategy, /* strategy */ 10039674Smckusick ufs_print, /* print */ 10139909Smckusick ufs_islocked, /* islocked */ 102*46207Smckusick ufs_advlock, /* advlock */ 10337737Smckusick }; 1046254Sroot 10539435Smckusick int spec_lookup(), 10639435Smckusick spec_open(), 10739628Smckusick ufsspec_read(), 10839628Smckusick ufsspec_write(), 10939435Smckusick spec_strategy(), 11039674Smckusick spec_bmap(), 11139435Smckusick spec_ioctl(), 11239435Smckusick spec_select(), 11339628Smckusick ufsspec_close(), 114*46207Smckusick spec_advlock(), 11539435Smckusick spec_badop(), 11639435Smckusick spec_nullop(); 11739435Smckusick 11839435Smckusick struct vnodeops spec_inodeops = { 11939597Smckusick spec_lookup, /* lookup */ 12039597Smckusick spec_badop, /* create */ 12139597Smckusick spec_badop, /* mknod */ 12239597Smckusick spec_open, /* open */ 12339628Smckusick ufsspec_close, /* close */ 12439597Smckusick ufs_access, /* access */ 12539597Smckusick ufs_getattr, /* getattr */ 12639597Smckusick ufs_setattr, /* setattr */ 12739628Smckusick ufsspec_read, /* read */ 12839628Smckusick ufsspec_write, /* write */ 12939597Smckusick spec_ioctl, /* ioctl */ 13039597Smckusick spec_select, /* select */ 13139597Smckusick spec_badop, /* mmap */ 13239597Smckusick spec_nullop, /* fsync */ 13339597Smckusick spec_badop, /* seek */ 13439597Smckusick spec_badop, /* remove */ 13539597Smckusick spec_badop, /* link */ 13639597Smckusick spec_badop, /* rename */ 13739597Smckusick spec_badop, /* mkdir */ 13839597Smckusick spec_badop, /* rmdir */ 13939597Smckusick spec_badop, /* symlink */ 14039597Smckusick spec_badop, /* readdir */ 14139597Smckusick spec_badop, /* readlink */ 14239597Smckusick spec_badop, /* abortop */ 14339597Smckusick ufs_inactive, /* inactive */ 14439597Smckusick ufs_reclaim, /* reclaim */ 14539597Smckusick ufs_lock, /* lock */ 14639597Smckusick ufs_unlock, /* unlock */ 14739674Smckusick spec_bmap, /* bmap */ 14839597Smckusick spec_strategy, /* strategy */ 14939674Smckusick ufs_print, /* print */ 15039909Smckusick ufs_islocked, /* islocked */ 151*46207Smckusick spec_advlock, /* advlock */ 15239435Smckusick }; 15339435Smckusick 15440290Smckusick #ifdef FIFO 15540290Smckusick int fifo_lookup(), 15640290Smckusick fifo_open(), 15740290Smckusick ufsfifo_read(), 15840290Smckusick ufsfifo_write(), 15940290Smckusick fifo_bmap(), 16040290Smckusick fifo_ioctl(), 16140290Smckusick fifo_select(), 16240290Smckusick ufsfifo_close(), 16340290Smckusick fifo_print(), 164*46207Smckusick fifo_advlock(), 16540290Smckusick fifo_badop(), 16640290Smckusick fifo_nullop(); 16740290Smckusick 16840290Smckusick struct vnodeops fifo_inodeops = { 16940290Smckusick fifo_lookup, /* lookup */ 17040290Smckusick fifo_badop, /* create */ 17140290Smckusick fifo_badop, /* mknod */ 17240290Smckusick fifo_open, /* open */ 17340290Smckusick ufsfifo_close, /* close */ 17440290Smckusick ufs_access, /* access */ 17540290Smckusick ufs_getattr, /* getattr */ 17640290Smckusick ufs_setattr, /* setattr */ 17740290Smckusick ufsfifo_read, /* read */ 17840290Smckusick ufsfifo_write, /* write */ 17940290Smckusick fifo_ioctl, /* ioctl */ 18040290Smckusick fifo_select, /* select */ 18140290Smckusick fifo_badop, /* mmap */ 18240290Smckusick fifo_nullop, /* fsync */ 18340290Smckusick fifo_badop, /* seek */ 18440290Smckusick fifo_badop, /* remove */ 18540290Smckusick fifo_badop, /* link */ 18640290Smckusick fifo_badop, /* rename */ 18740290Smckusick fifo_badop, /* mkdir */ 18840290Smckusick fifo_badop, /* rmdir */ 18940290Smckusick fifo_badop, /* symlink */ 19040290Smckusick fifo_badop, /* readdir */ 19140290Smckusick fifo_badop, /* readlink */ 19240290Smckusick fifo_badop, /* abortop */ 19340290Smckusick ufs_inactive, /* inactive */ 19440290Smckusick ufs_reclaim, /* reclaim */ 19540290Smckusick ufs_lock, /* lock */ 19640290Smckusick ufs_unlock, /* unlock */ 19740290Smckusick fifo_bmap, /* bmap */ 19840290Smckusick fifo_badop, /* strategy */ 19940290Smckusick ufs_print, /* print */ 20040290Smckusick ufs_islocked, /* islocked */ 201*46207Smckusick fifo_advlock, /* advlock */ 20237737Smckusick }; 20340290Smckusick #endif /* FIFO */ 20440290Smckusick 20540290Smckusick enum vtype iftovt_tab[16] = { 20640290Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 20740290Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 20837737Smckusick }; 20940290Smckusick int vttoif_tab[9] = { 21040290Smckusick 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT, 21140290Smckusick }; 2126254Sroot 2139167Ssam /* 21437737Smckusick * Create a regular file 2159167Ssam */ 21637737Smckusick ufs_create(ndp, vap) 21737737Smckusick struct nameidata *ndp; 21837737Smckusick struct vattr *vap; 2196254Sroot { 22037737Smckusick struct inode *ip; 22137737Smckusick int error; 2226254Sroot 22337737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 22437737Smckusick return (error); 22537737Smckusick ndp->ni_vp = ITOV(ip); 22637737Smckusick return (0); 2276254Sroot } 2286254Sroot 22937Sbill /* 23037737Smckusick * Mknod vnode call 2316254Sroot */ 23237737Smckusick /* ARGSUSED */ 23337737Smckusick ufs_mknod(ndp, vap, cred) 23437737Smckusick struct nameidata *ndp; 23537737Smckusick struct ucred *cred; 23637737Smckusick struct vattr *vap; 2376254Sroot { 23839435Smckusick register struct vnode *vp; 23937737Smckusick struct inode *ip; 24037737Smckusick int error; 2416254Sroot 24237737Smckusick if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip)) 24337737Smckusick return (error); 24440290Smckusick ip->i_flag |= IACC|IUPD|ICHG; 24540290Smckusick if (vap->va_rdev != VNOVAL) { 24637737Smckusick /* 24737737Smckusick * Want to be able to use this to make badblock 24837737Smckusick * inodes, so don't truncate the dev number. 24937737Smckusick */ 25039608Smckusick ip->i_rdev = vap->va_rdev; 25112756Ssam } 25237737Smckusick /* 25337737Smckusick * Remove inode so that it will be reloaded by iget and 25437737Smckusick * checked to see if it is an alias of an existing entry 25537737Smckusick * in the inode cache. 25637737Smckusick */ 25740290Smckusick vp = ITOV(ip); 25840290Smckusick vput(vp); 25939435Smckusick vp->v_type = VNON; 26039435Smckusick vgone(vp); 26137737Smckusick return (0); 2626254Sroot } 2636254Sroot 2646254Sroot /* 26537737Smckusick * Open called. 26637737Smckusick * 26737737Smckusick * Nothing to do. 2686254Sroot */ 26937737Smckusick /* ARGSUSED */ 27037737Smckusick ufs_open(vp, mode, cred) 27137737Smckusick struct vnode *vp; 27237737Smckusick int mode; 27337737Smckusick struct ucred *cred; 2746254Sroot { 2756254Sroot 27637737Smckusick return (0); 2776254Sroot } 2786254Sroot 2796254Sroot /* 28037737Smckusick * Close called 28137737Smckusick * 28237737Smckusick * Update the times on the inode. 2836254Sroot */ 28437737Smckusick /* ARGSUSED */ 28537737Smckusick ufs_close(vp, fflag, cred) 28637737Smckusick struct vnode *vp; 28737737Smckusick int fflag; 28837737Smckusick struct ucred *cred; 2896254Sroot { 29037737Smckusick register struct inode *ip = VTOI(vp); 2916254Sroot 29239815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 29337737Smckusick ITIMES(ip, &time, &time); 29437737Smckusick return (0); 2956254Sroot } 2966254Sroot 29741312Smckusick /* 29841312Smckusick * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 29941312Smckusick * The mode is shifted to select the owner/group/other fields. The 30041312Smckusick * super user is granted all permissions. 30141312Smckusick */ 30237737Smckusick ufs_access(vp, mode, cred) 30337737Smckusick struct vnode *vp; 30441312Smckusick register int mode; 30537737Smckusick struct ucred *cred; 3066254Sroot { 30741312Smckusick register struct inode *ip = VTOI(vp); 30841312Smckusick register gid_t *gp; 30941312Smckusick int i, error; 3106254Sroot 31141312Smckusick #ifdef DIAGNOSTIC 31241312Smckusick if (!VOP_ISLOCKED(vp)) { 31341312Smckusick vprint("ufs_access: not locked", vp); 31441312Smckusick panic("ufs_access: not locked"); 31541312Smckusick } 31641312Smckusick #endif 31741312Smckusick #ifdef QUOTA 31841312Smckusick if (mode & VWRITE) { 31941312Smckusick switch (vp->v_type) { 32041312Smckusick case VREG: case VDIR: case VLNK: 32141312Smckusick if (error = getinoquota(ip)) 32241312Smckusick return (error); 32341312Smckusick } 32441312Smckusick } 32541312Smckusick #endif /* QUOTA */ 32641312Smckusick /* 32741312Smckusick * If you're the super-user, you always get access. 32841312Smckusick */ 32941312Smckusick if (cred->cr_uid == 0) 33041312Smckusick return (0); 33141312Smckusick /* 33241312Smckusick * Access check is based on only one of owner, group, public. 33341312Smckusick * If not owner, then check group. If not a member of the 33441312Smckusick * group, then check public access. 33541312Smckusick */ 33641312Smckusick if (cred->cr_uid != ip->i_uid) { 33741312Smckusick mode >>= 3; 33841312Smckusick gp = cred->cr_groups; 33941312Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 34041312Smckusick if (ip->i_gid == *gp) 34141312Smckusick goto found; 34241312Smckusick mode >>= 3; 34341312Smckusick found: 34441312Smckusick ; 34541312Smckusick } 34641312Smckusick if ((ip->i_mode & mode) != 0) 34741312Smckusick return (0); 34841312Smckusick return (EACCES); 3496254Sroot } 3506254Sroot 35137737Smckusick /* ARGSUSED */ 35237737Smckusick ufs_getattr(vp, vap, cred) 35337737Smckusick struct vnode *vp; 35437737Smckusick register struct vattr *vap; 35537737Smckusick struct ucred *cred; 3566254Sroot { 35737737Smckusick register struct inode *ip = VTOI(vp); 3586254Sroot 35937737Smckusick ITIMES(ip, &time, &time); 3606254Sroot /* 36137737Smckusick * Copy from inode table 3626254Sroot */ 36337737Smckusick vap->va_fsid = ip->i_dev; 36437737Smckusick vap->va_fileid = ip->i_number; 36537737Smckusick vap->va_mode = ip->i_mode & ~IFMT; 36637737Smckusick vap->va_nlink = ip->i_nlink; 36737737Smckusick vap->va_uid = ip->i_uid; 36837737Smckusick vap->va_gid = ip->i_gid; 36937737Smckusick vap->va_rdev = (dev_t)ip->i_rdev; 37041312Smckusick #ifdef tahoe 37141312Smckusick vap->va_size = ip->i_size; 37241312Smckusick vap->va_size_rsv = 0; 37341312Smckusick #else 37440641Smckusick vap->va_qsize = ip->i_din.di_qsize; 37541312Smckusick #endif 37637737Smckusick vap->va_atime.tv_sec = ip->i_atime; 37738578Smckusick vap->va_atime.tv_usec = 0; 37837737Smckusick vap->va_mtime.tv_sec = ip->i_mtime; 37938578Smckusick vap->va_mtime.tv_usec = 0; 38037737Smckusick vap->va_ctime.tv_sec = ip->i_ctime; 38138578Smckusick vap->va_ctime.tv_usec = 0; 38238254Smckusick vap->va_flags = ip->i_flags; 38338254Smckusick vap->va_gen = ip->i_gen; 38437737Smckusick /* this doesn't belong here */ 38537737Smckusick if (vp->v_type == VBLK) 38637737Smckusick vap->va_blocksize = BLKDEV_IOSIZE; 38737737Smckusick else if (vp->v_type == VCHR) 38837737Smckusick vap->va_blocksize = MAXBSIZE; 3897142Smckusick else 39037737Smckusick vap->va_blocksize = ip->i_fs->fs_bsize; 39138657Smckusick vap->va_bytes = dbtob(ip->i_blocks); 39240641Smckusick vap->va_bytes_rsv = 0; 39337737Smckusick vap->va_type = vp->v_type; 39437737Smckusick return (0); 3956254Sroot } 3966254Sroot 3976254Sroot /* 39837737Smckusick * Set attribute vnode op. called from several syscalls 3996254Sroot */ 40037737Smckusick ufs_setattr(vp, vap, cred) 40137737Smckusick register struct vnode *vp; 40237737Smckusick register struct vattr *vap; 40337737Smckusick register struct ucred *cred; 4046254Sroot { 40537737Smckusick register struct inode *ip = VTOI(vp); 40637737Smckusick int error = 0; 4076254Sroot 40837737Smckusick /* 40937737Smckusick * Check for unsetable attributes. 41037737Smckusick */ 41137737Smckusick if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 41237737Smckusick (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 41337737Smckusick (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 41438254Smckusick ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 41537737Smckusick return (EINVAL); 41616540Ssam } 41737737Smckusick /* 41837737Smckusick * Go through the fields and update iff not VNOVAL. 41937737Smckusick */ 42037737Smckusick if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL) 42137737Smckusick if (error = chown1(vp, vap->va_uid, vap->va_gid, cred)) 42237737Smckusick return (error); 42337737Smckusick if (vap->va_size != VNOVAL) { 42437737Smckusick if (vp->v_type == VDIR) 42537737Smckusick return (EISDIR); 42639674Smckusick if (error = itrunc(ip, vap->va_size, 0)) /* XXX IO_SYNC? */ 42737737Smckusick return (error); 42813878Ssam } 42937737Smckusick if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 43037773Smckusick if (cred->cr_uid != ip->i_uid && 43137773Smckusick (error = suser(cred, &u.u_acflag))) 43237773Smckusick return (error); 43337737Smckusick if (vap->va_atime.tv_sec != VNOVAL) 43437737Smckusick ip->i_flag |= IACC; 43537737Smckusick if (vap->va_mtime.tv_sec != VNOVAL) 43637737Smckusick ip->i_flag |= IUPD; 43737737Smckusick ip->i_flag |= ICHG; 43837737Smckusick if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1)) 43937737Smckusick return (error); 4406254Sroot } 44137737Smckusick if (vap->va_mode != (u_short)VNOVAL) 44237737Smckusick error = chmod1(vp, (int)vap->va_mode, cred); 44338254Smckusick if (vap->va_flags != VNOVAL) { 44438254Smckusick if (cred->cr_uid != ip->i_uid && 44538254Smckusick (error = suser(cred, &u.u_acflag))) 44638254Smckusick return (error); 44738254Smckusick if (cred->cr_uid == 0) { 44838254Smckusick ip->i_flags = vap->va_flags; 44938254Smckusick } else { 45038254Smckusick ip->i_flags &= 0xffff0000; 45138254Smckusick ip->i_flags |= (vap->va_flags & 0xffff); 45238254Smckusick } 45338254Smckusick ip->i_flag |= ICHG; 45438254Smckusick } 45537737Smckusick return (error); 4566254Sroot } 4576254Sroot 4586254Sroot /* 4599167Ssam * Change the mode on a file. 4609167Ssam * Inode must be locked before calling. 4619167Ssam */ 46237737Smckusick chmod1(vp, mode, cred) 46337737Smckusick register struct vnode *vp; 4647701Ssam register int mode; 46537737Smckusick struct ucred *cred; 4667701Ssam { 46737737Smckusick register struct inode *ip = VTOI(vp); 46837773Smckusick int error; 4697868Sroot 47037773Smckusick if (cred->cr_uid != ip->i_uid && 47137773Smckusick (error = suser(cred, &u.u_acflag))) 47237773Smckusick return (error); 47337737Smckusick if (cred->cr_uid) { 47446206Smckusick if (vp->v_type != VDIR && (mode & ISVTX)) 47545783Sbostic return (EFTYPE); 47646206Smckusick if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) 47745783Sbostic return (EPERM); 4787439Sroot } 47945783Sbostic ip->i_mode &= ~07777; 48037737Smckusick ip->i_mode |= mode & 07777; 4816254Sroot ip->i_flag |= ICHG; 48237737Smckusick if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0) 48345722Smckusick (void) vnode_pager_uncache(vp); 48421015Smckusick return (0); 4855992Swnj } 4865992Swnj 4879167Ssam /* 4887701Ssam * Perform chown operation on inode ip; 4897701Ssam * inode must be locked prior to call. 4907701Ssam */ 49137737Smckusick chown1(vp, uid, gid, cred) 49237737Smckusick register struct vnode *vp; 49337737Smckusick uid_t uid; 49437737Smckusick gid_t gid; 49537737Smckusick struct ucred *cred; 4967701Ssam { 49737737Smckusick register struct inode *ip = VTOI(vp); 49841312Smckusick uid_t ouid; 49941312Smckusick gid_t ogid; 50041312Smckusick int error = 0; 5017701Ssam #ifdef QUOTA 50241312Smckusick register int i; 50341312Smckusick long change; 50411811Ssam #endif 5057701Ssam 50637737Smckusick if (uid == (u_short)VNOVAL) 50711811Ssam uid = ip->i_uid; 50837737Smckusick if (gid == (u_short)VNOVAL) 50911811Ssam gid = ip->i_gid; 51036614Sbostic /* 51136614Sbostic * If we don't own the file, are trying to change the owner 51236614Sbostic * of the file, or are not a member of the target group, 51336614Sbostic * the caller must be superuser or the call fails. 51436614Sbostic */ 51537737Smckusick if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid || 51637737Smckusick !groupmember((gid_t)gid, cred)) && 51737737Smckusick (error = suser(cred, &u.u_acflag))) 51837737Smckusick return (error); 51941312Smckusick ouid = ip->i_uid; 52041312Smckusick ogid = ip->i_gid; 52111811Ssam #ifdef QUOTA 52241312Smckusick if (error = getinoquota(ip)) 52341312Smckusick return (error); 52441312Smckusick if (ouid == uid) { 52541312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 52641312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 52741312Smckusick } 52841312Smckusick if (ogid == gid) { 52941312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 53041312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 53141312Smckusick } 53241312Smckusick change = ip->i_blocks; 53341312Smckusick (void) chkdq(ip, -change, cred, CHOWN); 53441312Smckusick (void) chkiq(ip, -1, cred, CHOWN); 53541312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 53641312Smckusick dqrele(vp, ip->i_dquot[i]); 53741312Smckusick ip->i_dquot[i] = NODQUOT; 53841312Smckusick } 5397482Skre #endif 54011811Ssam ip->i_uid = uid; 54111811Ssam ip->i_gid = gid; 5427701Ssam #ifdef QUOTA 54341312Smckusick if ((error = getinoquota(ip)) == 0) { 54441312Smckusick if (ouid == uid) { 54541312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 54641312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 54741312Smckusick } 54841312Smckusick if (ogid == gid) { 54941312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 55041312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 55141312Smckusick } 55241312Smckusick if ((error = chkdq(ip, change, cred, CHOWN)) == 0) { 55341312Smckusick if ((error = chkiq(ip, 1, cred, CHOWN)) == 0) 55441927Smckusick goto good; 55541312Smckusick else 55641312Smckusick (void) chkdq(ip, -change, cred, CHOWN|FORCE); 55741312Smckusick } 55841312Smckusick for (i = 0; i < MAXQUOTAS; i++) { 55941312Smckusick dqrele(vp, ip->i_dquot[i]); 56041312Smckusick ip->i_dquot[i] = NODQUOT; 56141312Smckusick } 56241312Smckusick } 56341312Smckusick ip->i_uid = ouid; 56441312Smckusick ip->i_gid = ogid; 56541312Smckusick if (getinoquota(ip) == 0) { 56641312Smckusick if (ouid == uid) { 56741312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]); 56841312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT; 56941312Smckusick } 57041312Smckusick if (ogid == gid) { 57141312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]); 57241312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT; 57341312Smckusick } 57441927Smckusick (void) chkdq(ip, change, cred, FORCE|CHOWN); 57541927Smckusick (void) chkiq(ip, 1, cred, FORCE|CHOWN); 57642440Smckusick (void) getinoquota(ip); 57741312Smckusick } 57842440Smckusick return (error); 57941927Smckusick good: 58042440Smckusick if (getinoquota(ip)) 58142440Smckusick panic("chown: lost quota"); 58242440Smckusick #endif /* QUOTA */ 58341312Smckusick if (ouid != uid || ogid != gid) 58441312Smckusick ip->i_flag |= ICHG; 58541312Smckusick if (ouid != uid && cred->cr_uid != 0) 58641312Smckusick ip->i_mode &= ~ISUID; 58741312Smckusick if (ogid != gid && cred->cr_uid != 0) 58841312Smckusick ip->i_mode &= ~ISGID; 58912646Ssam return (0); 59037Sbill } 59137Sbill 59239608Smckusick /* 59339608Smckusick * Vnode op for reading. 59439608Smckusick */ 59537737Smckusick /* ARGSUSED */ 59639608Smckusick ufs_read(vp, uio, ioflag, cred) 59739608Smckusick struct vnode *vp; 59839608Smckusick register struct uio *uio; 59939608Smckusick int ioflag; 60039608Smckusick struct ucred *cred; 60139608Smckusick { 60239608Smckusick register struct inode *ip = VTOI(vp); 60339608Smckusick register struct fs *fs; 60439608Smckusick struct buf *bp; 60539608Smckusick daddr_t lbn, bn, rablock; 60639896Smckusick int size, diff, error = 0; 60739608Smckusick long n, on, type; 60839608Smckusick 60939608Smckusick if (uio->uio_rw != UIO_READ) 61039608Smckusick panic("ufs_read mode"); 61139608Smckusick type = ip->i_mode & IFMT; 61239608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 61339608Smckusick panic("ufs_read type"); 61439608Smckusick if (uio->uio_resid == 0) 61539608Smckusick return (0); 61639608Smckusick if (uio->uio_offset < 0) 61739608Smckusick return (EINVAL); 61839608Smckusick ip->i_flag |= IACC; 61939608Smckusick fs = ip->i_fs; 62039608Smckusick do { 62139608Smckusick lbn = lblkno(fs, uio->uio_offset); 62239608Smckusick on = blkoff(fs, uio->uio_offset); 62339608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 62439608Smckusick diff = ip->i_size - uio->uio_offset; 62539608Smckusick if (diff <= 0) 62639608Smckusick return (0); 62739608Smckusick if (diff < n) 62839608Smckusick n = diff; 62939608Smckusick size = blksize(fs, ip, lbn); 63039674Smckusick rablock = lbn + 1; 63139896Smckusick if (vp->v_lastr + 1 == lbn && 63239896Smckusick lblktosize(fs, rablock) < ip->i_size) 63339896Smckusick error = breada(ITOV(ip), lbn, size, rablock, 63439896Smckusick blksize(fs, ip, rablock), NOCRED, &bp); 63539608Smckusick else 63639674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 63739815Smckusick vp->v_lastr = lbn; 63839608Smckusick n = MIN(n, size - bp->b_resid); 63939608Smckusick if (error) { 64039608Smckusick brelse(bp); 64139608Smckusick return (error); 64239608Smckusick } 64339608Smckusick error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 64439608Smckusick if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size) 64539608Smckusick bp->b_flags |= B_AGE; 64639608Smckusick brelse(bp); 64739608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 64839608Smckusick return (error); 64939608Smckusick } 65039608Smckusick 65139608Smckusick /* 65239608Smckusick * Vnode op for writing. 65339608Smckusick */ 65439608Smckusick ufs_write(vp, uio, ioflag, cred) 65539608Smckusick register struct vnode *vp; 65639608Smckusick struct uio *uio; 65739608Smckusick int ioflag; 65839608Smckusick struct ucred *cred; 65939608Smckusick { 66039608Smckusick register struct inode *ip = VTOI(vp); 66139608Smckusick register struct fs *fs; 66239608Smckusick struct buf *bp; 66339608Smckusick daddr_t lbn, bn; 66439608Smckusick u_long osize; 66545722Smckusick int n, on, flags; 66645722Smckusick int size, resid, error = 0; 66739608Smckusick 66839608Smckusick if (uio->uio_rw != UIO_WRITE) 66939608Smckusick panic("ufs_write mode"); 67039608Smckusick switch (vp->v_type) { 67139608Smckusick case VREG: 67239608Smckusick if (ioflag & IO_APPEND) 67339608Smckusick uio->uio_offset = ip->i_size; 67439608Smckusick /* fall through */ 67539608Smckusick case VLNK: 67639608Smckusick break; 67739608Smckusick 67839608Smckusick case VDIR: 67939608Smckusick if ((ioflag & IO_SYNC) == 0) 68039608Smckusick panic("ufs_write nonsync dir write"); 68139608Smckusick break; 68239608Smckusick 68339608Smckusick default: 68439608Smckusick panic("ufs_write type"); 68539608Smckusick } 68639608Smckusick if (uio->uio_offset < 0) 68739608Smckusick return (EINVAL); 68839608Smckusick if (uio->uio_resid == 0) 68939608Smckusick return (0); 69039608Smckusick /* 69139608Smckusick * Maybe this should be above the vnode op call, but so long as 69239608Smckusick * file servers have no limits, i don't think it matters 69339608Smckusick */ 69439608Smckusick if (vp->v_type == VREG && 69539608Smckusick uio->uio_offset + uio->uio_resid > 69639608Smckusick u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { 69739608Smckusick psignal(u.u_procp, SIGXFSZ); 69839608Smckusick return (EFBIG); 69939608Smckusick } 70039608Smckusick resid = uio->uio_resid; 70139608Smckusick osize = ip->i_size; 70239608Smckusick fs = ip->i_fs; 70339674Smckusick flags = 0; 70439674Smckusick if (ioflag & IO_SYNC) 70539674Smckusick flags = B_SYNC; 70639608Smckusick do { 70739608Smckusick lbn = lblkno(fs, uio->uio_offset); 70839608Smckusick on = blkoff(fs, uio->uio_offset); 70939608Smckusick n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid); 71039608Smckusick if (n < fs->fs_bsize) 71139674Smckusick flags |= B_CLRBUF; 71239608Smckusick else 71339674Smckusick flags &= ~B_CLRBUF; 71439674Smckusick if (error = balloc(ip, lbn, (int)(on + n), &bp, flags)) 71539608Smckusick break; 71639674Smckusick bn = bp->b_blkno; 71745722Smckusick if (uio->uio_offset + n > ip->i_size) { 71839608Smckusick ip->i_size = uio->uio_offset + n; 71945722Smckusick vnode_pager_setsize(vp, ip->i_size); 72045722Smckusick } 72139608Smckusick size = blksize(fs, ip, lbn); 72245722Smckusick (void) vnode_pager_uncache(vp); 72339608Smckusick n = MIN(n, size - bp->b_resid); 72439608Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 72539608Smckusick if (ioflag & IO_SYNC) 72639608Smckusick (void) bwrite(bp); 72739608Smckusick else if (n + on == fs->fs_bsize) { 72839608Smckusick bp->b_flags |= B_AGE; 72939608Smckusick bawrite(bp); 73039608Smckusick } else 73139608Smckusick bdwrite(bp); 73239608Smckusick ip->i_flag |= IUPD|ICHG; 73339608Smckusick if (cred->cr_uid != 0) 73439608Smckusick ip->i_mode &= ~(ISUID|ISGID); 73539608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 73639608Smckusick if (error && (ioflag & IO_UNIT)) { 73739674Smckusick (void) itrunc(ip, osize, ioflag & IO_SYNC); 73839608Smckusick uio->uio_offset -= resid - uio->uio_resid; 73939608Smckusick uio->uio_resid = resid; 74039608Smckusick } 74142493Smckusick if (!error && (ioflag & IO_SYNC)) 74242493Smckusick error = iupdat(ip, &time, &time, 1); 74339608Smckusick return (error); 74439608Smckusick } 74539608Smckusick 74639608Smckusick /* ARGSUSED */ 74737737Smckusick ufs_ioctl(vp, com, data, fflag, cred) 74837737Smckusick struct vnode *vp; 74937737Smckusick int com; 75037737Smckusick caddr_t data; 75137737Smckusick int fflag; 75237737Smckusick struct ucred *cred; 75311811Ssam { 75411811Ssam 75537737Smckusick return (ENOTTY); 75611811Ssam } 75711811Ssam 75837737Smckusick /* ARGSUSED */ 75940290Smckusick ufs_select(vp, which, fflags, cred) 76037737Smckusick struct vnode *vp; 76140290Smckusick int which, fflags; 76237737Smckusick struct ucred *cred; 76337737Smckusick { 76437737Smckusick 76537737Smckusick return (1); /* XXX */ 76637737Smckusick } 76737737Smckusick 7689167Ssam /* 76937737Smckusick * Mmap a file 77037737Smckusick * 77137737Smckusick * NB Currently unsupported. 7729167Ssam */ 77337737Smckusick /* ARGSUSED */ 77437737Smckusick ufs_mmap(vp, fflags, cred) 77537737Smckusick struct vnode *vp; 77637737Smckusick int fflags; 77737737Smckusick struct ucred *cred; 77837Sbill { 77937Sbill 78037737Smckusick return (EINVAL); 78137Sbill } 7827535Sroot 7839167Ssam /* 78437737Smckusick * Synch an open file. 7859167Ssam */ 78637737Smckusick /* ARGSUSED */ 78739597Smckusick ufs_fsync(vp, fflags, cred, waitfor) 78837737Smckusick struct vnode *vp; 78937737Smckusick int fflags; 79037737Smckusick struct ucred *cred; 79139597Smckusick int waitfor; 7927701Ssam { 79339597Smckusick struct inode *ip = VTOI(vp); 7947701Ssam 79537737Smckusick if (fflags&FWRITE) 79637737Smckusick ip->i_flag |= ICHG; 79739674Smckusick vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0); 79839674Smckusick return (iupdat(ip, &time, &time, waitfor == MNT_WAIT)); 7997701Ssam } 8007701Ssam 8019167Ssam /* 80237737Smckusick * Seek on a file 80337737Smckusick * 80437737Smckusick * Nothing to do, so just return. 8059167Ssam */ 80637737Smckusick /* ARGSUSED */ 80737737Smckusick ufs_seek(vp, oldoff, newoff, cred) 80837737Smckusick struct vnode *vp; 80937737Smckusick off_t oldoff, newoff; 81037737Smckusick struct ucred *cred; 8117701Ssam { 8127701Ssam 81337737Smckusick return (0); 81437737Smckusick } 81537737Smckusick 81637737Smckusick /* 81737737Smckusick * ufs remove 81837737Smckusick * Hard to avoid races here, especially 81937737Smckusick * in unlinking directories. 82037737Smckusick */ 82137737Smckusick ufs_remove(ndp) 82237737Smckusick struct nameidata *ndp; 82337737Smckusick { 82437737Smckusick register struct inode *ip, *dp; 82537737Smckusick int error; 82637737Smckusick 82737737Smckusick ip = VTOI(ndp->ni_vp); 82837737Smckusick dp = VTOI(ndp->ni_dvp); 82937737Smckusick error = dirremove(ndp); 83037737Smckusick if (!error) { 83137737Smckusick ip->i_nlink--; 83237737Smckusick ip->i_flag |= ICHG; 8337701Ssam } 83437737Smckusick if (dp == ip) 83537737Smckusick vrele(ITOV(ip)); 83637737Smckusick else 83737737Smckusick iput(ip); 83837737Smckusick iput(dp); 83937737Smckusick return (error); 8407701Ssam } 8417701Ssam 8429167Ssam /* 84337737Smckusick * link vnode call 8449167Ssam */ 84537737Smckusick ufs_link(vp, ndp) 84637737Smckusick register struct vnode *vp; 84737737Smckusick register struct nameidata *ndp; 8489167Ssam { 84937737Smckusick register struct inode *ip = VTOI(vp); 85037737Smckusick int error; 8519167Ssam 85237737Smckusick if (ndp->ni_dvp != vp) 85337737Smckusick ILOCK(ip); 85437737Smckusick if (ip->i_nlink == LINK_MAX - 1) { 85537737Smckusick error = EMLINK; 85637737Smckusick goto out; 85737737Smckusick } 85837737Smckusick ip->i_nlink++; 85937737Smckusick ip->i_flag |= ICHG; 86037737Smckusick error = iupdat(ip, &time, &time, 1); 86137737Smckusick if (!error) 86237737Smckusick error = direnter(ip, ndp); 86337737Smckusick out: 86437737Smckusick if (ndp->ni_dvp != vp) 86537737Smckusick IUNLOCK(ip); 86637737Smckusick if (error) { 86737737Smckusick ip->i_nlink--; 86830598Smckusick ip->i_flag |= ICHG; 86937737Smckusick } 87037737Smckusick return (error); 8719167Ssam } 8729167Ssam 8739167Ssam /* 8749167Ssam * Rename system call. 8759167Ssam * rename("foo", "bar"); 8769167Ssam * is essentially 8779167Ssam * unlink("bar"); 8789167Ssam * link("foo", "bar"); 8799167Ssam * unlink("foo"); 8809167Ssam * but ``atomically''. Can't do full commit without saving state in the 8819167Ssam * inode on disk which isn't feasible at this time. Best we can do is 8829167Ssam * always guarantee the target exists. 8839167Ssam * 8849167Ssam * Basic algorithm is: 8859167Ssam * 8869167Ssam * 1) Bump link count on source while we're linking it to the 88737737Smckusick * target. This also ensure the inode won't be deleted out 88816776Smckusick * from underneath us while we work (it may be truncated by 88916776Smckusick * a concurrent `trunc' or `open' for creation). 8909167Ssam * 2) Link source to destination. If destination already exists, 8919167Ssam * delete it first. 89216776Smckusick * 3) Unlink source reference to inode if still around. If a 89316776Smckusick * directory was moved and the parent of the destination 8949167Ssam * is different from the source, patch the ".." entry in the 8959167Ssam * directory. 8969167Ssam */ 89737737Smckusick ufs_rename(fndp, tndp) 89837737Smckusick register struct nameidata *fndp, *tndp; 8997701Ssam { 9009167Ssam register struct inode *ip, *xp, *dp; 90116776Smckusick struct dirtemplate dirbuf; 90216776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 90310051Ssam int error = 0; 9047701Ssam 90537737Smckusick dp = VTOI(fndp->ni_dvp); 90637737Smckusick ip = VTOI(fndp->ni_vp); 90737737Smckusick ILOCK(ip); 9089167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 90937737Smckusick register struct direct *d = &fndp->ni_dent; 9109167Ssam 9119167Ssam /* 91211641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 9139167Ssam */ 91437737Smckusick if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip || 91537737Smckusick fndp->ni_isdotdot || (ip->i_flag & IRENAME)) { 91642466Smckusick VOP_ABORTOP(tndp); 91742466Smckusick vput(tndp->ni_dvp); 91842466Smckusick if (tndp->ni_vp) 91942466Smckusick vput(tndp->ni_vp); 92042466Smckusick VOP_ABORTOP(fndp); 92142466Smckusick vrele(fndp->ni_dvp); 92242466Smckusick vput(fndp->ni_vp); 92337737Smckusick return (EINVAL); 9249167Ssam } 92516776Smckusick ip->i_flag |= IRENAME; 9269167Ssam oldparent = dp->i_number; 9279167Ssam doingdirectory++; 9289167Ssam } 92937737Smckusick vrele(fndp->ni_dvp); 9309167Ssam 9319167Ssam /* 9329167Ssam * 1) Bump link count while we're moving stuff 9339167Ssam * around. If we crash somewhere before 9349167Ssam * completing our work, the link count 9359167Ssam * may be wrong, but correctable. 9369167Ssam */ 9379167Ssam ip->i_nlink++; 9389167Ssam ip->i_flag |= ICHG; 93937737Smckusick error = iupdat(ip, &time, &time, 1); 94016664Smckusick IUNLOCK(ip); 9419167Ssam 9429167Ssam /* 9439167Ssam * When the target exists, both the directory 94437737Smckusick * and target vnodes are returned locked. 9459167Ssam */ 94637737Smckusick dp = VTOI(tndp->ni_dvp); 94737737Smckusick xp = NULL; 94837737Smckusick if (tndp->ni_vp) 94937737Smckusick xp = VTOI(tndp->ni_vp); 9509167Ssam /* 95111641Ssam * If ".." must be changed (ie the directory gets a new 95212816Smckusick * parent) then the source directory must not be in the 95312816Smckusick * directory heirarchy above the target, as this would 95412816Smckusick * orphan everything below the source directory. Also 95512816Smckusick * the user must have write permission in the source so 95612816Smckusick * as to be able to change "..". We must repeat the call 95712816Smckusick * to namei, as the parent directory is unlocked by the 95812816Smckusick * call to checkpath(). 95911641Ssam */ 96016776Smckusick if (oldparent != dp->i_number) 96116776Smckusick newparent = dp->i_number; 96216776Smckusick if (doingdirectory && newparent) { 96341466Smckusick VOP_LOCK(fndp->ni_vp); 96441466Smckusick error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred); 96541466Smckusick VOP_UNLOCK(fndp->ni_vp); 96641466Smckusick if (error) 96712816Smckusick goto bad; 96837737Smckusick tndp->ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 96912816Smckusick do { 97037737Smckusick dp = VTOI(tndp->ni_dvp); 97112816Smckusick if (xp != NULL) 97238069Smckusick iput(xp); 97337737Smckusick if (error = checkpath(ip, dp, tndp->ni_cred)) 97412816Smckusick goto out; 97537737Smckusick if (error = namei(tndp)) 97612816Smckusick goto out; 97737737Smckusick xp = NULL; 97837737Smckusick if (tndp->ni_vp) 97937737Smckusick xp = VTOI(tndp->ni_vp); 98037737Smckusick } while (dp != VTOI(tndp->ni_dvp)); 98112816Smckusick } 98211641Ssam /* 9839167Ssam * 2) If target doesn't exist, link the target 9849167Ssam * to the source and unlink the source. 9859167Ssam * Otherwise, rewrite the target directory 9869167Ssam * entry to reference the source inode and 9879167Ssam * expunge the original entry's existence. 9889167Ssam */ 9899167Ssam if (xp == NULL) { 99037737Smckusick if (dp->i_dev != ip->i_dev) 99137737Smckusick panic("rename: EXDEV"); 9929167Ssam /* 99316776Smckusick * Account for ".." in new directory. 99416776Smckusick * When source and destination have the same 99516776Smckusick * parent we don't fool with the link count. 9969167Ssam */ 99716776Smckusick if (doingdirectory && newparent) { 9989167Ssam dp->i_nlink++; 9999167Ssam dp->i_flag |= ICHG; 100037737Smckusick error = iupdat(dp, &time, &time, 1); 10019167Ssam } 100237737Smckusick if (error = direnter(ip, tndp)) 10039167Ssam goto out; 10049167Ssam } else { 100537737Smckusick if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 100637737Smckusick panic("rename: EXDEV"); 10079167Ssam /* 100810590Ssam * Short circuit rename(foo, foo). 100910590Ssam */ 101010590Ssam if (xp->i_number == ip->i_number) 101137737Smckusick panic("rename: same file"); 101210590Ssam /* 101324433Sbloom * If the parent directory is "sticky", then the user must 101424433Sbloom * own the parent directory, or the destination of the rename, 101524433Sbloom * otherwise the destination may not be changed (except by 101624433Sbloom * root). This implements append-only directories. 101724433Sbloom */ 101837737Smckusick if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 && 101937737Smckusick tndp->ni_cred->cr_uid != dp->i_uid && 102037737Smckusick xp->i_uid != tndp->ni_cred->cr_uid) { 102124433Sbloom error = EPERM; 102224433Sbloom goto bad; 102324433Sbloom } 102424433Sbloom /* 102510051Ssam * Target must be empty if a directory 102610051Ssam * and have no links to it. 10279167Ssam * Also, insure source and target are 10289167Ssam * compatible (both directories, or both 10299167Ssam * not directories). 10309167Ssam */ 10319167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 103237737Smckusick if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 103337737Smckusick xp->i_nlink > 2) { 103410051Ssam error = ENOTEMPTY; 10359167Ssam goto bad; 10369167Ssam } 10379167Ssam if (!doingdirectory) { 103810051Ssam error = ENOTDIR; 10399167Ssam goto bad; 10409167Ssam } 104137737Smckusick cache_purge(ITOV(dp)); 10429167Ssam } else if (doingdirectory) { 104310051Ssam error = EISDIR; 10449167Ssam goto bad; 10459167Ssam } 104637737Smckusick if (error = dirrewrite(dp, ip, tndp)) 104737737Smckusick goto bad; 104845354Smckusick /* 104945354Smckusick * If the target directory is in the same 105045354Smckusick * directory as the source directory, 105145354Smckusick * decrement the link count on the parent 105245354Smckusick * of the target directory. 105345354Smckusick */ 105445354Smckusick if (doingdirectory && !newparent) { 105545354Smckusick dp->i_nlink--; 105645354Smckusick dp->i_flag |= ICHG; 105745354Smckusick } 105837737Smckusick vput(ITOV(dp)); 10599167Ssam /* 106010051Ssam * Adjust the link count of the target to 106110051Ssam * reflect the dirrewrite above. If this is 106210051Ssam * a directory it is empty and there are 106310051Ssam * no links to it, so we can squash the inode and 106410051Ssam * any space associated with it. We disallowed 106510051Ssam * renaming over top of a directory with links to 106616776Smckusick * it above, as the remaining link would point to 106716776Smckusick * a directory without "." or ".." entries. 10689167Ssam */ 106910051Ssam xp->i_nlink--; 10709167Ssam if (doingdirectory) { 107110051Ssam if (--xp->i_nlink != 0) 107210051Ssam panic("rename: linked directory"); 107339674Smckusick error = itrunc(xp, (u_long)0, IO_SYNC); 107410051Ssam } 10759167Ssam xp->i_flag |= ICHG; 107638398Smckusick iput(xp); 107710246Ssam xp = NULL; 10789167Ssam } 10799167Ssam 10809167Ssam /* 10819167Ssam * 3) Unlink the source. 10829167Ssam */ 108337737Smckusick fndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 108437737Smckusick (void)namei(fndp); 108537737Smckusick if (fndp->ni_vp != NULL) { 108637737Smckusick xp = VTOI(fndp->ni_vp); 108737737Smckusick dp = VTOI(fndp->ni_dvp); 108837737Smckusick } else { 108938069Smckusick if (fndp->ni_dvp != NULL) 109038069Smckusick vput(fndp->ni_dvp); 109137737Smckusick xp = NULL; 109217758Smckusick dp = NULL; 109337737Smckusick } 10949167Ssam /* 109537737Smckusick * Ensure that the directory entry still exists and has not 109616776Smckusick * changed while the new name has been entered. If the source is 109716776Smckusick * a file then the entry may have been unlinked or renamed. In 109816776Smckusick * either case there is no further work to be done. If the source 109916776Smckusick * is a directory then it cannot have been rmdir'ed; its link 110016776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 110137737Smckusick * The IRENAME flag ensures that it cannot be moved by another 110216776Smckusick * rename. 11039167Ssam */ 110417758Smckusick if (xp != ip) { 110516776Smckusick if (doingdirectory) 110617758Smckusick panic("rename: lost dir entry"); 110716776Smckusick } else { 11089167Ssam /* 110916776Smckusick * If the source is a directory with a 111016776Smckusick * new parent, the link count of the old 111116776Smckusick * parent directory must be decremented 111216776Smckusick * and ".." set to point to the new parent. 11139167Ssam */ 111416776Smckusick if (doingdirectory && newparent) { 11159167Ssam dp->i_nlink--; 11169167Ssam dp->i_flag |= ICHG; 111739597Smckusick error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf, 111837737Smckusick sizeof (struct dirtemplate), (off_t)0, 111939597Smckusick UIO_SYSSPACE, IO_NODELOCKED, 112039597Smckusick tndp->ni_cred, (int *)0); 112116776Smckusick if (error == 0) { 112216776Smckusick if (dirbuf.dotdot_namlen != 2 || 112316776Smckusick dirbuf.dotdot_name[0] != '.' || 112416776Smckusick dirbuf.dotdot_name[1] != '.') { 112539610Smckusick dirbad(xp, 12, "rename: mangled dir"); 112616776Smckusick } else { 112716776Smckusick dirbuf.dotdot_ino = newparent; 112839597Smckusick (void) vn_rdwr(UIO_WRITE, ITOV(xp), 112916776Smckusick (caddr_t)&dirbuf, 113016776Smckusick sizeof (struct dirtemplate), 113137740Smckusick (off_t)0, UIO_SYSSPACE, 113239597Smckusick IO_NODELOCKED|IO_SYNC, 113337737Smckusick tndp->ni_cred, (int *)0); 113437737Smckusick cache_purge(ITOV(dp)); 113516776Smckusick } 113616776Smckusick } 11379167Ssam } 113837737Smckusick error = dirremove(fndp); 113937737Smckusick if (!error) { 114016776Smckusick xp->i_nlink--; 114116776Smckusick xp->i_flag |= ICHG; 11429167Ssam } 114316776Smckusick xp->i_flag &= ~IRENAME; 11449167Ssam } 11459167Ssam if (dp) 114637737Smckusick vput(ITOV(dp)); 114716776Smckusick if (xp) 114837737Smckusick vput(ITOV(xp)); 114937737Smckusick vrele(ITOV(ip)); 115037737Smckusick return (error); 11519167Ssam 11529167Ssam bad: 11539167Ssam if (xp) 115437737Smckusick vput(ITOV(xp)); 115537737Smckusick vput(ITOV(dp)); 11569167Ssam out: 11579167Ssam ip->i_nlink--; 11589167Ssam ip->i_flag |= ICHG; 115937737Smckusick vrele(ITOV(ip)); 116037737Smckusick return (error); 11617701Ssam } 11627701Ssam 11637535Sroot /* 116412756Ssam * A virgin directory (no blushing please). 116512756Ssam */ 116612756Ssam struct dirtemplate mastertemplate = { 116712756Ssam 0, 12, 1, ".", 116812756Ssam 0, DIRBLKSIZ - 12, 2, ".." 116912756Ssam }; 117012756Ssam 117112756Ssam /* 117212756Ssam * Mkdir system call 117312756Ssam */ 117437737Smckusick ufs_mkdir(ndp, vap) 117537737Smckusick struct nameidata *ndp; 117637737Smckusick struct vattr *vap; 117712756Ssam { 117812756Ssam register struct inode *ip, *dp; 117937737Smckusick struct inode *tip; 118037737Smckusick struct vnode *dvp; 118112756Ssam struct dirtemplate dirtemplate; 118237737Smckusick int error; 118337737Smckusick int dmode; 118412756Ssam 118537737Smckusick dvp = ndp->ni_dvp; 118637737Smckusick dp = VTOI(dvp); 118737737Smckusick dmode = vap->va_mode&0777; 118837737Smckusick dmode |= IFDIR; 118912756Ssam /* 119012756Ssam * Must simulate part of maknode here 119112756Ssam * in order to acquire the inode, but 119212756Ssam * not have it entered in the parent 119312756Ssam * directory. The entry is made later 119412756Ssam * after writing "." and ".." entries out. 119512756Ssam */ 119641312Smckusick if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) { 119712756Ssam iput(dp); 119837737Smckusick return (error); 119912756Ssam } 120037737Smckusick ip = tip; 120141312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 120241312Smckusick ip->i_gid = dp->i_gid; 120312756Ssam #ifdef QUOTA 120441312Smckusick if ((error = getinoquota(ip)) || 120541312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 120641312Smckusick ifree(ip, ip->i_number, dmode); 120741312Smckusick iput(ip); 120841312Smckusick iput(dp); 120941312Smckusick return (error); 121041312Smckusick } 121112756Ssam #endif 121212756Ssam ip->i_flag |= IACC|IUPD|ICHG; 121337737Smckusick ip->i_mode = dmode; 121437737Smckusick ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */ 121512756Ssam ip->i_nlink = 2; 121637737Smckusick error = iupdat(ip, &time, &time, 1); 121712756Ssam 121812756Ssam /* 121912756Ssam * Bump link count in parent directory 122012756Ssam * to reflect work done below. Should 122112756Ssam * be done before reference is created 122212756Ssam * so reparation is possible if we crash. 122312756Ssam */ 122412756Ssam dp->i_nlink++; 122512756Ssam dp->i_flag |= ICHG; 122637737Smckusick error = iupdat(dp, &time, &time, 1); 122712756Ssam 122812756Ssam /* 122912756Ssam * Initialize directory with "." 123012756Ssam * and ".." from static template. 123112756Ssam */ 123212756Ssam dirtemplate = mastertemplate; 123312756Ssam dirtemplate.dot_ino = ip->i_number; 123412756Ssam dirtemplate.dotdot_ino = dp->i_number; 123539597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate, 123637737Smckusick sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 123739597Smckusick IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0); 123837737Smckusick if (error) { 123912756Ssam dp->i_nlink--; 124012756Ssam dp->i_flag |= ICHG; 124112756Ssam goto bad; 124212756Ssam } 124343288Smckusick if (DIRBLKSIZ > dp->i_fs->fs_fsize) { 124437737Smckusick panic("mkdir: blksize"); /* XXX - should grow w/balloc() */ 124543288Smckusick } else { 124618103Smckusick ip->i_size = DIRBLKSIZ; 124743288Smckusick ip->i_flag |= ICHG; 124843288Smckusick } 124912756Ssam /* 125012756Ssam * Directory all set up, now 125112756Ssam * install the entry for it in 125212756Ssam * the parent directory. 125312756Ssam */ 125437737Smckusick error = direnter(ip, ndp); 125512756Ssam dp = NULL; 125637737Smckusick if (error) { 125716694Smckusick ndp->ni_nameiop = LOOKUP | NOCACHE; 125837737Smckusick error = namei(ndp); 125937737Smckusick if (!error) { 126037737Smckusick dp = VTOI(ndp->ni_vp); 126112756Ssam dp->i_nlink--; 126212756Ssam dp->i_flag |= ICHG; 126312756Ssam } 126412756Ssam } 126512756Ssam bad: 126612756Ssam /* 126712756Ssam * No need to do an explicit itrunc here, 126837737Smckusick * vrele will do this for us because we set 126912756Ssam * the link count to 0. 127012756Ssam */ 127137737Smckusick if (error) { 127212756Ssam ip->i_nlink = 0; 127312756Ssam ip->i_flag |= ICHG; 127438144Smckusick iput(ip); 127538144Smckusick } else 127638144Smckusick ndp->ni_vp = ITOV(ip); 127712756Ssam if (dp) 127812756Ssam iput(dp); 127937737Smckusick return (error); 128012756Ssam } 128112756Ssam 128212756Ssam /* 128312756Ssam * Rmdir system call. 128412756Ssam */ 128537737Smckusick ufs_rmdir(ndp) 128637737Smckusick register struct nameidata *ndp; 128712756Ssam { 128812756Ssam register struct inode *ip, *dp; 128937737Smckusick int error = 0; 129012756Ssam 129137737Smckusick ip = VTOI(ndp->ni_vp); 129237737Smckusick dp = VTOI(ndp->ni_dvp); 129312756Ssam /* 129412756Ssam * No rmdir "." please. 129512756Ssam */ 129612756Ssam if (dp == ip) { 129737737Smckusick vrele(ITOV(dp)); 129812756Ssam iput(ip); 129937737Smckusick return (EINVAL); 130012756Ssam } 130112756Ssam /* 130212756Ssam * Verify the directory is empty (and valid). 130312756Ssam * (Rmdir ".." won't be valid since 130412756Ssam * ".." will contain a reference to 130512756Ssam * the current directory and thus be 130612756Ssam * non-empty.) 130712756Ssam */ 130837737Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) { 130937737Smckusick error = ENOTEMPTY; 131012756Ssam goto out; 131112756Ssam } 131212756Ssam /* 131312756Ssam * Delete reference to directory before purging 131412756Ssam * inode. If we crash in between, the directory 131512756Ssam * will be reattached to lost+found, 131612756Ssam */ 131737737Smckusick if (error = dirremove(ndp)) 131812756Ssam goto out; 131912756Ssam dp->i_nlink--; 132012756Ssam dp->i_flag |= ICHG; 132137737Smckusick cache_purge(ITOV(dp)); 132212756Ssam iput(dp); 132337737Smckusick ndp->ni_dvp = NULL; 132412756Ssam /* 132512756Ssam * Truncate inode. The only stuff left 132612756Ssam * in the directory is "." and "..". The 132712756Ssam * "." reference is inconsequential since 132812756Ssam * we're quashing it. The ".." reference 132912756Ssam * has already been adjusted above. We've 133012756Ssam * removed the "." reference and the reference 133112756Ssam * in the parent directory, but there may be 133212756Ssam * other hard links so decrement by 2 and 133312756Ssam * worry about them later. 133412756Ssam */ 133512756Ssam ip->i_nlink -= 2; 133639674Smckusick error = itrunc(ip, (u_long)0, IO_SYNC); 133737737Smckusick cache_purge(ITOV(ip)); 133812756Ssam out: 133937737Smckusick if (ndp->ni_dvp) 134012756Ssam iput(dp); 134112756Ssam iput(ip); 134237737Smckusick return (error); 134312756Ssam } 134412756Ssam 134537737Smckusick /* 134637737Smckusick * symlink -- make a symbolic link 134737737Smckusick */ 134837737Smckusick ufs_symlink(ndp, vap, target) 134937737Smckusick struct nameidata *ndp; 135037737Smckusick struct vattr *vap; 135137737Smckusick char *target; 135212756Ssam { 135337737Smckusick struct inode *ip; 135437737Smckusick int error; 135512756Ssam 135637737Smckusick error = maknode(IFLNK | vap->va_mode, ndp, &ip); 135737737Smckusick if (error) 135837737Smckusick return (error); 135939597Smckusick error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0, 136039597Smckusick UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0); 136137737Smckusick iput(ip); 136237737Smckusick return (error); 136337737Smckusick } 136437737Smckusick 136537737Smckusick /* 136637737Smckusick * Vnode op for read and write 136737737Smckusick */ 136840345Smckusick ufs_readdir(vp, uio, cred, eofflagp) 136937737Smckusick struct vnode *vp; 137037737Smckusick register struct uio *uio; 137137737Smckusick struct ucred *cred; 137240345Smckusick int *eofflagp; 137337737Smckusick { 137439597Smckusick int count, lost, error; 137537737Smckusick 137637737Smckusick count = uio->uio_resid; 137737737Smckusick count &= ~(DIRBLKSIZ - 1); 137839597Smckusick lost = uio->uio_resid - count; 137939597Smckusick if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) 138037737Smckusick return (EINVAL); 138137737Smckusick uio->uio_resid = count; 138237737Smckusick uio->uio_iov->iov_len = count; 138339597Smckusick error = ufs_read(vp, uio, 0, cred); 138439597Smckusick uio->uio_resid += lost; 138540345Smckusick if ((VTOI(vp)->i_size - uio->uio_offset) <= 0) 138640345Smckusick *eofflagp = 1; 138740345Smckusick else 138840345Smckusick *eofflagp = 0; 138937737Smckusick return (error); 139037737Smckusick } 139137737Smckusick 139237737Smckusick /* 139337737Smckusick * Return target name of a symbolic link 139437737Smckusick */ 139537737Smckusick ufs_readlink(vp, uiop, cred) 139637737Smckusick struct vnode *vp; 139737737Smckusick struct uio *uiop; 139837737Smckusick struct ucred *cred; 139937737Smckusick { 140037737Smckusick 140139597Smckusick return (ufs_read(vp, uiop, 0, cred)); 140237737Smckusick } 140337737Smckusick 140437737Smckusick /* 140537737Smckusick * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 140642466Smckusick * done. Nothing to do at the moment. 140737737Smckusick */ 140842466Smckusick /* ARGSUSED */ 140937737Smckusick ufs_abortop(ndp) 141042466Smckusick struct nameidata *ndp; 141137737Smckusick { 141237737Smckusick 141342466Smckusick return (0); 141412756Ssam } 141512756Ssam 141639909Smckusick /* 141739909Smckusick * Lock an inode. 141839909Smckusick */ 141937737Smckusick ufs_lock(vp) 142037737Smckusick struct vnode *vp; 142137737Smckusick { 142237737Smckusick register struct inode *ip = VTOI(vp); 142337737Smckusick 142437737Smckusick ILOCK(ip); 142537737Smckusick return (0); 142637737Smckusick } 142737737Smckusick 142839909Smckusick /* 142939909Smckusick * Unlock an inode. 143039909Smckusick */ 143137737Smckusick ufs_unlock(vp) 143237737Smckusick struct vnode *vp; 143337737Smckusick { 143437737Smckusick register struct inode *ip = VTOI(vp); 143537737Smckusick 143637737Smckusick if (!(ip->i_flag & ILOCKED)) 143737737Smckusick panic("ufs_unlock NOT LOCKED"); 143837737Smckusick IUNLOCK(ip); 143937737Smckusick return (0); 144037737Smckusick } 144137737Smckusick 144212756Ssam /* 144339909Smckusick * Check for a locked inode. 144439909Smckusick */ 144539909Smckusick ufs_islocked(vp) 144639909Smckusick struct vnode *vp; 144739909Smckusick { 144839909Smckusick 144939909Smckusick if (VTOI(vp)->i_flag & ILOCKED) 145039909Smckusick return (1); 145139909Smckusick return (0); 145239909Smckusick } 145339909Smckusick 145439909Smckusick /* 145537737Smckusick * Get access to bmap 145612756Ssam */ 145737737Smckusick ufs_bmap(vp, bn, vpp, bnp) 145837737Smckusick struct vnode *vp; 145937737Smckusick daddr_t bn; 146037737Smckusick struct vnode **vpp; 146137737Smckusick daddr_t *bnp; 146212756Ssam { 146337737Smckusick struct inode *ip = VTOI(vp); 146412756Ssam 146537737Smckusick if (vpp != NULL) 146637737Smckusick *vpp = ip->i_devvp; 146737737Smckusick if (bnp == NULL) 146837737Smckusick return (0); 146941538Smckusick return (bmap(ip, bn, bnp)); 147012756Ssam } 147137737Smckusick 147237737Smckusick /* 147341538Smckusick * Calculate the logical to physical mapping if not done already, 147441538Smckusick * then call the device strategy routine. 147537737Smckusick */ 147641538Smckusick int checkoverlap = 0; 147739674Smckusick 147837737Smckusick ufs_strategy(bp) 147937737Smckusick register struct buf *bp; 148037737Smckusick { 148139674Smckusick register struct inode *ip = VTOI(bp->b_vp); 148239674Smckusick struct vnode *vp; 148339674Smckusick int error; 148439674Smckusick 148539674Smckusick if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR) 148639674Smckusick panic("ufs_strategy: spec"); 148739674Smckusick if (bp->b_blkno == bp->b_lblkno) { 148839674Smckusick if (error = bmap(ip, bp->b_lblkno, &bp->b_blkno)) 148939674Smckusick return (error); 149039896Smckusick if ((long)bp->b_blkno == -1) 149139674Smckusick clrbuf(bp); 149239674Smckusick } 149339896Smckusick if ((long)bp->b_blkno == -1) { 149439896Smckusick biodone(bp); 149539674Smckusick return (0); 149639896Smckusick } 149741538Smckusick #ifdef DIAGNOSTIC 149839674Smckusick if (checkoverlap) { 149941538Smckusick register struct buf *ep; 150041538Smckusick struct buf *ebp; 150141538Smckusick daddr_t start, last; 150241538Smckusick 150339674Smckusick ebp = &buf[nbuf]; 150439674Smckusick start = bp->b_blkno; 150539674Smckusick last = start + btodb(bp->b_bcount) - 1; 150639674Smckusick for (ep = buf; ep < ebp; ep++) { 150739674Smckusick if (ep == bp || (ep->b_flags & B_INVAL) || 150841396Smckusick ep->b_vp == NULLVP) 150939674Smckusick continue; 151039674Smckusick if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0)) 151139674Smckusick continue; 151239674Smckusick if (vp != ip->i_devvp) 151339674Smckusick continue; 151439674Smckusick /* look for overlap */ 151539674Smckusick if (ep->b_bcount == 0 || ep->b_blkno > last || 151639674Smckusick ep->b_blkno + btodb(ep->b_bcount) <= start) 151739674Smckusick continue; 151839896Smckusick vprint("Disk overlap", vp); 151939896Smckusick printf("\tstart %d, end %d overlap start %d, end %d\n", 152039896Smckusick start, last, ep->b_blkno, 152139896Smckusick ep->b_blkno + btodb(ep->b_bcount) - 1); 152241538Smckusick panic("Disk buffer overlap"); 152339674Smckusick } 152439674Smckusick } 152541538Smckusick #endif /* DIAGNOSTIC */ 152639674Smckusick vp = ip->i_devvp; 152739674Smckusick bp->b_dev = vp->v_rdev; 152839674Smckusick (*(vp->v_op->vn_strategy))(bp); 152937737Smckusick return (0); 153037737Smckusick } 153137737Smckusick 153237737Smckusick /* 153339674Smckusick * Print out the contents of an inode. 153439674Smckusick */ 153539674Smckusick ufs_print(vp) 153639674Smckusick struct vnode *vp; 153739674Smckusick { 153839674Smckusick register struct inode *ip = VTOI(vp); 153939674Smckusick 154040293Smckusick printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number, 154140293Smckusick major(ip->i_dev), minor(ip->i_dev)); 154240293Smckusick #ifdef FIFO 154340293Smckusick if (vp->v_type == VFIFO) 154440293Smckusick fifo_printinfo(vp); 154540293Smckusick #endif /* FIFO */ 154640293Smckusick printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : ""); 154739900Smckusick if (ip->i_spare0 == 0) 154839900Smckusick return; 154939900Smckusick printf("\towner pid %d", ip->i_spare0); 155039900Smckusick if (ip->i_spare1) 155139900Smckusick printf(" waiting pid %d", ip->i_spare1); 155239900Smckusick printf("\n"); 155339674Smckusick } 155439674Smckusick 155539674Smckusick /* 155639628Smckusick * Read wrapper for special devices. 155739628Smckusick */ 155839628Smckusick ufsspec_read(vp, uio, ioflag, cred) 155939628Smckusick struct vnode *vp; 156039628Smckusick struct uio *uio; 156139628Smckusick int ioflag; 156239628Smckusick struct ucred *cred; 156339628Smckusick { 156439628Smckusick 156539628Smckusick /* 156639628Smckusick * Set access flag. 156739628Smckusick */ 156839628Smckusick VTOI(vp)->i_flag |= IACC; 156939628Smckusick return (spec_read(vp, uio, ioflag, cred)); 157039628Smckusick } 157139628Smckusick 157239628Smckusick /* 157339628Smckusick * Write wrapper for special devices. 157439628Smckusick */ 157539628Smckusick ufsspec_write(vp, uio, ioflag, cred) 157639628Smckusick struct vnode *vp; 157739628Smckusick struct uio *uio; 157839628Smckusick int ioflag; 157939628Smckusick struct ucred *cred; 158039628Smckusick { 158139628Smckusick 158239628Smckusick /* 158339628Smckusick * Set update and change flags. 158439628Smckusick */ 158539628Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 158639628Smckusick return (spec_write(vp, uio, ioflag, cred)); 158739628Smckusick } 158839628Smckusick 158939628Smckusick /* 159039628Smckusick * Close wrapper for special devices. 159139628Smckusick * 159239628Smckusick * Update the times on the inode then do device close. 159339628Smckusick */ 159439628Smckusick ufsspec_close(vp, fflag, cred) 159539628Smckusick struct vnode *vp; 159639628Smckusick int fflag; 159739628Smckusick struct ucred *cred; 159839628Smckusick { 159939628Smckusick register struct inode *ip = VTOI(vp); 160039628Smckusick 160139815Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 160239628Smckusick ITIMES(ip, &time, &time); 160339628Smckusick return (spec_close(vp, fflag, cred)); 160439628Smckusick } 160539628Smckusick 160640290Smckusick #ifdef FIFO 160739628Smckusick /* 160840290Smckusick * Read wrapper for fifo's 160940290Smckusick */ 161040290Smckusick ufsfifo_read(vp, uio, ioflag, cred) 161140290Smckusick struct vnode *vp; 161240290Smckusick struct uio *uio; 161340290Smckusick int ioflag; 161440290Smckusick struct ucred *cred; 161540290Smckusick { 161640290Smckusick 161740290Smckusick /* 161840290Smckusick * Set access flag. 161940290Smckusick */ 162040290Smckusick VTOI(vp)->i_flag |= IACC; 162140290Smckusick return (fifo_read(vp, uio, ioflag, cred)); 162240290Smckusick } 162340290Smckusick 162440290Smckusick /* 162540290Smckusick * Write wrapper for fifo's. 162640290Smckusick */ 162740290Smckusick ufsfifo_write(vp, uio, ioflag, cred) 162840290Smckusick struct vnode *vp; 162940290Smckusick struct uio *uio; 163040290Smckusick int ioflag; 163140290Smckusick struct ucred *cred; 163240290Smckusick { 163340290Smckusick 163440290Smckusick /* 163540290Smckusick * Set update and change flags. 163640290Smckusick */ 163740290Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 163840290Smckusick return (fifo_write(vp, uio, ioflag, cred)); 163940290Smckusick } 164040290Smckusick 164140290Smckusick /* 164240290Smckusick * Close wrapper for fifo's. 164340290Smckusick * 164440290Smckusick * Update the times on the inode then do device close. 164540290Smckusick */ 164640290Smckusick ufsfifo_close(vp, fflag, cred) 164740290Smckusick struct vnode *vp; 164840290Smckusick int fflag; 164940290Smckusick struct ucred *cred; 165040290Smckusick { 165140290Smckusick register struct inode *ip = VTOI(vp); 165240290Smckusick 165340290Smckusick if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) 165440290Smckusick ITIMES(ip, &time, &time); 165540290Smckusick return (fifo_close(vp, fflag, cred)); 165640290Smckusick } 165740290Smckusick #endif /* FIFO */ 165840290Smckusick 165940290Smckusick /* 166037737Smckusick * Make a new file. 166137737Smckusick */ 166237737Smckusick maknode(mode, ndp, ipp) 166337737Smckusick int mode; 166437737Smckusick register struct nameidata *ndp; 166537737Smckusick struct inode **ipp; 166637737Smckusick { 166737737Smckusick register struct inode *ip; 166837737Smckusick struct inode *tip; 166937737Smckusick register struct inode *pdir = VTOI(ndp->ni_dvp); 167037737Smckusick ino_t ipref; 167137737Smckusick int error; 167237737Smckusick 167337737Smckusick *ipp = 0; 167441312Smckusick if ((mode & IFMT) == 0) 167541312Smckusick mode |= IFREG; 167637737Smckusick if ((mode & IFMT) == IFDIR) 167737737Smckusick ipref = dirpref(pdir->i_fs); 167837737Smckusick else 167937737Smckusick ipref = pdir->i_number; 168041312Smckusick if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) { 168137737Smckusick iput(pdir); 168237737Smckusick return (error); 168337737Smckusick } 168437737Smckusick ip = tip; 168541312Smckusick ip->i_uid = ndp->ni_cred->cr_uid; 168641312Smckusick ip->i_gid = pdir->i_gid; 168737737Smckusick #ifdef QUOTA 168841312Smckusick if ((error = getinoquota(ip)) || 168941312Smckusick (error = chkiq(ip, 1, ndp->ni_cred, 0))) { 169041312Smckusick ifree(ip, ip->i_number, mode); 169141312Smckusick iput(ip); 169241312Smckusick iput(pdir); 169341312Smckusick return (error); 169441312Smckusick } 169537737Smckusick #endif 169637737Smckusick ip->i_flag |= IACC|IUPD|ICHG; 169737737Smckusick ip->i_mode = mode; 169837737Smckusick ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */ 169937737Smckusick ip->i_nlink = 1; 170037737Smckusick if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) && 170137737Smckusick suser(ndp->ni_cred, NULL)) 170237737Smckusick ip->i_mode &= ~ISGID; 170337737Smckusick 170437737Smckusick /* 170537737Smckusick * Make sure inode goes to disk before directory entry. 170637737Smckusick */ 170741312Smckusick if (error = iupdat(ip, &time, &time, 1)) 170841312Smckusick goto bad; 170941312Smckusick if (error = direnter(ip, ndp)) { 171041312Smckusick pdir = NULL; 171141312Smckusick goto bad; 171237737Smckusick } 171337737Smckusick *ipp = ip; 171437737Smckusick return (0); 171541312Smckusick 171641312Smckusick bad: 171741312Smckusick /* 171841312Smckusick * Write error occurred trying to update the inode 171941312Smckusick * or the directory so must deallocate the inode. 172041312Smckusick */ 172141312Smckusick if (pdir) 172241312Smckusick iput(pdir); 172341312Smckusick ip->i_nlink = 0; 172441312Smckusick ip->i_flag |= ICHG; 172541312Smckusick iput(ip); 172641312Smckusick return (error); 172737737Smckusick } 1728*46207Smckusick 1729*46207Smckusick /* 1730*46207Smckusick * Advisory record locking support 1731*46207Smckusick */ 1732*46207Smckusick ufs_advlock(vp, id, op, fl, flags) 1733*46207Smckusick struct vnode *vp; 1734*46207Smckusick caddr_t id; 1735*46207Smckusick int op; 1736*46207Smckusick register struct flock *fl; 1737*46207Smckusick int flags; 1738*46207Smckusick { 1739*46207Smckusick register struct inode *ip = VTOI(vp); 1740*46207Smckusick register struct lockf *lock; 1741*46207Smckusick off_t start, end; 1742*46207Smckusick int error; 1743*46207Smckusick 1744*46207Smckusick /* 1745*46207Smckusick * Avoid the common case of unlocking when inode has no locks. 1746*46207Smckusick */ 1747*46207Smckusick if (ip->i_lockf == (struct lockf *)0) { 1748*46207Smckusick if (op != F_SETLK) { 1749*46207Smckusick fl->l_type = F_UNLCK; 1750*46207Smckusick return (0); 1751*46207Smckusick } 1752*46207Smckusick } 1753*46207Smckusick /* 1754*46207Smckusick * Convert the flock structure into a start and end. 1755*46207Smckusick */ 1756*46207Smckusick switch (fl->l_whence) { 1757*46207Smckusick 1758*46207Smckusick case SEEK_SET: 1759*46207Smckusick case SEEK_CUR: 1760*46207Smckusick /* 1761*46207Smckusick * Caller is responsible for adding any necessary offset 1762*46207Smckusick * when SEEK_CUR is used. 1763*46207Smckusick */ 1764*46207Smckusick start = fl->l_start; 1765*46207Smckusick break; 1766*46207Smckusick 1767*46207Smckusick case SEEK_END: 1768*46207Smckusick start = ip->i_size + fl->l_start; 1769*46207Smckusick break; 1770*46207Smckusick 1771*46207Smckusick default: 1772*46207Smckusick return (EINVAL); 1773*46207Smckusick } 1774*46207Smckusick if (start < 0) 1775*46207Smckusick return (EINVAL); 1776*46207Smckusick if (fl->l_len == 0) 1777*46207Smckusick end = -1; 1778*46207Smckusick else 1779*46207Smckusick end = start + fl->l_len; 1780*46207Smckusick /* 1781*46207Smckusick * Create the lockf structure 1782*46207Smckusick */ 1783*46207Smckusick MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK); 1784*46207Smckusick lock->lf_start = start; 1785*46207Smckusick lock->lf_end = end; 1786*46207Smckusick lock->lf_id = id; 1787*46207Smckusick lock->lf_inode = ip; 1788*46207Smckusick lock->lf_type = fl->l_type; 1789*46207Smckusick lock->lf_next = (struct lockf *)0; 1790*46207Smckusick lock->lf_block = (struct lockf *)0; 1791*46207Smckusick lock->lf_flags = flags; 1792*46207Smckusick /* 1793*46207Smckusick * Do the requested operation. 1794*46207Smckusick */ 1795*46207Smckusick switch(op) { 1796*46207Smckusick case F_SETLK: 1797*46207Smckusick return (ufs_setlock(lock)); 1798*46207Smckusick 1799*46207Smckusick case F_UNLCK: 1800*46207Smckusick return (ufs_advunlock(lock)); 1801*46207Smckusick 1802*46207Smckusick case F_GETLK: 1803*46207Smckusick return (ufs_advgetlock(lock, fl)); 1804*46207Smckusick 1805*46207Smckusick default: 1806*46207Smckusick free(lock, M_LOCKF); 1807*46207Smckusick return (EINVAL); 1808*46207Smckusick } 1809*46207Smckusick /* NOTREACHED */ 1810*46207Smckusick } 1811*46207Smckusick 1812*46207Smckusick /* 1813*46207Smckusick * This variable controls the maximum number of processes that will 1814*46207Smckusick * be checked in doing deadlock detection. 1815*46207Smckusick */ 1816*46207Smckusick int maxlockdepth = MAXDEPTH; 1817*46207Smckusick 1818*46207Smckusick /* 1819*46207Smckusick * Set a byte-range lock. 1820*46207Smckusick */ 1821*46207Smckusick ufs_setlock(lock) 1822*46207Smckusick register struct lockf *lock; 1823*46207Smckusick { 1824*46207Smckusick register struct inode *ip = lock->lf_inode; 1825*46207Smckusick register struct lockf *block; 1826*46207Smckusick static char lockstr[] = "lockf"; 1827*46207Smckusick int priority, error; 1828*46207Smckusick 1829*46207Smckusick #ifdef LOCKF_DEBUG 1830*46207Smckusick if (lockf_debug & 4) 1831*46207Smckusick lf_print("ufs_setlock", lock); 1832*46207Smckusick #endif /* LOCKF_DEBUG */ 1833*46207Smckusick 1834*46207Smckusick /* 1835*46207Smckusick * Set the priority 1836*46207Smckusick */ 1837*46207Smckusick priority = PLOCK; 1838*46207Smckusick if ((lock->lf_type & F_WRLCK) == 0) 1839*46207Smckusick priority += 4; 1840*46207Smckusick priority |= PCATCH; 1841*46207Smckusick /* 1842*46207Smckusick * Scan lock list for this file looking for locks that would block us. 1843*46207Smckusick */ 1844*46207Smckusick while (block = lf_getblock(lock)) { 1845*46207Smckusick /* 1846*46207Smckusick * Free the structure and return if nonblocking. 1847*46207Smckusick */ 1848*46207Smckusick if ((lock->lf_flags & F_WAIT) == 0) { 1849*46207Smckusick free(lock, M_LOCKF); 1850*46207Smckusick return (EAGAIN); 1851*46207Smckusick } 1852*46207Smckusick /* 1853*46207Smckusick * We are blocked. Since flock style locks cover 1854*46207Smckusick * the whole file, there is no chance for deadlock. 1855*46207Smckusick * For byte-range locks we must check for deadlock. 1856*46207Smckusick * 1857*46207Smckusick * Deadlock detection is done by looking through the 1858*46207Smckusick * wait channels to see if there are any cycles that 1859*46207Smckusick * involve us. MAXDEPTH is set just to make sure we 1860*46207Smckusick * do not go off into neverland. 1861*46207Smckusick */ 1862*46207Smckusick if ((lock->lf_flags & F_POSIX) && 1863*46207Smckusick (block->lf_flags & F_POSIX)) { 1864*46207Smckusick register struct proc *wproc; 1865*46207Smckusick register struct lockf *waitblock; 1866*46207Smckusick int i = 0; 1867*46207Smckusick 1868*46207Smckusick /* The block is waiting on something */ 1869*46207Smckusick wproc = (struct proc *)block->lf_id; 1870*46207Smckusick while (wproc->p_wchan && 1871*46207Smckusick (wproc->p_wmesg == lockstr) && 1872*46207Smckusick (i++ < maxlockdepth)) { 1873*46207Smckusick waitblock = (struct lockf *)wproc->p_wchan; 1874*46207Smckusick /* Get the owner of the blocking lock */ 1875*46207Smckusick waitblock = waitblock->lf_next; 1876*46207Smckusick if ((waitblock->lf_flags & F_POSIX) == 0) 1877*46207Smckusick break; 1878*46207Smckusick wproc = (struct proc *)waitblock->lf_id; 1879*46207Smckusick if (wproc == (struct proc *)lock->lf_id) { 1880*46207Smckusick free(lock, M_LOCKF); 1881*46207Smckusick return (EDEADLK); 1882*46207Smckusick } 1883*46207Smckusick } 1884*46207Smckusick } 1885*46207Smckusick /* 1886*46207Smckusick * Add our lock to the blocked 1887*46207Smckusick * list and sleep until we're free. 1888*46207Smckusick */ 1889*46207Smckusick #ifdef LOCKF_DEBUG 1890*46207Smckusick if (lockf_debug & 4) 1891*46207Smckusick lf_print("ufs_advlock: blocking on", block); 1892*46207Smckusick #endif /* LOCKF_DEBUG */ 1893*46207Smckusick /* 1894*46207Smckusick * Remember who blocked us (for deadlock detection) 1895*46207Smckusick */ 1896*46207Smckusick lock->lf_next = block; 1897*46207Smckusick lf_addblock(block, lock); 1898*46207Smckusick if (error = tsleep((caddr_t *)lock, priority, lockstr, 0)) { 1899*46207Smckusick free(lock, M_LOCKF); 1900*46207Smckusick return (error); 1901*46207Smckusick } 1902*46207Smckusick } 1903*46207Smckusick /* 1904*46207Smckusick * No blocks!! Add the lock. Note that addlock will 1905*46207Smckusick * downgrade or upgrade any overlapping locks this 1906*46207Smckusick * process already owns. 1907*46207Smckusick */ 1908*46207Smckusick #ifdef LOCKF_DEBUG 1909*46207Smckusick if (lockf_debug & 4) 1910*46207Smckusick lf_print("ufs_advlock: got the lock", lock); 1911*46207Smckusick #endif /* LOCKF_DEBUG */ 1912*46207Smckusick lf_addlock(lock); 1913*46207Smckusick return (0); 1914*46207Smckusick } 1915*46207Smckusick 1916*46207Smckusick /* 1917*46207Smckusick * Remove a byte-range lock on an inode. 1918*46207Smckusick */ 1919*46207Smckusick ufs_advunlock(lock) 1920*46207Smckusick struct lockf *lock; 1921*46207Smckusick { 1922*46207Smckusick struct lockf *blocklist; 1923*46207Smckusick 1924*46207Smckusick if (lock->lf_inode->i_lockf == (struct lockf *)0) 1925*46207Smckusick return (0); 1926*46207Smckusick #ifdef LOCKF_DEBUG 1927*46207Smckusick if (lockf_debug & 4) 1928*46207Smckusick lf_print("ufs_advunlock", lock); 1929*46207Smckusick #endif /* LOCKF_DEBUG */ 1930*46207Smckusick /* 1931*46207Smckusick * Generally, find the lock (or an overlap to that lock) 1932*46207Smckusick * and remove it (or shrink it), then wakeup anyone we can. 1933*46207Smckusick */ 1934*46207Smckusick blocklist = lf_remove(lock); 1935*46207Smckusick FREE(lock, M_LOCKF); 1936*46207Smckusick lf_wakelock(blocklist); 1937*46207Smckusick return (0); 1938*46207Smckusick } 1939*46207Smckusick 1940*46207Smckusick /* 1941*46207Smckusick * Return the blocking pid 1942*46207Smckusick */ 1943*46207Smckusick ufs_advgetlock(lock, fl) 1944*46207Smckusick register struct lockf *lock; 1945*46207Smckusick register struct flock *fl; 1946*46207Smckusick { 1947*46207Smckusick register struct lockf *block; 1948*46207Smckusick off_t start, end; 1949*46207Smckusick 1950*46207Smckusick #ifdef LOCKF_DEBUG 1951*46207Smckusick if (lockf_debug & 4) 1952*46207Smckusick lf_print("ufs_advgetlock", lock); 1953*46207Smckusick #endif /* LOCKF_DEBUG */ 1954*46207Smckusick 1955*46207Smckusick if (block = lf_getblock(lock)) { 1956*46207Smckusick fl->l_type = block->lf_type; 1957*46207Smckusick fl->l_whence = SEEK_SET; 1958*46207Smckusick fl->l_start = block->lf_start; 1959*46207Smckusick if (block->lf_end == -1) 1960*46207Smckusick fl->l_len = 0; 1961*46207Smckusick else 1962*46207Smckusick fl->l_len = block->lf_end - block->lf_start; 1963*46207Smckusick if (block->lf_flags & F_POSIX) 1964*46207Smckusick fl->l_pid = ((struct proc *)(block->lf_id))->p_pid; 1965*46207Smckusick else 1966*46207Smckusick fl->l_pid = -1; 1967*46207Smckusick } 1968*46207Smckusick FREE(lock, M_LOCKF); 1969*46207Smckusick return (0); 1970*46207Smckusick } 1971