xref: /csrg-svn/sys/ufs/lfs/lfs_vnops.c (revision 51134)
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