ufs_vnops.c revision 137035
1/*
2 * Copyright (c) 1982, 1986, 1989, 1993, 1995
3 *	The Regents of the University of California.  All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 4. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 *	@(#)ufs_vnops.c	8.27 (Berkeley) 5/27/95
35 */
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD: head/sys/ufs/ufs/ufs_vnops.c 137035 2004-10-29 10:15:56Z phk $");
39
40#include "opt_mac.h"
41#include "opt_quota.h"
42#include "opt_suiddir.h"
43#include "opt_ufs.h"
44#include "opt_ffs.h"
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/malloc.h>
49#include <sys/namei.h>
50#include <sys/kernel.h>
51#include <sys/fcntl.h>
52#include <sys/stat.h>
53#include <sys/bio.h>
54#include <sys/buf.h>
55#include <sys/mount.h>
56#include <sys/unistd.h>
57#include <sys/vnode.h>
58#include <sys/dirent.h>
59#include <sys/lockf.h>
60#include <sys/event.h>
61#include <sys/conf.h>
62#include <sys/acl.h>
63#include <sys/mac.h>
64
65#include <machine/mutex.h>
66
67#include <sys/file.h>		/* XXX */
68
69#include <vm/vm.h>
70#include <vm/vm_extern.h>
71
72#include <fs/fifofs/fifo.h>
73
74#include <ufs/ufs/acl.h>
75#include <ufs/ufs/extattr.h>
76#include <ufs/ufs/quota.h>
77#include <ufs/ufs/inode.h>
78#include <ufs/ufs/dir.h>
79#include <ufs/ufs/ufsmount.h>
80#include <ufs/ufs/ufs_extern.h>
81#ifdef UFS_DIRHASH
82#include <ufs/ufs/dirhash.h>
83#endif
84
85#include <ufs/ffs/ffs_extern.h>
86
87static int ufs_access(struct vop_access_args *);
88static int ufs_advlock(struct vop_advlock_args *);
89static int ufs_chmod(struct vnode *, int, struct ucred *, struct thread *);
90static int ufs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct thread *);
91static int ufs_close(struct vop_close_args *);
92static int ufs_create(struct vop_create_args *);
93static int ufs_getattr(struct vop_getattr_args *);
94static int ufs_link(struct vop_link_args *);
95static int ufs_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *);
96static int ufs_mkdir(struct vop_mkdir_args *);
97static int ufs_mknod(struct vop_mknod_args *);
98static int ufs_open(struct vop_open_args *);
99static int ufs_pathconf(struct vop_pathconf_args *);
100static int ufs_lock(struct vop_lock_args *);
101static int ufs_print(struct vop_print_args *);
102static int ufs_readlink(struct vop_readlink_args *);
103static int ufs_remove(struct vop_remove_args *);
104static int ufs_rename(struct vop_rename_args *);
105static int ufs_rmdir(struct vop_rmdir_args *);
106static int ufs_setattr(struct vop_setattr_args *);
107static int ufs_strategy(struct vop_strategy_args *);
108static int ufs_symlink(struct vop_symlink_args *);
109static int ufs_whiteout(struct vop_whiteout_args *);
110static int ufsfifo_close(struct vop_close_args *);
111static int ufsfifo_kqfilter(struct vop_kqfilter_args *);
112static int ufsfifo_read(struct vop_read_args *);
113static int ufsfifo_write(struct vop_write_args *);
114static int filt_ufsread(struct knote *kn, long hint);
115static int filt_ufswrite(struct knote *kn, long hint);
116static int filt_ufsvnode(struct knote *kn, long hint);
117static void filt_ufsdetach(struct knote *kn);
118static int ufs_kqfilter(struct vop_kqfilter_args *ap);
119
120/*
121 * A virgin directory (no blushing please).
122 */
123static struct dirtemplate mastertemplate = {
124	0, 12, DT_DIR, 1, ".",
125	0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
126};
127static struct odirtemplate omastertemplate = {
128	0, 12, 1, ".",
129	0, DIRBLKSIZ - 12, 2, ".."
130};
131
132void
133ufs_itimes(vp)
134	struct vnode *vp;
135{
136	struct inode *ip;
137	struct timespec ts;
138
139	ip = VTOI(vp);
140	if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0)
141		return;
142	if ((vp->v_type == VBLK || vp->v_type == VCHR) && !DOINGSOFTDEP(vp))
143		ip->i_flag |= IN_LAZYMOD;
144	else
145		ip->i_flag |= IN_MODIFIED;
146	if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
147		vfs_timestamp(&ts);
148		if (ip->i_flag & IN_ACCESS) {
149			DIP_SET(ip, i_atime, ts.tv_sec);
150			DIP_SET(ip, i_atimensec, ts.tv_nsec);
151		}
152		if (ip->i_flag & IN_UPDATE) {
153			DIP_SET(ip, i_mtime, ts.tv_sec);
154			DIP_SET(ip, i_mtimensec, ts.tv_nsec);
155			ip->i_modrev++;
156		}
157		if (ip->i_flag & IN_CHANGE) {
158			DIP_SET(ip, i_ctime, ts.tv_sec);
159			DIP_SET(ip, i_ctimensec, ts.tv_nsec);
160		}
161	}
162	ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);
163}
164
165/*
166 * Create a regular file
167 */
168static int
169ufs_create(ap)
170	struct vop_create_args /* {
171		struct vnode *a_dvp;
172		struct vnode **a_vpp;
173		struct componentname *a_cnp;
174		struct vattr *a_vap;
175	} */ *ap;
176{
177	int error;
178
179	error =
180	    ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
181	    ap->a_dvp, ap->a_vpp, ap->a_cnp);
182	if (error)
183		return (error);
184	VN_KNOTE_UNLOCKED(ap->a_dvp, NOTE_WRITE);
185	return (0);
186}
187
188/*
189 * Mknod vnode call
190 */
191/* ARGSUSED */
192static int
193ufs_mknod(ap)
194	struct vop_mknod_args /* {
195		struct vnode *a_dvp;
196		struct vnode **a_vpp;
197		struct componentname *a_cnp;
198		struct vattr *a_vap;
199	} */ *ap;
200{
201	struct vattr *vap = ap->a_vap;
202	struct vnode **vpp = ap->a_vpp;
203	struct inode *ip;
204	ino_t ino;
205	int error;
206
207	error = ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
208	    ap->a_dvp, vpp, ap->a_cnp);
209	if (error)
210		return (error);
211	VN_KNOTE_UNLOCKED(ap->a_dvp, NOTE_WRITE);
212	ip = VTOI(*vpp);
213	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
214	if (vap->va_rdev != VNOVAL) {
215		/*
216		 * Want to be able to use this to make badblock
217		 * inodes, so don't truncate the dev number.
218		 */
219		DIP_SET(ip, i_rdev, vap->va_rdev);
220	}
221	/*
222	 * Remove inode, then reload it through VFS_VGET so it is
223	 * checked to see if it is an alias of an existing entry in
224	 * the inode cache.
225	 */
226	vput(*vpp);
227	(*vpp)->v_type = VNON;
228	ino = ip->i_number;	/* Save this before vgone() invalidates ip. */
229	vgone(*vpp);
230	error = VFS_VGET(ap->a_dvp->v_mount, ino, LK_EXCLUSIVE, vpp);
231	if (error) {
232		*vpp = NULL;
233		return (error);
234	}
235	return (0);
236}
237
238/*
239 * Open called.
240 *
241 * Nothing to do.
242 */
243/* ARGSUSED */
244static int
245ufs_open(ap)
246	struct vop_open_args /* {
247		struct vnode *a_vp;
248		int  a_mode;
249		struct ucred *a_cred;
250		struct thread *a_td;
251	} */ *ap;
252{
253
254	if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
255		return (EOPNOTSUPP);
256
257	/*
258	 * Files marked append-only must be opened for appending.
259	 */
260	if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
261	    (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
262		return (EPERM);
263	return (0);
264}
265
266/*
267 * Close called.
268 *
269 * Update the times on the inode.
270 */
271/* ARGSUSED */
272static int
273ufs_close(ap)
274	struct vop_close_args /* {
275		struct vnode *a_vp;
276		int  a_fflag;
277		struct ucred *a_cred;
278		struct thread *a_td;
279	} */ *ap;
280{
281	struct vnode *vp = ap->a_vp;
282	struct mount *mp;
283
284	VI_LOCK(vp);
285	if (vp->v_usecount > 1) {
286		ufs_itimes(vp);
287		VI_UNLOCK(vp);
288	} else {
289		VI_UNLOCK(vp);
290		/*
291		 * If we are closing the last reference to an unlinked
292		 * file, then it will be freed by the inactive routine.
293		 * Because the freeing causes a the filesystem to be
294		 * modified, it must be held up during periods when the
295		 * filesystem is suspended.
296		 *
297		 * XXX - EAGAIN is returned to prevent vn_close from
298		 * repeating the vrele operation.
299		 */
300		if (vp->v_type == VREG && VTOI(vp)->i_effnlink == 0) {
301			(void) vn_start_write(vp, &mp, V_WAIT);
302			vrele(vp);
303			vn_finished_write(mp);
304			return (EAGAIN);
305		}
306	}
307	return (0);
308}
309
310static int
311ufs_access(ap)
312	struct vop_access_args /* {
313		struct vnode *a_vp;
314		int  a_mode;
315		struct ucred *a_cred;
316		struct thread *a_td;
317	} */ *ap;
318{
319	struct vnode *vp = ap->a_vp;
320	struct inode *ip = VTOI(vp);
321	mode_t mode = ap->a_mode;
322	int error;
323#ifdef UFS_ACL
324	struct acl *acl;
325#endif
326
327	/*
328	 * Disallow write attempts on read-only filesystems;
329	 * unless the file is a socket, fifo, or a block or
330	 * character device resident on the filesystem.
331	 */
332	if (mode & VWRITE) {
333		switch (vp->v_type) {
334		case VDIR:
335		case VLNK:
336		case VREG:
337			if (vp->v_mount->mnt_flag & MNT_RDONLY)
338				return (EROFS);
339#ifdef QUOTA
340			if ((error = getinoquota(ip)) != 0)
341				return (error);
342#endif
343			break;
344		default:
345			break;
346		}
347	}
348
349	/* If immutable bit set, nobody gets to write it. */
350	if ((mode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT)))
351		return (EPERM);
352
353#ifdef UFS_ACL
354	if ((vp->v_mount->mnt_flag & MNT_ACLS) != 0) {
355		MALLOC(acl, struct acl *, sizeof(*acl), M_ACL, M_WAITOK);
356		error = VOP_GETACL(vp, ACL_TYPE_ACCESS, acl, ap->a_cred,
357		    ap->a_td);
358		switch (error) {
359		case EOPNOTSUPP:
360			error = vaccess(vp->v_type, ip->i_mode, ip->i_uid,
361			    ip->i_gid, ap->a_mode, ap->a_cred, NULL);
362			break;
363		case 0:
364			error = vaccess_acl_posix1e(vp->v_type, ip->i_uid,
365			    ip->i_gid, acl, ap->a_mode, ap->a_cred, NULL);
366			break;
367		default:
368			printf(
369"ufs_access(): Error retrieving ACL on object (%d).\n",
370			    error);
371			/*
372			 * XXX: Fall back until debugged.  Should
373			 * eventually possibly log an error, and return
374			 * EPERM for safety.
375			 */
376			error = vaccess(vp->v_type, ip->i_mode, ip->i_uid,
377			    ip->i_gid, ap->a_mode, ap->a_cred, NULL);
378		}
379		FREE(acl, M_ACL);
380	} else
381#endif /* !UFS_ACL */
382		error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid,
383		    ap->a_mode, ap->a_cred, NULL);
384	return (error);
385}
386
387/* ARGSUSED */
388static int
389ufs_getattr(ap)
390	struct vop_getattr_args /* {
391		struct vnode *a_vp;
392		struct vattr *a_vap;
393		struct ucred *a_cred;
394		struct thread *a_td;
395	} */ *ap;
396{
397	struct vnode *vp = ap->a_vp;
398	struct inode *ip = VTOI(vp);
399	struct vattr *vap = ap->a_vap;
400
401	ufs_itimes(vp);
402	/*
403	 * Copy from inode table
404	 */
405	vap->va_fsid = dev2udev(ip->i_dev);
406	vap->va_fileid = ip->i_number;
407	vap->va_mode = ip->i_mode & ~IFMT;
408	vap->va_nlink = ip->i_effnlink;
409	vap->va_uid = ip->i_uid;
410	vap->va_gid = ip->i_gid;
411	if (ip->i_ump->um_fstype == UFS1) {
412		vap->va_rdev = ip->i_din1->di_rdev;
413		vap->va_size = ip->i_din1->di_size;
414		vap->va_atime.tv_sec = ip->i_din1->di_atime;
415		vap->va_atime.tv_nsec = ip->i_din1->di_atimensec;
416		vap->va_mtime.tv_sec = ip->i_din1->di_mtime;
417		vap->va_mtime.tv_nsec = ip->i_din1->di_mtimensec;
418		vap->va_ctime.tv_sec = ip->i_din1->di_ctime;
419		vap->va_ctime.tv_nsec = ip->i_din1->di_ctimensec;
420		vap->va_birthtime.tv_sec = 0;
421		vap->va_birthtime.tv_nsec = 0;
422		vap->va_bytes = dbtob((u_quad_t)ip->i_din1->di_blocks);
423	} else {
424		vap->va_rdev = ip->i_din2->di_rdev;
425		vap->va_size = ip->i_din2->di_size;
426		vap->va_atime.tv_sec = ip->i_din2->di_atime;
427		vap->va_atime.tv_nsec = ip->i_din2->di_atimensec;
428		vap->va_mtime.tv_sec = ip->i_din2->di_mtime;
429		vap->va_mtime.tv_nsec = ip->i_din2->di_mtimensec;
430		vap->va_ctime.tv_sec = ip->i_din2->di_ctime;
431		vap->va_ctime.tv_nsec = ip->i_din2->di_ctimensec;
432		vap->va_birthtime.tv_sec = ip->i_din2->di_birthtime;
433		vap->va_birthtime.tv_nsec = ip->i_din2->di_birthnsec;
434		vap->va_bytes = dbtob((u_quad_t)ip->i_din2->di_blocks);
435	}
436	vap->va_flags = ip->i_flags;
437	vap->va_gen = ip->i_gen;
438	vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
439	vap->va_type = IFTOVT(ip->i_mode);
440	vap->va_filerev = ip->i_modrev;
441	return (0);
442}
443
444/*
445 * Set attribute vnode op. called from several syscalls
446 */
447static int
448ufs_setattr(ap)
449	struct vop_setattr_args /* {
450		struct vnode *a_vp;
451		struct vattr *a_vap;
452		struct ucred *a_cred;
453		struct thread *a_td;
454	} */ *ap;
455{
456	struct vattr *vap = ap->a_vap;
457	struct vnode *vp = ap->a_vp;
458	struct inode *ip = VTOI(vp);
459	struct ucred *cred = ap->a_cred;
460	struct thread *td = ap->a_td;
461	int error;
462
463	/*
464	 * Check for unsettable attributes.
465	 */
466	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
467	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
468	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
469	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
470		return (EINVAL);
471	}
472	if (vap->va_flags != VNOVAL) {
473		if (vp->v_mount->mnt_flag & MNT_RDONLY)
474			return (EROFS);
475		/*
476		 * Callers may only modify the file flags on objects they
477		 * have VADMIN rights for.
478		 */
479		if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
480			return (error);
481		/*
482		 * Unprivileged processes and privileged processes in
483		 * jail() are not permitted to unset system flags, or
484		 * modify flags if any system flags are set.
485		 * Privileged non-jail processes may not modify system flags
486		 * if securelevel > 0 and any existing system flags are set.
487		 */
488		if (!suser_cred(cred, 0)) {
489			if (ip->i_flags
490			    & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) {
491				error = securelevel_gt(cred, 0);
492				if (error)
493					return (error);
494			}
495			/* Snapshot flag cannot be set or cleared */
496			if (((vap->va_flags & SF_SNAPSHOT) != 0 &&
497			     (ip->i_flags & SF_SNAPSHOT) == 0) ||
498			    ((vap->va_flags & SF_SNAPSHOT) == 0 &&
499			     (ip->i_flags & SF_SNAPSHOT) != 0))
500				return (EPERM);
501			ip->i_flags = vap->va_flags;
502			DIP_SET(ip, i_flags, vap->va_flags);
503		} else {
504			if (ip->i_flags
505			    & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) ||
506			    (vap->va_flags & UF_SETTABLE) != vap->va_flags)
507				return (EPERM);
508			ip->i_flags &= SF_SETTABLE;
509			ip->i_flags |= (vap->va_flags & UF_SETTABLE);
510			DIP_SET(ip, i_flags, ip->i_flags);
511		}
512		ip->i_flag |= IN_CHANGE;
513		if (vap->va_flags & (IMMUTABLE | APPEND))
514			return (0);
515	}
516	if (ip->i_flags & (IMMUTABLE | APPEND))
517		return (EPERM);
518	/*
519	 * Go through the fields and update iff not VNOVAL.
520	 */
521	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
522		if (vp->v_mount->mnt_flag & MNT_RDONLY)
523			return (EROFS);
524		if ((error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred,
525		    td)) != 0)
526			return (error);
527	}
528	if (vap->va_size != VNOVAL) {
529		/*
530		 * Disallow write attempts on read-only filesystems;
531		 * unless the file is a socket, fifo, or a block or
532		 * character device resident on the filesystem.
533		 */
534		switch (vp->v_type) {
535		case VDIR:
536			return (EISDIR);
537		case VLNK:
538		case VREG:
539			if (vp->v_mount->mnt_flag & MNT_RDONLY)
540				return (EROFS);
541			if ((ip->i_flags & SF_SNAPSHOT) != 0)
542				return (EPERM);
543			break;
544		default:
545			break;
546		}
547		if ((error = UFS_TRUNCATE(vp, vap->va_size, IO_NORMAL,
548		    cred, td)) != 0)
549			return (error);
550	}
551	if (vap->va_atime.tv_sec != VNOVAL ||
552	    vap->va_mtime.tv_sec != VNOVAL ||
553	    vap->va_birthtime.tv_sec != VNOVAL) {
554		if (vp->v_mount->mnt_flag & MNT_RDONLY)
555			return (EROFS);
556		if ((ip->i_flags & SF_SNAPSHOT) != 0)
557			return (EPERM);
558		/*
559		 * From utimes(2):
560		 * If times is NULL, ... The caller must be the owner of
561		 * the file, have permission to write the file, or be the
562		 * super-user.
563		 * If times is non-NULL, ... The caller must be the owner of
564		 * the file or be the super-user.
565		 */
566		if ((error = VOP_ACCESS(vp, VADMIN, cred, td)) &&
567		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
568		    (error = VOP_ACCESS(vp, VWRITE, cred, td))))
569			return (error);
570		if (vap->va_atime.tv_sec != VNOVAL)
571			ip->i_flag |= IN_ACCESS;
572		if (vap->va_mtime.tv_sec != VNOVAL)
573			ip->i_flag |= IN_CHANGE | IN_UPDATE;
574		if (vap->va_birthtime.tv_sec != VNOVAL &&
575		    ip->i_ump->um_fstype == UFS2)
576			ip->i_flag |= IN_MODIFIED;
577		ufs_itimes(vp);
578		if (vap->va_atime.tv_sec != VNOVAL) {
579			DIP_SET(ip, i_atime, vap->va_atime.tv_sec);
580			DIP_SET(ip, i_atimensec, vap->va_atime.tv_nsec);
581		}
582		if (vap->va_mtime.tv_sec != VNOVAL) {
583			DIP_SET(ip, i_mtime, vap->va_mtime.tv_sec);
584			DIP_SET(ip, i_mtimensec, vap->va_mtime.tv_nsec);
585		}
586		if (vap->va_birthtime.tv_sec != VNOVAL &&
587		    ip->i_ump->um_fstype == UFS2) {
588			ip->i_din2->di_birthtime = vap->va_birthtime.tv_sec;
589			ip->i_din2->di_birthnsec = vap->va_birthtime.tv_nsec;
590		}
591		error = UFS_UPDATE(vp, 0);
592		if (error)
593			return (error);
594	}
595	error = 0;
596	if (vap->va_mode != (mode_t)VNOVAL) {
597		if (vp->v_mount->mnt_flag & MNT_RDONLY)
598			return (EROFS);
599		if ((ip->i_flags & SF_SNAPSHOT) != 0 && (vap->va_mode &
600		   (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP | S_IXOTH | S_IWOTH)))
601			return (EPERM);
602		error = ufs_chmod(vp, (int)vap->va_mode, cred, td);
603	}
604	VN_KNOTE_UNLOCKED(vp, NOTE_ATTRIB);
605	return (error);
606}
607
608/*
609 * Change the mode on a file.
610 * Inode must be locked before calling.
611 */
612static int
613ufs_chmod(vp, mode, cred, td)
614	struct vnode *vp;
615	int mode;
616	struct ucred *cred;
617	struct thread *td;
618{
619	struct inode *ip = VTOI(vp);
620	int error;
621
622	/*
623	 * To modify the permissions on a file, must possess VADMIN
624	 * for that file.
625	 */
626	if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
627		return (error);
628	/*
629	 * Privileged processes may set the sticky bit on non-directories,
630	 * as well as set the setgid bit on a file with a group that the
631	 * process is not a member of.  Both of these are allowed in
632	 * jail(8).
633	 */
634	if (vp->v_type != VDIR && (mode & S_ISTXT)) {
635		if (suser_cred(cred, SUSER_ALLOWJAIL))
636			return (EFTYPE);
637	}
638	if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) {
639		error = suser_cred(cred, SUSER_ALLOWJAIL);
640		if (error)
641			return (error);
642	}
643	ip->i_mode &= ~ALLPERMS;
644	ip->i_mode |= (mode & ALLPERMS);
645	DIP_SET(ip, i_mode, ip->i_mode);
646	ip->i_flag |= IN_CHANGE;
647	return (0);
648}
649
650/*
651 * Perform chown operation on inode ip;
652 * inode must be locked prior to call.
653 */
654static int
655ufs_chown(vp, uid, gid, cred, td)
656	struct vnode *vp;
657	uid_t uid;
658	gid_t gid;
659	struct ucred *cred;
660	struct thread *td;
661{
662	struct inode *ip = VTOI(vp);
663	uid_t ouid;
664	gid_t ogid;
665	int error = 0;
666#ifdef QUOTA
667	int i;
668	ufs2_daddr_t change;
669#endif
670
671	if (uid == (uid_t)VNOVAL)
672		uid = ip->i_uid;
673	if (gid == (gid_t)VNOVAL)
674		gid = ip->i_gid;
675	/*
676	 * To modify the ownership of a file, must possess VADMIN
677	 * for that file.
678	 */
679	if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
680		return (error);
681	/*
682	 * To change the owner of a file, or change the group of a file
683	 * to a group of which we are not a member, the caller must
684	 * have privilege.
685	 */
686	if ((uid != ip->i_uid ||
687	    (gid != ip->i_gid && !groupmember(gid, cred))) &&
688	    (error = suser_cred(cred, SUSER_ALLOWJAIL)))
689		return (error);
690	ogid = ip->i_gid;
691	ouid = ip->i_uid;
692#ifdef QUOTA
693	if ((error = getinoquota(ip)) != 0)
694		return (error);
695	if (ouid == uid) {
696		dqrele(vp, ip->i_dquot[USRQUOTA]);
697		ip->i_dquot[USRQUOTA] = NODQUOT;
698	}
699	if (ogid == gid) {
700		dqrele(vp, ip->i_dquot[GRPQUOTA]);
701		ip->i_dquot[GRPQUOTA] = NODQUOT;
702	}
703	change = DIP(ip, i_blocks);
704	(void) chkdq(ip, -change, cred, CHOWN);
705	(void) chkiq(ip, -1, cred, CHOWN);
706	for (i = 0; i < MAXQUOTAS; i++) {
707		dqrele(vp, ip->i_dquot[i]);
708		ip->i_dquot[i] = NODQUOT;
709	}
710#endif
711	ip->i_gid = gid;
712	DIP_SET(ip, i_gid, gid);
713	ip->i_uid = uid;
714	DIP_SET(ip, i_uid, uid);
715#ifdef QUOTA
716	if ((error = getinoquota(ip)) == 0) {
717		if (ouid == uid) {
718			dqrele(vp, ip->i_dquot[USRQUOTA]);
719			ip->i_dquot[USRQUOTA] = NODQUOT;
720		}
721		if (ogid == gid) {
722			dqrele(vp, ip->i_dquot[GRPQUOTA]);
723			ip->i_dquot[GRPQUOTA] = NODQUOT;
724		}
725		if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {
726			if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)
727				goto good;
728			else
729				(void) chkdq(ip, -change, cred, CHOWN|FORCE);
730		}
731		for (i = 0; i < MAXQUOTAS; i++) {
732			dqrele(vp, ip->i_dquot[i]);
733			ip->i_dquot[i] = NODQUOT;
734		}
735	}
736	ip->i_gid = ogid;
737	DIP_SET(ip, i_gid, ogid);
738	ip->i_uid = ouid;
739	DIP_SET(ip, i_uid, ouid);
740	if (getinoquota(ip) == 0) {
741		if (ouid == uid) {
742			dqrele(vp, ip->i_dquot[USRQUOTA]);
743			ip->i_dquot[USRQUOTA] = NODQUOT;
744		}
745		if (ogid == gid) {
746			dqrele(vp, ip->i_dquot[GRPQUOTA]);
747			ip->i_dquot[GRPQUOTA] = NODQUOT;
748		}
749		(void) chkdq(ip, change, cred, FORCE|CHOWN);
750		(void) chkiq(ip, 1, cred, FORCE|CHOWN);
751		(void) getinoquota(ip);
752	}
753	return (error);
754good:
755	if (getinoquota(ip))
756		panic("ufs_chown: lost quota");
757#endif /* QUOTA */
758	ip->i_flag |= IN_CHANGE;
759	if (suser_cred(cred, SUSER_ALLOWJAIL) && (ouid != uid || ogid != gid)) {
760		ip->i_mode &= ~(ISUID | ISGID);
761		DIP_SET(ip, i_mode, ip->i_mode);
762	}
763	return (0);
764}
765
766static int
767ufs_remove(ap)
768	struct vop_remove_args /* {
769		struct vnode *a_dvp;
770		struct vnode *a_vp;
771		struct componentname *a_cnp;
772	} */ *ap;
773{
774	struct inode *ip;
775	struct vnode *vp = ap->a_vp;
776	struct vnode *dvp = ap->a_dvp;
777	int error;
778
779	ip = VTOI(vp);
780	if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
781	    (VTOI(dvp)->i_flags & APPEND)) {
782		error = EPERM;
783		goto out;
784	}
785	error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
786	if (ip->i_nlink <= 0)
787		vp->v_vflag |= VV_NOSYNC;
788	VN_KNOTE_UNLOCKED(vp, NOTE_DELETE);
789	VN_KNOTE_UNLOCKED(dvp, NOTE_WRITE);
790out:
791	return (error);
792}
793
794/*
795 * link vnode call
796 */
797static int
798ufs_link(ap)
799	struct vop_link_args /* {
800		struct vnode *a_tdvp;
801		struct vnode *a_vp;
802		struct componentname *a_cnp;
803	} */ *ap;
804{
805	struct vnode *vp = ap->a_vp;
806	struct vnode *tdvp = ap->a_tdvp;
807	struct componentname *cnp = ap->a_cnp;
808	struct inode *ip;
809	struct direct newdir;
810	int error;
811
812#ifdef DIAGNOSTIC
813	if ((cnp->cn_flags & HASBUF) == 0)
814		panic("ufs_link: no name");
815#endif
816	if (tdvp->v_mount != vp->v_mount) {
817		error = EXDEV;
818		goto out;
819	}
820	ip = VTOI(vp);
821	if ((nlink_t)ip->i_nlink >= LINK_MAX) {
822		error = EMLINK;
823		goto out;
824	}
825	if (ip->i_flags & (IMMUTABLE | APPEND)) {
826		error = EPERM;
827		goto out;
828	}
829	ip->i_effnlink++;
830	ip->i_nlink++;
831	DIP_SET(ip, i_nlink, ip->i_nlink);
832	ip->i_flag |= IN_CHANGE;
833	if (DOINGSOFTDEP(vp))
834		softdep_change_linkcnt(ip);
835	error = UFS_UPDATE(vp, !(DOINGSOFTDEP(vp) | DOINGASYNC(vp)));
836	if (!error) {
837		ufs_makedirentry(ip, cnp, &newdir);
838		error = ufs_direnter(tdvp, vp, &newdir, cnp, NULL);
839	}
840
841	if (error) {
842		ip->i_effnlink--;
843		ip->i_nlink--;
844		DIP_SET(ip, i_nlink, ip->i_nlink);
845		ip->i_flag |= IN_CHANGE;
846		if (DOINGSOFTDEP(vp))
847			softdep_change_linkcnt(ip);
848	}
849out:
850	VN_KNOTE_UNLOCKED(vp, NOTE_LINK);
851	VN_KNOTE_UNLOCKED(tdvp, NOTE_WRITE);
852	return (error);
853}
854
855/*
856 * whiteout vnode call
857 */
858static int
859ufs_whiteout(ap)
860	struct vop_whiteout_args /* {
861		struct vnode *a_dvp;
862		struct componentname *a_cnp;
863		int a_flags;
864	} */ *ap;
865{
866	struct vnode *dvp = ap->a_dvp;
867	struct componentname *cnp = ap->a_cnp;
868	struct direct newdir;
869	int error = 0;
870
871	switch (ap->a_flags) {
872	case LOOKUP:
873		/* 4.4 format directories support whiteout operations */
874		if (dvp->v_mount->mnt_maxsymlinklen > 0)
875			return (0);
876		return (EOPNOTSUPP);
877
878	case CREATE:
879		/* create a new directory whiteout */
880#ifdef DIAGNOSTIC
881		if ((cnp->cn_flags & SAVENAME) == 0)
882			panic("ufs_whiteout: missing name");
883		if (dvp->v_mount->mnt_maxsymlinklen <= 0)
884			panic("ufs_whiteout: old format filesystem");
885#endif
886
887		newdir.d_ino = WINO;
888		newdir.d_namlen = cnp->cn_namelen;
889		bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1);
890		newdir.d_type = DT_WHT;
891		error = ufs_direnter(dvp, NULL, &newdir, cnp, NULL);
892		break;
893
894	case DELETE:
895		/* remove an existing directory whiteout */
896#ifdef DIAGNOSTIC
897		if (dvp->v_mount->mnt_maxsymlinklen <= 0)
898			panic("ufs_whiteout: old format filesystem");
899#endif
900
901		cnp->cn_flags &= ~DOWHITEOUT;
902		error = ufs_dirremove(dvp, NULL, cnp->cn_flags, 0);
903		break;
904	default:
905		panic("ufs_whiteout: unknown op");
906	}
907	return (error);
908}
909
910/*
911 * Rename system call.
912 * 	rename("foo", "bar");
913 * is essentially
914 *	unlink("bar");
915 *	link("foo", "bar");
916 *	unlink("foo");
917 * but ``atomically''.  Can't do full commit without saving state in the
918 * inode on disk which isn't feasible at this time.  Best we can do is
919 * always guarantee the target exists.
920 *
921 * Basic algorithm is:
922 *
923 * 1) Bump link count on source while we're linking it to the
924 *    target.  This also ensure the inode won't be deleted out
925 *    from underneath us while we work (it may be truncated by
926 *    a concurrent `trunc' or `open' for creation).
927 * 2) Link source to destination.  If destination already exists,
928 *    delete it first.
929 * 3) Unlink source reference to inode if still around. If a
930 *    directory was moved and the parent of the destination
931 *    is different from the source, patch the ".." entry in the
932 *    directory.
933 */
934static int
935ufs_rename(ap)
936	struct vop_rename_args  /* {
937		struct vnode *a_fdvp;
938		struct vnode *a_fvp;
939		struct componentname *a_fcnp;
940		struct vnode *a_tdvp;
941		struct vnode *a_tvp;
942		struct componentname *a_tcnp;
943	} */ *ap;
944{
945	struct vnode *tvp = ap->a_tvp;
946	struct vnode *tdvp = ap->a_tdvp;
947	struct vnode *fvp = ap->a_fvp;
948	struct vnode *fdvp = ap->a_fdvp;
949	struct componentname *tcnp = ap->a_tcnp;
950	struct componentname *fcnp = ap->a_fcnp;
951	struct thread *td = fcnp->cn_thread;
952	struct inode *ip, *xp, *dp;
953	struct direct newdir;
954	int doingdirectory = 0, oldparent = 0, newparent = 0;
955	int error = 0, ioflag;
956
957#ifdef DIAGNOSTIC
958	if ((tcnp->cn_flags & HASBUF) == 0 ||
959	    (fcnp->cn_flags & HASBUF) == 0)
960		panic("ufs_rename: no name");
961#endif
962	/*
963	 * Check for cross-device rename.
964	 */
965	if ((fvp->v_mount != tdvp->v_mount) ||
966	    (tvp && (fvp->v_mount != tvp->v_mount))) {
967		error = EXDEV;
968abortit:
969		if (tdvp == tvp)
970			vrele(tdvp);
971		else
972			vput(tdvp);
973		if (tvp)
974			vput(tvp);
975		vrele(fdvp);
976		vrele(fvp);
977		return (error);
978	}
979
980	if (tvp && ((VTOI(tvp)->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
981	    (VTOI(tdvp)->i_flags & APPEND))) {
982		error = EPERM;
983		goto abortit;
984	}
985
986	/*
987	 * Renaming a file to itself has no effect.  The upper layers should
988	 * not call us in that case.  Temporarily just warn if they do.
989	 */
990	if (fvp == tvp) {
991		printf("ufs_rename: fvp == tvp (can't happen)\n");
992		error = 0;
993		goto abortit;
994	}
995
996	if ((error = vn_lock(fvp, LK_EXCLUSIVE, td)) != 0)
997		goto abortit;
998	dp = VTOI(fdvp);
999	ip = VTOI(fvp);
1000	if (ip->i_nlink >= LINK_MAX) {
1001		VOP_UNLOCK(fvp, 0, td);
1002		error = EMLINK;
1003		goto abortit;
1004	}
1005	if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))
1006	    || (dp->i_flags & APPEND)) {
1007		VOP_UNLOCK(fvp, 0, td);
1008		error = EPERM;
1009		goto abortit;
1010	}
1011	if ((ip->i_mode & IFMT) == IFDIR) {
1012		/*
1013		 * Avoid ".", "..", and aliases of "." for obvious reasons.
1014		 */
1015		if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
1016		    dp == ip || (fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT ||
1017		    (ip->i_flag & IN_RENAME)) {
1018			VOP_UNLOCK(fvp, 0, td);
1019			error = EINVAL;
1020			goto abortit;
1021		}
1022		ip->i_flag |= IN_RENAME;
1023		oldparent = dp->i_number;
1024		doingdirectory = 1;
1025	}
1026	VN_KNOTE_UNLOCKED(fdvp, NOTE_WRITE);		/* XXX right place? */
1027	vrele(fdvp);
1028
1029	/*
1030	 * When the target exists, both the directory
1031	 * and target vnodes are returned locked.
1032	 */
1033	dp = VTOI(tdvp);
1034	xp = NULL;
1035	if (tvp)
1036		xp = VTOI(tvp);
1037
1038	/*
1039	 * 1) Bump link count while we're moving stuff
1040	 *    around.  If we crash somewhere before
1041	 *    completing our work, the link count
1042	 *    may be wrong, but correctable.
1043	 */
1044	ip->i_effnlink++;
1045	ip->i_nlink++;
1046	DIP_SET(ip, i_nlink, ip->i_nlink);
1047	ip->i_flag |= IN_CHANGE;
1048	if (DOINGSOFTDEP(fvp))
1049		softdep_change_linkcnt(ip);
1050	if ((error = UFS_UPDATE(fvp, !(DOINGSOFTDEP(fvp) |
1051				       DOINGASYNC(fvp)))) != 0) {
1052		VOP_UNLOCK(fvp, 0, td);
1053		goto bad;
1054	}
1055
1056	/*
1057	 * If ".." must be changed (ie the directory gets a new
1058	 * parent) then the source directory must not be in the
1059	 * directory heirarchy above the target, as this would
1060	 * orphan everything below the source directory. Also
1061	 * the user must have write permission in the source so
1062	 * as to be able to change "..". We must repeat the call
1063	 * to namei, as the parent directory is unlocked by the
1064	 * call to checkpath().
1065	 */
1066	error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread);
1067	VOP_UNLOCK(fvp, 0, td);
1068	if (oldparent != dp->i_number)
1069		newparent = dp->i_number;
1070	if (doingdirectory && newparent) {
1071		if (error)	/* write access check above */
1072			goto bad;
1073		if (xp != NULL)
1074			vput(tvp);
1075		error = ufs_checkpath(ip, dp, tcnp->cn_cred);
1076		if (error)
1077			goto out;
1078		if ((tcnp->cn_flags & SAVESTART) == 0)
1079			panic("ufs_rename: lost to startdir");
1080		VREF(tdvp);
1081		error = relookup(tdvp, &tvp, tcnp);
1082		if (error)
1083			goto out;
1084		vrele(tdvp);
1085		dp = VTOI(tdvp);
1086		xp = NULL;
1087		if (tvp)
1088			xp = VTOI(tvp);
1089	}
1090	/*
1091	 * 2) If target doesn't exist, link the target
1092	 *    to the source and unlink the source.
1093	 *    Otherwise, rewrite the target directory
1094	 *    entry to reference the source inode and
1095	 *    expunge the original entry's existence.
1096	 */
1097	if (xp == NULL) {
1098		if (dp->i_dev != ip->i_dev)
1099			panic("ufs_rename: EXDEV");
1100		/*
1101		 * Account for ".." in new directory.
1102		 * When source and destination have the same
1103		 * parent we don't fool with the link count.
1104		 */
1105		if (doingdirectory && newparent) {
1106			if ((nlink_t)dp->i_nlink >= LINK_MAX) {
1107				error = EMLINK;
1108				goto bad;
1109			}
1110			dp->i_effnlink++;
1111			dp->i_nlink++;
1112			DIP_SET(dp, i_nlink, dp->i_nlink);
1113			dp->i_flag |= IN_CHANGE;
1114			if (DOINGSOFTDEP(tdvp))
1115				softdep_change_linkcnt(dp);
1116			error = UFS_UPDATE(tdvp, !(DOINGSOFTDEP(tdvp) |
1117						   DOINGASYNC(tdvp)));
1118			if (error)
1119				goto bad;
1120		}
1121		ufs_makedirentry(ip, tcnp, &newdir);
1122		error = ufs_direnter(tdvp, NULL, &newdir, tcnp, NULL);
1123		if (error) {
1124			if (doingdirectory && newparent) {
1125				dp->i_effnlink--;
1126				dp->i_nlink--;
1127				DIP_SET(dp, i_nlink, dp->i_nlink);
1128				dp->i_flag |= IN_CHANGE;
1129				if (DOINGSOFTDEP(tdvp))
1130					softdep_change_linkcnt(dp);
1131				(void)UFS_UPDATE(tdvp, 1);
1132			}
1133			goto bad;
1134		}
1135		VN_KNOTE_UNLOCKED(tdvp, NOTE_WRITE);
1136		vput(tdvp);
1137	} else {
1138		if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
1139			panic("ufs_rename: EXDEV");
1140		/*
1141		 * Short circuit rename(foo, foo).
1142		 */
1143		if (xp->i_number == ip->i_number)
1144			panic("ufs_rename: same file");
1145		/*
1146		 * If the parent directory is "sticky", then the caller
1147		 * must possess VADMIN for the parent directory, or the
1148		 * destination of the rename.  This implements append-only
1149		 * directories.
1150		 */
1151		if ((dp->i_mode & S_ISTXT) &&
1152		    VOP_ACCESS(tdvp, VADMIN, tcnp->cn_cred, td) &&
1153		    VOP_ACCESS(tvp, VADMIN, tcnp->cn_cred, td)) {
1154			error = EPERM;
1155			goto bad;
1156		}
1157		/*
1158		 * Target must be empty if a directory and have no links
1159		 * to it. Also, ensure source and target are compatible
1160		 * (both directories, or both not directories).
1161		 */
1162		if ((xp->i_mode&IFMT) == IFDIR) {
1163			if ((xp->i_effnlink > 2) ||
1164			    !ufs_dirempty(xp, dp->i_number, tcnp->cn_cred)) {
1165				error = ENOTEMPTY;
1166				goto bad;
1167			}
1168			if (!doingdirectory) {
1169				error = ENOTDIR;
1170				goto bad;
1171			}
1172			cache_purge(tdvp);
1173		} else if (doingdirectory) {
1174			error = EISDIR;
1175			goto bad;
1176		}
1177		error = ufs_dirrewrite(dp, xp, ip->i_number,
1178		    IFTODT(ip->i_mode),
1179		    (doingdirectory && newparent) ? newparent : doingdirectory);
1180		if (error)
1181			goto bad;
1182		if (doingdirectory) {
1183			if (!newparent) {
1184				dp->i_effnlink--;
1185				if (DOINGSOFTDEP(tdvp))
1186					softdep_change_linkcnt(dp);
1187			}
1188			xp->i_effnlink--;
1189			if (DOINGSOFTDEP(tvp))
1190				softdep_change_linkcnt(xp);
1191		}
1192		if (doingdirectory && !DOINGSOFTDEP(tvp)) {
1193			/*
1194			 * Truncate inode. The only stuff left in the directory
1195			 * is "." and "..". The "." reference is inconsequential
1196			 * since we are quashing it. We have removed the "."
1197			 * reference and the reference in the parent directory,
1198			 * but there may be other hard links. The soft
1199			 * dependency code will arrange to do these operations
1200			 * after the parent directory entry has been deleted on
1201			 * disk, so when running with that code we avoid doing
1202			 * them now.
1203			 */
1204			if (!newparent) {
1205				dp->i_nlink--;
1206				DIP_SET(dp, i_nlink, dp->i_nlink);
1207				dp->i_flag |= IN_CHANGE;
1208			}
1209			xp->i_nlink--;
1210			DIP_SET(xp, i_nlink, xp->i_nlink);
1211			xp->i_flag |= IN_CHANGE;
1212			ioflag = IO_NORMAL;
1213			if (DOINGASYNC(tvp))
1214				ioflag |= IO_SYNC;
1215			if ((error = UFS_TRUNCATE(tvp, (off_t)0, ioflag,
1216			    tcnp->cn_cred, tcnp->cn_thread)) != 0)
1217				goto bad;
1218		}
1219		VN_KNOTE_UNLOCKED(tdvp, NOTE_WRITE);
1220		vput(tdvp);
1221		VN_KNOTE_UNLOCKED(tvp, NOTE_DELETE);
1222		vput(tvp);
1223		xp = NULL;
1224	}
1225
1226	/*
1227	 * 3) Unlink the source.
1228	 */
1229	fcnp->cn_flags &= ~MODMASK;
1230	fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1231	if ((fcnp->cn_flags & SAVESTART) == 0)
1232		panic("ufs_rename: lost from startdir");
1233	VREF(fdvp);
1234	error = relookup(fdvp, &fvp, fcnp);
1235	if (error == 0)
1236		vrele(fdvp);
1237	if (fvp != NULL) {
1238		xp = VTOI(fvp);
1239		dp = VTOI(fdvp);
1240	} else {
1241		/*
1242		 * From name has disappeared.  IN_RENAME is not sufficient
1243		 * to protect against directory races due to timing windows,
1244		 * so we have to remove the panic.  XXX the only real way
1245		 * to solve this issue is at a much higher level.  By the
1246		 * time we hit ufs_rename() it's too late.
1247		 */
1248#if 0
1249		if (doingdirectory)
1250			panic("ufs_rename: lost dir entry");
1251#endif
1252		vrele(ap->a_fvp);
1253		return (0);
1254	}
1255	/*
1256	 * Ensure that the directory entry still exists and has not
1257	 * changed while the new name has been entered. If the source is
1258	 * a file then the entry may have been unlinked or renamed. In
1259	 * either case there is no further work to be done. If the source
1260	 * is a directory then it cannot have been rmdir'ed; the IN_RENAME
1261	 * flag ensures that it cannot be moved by another rename or removed
1262	 * by a rmdir.
1263	 */
1264	if (xp != ip) {
1265		/*
1266		 * From name resolves to a different inode.  IN_RENAME is
1267		 * not sufficient protection against timing window races
1268		 * so we can't panic here.  XXX the only real way
1269		 * to solve this issue is at a much higher level.  By the
1270		 * time we hit ufs_rename() it's too late.
1271		 */
1272#if 0
1273		if (doingdirectory)
1274			panic("ufs_rename: lost dir entry");
1275#endif
1276	} else {
1277		/*
1278		 * If the source is a directory with a
1279		 * new parent, the link count of the old
1280		 * parent directory must be decremented
1281		 * and ".." set to point to the new parent.
1282		 */
1283		if (doingdirectory && newparent) {
1284			xp->i_offset = mastertemplate.dot_reclen;
1285			ufs_dirrewrite(xp, dp, newparent, DT_DIR, 0);
1286			cache_purge(fdvp);
1287		}
1288		error = ufs_dirremove(fdvp, xp, fcnp->cn_flags, 0);
1289		xp->i_flag &= ~IN_RENAME;
1290	}
1291	VN_KNOTE_UNLOCKED(fvp, NOTE_RENAME);
1292	if (dp)
1293		vput(fdvp);
1294	if (xp)
1295		vput(fvp);
1296	vrele(ap->a_fvp);
1297	return (error);
1298
1299bad:
1300	if (xp)
1301		vput(ITOV(xp));
1302	vput(ITOV(dp));
1303out:
1304	if (doingdirectory)
1305		ip->i_flag &= ~IN_RENAME;
1306	if (vn_lock(fvp, LK_EXCLUSIVE, td) == 0) {
1307		ip->i_effnlink--;
1308		ip->i_nlink--;
1309		DIP_SET(ip, i_nlink, ip->i_nlink);
1310		ip->i_flag |= IN_CHANGE;
1311		ip->i_flag &= ~IN_RENAME;
1312		if (DOINGSOFTDEP(fvp))
1313			softdep_change_linkcnt(ip);
1314		vput(fvp);
1315	} else
1316		vrele(fvp);
1317	return (error);
1318}
1319
1320/*
1321 * Mkdir system call
1322 */
1323static int
1324ufs_mkdir(ap)
1325	struct vop_mkdir_args /* {
1326		struct vnode *a_dvp;
1327		struct vnode **a_vpp;
1328		struct componentname *a_cnp;
1329		struct vattr *a_vap;
1330	} */ *ap;
1331{
1332	struct vnode *dvp = ap->a_dvp;
1333	struct vattr *vap = ap->a_vap;
1334	struct componentname *cnp = ap->a_cnp;
1335	struct inode *ip, *dp;
1336	struct vnode *tvp;
1337	struct buf *bp;
1338	struct dirtemplate dirtemplate, *dtp;
1339	struct direct newdir;
1340#ifdef UFS_ACL
1341	struct acl *acl, *dacl;
1342#endif
1343	int error, dmode;
1344	long blkoff;
1345
1346#ifdef DIAGNOSTIC
1347	if ((cnp->cn_flags & HASBUF) == 0)
1348		panic("ufs_mkdir: no name");
1349#endif
1350	dp = VTOI(dvp);
1351	if ((nlink_t)dp->i_nlink >= LINK_MAX) {
1352		error = EMLINK;
1353		goto out;
1354	}
1355	dmode = vap->va_mode & 0777;
1356	dmode |= IFDIR;
1357	/*
1358	 * Must simulate part of ufs_makeinode here to acquire the inode,
1359	 * but not have it entered in the parent directory. The entry is
1360	 * made later after writing "." and ".." entries.
1361	 */
1362	error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp);
1363	if (error)
1364		goto out;
1365	ip = VTOI(tvp);
1366	ip->i_gid = dp->i_gid;
1367	DIP_SET(ip, i_gid, dp->i_gid);
1368#ifdef SUIDDIR
1369	{
1370#ifdef QUOTA
1371		struct ucred ucred, *ucp;
1372		ucp = cnp->cn_cred;
1373#endif
1374		/*
1375		 * If we are hacking owners here, (only do this where told to)
1376		 * and we are not giving it TO root, (would subvert quotas)
1377		 * then go ahead and give it to the other user.
1378		 * The new directory also inherits the SUID bit.
1379		 * If user's UID and dir UID are the same,
1380		 * 'give it away' so that the SUID is still forced on.
1381		 */
1382		if ((dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
1383		    (dp->i_mode & ISUID) && dp->i_uid) {
1384			dmode |= ISUID;
1385			ip->i_uid = dp->i_uid;
1386			DIP_SET(ip, i_uid, dp->i_uid);
1387#ifdef QUOTA
1388			if (dp->i_uid != cnp->cn_cred->cr_uid) {
1389				/*
1390				 * Make sure the correct user gets charged
1391				 * for the space.
1392				 * Make a dummy credential for the victim.
1393				 * XXX This seems to never be accessed out of
1394				 * our context so a stack variable is ok.
1395				 */
1396				ucred.cr_ref = 1;
1397				ucred.cr_uid = ip->i_uid;
1398				ucred.cr_ngroups = 1;
1399				ucred.cr_groups[0] = dp->i_gid;
1400				ucp = &ucred;
1401			}
1402#endif
1403		} else {
1404			ip->i_uid = cnp->cn_cred->cr_uid;
1405			DIP_SET(ip, i_uid, ip->i_uid);
1406		}
1407#ifdef QUOTA
1408		if ((error = getinoquota(ip)) ||
1409	    	    (error = chkiq(ip, 1, ucp, 0))) {
1410			UFS_VFREE(tvp, ip->i_number, dmode);
1411			vput(tvp);
1412			return (error);
1413		}
1414#endif
1415	}
1416#else	/* !SUIDDIR */
1417	ip->i_uid = cnp->cn_cred->cr_uid;
1418	DIP_SET(ip, i_uid, ip->i_uid);
1419#ifdef QUOTA
1420	if ((error = getinoquota(ip)) ||
1421	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
1422		UFS_VFREE(tvp, ip->i_number, dmode);
1423		vput(tvp);
1424		return (error);
1425	}
1426#endif
1427#endif	/* !SUIDDIR */
1428	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1429#ifdef UFS_ACL
1430	acl = dacl = NULL;
1431	if ((dvp->v_mount->mnt_flag & MNT_ACLS) != 0) {
1432		MALLOC(acl, struct acl *, sizeof(*acl), M_ACL, M_WAITOK);
1433		MALLOC(dacl, struct acl *, sizeof(*dacl), M_ACL, M_WAITOK);
1434
1435		/*
1436		 * Retrieve default ACL from parent, if any.
1437		 */
1438		error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cnp->cn_cred,
1439		    cnp->cn_thread);
1440		switch (error) {
1441		case 0:
1442			/*
1443			 * Retrieved a default ACL, so merge mode and ACL if
1444			 * necessary.  If the ACL is empty, fall through to
1445			 * the "not defined or available" case.
1446			 */
1447			if (acl->acl_cnt != 0) {
1448				dmode = acl_posix1e_newfilemode(dmode, acl);
1449				ip->i_mode = dmode;
1450				DIP_SET(ip, i_mode, dmode);
1451				*dacl = *acl;
1452				ufs_sync_acl_from_inode(ip, acl);
1453				break;
1454			}
1455			/* FALLTHROUGH */
1456
1457		case EOPNOTSUPP:
1458			/*
1459			 * Just use the mode as-is.
1460			 */
1461			ip->i_mode = dmode;
1462			DIP_SET(ip, i_mode, dmode);
1463			FREE(acl, M_ACL);
1464			FREE(dacl, M_ACL);
1465			dacl = acl = NULL;
1466			break;
1467
1468		default:
1469			UFS_VFREE(tvp, ip->i_number, dmode);
1470			vput(tvp);
1471			FREE(acl, M_ACL);
1472				FREE(dacl, M_ACL);
1473			return (error);
1474		}
1475	} else {
1476#endif /* !UFS_ACL */
1477		ip->i_mode = dmode;
1478		DIP_SET(ip, i_mode, dmode);
1479#ifdef UFS_ACL
1480	}
1481#endif
1482	tvp->v_type = VDIR;	/* Rest init'd in getnewvnode(). */
1483	ip->i_effnlink = 2;
1484	ip->i_nlink = 2;
1485	DIP_SET(ip, i_nlink, 2);
1486	if (DOINGSOFTDEP(tvp))
1487		softdep_change_linkcnt(ip);
1488	if (cnp->cn_flags & ISWHITEOUT) {
1489		ip->i_flags |= UF_OPAQUE;
1490		DIP_SET(ip, i_flags, ip->i_flags);
1491	}
1492
1493	/*
1494	 * Bump link count in parent directory to reflect work done below.
1495	 * Should be done before reference is created so cleanup is
1496	 * possible if we crash.
1497	 */
1498	dp->i_effnlink++;
1499	dp->i_nlink++;
1500	DIP_SET(dp, i_nlink, dp->i_nlink);
1501	dp->i_flag |= IN_CHANGE;
1502	if (DOINGSOFTDEP(dvp))
1503		softdep_change_linkcnt(dp);
1504	error = UFS_UPDATE(tvp, !(DOINGSOFTDEP(dvp) | DOINGASYNC(dvp)));
1505	if (error)
1506		goto bad;
1507#ifdef MAC
1508	if (dvp->v_mount->mnt_flag & MNT_MULTILABEL) {
1509		error = mac_create_vnode_extattr(cnp->cn_cred, dvp->v_mount,
1510		    dvp, tvp, cnp);
1511		if (error)
1512			goto bad;
1513	}
1514#endif
1515#ifdef UFS_ACL
1516	if (acl != NULL) {
1517		/*
1518		 * XXX: If we abort now, will Soft Updates notify the extattr
1519		 * code that the EAs for the file need to be released?
1520		 */
1521		error = VOP_SETACL(tvp, ACL_TYPE_ACCESS, acl, cnp->cn_cred,
1522		    cnp->cn_thread);
1523		if (error == 0)
1524			error = VOP_SETACL(tvp, ACL_TYPE_DEFAULT, dacl,
1525			    cnp->cn_cred, cnp->cn_thread);
1526		switch (error) {
1527		case 0:
1528			break;
1529
1530		case EOPNOTSUPP:
1531			/*
1532			 * XXX: This should not happen, as EOPNOTSUPP above
1533			 * was supposed to free acl.
1534			 */
1535			printf("ufs_mkdir: VOP_GETACL() but no VOP_SETACL()\n");
1536			/*
1537			panic("ufs_mkdir: VOP_GETACL() but no VOP_SETACL()");
1538			 */
1539			break;
1540
1541		default:
1542			FREE(acl, M_ACL);
1543			FREE(dacl, M_ACL);
1544			goto bad;
1545		}
1546		FREE(acl, M_ACL);
1547		FREE(dacl, M_ACL);
1548	}
1549#endif /* !UFS_ACL */
1550
1551	/*
1552	 * Initialize directory with "." and ".." from static template.
1553	 */
1554	if (dvp->v_mount->mnt_maxsymlinklen > 0
1555	)
1556		dtp = &mastertemplate;
1557	else
1558		dtp = (struct dirtemplate *)&omastertemplate;
1559	dirtemplate = *dtp;
1560	dirtemplate.dot_ino = ip->i_number;
1561	dirtemplate.dotdot_ino = dp->i_number;
1562	if ((error = UFS_BALLOC(tvp, (off_t)0, DIRBLKSIZ, cnp->cn_cred,
1563	    BA_CLRBUF, &bp)) != 0)
1564		goto bad;
1565	ip->i_size = DIRBLKSIZ;
1566	DIP_SET(ip, i_size, DIRBLKSIZ);
1567	ip->i_flag |= IN_CHANGE | IN_UPDATE;
1568	vnode_pager_setsize(tvp, (u_long)ip->i_size);
1569	bcopy((caddr_t)&dirtemplate, (caddr_t)bp->b_data, sizeof dirtemplate);
1570	if (DOINGSOFTDEP(tvp)) {
1571		/*
1572		 * Ensure that the entire newly allocated block is a
1573		 * valid directory so that future growth within the
1574		 * block does not have to ensure that the block is
1575		 * written before the inode.
1576		 */
1577		blkoff = DIRBLKSIZ;
1578		while (blkoff < bp->b_bcount) {
1579			((struct direct *)
1580			   (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ;
1581			blkoff += DIRBLKSIZ;
1582		}
1583	}
1584	if ((error = UFS_UPDATE(tvp, !(DOINGSOFTDEP(tvp) |
1585				       DOINGASYNC(tvp)))) != 0) {
1586		(void)bwrite(bp);
1587		goto bad;
1588	}
1589	/*
1590	 * Directory set up, now install its entry in the parent directory.
1591	 *
1592	 * If we are not doing soft dependencies, then we must write out the
1593	 * buffer containing the new directory body before entering the new
1594	 * name in the parent. If we are doing soft dependencies, then the
1595	 * buffer containing the new directory body will be passed to and
1596	 * released in the soft dependency code after the code has attached
1597	 * an appropriate ordering dependency to the buffer which ensures that
1598	 * the buffer is written before the new name is written in the parent.
1599	 */
1600	if (DOINGASYNC(dvp))
1601		bdwrite(bp);
1602	else if (!DOINGSOFTDEP(dvp) && ((error = bwrite(bp))))
1603		goto bad;
1604	ufs_makedirentry(ip, cnp, &newdir);
1605	error = ufs_direnter(dvp, tvp, &newdir, cnp, bp);
1606
1607bad:
1608	if (error == 0) {
1609		VN_KNOTE_UNLOCKED(dvp, NOTE_WRITE | NOTE_LINK);
1610		*ap->a_vpp = tvp;
1611	} else {
1612		dp->i_effnlink--;
1613		dp->i_nlink--;
1614		DIP_SET(dp, i_nlink, dp->i_nlink);
1615		dp->i_flag |= IN_CHANGE;
1616		if (DOINGSOFTDEP(dvp))
1617			softdep_change_linkcnt(dp);
1618		/*
1619		 * No need to do an explicit VOP_TRUNCATE here, vrele will
1620		 * do this for us because we set the link count to 0.
1621		 */
1622		ip->i_effnlink = 0;
1623		ip->i_nlink = 0;
1624		DIP_SET(ip, i_nlink, 0);
1625		ip->i_flag |= IN_CHANGE;
1626		if (DOINGSOFTDEP(tvp))
1627			softdep_change_linkcnt(ip);
1628		vput(tvp);
1629	}
1630out:
1631	return (error);
1632}
1633
1634/*
1635 * Rmdir system call.
1636 */
1637static int
1638ufs_rmdir(ap)
1639	struct vop_rmdir_args /* {
1640		struct vnode *a_dvp;
1641		struct vnode *a_vp;
1642		struct componentname *a_cnp;
1643	} */ *ap;
1644{
1645	struct vnode *vp = ap->a_vp;
1646	struct vnode *dvp = ap->a_dvp;
1647	struct componentname *cnp = ap->a_cnp;
1648	struct inode *ip, *dp;
1649	int error, ioflag;
1650
1651	ip = VTOI(vp);
1652	dp = VTOI(dvp);
1653
1654	/*
1655	 * Do not remove a directory that is in the process of being renamed.
1656	 * Verify the directory is empty (and valid). Rmdir ".." will not be
1657	 * valid since ".." will contain a reference to the current directory
1658	 * and thus be non-empty. Do not allow the removal of mounted on
1659	 * directories (this can happen when an NFS exported filesystem
1660	 * tries to remove a locally mounted on directory).
1661	 */
1662	error = 0;
1663	if (ip->i_flag & IN_RENAME) {
1664		error = EINVAL;
1665		goto out;
1666	}
1667	if (ip->i_effnlink != 2 ||
1668	    !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1669		error = ENOTEMPTY;
1670		goto out;
1671	}
1672	if ((dp->i_flags & APPEND)
1673	    || (ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
1674		error = EPERM;
1675		goto out;
1676	}
1677	if (vp->v_mountedhere != 0) {
1678		error = EINVAL;
1679		goto out;
1680	}
1681	/*
1682	 * Delete reference to directory before purging
1683	 * inode.  If we crash in between, the directory
1684	 * will be reattached to lost+found,
1685	 */
1686	dp->i_effnlink--;
1687	ip->i_effnlink--;
1688	if (DOINGSOFTDEP(vp)) {
1689		softdep_change_linkcnt(dp);
1690		softdep_change_linkcnt(ip);
1691	}
1692	error = ufs_dirremove(dvp, ip, cnp->cn_flags, 1);
1693	if (error) {
1694		dp->i_effnlink++;
1695		ip->i_effnlink++;
1696		if (DOINGSOFTDEP(vp)) {
1697			softdep_change_linkcnt(dp);
1698			softdep_change_linkcnt(ip);
1699		}
1700		goto out;
1701	}
1702	VN_KNOTE_UNLOCKED(dvp, NOTE_WRITE | NOTE_LINK);
1703	cache_purge(dvp);
1704	/*
1705	 * Truncate inode. The only stuff left in the directory is "." and
1706	 * "..". The "." reference is inconsequential since we are quashing
1707	 * it. The soft dependency code will arrange to do these operations
1708	 * after the parent directory entry has been deleted on disk, so
1709	 * when running with that code we avoid doing them now.
1710	 */
1711	if (!DOINGSOFTDEP(vp)) {
1712		dp->i_nlink--;
1713		DIP_SET(dp, i_nlink, dp->i_nlink);
1714		dp->i_flag |= IN_CHANGE;
1715		ip->i_nlink--;
1716		DIP_SET(ip, i_nlink, ip->i_nlink);
1717		ip->i_flag |= IN_CHANGE;
1718		ioflag = IO_NORMAL;
1719		if (DOINGASYNC(vp))
1720			ioflag |= IO_SYNC;
1721		error = UFS_TRUNCATE(vp, (off_t)0, ioflag, cnp->cn_cred,
1722		    cnp->cn_thread);
1723	}
1724	cache_purge(vp);
1725#ifdef UFS_DIRHASH
1726	/* Kill any active hash; i_effnlink == 0, so it will not come back. */
1727	if (ip->i_dirhash != NULL)
1728		ufsdirhash_free(ip);
1729#endif
1730out:
1731	VN_KNOTE_UNLOCKED(vp, NOTE_DELETE);
1732	return (error);
1733}
1734
1735/*
1736 * symlink -- make a symbolic link
1737 */
1738static int
1739ufs_symlink(ap)
1740	struct vop_symlink_args /* {
1741		struct vnode *a_dvp;
1742		struct vnode **a_vpp;
1743		struct componentname *a_cnp;
1744		struct vattr *a_vap;
1745		char *a_target;
1746	} */ *ap;
1747{
1748	struct vnode *vp, **vpp = ap->a_vpp;
1749	struct inode *ip;
1750	int len, error;
1751
1752	error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1753	    vpp, ap->a_cnp);
1754	if (error)
1755		return (error);
1756	VN_KNOTE_UNLOCKED(ap->a_dvp, NOTE_WRITE);
1757	vp = *vpp;
1758	len = strlen(ap->a_target);
1759	if (len < vp->v_mount->mnt_maxsymlinklen) {
1760		ip = VTOI(vp);
1761		bcopy(ap->a_target, SHORTLINK(ip), len);
1762		ip->i_size = len;
1763		DIP_SET(ip, i_size, len);
1764		ip->i_flag |= IN_CHANGE | IN_UPDATE;
1765	} else
1766		error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1767		    UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK,
1768		    ap->a_cnp->cn_cred, NOCRED, (int *)0, (struct thread *)0);
1769	if (error)
1770		vput(vp);
1771	return (error);
1772}
1773
1774/*
1775 * Vnode op for reading directories.
1776 *
1777 * The routine below assumes that the on-disk format of a directory
1778 * is the same as that defined by <sys/dirent.h>. If the on-disk
1779 * format changes, then it will be necessary to do a conversion
1780 * from the on-disk format that read returns to the format defined
1781 * by <sys/dirent.h>.
1782 */
1783int
1784ufs_readdir(ap)
1785	struct vop_readdir_args /* {
1786		struct vnode *a_vp;
1787		struct uio *a_uio;
1788		struct ucred *a_cred;
1789		int *a_eofflag;
1790		int *ncookies;
1791		u_long **a_cookies;
1792	} */ *ap;
1793{
1794	struct uio *uio = ap->a_uio;
1795	int error;
1796	size_t count, lost;
1797	off_t off;
1798
1799	if (ap->a_ncookies != NULL)
1800		/*
1801		 * Ensure that the block is aligned.  The caller can use
1802		 * the cookies to determine where in the block to start.
1803		 */
1804		uio->uio_offset &= ~(DIRBLKSIZ - 1);
1805	off = uio->uio_offset;
1806	count = uio->uio_resid;
1807	/* Make sure we don't return partial entries. */
1808	if (count <= ((uio->uio_offset + count) & (DIRBLKSIZ -1)))
1809		return (EINVAL);
1810	count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
1811	lost = uio->uio_resid - count;
1812	uio->uio_resid = count;
1813	uio->uio_iov->iov_len = count;
1814#	if (BYTE_ORDER == LITTLE_ENDIAN)
1815		if (ap->a_vp->v_mount->mnt_maxsymlinklen > 0) {
1816			error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
1817		} else {
1818			struct dirent *dp, *edp;
1819			struct uio auio;
1820			struct iovec aiov;
1821			caddr_t dirbuf;
1822			int readcnt;
1823			u_char tmp;
1824
1825			auio = *uio;
1826			auio.uio_iov = &aiov;
1827			auio.uio_iovcnt = 1;
1828			auio.uio_segflg = UIO_SYSSPACE;
1829			aiov.iov_len = count;
1830			MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK);
1831			aiov.iov_base = dirbuf;
1832			error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
1833			if (error == 0) {
1834				readcnt = count - auio.uio_resid;
1835				edp = (struct dirent *)&dirbuf[readcnt];
1836				for (dp = (struct dirent *)dirbuf; dp < edp; ) {
1837					tmp = dp->d_namlen;
1838					dp->d_namlen = dp->d_type;
1839					dp->d_type = tmp;
1840					if (dp->d_reclen > 0) {
1841						dp = (struct dirent *)
1842						    ((char *)dp + dp->d_reclen);
1843					} else {
1844						error = EIO;
1845						break;
1846					}
1847				}
1848				if (dp >= edp)
1849					error = uiomove(dirbuf, readcnt, uio);
1850			}
1851			FREE(dirbuf, M_TEMP);
1852		}
1853#	else
1854		error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
1855#	endif
1856	if (!error && ap->a_ncookies != NULL) {
1857		struct dirent* dpStart;
1858		struct dirent* dpEnd;
1859		struct dirent* dp;
1860		int ncookies;
1861		u_long *cookies;
1862		u_long *cookiep;
1863
1864		if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1865			panic("ufs_readdir: unexpected uio from NFS server");
1866		dpStart = (struct dirent *)
1867		    ((char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1868		dpEnd = (struct dirent *) uio->uio_iov->iov_base;
1869		for (dp = dpStart, ncookies = 0;
1870		     dp < dpEnd;
1871		     dp = (struct dirent *)((caddr_t) dp + dp->d_reclen))
1872			ncookies++;
1873		MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1874		    M_WAITOK);
1875		for (dp = dpStart, cookiep = cookies;
1876		     dp < dpEnd;
1877		     dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
1878			off += dp->d_reclen;
1879			*cookiep++ = (u_long) off;
1880		}
1881		*ap->a_ncookies = ncookies;
1882		*ap->a_cookies = cookies;
1883	}
1884	uio->uio_resid += lost;
1885	if (ap->a_eofflag)
1886	    *ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset;
1887	return (error);
1888}
1889
1890/*
1891 * Return target name of a symbolic link
1892 */
1893static int
1894ufs_readlink(ap)
1895	struct vop_readlink_args /* {
1896		struct vnode *a_vp;
1897		struct uio *a_uio;
1898		struct ucred *a_cred;
1899	} */ *ap;
1900{
1901	struct vnode *vp = ap->a_vp;
1902	struct inode *ip = VTOI(vp);
1903	doff_t isize;
1904
1905	isize = ip->i_size;
1906	if ((isize < vp->v_mount->mnt_maxsymlinklen) ||
1907	    DIP(ip, i_blocks) == 0) { /* XXX - for old fastlink support */
1908		uiomove(SHORTLINK(ip), isize, ap->a_uio);
1909		return (0);
1910	}
1911	return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1912}
1913
1914/*
1915 * Calculate the logical to physical mapping if not done already,
1916 * then call the device strategy routine.
1917 *
1918 * In order to be able to swap to a file, the ufs_bmaparray() operation may not
1919 * deadlock on memory.  See ufs_bmap() for details.
1920 */
1921static int
1922ufs_strategy(ap)
1923	struct vop_strategy_args /* {
1924		struct vnode *a_vp;
1925		struct buf *a_bp;
1926	} */ *ap;
1927{
1928	struct buf *bp = ap->a_bp;
1929	struct vnode *vp = ap->a_vp;
1930	struct bufobj *bo;
1931	struct inode *ip;
1932	ufs2_daddr_t blkno;
1933	int error;
1934
1935	ip = VTOI(vp);
1936	if (bp->b_blkno == bp->b_lblkno) {
1937		error = ufs_bmaparray(vp, bp->b_lblkno, &blkno, bp, NULL, NULL);
1938		bp->b_blkno = blkno;
1939		if (error) {
1940			bp->b_error = error;
1941			bp->b_ioflags |= BIO_ERROR;
1942			bufdone(bp);
1943			return (error);
1944		}
1945		if ((long)bp->b_blkno == -1)
1946			vfs_bio_clrbuf(bp);
1947	}
1948	if ((long)bp->b_blkno == -1) {
1949		bufdone(bp);
1950		return (0);
1951	}
1952	bp->b_iooffset = dbtob(bp->b_blkno);
1953	bo = ip->i_umbufobj;
1954	bo->bo_ops->bop_strategy(bo, bp);
1955	return (0);
1956}
1957
1958/*
1959 * Snapshots require all lock requests to be exclusive.
1960 */
1961static int
1962ufs_lock(ap)
1963	struct vop_lock_args /* {
1964		struct vnode *a_vp;
1965		int a_flags;
1966		struct thread *a_td;
1967	} */ *ap;
1968{
1969	struct vnode *vp = ap->a_vp;
1970	int flags = ap->a_flags;
1971
1972	if ((VTOI(vp)->i_flags & SF_SNAPSHOT) &&
1973	    ((flags & LK_TYPE_MASK) == LK_SHARED)) {
1974		flags &= ~LK_TYPE_MASK;
1975		flags |= LK_EXCLUSIVE;
1976	}
1977#ifndef	DEBUG_LOCKS
1978	return (lockmgr(vp->v_vnlock, flags, VI_MTX(vp), ap->a_td));
1979#else
1980	return (debuglockmgr(vp->v_vnlock, flags, VI_MTX(vp),
1981	    ap->a_td, "vop_stdlock", vp->filename, vp->line));
1982#endif
1983}
1984
1985/*
1986 * Print out the contents of an inode.
1987 */
1988static int
1989ufs_print(ap)
1990	struct vop_print_args /* {
1991		struct vnode *a_vp;
1992	} */ *ap;
1993{
1994	struct vnode *vp = ap->a_vp;
1995	struct inode *ip = VTOI(vp);
1996
1997	printf("\tino %lu, on dev %s (%d, %d)", (u_long)ip->i_number,
1998	    devtoname(ip->i_dev), major(ip->i_dev), minor(ip->i_dev));
1999	if (vp->v_type == VFIFO)
2000		fifo_printinfo(vp);
2001	printf("\n");
2002	return (0);
2003}
2004
2005/*
2006 * Read wrapper for fifos.
2007 */
2008static int
2009ufsfifo_read(ap)
2010	struct vop_read_args /* {
2011		struct vnode *a_vp;
2012		struct uio *a_uio;
2013		int  a_ioflag;
2014		struct ucred *a_cred;
2015	} */ *ap;
2016{
2017	int error, resid;
2018	struct inode *ip;
2019	struct uio *uio;
2020
2021	uio = ap->a_uio;
2022	resid = uio->uio_resid;
2023	error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap);
2024	ip = VTOI(ap->a_vp);
2025	if ((ap->a_vp->v_mount->mnt_flag & MNT_NOATIME) == 0 && ip != NULL &&
2026	    (uio->uio_resid != resid || (error == 0 && resid != 0)))
2027		ip->i_flag |= IN_ACCESS;
2028	return (error);
2029}
2030
2031/*
2032 * Write wrapper for fifos.
2033 */
2034static int
2035ufsfifo_write(ap)
2036	struct vop_write_args /* {
2037		struct vnode *a_vp;
2038		struct uio *a_uio;
2039		int  a_ioflag;
2040		struct ucred *a_cred;
2041	} */ *ap;
2042{
2043	int error, resid;
2044	struct inode *ip;
2045	struct uio *uio;
2046
2047	uio = ap->a_uio;
2048	resid = uio->uio_resid;
2049	error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap);
2050	ip = VTOI(ap->a_vp);
2051	if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
2052		ip->i_flag |= IN_CHANGE | IN_UPDATE;
2053	return (error);
2054}
2055
2056/*
2057 * Close wrapper for fifos.
2058 *
2059 * Update the times on the inode then do device close.
2060 */
2061static int
2062ufsfifo_close(ap)
2063	struct vop_close_args /* {
2064		struct vnode *a_vp;
2065		int  a_fflag;
2066		struct ucred *a_cred;
2067		struct thread *a_td;
2068	} */ *ap;
2069{
2070	struct vnode *vp = ap->a_vp;
2071
2072	VI_LOCK(vp);
2073	if (vp->v_usecount > 1)
2074		ufs_itimes(vp);
2075	VI_UNLOCK(vp);
2076	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
2077}
2078
2079/*
2080 * Kqfilter wrapper for fifos.
2081 *
2082 * Fall through to ufs kqfilter routines if needed
2083 */
2084static int
2085ufsfifo_kqfilter(ap)
2086	struct vop_kqfilter_args *ap;
2087{
2088	int error;
2089
2090	error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_kqfilter), ap);
2091	if (error)
2092		error = ufs_kqfilter(ap);
2093	return (error);
2094}
2095
2096/*
2097 * Return POSIX pathconf information applicable to ufs filesystems.
2098 */
2099static int
2100ufs_pathconf(ap)
2101	struct vop_pathconf_args /* {
2102		struct vnode *a_vp;
2103		int a_name;
2104		int *a_retval;
2105	} */ *ap;
2106{
2107	int error;
2108
2109	error = 0;
2110	switch (ap->a_name) {
2111	case _PC_LINK_MAX:
2112		*ap->a_retval = LINK_MAX;
2113		break;
2114	case _PC_NAME_MAX:
2115		*ap->a_retval = NAME_MAX;
2116		break;
2117	case _PC_PATH_MAX:
2118		*ap->a_retval = PATH_MAX;
2119		break;
2120	case _PC_PIPE_BUF:
2121		*ap->a_retval = PIPE_BUF;
2122		break;
2123	case _PC_CHOWN_RESTRICTED:
2124		*ap->a_retval = 1;
2125		break;
2126	case _PC_NO_TRUNC:
2127		*ap->a_retval = 1;
2128		break;
2129	case _PC_ACL_EXTENDED:
2130#ifdef UFS_ACL
2131		if (ap->a_vp->v_mount->mnt_flag & MNT_ACLS)
2132			*ap->a_retval = 1;
2133		else
2134			*ap->a_retval = 0;
2135#else
2136		*ap->a_retval = 0;
2137#endif
2138		break;
2139	case _PC_ACL_PATH_MAX:
2140#ifdef UFS_ACL
2141		if (ap->a_vp->v_mount->mnt_flag & MNT_ACLS)
2142			*ap->a_retval = ACL_MAX_ENTRIES;
2143		else
2144			*ap->a_retval = 3;
2145#else
2146		*ap->a_retval = 3;
2147#endif
2148		break;
2149	case _PC_MAC_PRESENT:
2150#ifdef MAC
2151		if (ap->a_vp->v_mount->mnt_flag & MNT_MULTILABEL)
2152			*ap->a_retval = 1;
2153		else
2154			*ap->a_retval = 0;
2155#else
2156		*ap->a_retval = 0;
2157#endif
2158		break;
2159	case _PC_ASYNC_IO:
2160		/* _PC_ASYNC_IO should have been handled by upper layers. */
2161		KASSERT(0, ("_PC_ASYNC_IO should not get here"));
2162		error = EINVAL;
2163		break;
2164	case _PC_PRIO_IO:
2165		*ap->a_retval = 0;
2166		break;
2167	case _PC_SYNC_IO:
2168		*ap->a_retval = 0;
2169		break;
2170	case _PC_ALLOC_SIZE_MIN:
2171		*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize;
2172		break;
2173	case _PC_FILESIZEBITS:
2174		*ap->a_retval = 64;
2175		break;
2176	case _PC_REC_INCR_XFER_SIZE:
2177		*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
2178		break;
2179	case _PC_REC_MAX_XFER_SIZE:
2180		*ap->a_retval = -1; /* means ``unlimited'' */
2181		break;
2182	case _PC_REC_MIN_XFER_SIZE:
2183		*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
2184		break;
2185	case _PC_REC_XFER_ALIGN:
2186		*ap->a_retval = PAGE_SIZE;
2187		break;
2188	case _PC_SYMLINK_MAX:
2189		*ap->a_retval = MAXPATHLEN;
2190		break;
2191
2192	default:
2193		error = EINVAL;
2194		break;
2195	}
2196	return (error);
2197}
2198
2199/*
2200 * Advisory record locking support
2201 */
2202static int
2203ufs_advlock(ap)
2204	struct vop_advlock_args /* {
2205		struct vnode *a_vp;
2206		caddr_t  a_id;
2207		int  a_op;
2208		struct flock *a_fl;
2209		int  a_flags;
2210	} */ *ap;
2211{
2212	struct inode *ip = VTOI(ap->a_vp);
2213
2214	return (lf_advlock(ap, &(ip->i_lockf), ip->i_size));
2215}
2216
2217/*
2218 * Initialize the vnode associated with a new inode, handle aliased
2219 * vnodes.
2220 */
2221int
2222ufs_vinit(mntp, fifoops, vpp)
2223	struct mount *mntp;
2224	vop_t **fifoops;
2225	struct vnode **vpp;
2226{
2227	struct inode *ip;
2228	struct vnode *vp;
2229
2230	vp = *vpp;
2231	ip = VTOI(vp);
2232	vp->v_type = IFTOVT(ip->i_mode);
2233	if (vp->v_type == VFIFO)
2234		vp->v_op = fifoops;
2235	ASSERT_VOP_LOCKED(vp, "ufs_vinit");
2236	if (ip->i_number == ROOTINO)
2237		vp->v_vflag |= VV_ROOT;
2238	ip->i_modrev = init_va_filerev();
2239	*vpp = vp;
2240	return (0);
2241}
2242
2243/*
2244 * Allocate a new inode.
2245 * Vnode dvp must be locked.
2246 */
2247static int
2248ufs_makeinode(mode, dvp, vpp, cnp)
2249	int mode;
2250	struct vnode *dvp;
2251	struct vnode **vpp;
2252	struct componentname *cnp;
2253{
2254	struct inode *ip, *pdir;
2255	struct direct newdir;
2256	struct vnode *tvp;
2257#ifdef UFS_ACL
2258	struct acl *acl;
2259#endif
2260	int error;
2261
2262	pdir = VTOI(dvp);
2263#ifdef DIAGNOSTIC
2264	if ((cnp->cn_flags & HASBUF) == 0)
2265		panic("ufs_makeinode: no name");
2266#endif
2267	*vpp = NULL;
2268	if ((mode & IFMT) == 0)
2269		mode |= IFREG;
2270
2271	error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp);
2272	if (error)
2273		return (error);
2274	ip = VTOI(tvp);
2275	ip->i_gid = pdir->i_gid;
2276	DIP_SET(ip, i_gid, pdir->i_gid);
2277#ifdef SUIDDIR
2278	{
2279#ifdef QUOTA
2280		struct ucred ucred, *ucp;
2281		ucp = cnp->cn_cred;
2282#endif
2283		/*
2284		 * If we are not the owner of the directory,
2285		 * and we are hacking owners here, (only do this where told to)
2286		 * and we are not giving it TO root, (would subvert quotas)
2287		 * then go ahead and give it to the other user.
2288		 * Note that this drops off the execute bits for security.
2289		 */
2290		if ((dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
2291		    (pdir->i_mode & ISUID) &&
2292		    (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) {
2293			ip->i_uid = pdir->i_uid;
2294			DIP_SET(ip, i_uid, ip->i_uid);
2295			mode &= ~07111;
2296#ifdef QUOTA
2297			/*
2298			 * Make sure the correct user gets charged
2299			 * for the space.
2300			 * Quickly knock up a dummy credential for the victim.
2301			 * XXX This seems to never be accessed out of our
2302			 * context so a stack variable is ok.
2303			 */
2304			ucred.cr_ref = 1;
2305			ucred.cr_uid = ip->i_uid;
2306			ucred.cr_ngroups = 1;
2307			ucred.cr_groups[0] = pdir->i_gid;
2308			ucp = &ucred;
2309#endif
2310		} else {
2311			ip->i_uid = cnp->cn_cred->cr_uid;
2312			DIP_SET(ip, i_uid, ip->i_uid);
2313		}
2314
2315#ifdef QUOTA
2316		if ((error = getinoquota(ip)) ||
2317	    	    (error = chkiq(ip, 1, ucp, 0))) {
2318			UFS_VFREE(tvp, ip->i_number, mode);
2319			vput(tvp);
2320			return (error);
2321		}
2322#endif
2323	}
2324#else	/* !SUIDDIR */
2325	ip->i_uid = cnp->cn_cred->cr_uid;
2326	DIP_SET(ip, i_uid, ip->i_uid);
2327#ifdef QUOTA
2328	if ((error = getinoquota(ip)) ||
2329	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
2330		UFS_VFREE(tvp, ip->i_number, mode);
2331		vput(tvp);
2332		return (error);
2333	}
2334#endif
2335#endif	/* !SUIDDIR */
2336	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
2337#ifdef UFS_ACL
2338	acl = NULL;
2339	if ((dvp->v_mount->mnt_flag & MNT_ACLS) != 0) {
2340		MALLOC(acl, struct acl *, sizeof(*acl), M_ACL, M_WAITOK);
2341
2342		/*
2343		 * Retrieve default ACL for parent, if any.
2344		 */
2345		error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cnp->cn_cred,
2346		    cnp->cn_thread);
2347		switch (error) {
2348		case 0:
2349			/*
2350			 * Retrieved a default ACL, so merge mode and ACL if
2351			 * necessary.
2352			 */
2353			if (acl->acl_cnt != 0) {
2354				/*
2355				 * Two possible ways for default ACL to not
2356				 * be present.  First, the EA can be
2357				 * undefined, or second, the default ACL can
2358				 * be blank.  If it's blank, fall through to
2359				 * the it's not defined case.
2360				 */
2361				mode = acl_posix1e_newfilemode(mode, acl);
2362				ip->i_mode = mode;
2363				DIP_SET(ip, i_mode, mode);
2364				ufs_sync_acl_from_inode(ip, acl);
2365				break;
2366			}
2367			/* FALLTHROUGH */
2368
2369		case EOPNOTSUPP:
2370			/*
2371			 * Just use the mode as-is.
2372			 */
2373			ip->i_mode = mode;
2374			DIP_SET(ip, i_mode, mode);
2375			FREE(acl, M_ACL);
2376			acl = NULL;
2377			break;
2378
2379		default:
2380			UFS_VFREE(tvp, ip->i_number, mode);
2381			vput(tvp);
2382			FREE(acl, M_ACL);
2383			acl = NULL;
2384			return (error);
2385		}
2386	} else {
2387#endif
2388		ip->i_mode = mode;
2389		DIP_SET(ip, i_mode, mode);
2390#ifdef UFS_ACL
2391	}
2392#endif
2393	tvp->v_type = IFTOVT(mode);	/* Rest init'd in getnewvnode(). */
2394	ip->i_effnlink = 1;
2395	ip->i_nlink = 1;
2396	DIP_SET(ip, i_nlink, 1);
2397	if (DOINGSOFTDEP(tvp))
2398		softdep_change_linkcnt(ip);
2399	if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
2400	    suser_cred(cnp->cn_cred, SUSER_ALLOWJAIL)) {
2401		ip->i_mode &= ~ISGID;
2402		DIP_SET(ip, i_mode, ip->i_mode);
2403	}
2404
2405	if (cnp->cn_flags & ISWHITEOUT) {
2406		ip->i_flags |= UF_OPAQUE;
2407		DIP_SET(ip, i_flags, ip->i_flags);
2408	}
2409
2410	/*
2411	 * Make sure inode goes to disk before directory entry.
2412	 */
2413	error = UFS_UPDATE(tvp, !(DOINGSOFTDEP(tvp) | DOINGASYNC(tvp)));
2414	if (error)
2415		goto bad;
2416#ifdef MAC
2417	if (dvp->v_mount->mnt_flag & MNT_MULTILABEL) {
2418		error = mac_create_vnode_extattr(cnp->cn_cred, dvp->v_mount,
2419		    dvp, tvp, cnp);
2420		if (error)
2421			goto bad;
2422	}
2423#endif
2424#ifdef UFS_ACL
2425	if (acl != NULL) {
2426		/*
2427		 * XXX: If we abort now, will Soft Updates notify the extattr
2428		 * code that the EAs for the file need to be released?
2429		 */
2430		error = VOP_SETACL(tvp, ACL_TYPE_ACCESS, acl, cnp->cn_cred,
2431		    cnp->cn_thread);
2432		switch (error) {
2433		case 0:
2434			break;
2435
2436		case EOPNOTSUPP:
2437			/*
2438			 * XXX: This should not happen, as EOPNOTSUPP above was
2439			 * supposed to free acl.
2440			 */
2441			printf("ufs_makeinode: VOP_GETACL() but no "
2442			    "VOP_SETACL()\n");
2443			/* panic("ufs_makeinode: VOP_GETACL() but no "
2444			    "VOP_SETACL()"); */
2445			break;
2446
2447		default:
2448			FREE(acl, M_ACL);
2449			goto bad;
2450		}
2451		FREE(acl, M_ACL);
2452	}
2453#endif /* !UFS_ACL */
2454	ufs_makedirentry(ip, cnp, &newdir);
2455	error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL);
2456	if (error)
2457		goto bad;
2458	*vpp = tvp;
2459	return (0);
2460
2461bad:
2462	/*
2463	 * Write error occurred trying to update the inode
2464	 * or the directory so must deallocate the inode.
2465	 */
2466	ip->i_effnlink = 0;
2467	ip->i_nlink = 0;
2468	DIP_SET(ip, i_nlink, 0);
2469	ip->i_flag |= IN_CHANGE;
2470	if (DOINGSOFTDEP(tvp))
2471		softdep_change_linkcnt(ip);
2472	vput(tvp);
2473	return (error);
2474}
2475
2476static struct filterops ufsread_filtops =
2477	{ 1, NULL, filt_ufsdetach, filt_ufsread };
2478static struct filterops ufswrite_filtops =
2479	{ 1, NULL, filt_ufsdetach, filt_ufswrite };
2480static struct filterops ufsvnode_filtops =
2481	{ 1, NULL, filt_ufsdetach, filt_ufsvnode };
2482
2483static int
2484ufs_kqfilter(ap)
2485	struct vop_kqfilter_args /* {
2486		struct vnode *a_vp;
2487		struct knote *a_kn;
2488	} */ *ap;
2489{
2490	struct vnode *vp = ap->a_vp;
2491	struct knote *kn = ap->a_kn;
2492
2493	switch (kn->kn_filter) {
2494	case EVFILT_READ:
2495		kn->kn_fop = &ufsread_filtops;
2496		break;
2497	case EVFILT_WRITE:
2498		kn->kn_fop = &ufswrite_filtops;
2499		break;
2500	case EVFILT_VNODE:
2501		kn->kn_fop = &ufsvnode_filtops;
2502		break;
2503	default:
2504		return (1);
2505	}
2506
2507	kn->kn_hook = (caddr_t)vp;
2508
2509	if (vp->v_pollinfo == NULL)
2510		v_addpollinfo(vp);
2511	if (vp->v_pollinfo == NULL)
2512		return ENOMEM;
2513	knlist_add(&vp->v_pollinfo->vpi_selinfo.si_note, kn, 0);
2514
2515	return (0);
2516}
2517
2518static void
2519filt_ufsdetach(struct knote *kn)
2520{
2521	struct vnode *vp = (struct vnode *)kn->kn_hook;
2522
2523	KASSERT(vp->v_pollinfo != NULL, ("Mising v_pollinfo"));
2524	knlist_remove(&vp->v_pollinfo->vpi_selinfo.si_note, kn, 0);
2525}
2526
2527/*ARGSUSED*/
2528static int
2529filt_ufsread(struct knote *kn, long hint)
2530{
2531	struct vnode *vp = (struct vnode *)kn->kn_hook;
2532	struct inode *ip = VTOI(vp);
2533
2534	/*
2535	 * filesystem is gone, so set the EOF flag and schedule
2536	 * the knote for deletion.
2537	 */
2538	if (hint == NOTE_REVOKE) {
2539		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
2540		return (1);
2541	}
2542
2543        kn->kn_data = ip->i_size - kn->kn_fp->f_offset;
2544        return (kn->kn_data != 0);
2545}
2546
2547/*ARGSUSED*/
2548static int
2549filt_ufswrite(struct knote *kn, long hint)
2550{
2551
2552	/*
2553	 * filesystem is gone, so set the EOF flag and schedule
2554	 * the knote for deletion.
2555	 */
2556	if (hint == NOTE_REVOKE)
2557		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
2558
2559        kn->kn_data = 0;
2560        return (1);
2561}
2562
2563static int
2564filt_ufsvnode(struct knote *kn, long hint)
2565{
2566
2567	if (kn->kn_sfflags & hint)
2568		kn->kn_fflags |= hint;
2569	if (hint == NOTE_REVOKE) {
2570		kn->kn_flags |= EV_EOF;
2571		return (1);
2572	}
2573	return (kn->kn_fflags != 0);
2574}
2575
2576/* Global vfs data structures for ufs. */
2577static vop_t **ufs_vnodeop_p;
2578static struct vnodeopv_entry_desc ufs_vnodeop_entries[] = {
2579	{ &vop_default_desc,		(vop_t *) vop_defaultop },
2580	{ &vop_fsync_desc,		(vop_t *) vop_panic },
2581	{ &vop_read_desc,		(vop_t *) vop_panic },
2582	{ &vop_reallocblks_desc,	(vop_t *) vop_panic },
2583	{ &vop_write_desc,		(vop_t *) vop_panic },
2584	{ &vop_access_desc,		(vop_t *) ufs_access },
2585	{ &vop_advlock_desc,		(vop_t *) ufs_advlock },
2586	{ &vop_lock_desc,		(vop_t *) ufs_lock },
2587	{ &vop_bmap_desc,		(vop_t *) ufs_bmap },
2588	{ &vop_cachedlookup_desc,	(vop_t *) ufs_lookup },
2589	{ &vop_close_desc,		(vop_t *) ufs_close },
2590	{ &vop_create_desc,		(vop_t *) ufs_create },
2591	{ &vop_getattr_desc,		(vop_t *) ufs_getattr },
2592	{ &vop_inactive_desc,		(vop_t *) ufs_inactive },
2593	{ &vop_link_desc,		(vop_t *) ufs_link },
2594	{ &vop_lookup_desc,		(vop_t *) vfs_cache_lookup },
2595	{ &vop_mkdir_desc,		(vop_t *) ufs_mkdir },
2596	{ &vop_mknod_desc,		(vop_t *) ufs_mknod },
2597	{ &vop_open_desc,		(vop_t *) ufs_open },
2598	{ &vop_pathconf_desc,		(vop_t *) ufs_pathconf },
2599	{ &vop_poll_desc,		(vop_t *) vop_stdpoll },
2600	{ &vop_kqfilter_desc,		(vop_t *) ufs_kqfilter },
2601	{ &vop_getwritemount_desc, 	(vop_t *) vop_stdgetwritemount },
2602	{ &vop_print_desc,		(vop_t *) ufs_print },
2603	{ &vop_readdir_desc,		(vop_t *) ufs_readdir },
2604	{ &vop_readlink_desc,		(vop_t *) ufs_readlink },
2605	{ &vop_reclaim_desc,		(vop_t *) ufs_reclaim },
2606	{ &vop_remove_desc,		(vop_t *) ufs_remove },
2607	{ &vop_rename_desc,		(vop_t *) ufs_rename },
2608	{ &vop_rmdir_desc,		(vop_t *) ufs_rmdir },
2609	{ &vop_setattr_desc,		(vop_t *) ufs_setattr },
2610#ifdef MAC
2611	{ &vop_setlabel_desc,		(vop_t *) vop_stdsetlabel_ea },
2612#endif
2613	{ &vop_strategy_desc,		(vop_t *) ufs_strategy },
2614	{ &vop_symlink_desc,		(vop_t *) ufs_symlink },
2615	{ &vop_whiteout_desc,		(vop_t *) ufs_whiteout },
2616#ifdef UFS_EXTATTR
2617	{ &vop_getextattr_desc,		(vop_t *) ufs_getextattr },
2618	{ &vop_deleteextattr_desc,		(vop_t *) ufs_deleteextattr },
2619	{ &vop_setextattr_desc,		(vop_t *) ufs_setextattr },
2620#endif
2621#ifdef UFS_ACL
2622	{ &vop_getacl_desc,		(vop_t *) ufs_getacl },
2623	{ &vop_setacl_desc,		(vop_t *) ufs_setacl },
2624	{ &vop_aclcheck_desc,		(vop_t *) ufs_aclcheck },
2625#endif
2626	{ NULL, NULL }
2627};
2628static struct vnodeopv_desc ufs_vnodeop_opv_desc =
2629	{ &ufs_vnodeop_p, ufs_vnodeop_entries };
2630
2631static vop_t **ufs_fifoop_p;
2632static struct vnodeopv_entry_desc ufs_fifoop_entries[] = {
2633	{ &vop_default_desc,		(vop_t *) fifo_vnoperate },
2634	{ &vop_fsync_desc,		(vop_t *) vop_panic },
2635	{ &vop_access_desc,		(vop_t *) ufs_access },
2636	{ &vop_close_desc,		(vop_t *) ufsfifo_close },
2637	{ &vop_getattr_desc,		(vop_t *) ufs_getattr },
2638	{ &vop_inactive_desc,		(vop_t *) ufs_inactive },
2639	{ &vop_kqfilter_desc,		(vop_t *) ufsfifo_kqfilter },
2640	{ &vop_print_desc,		(vop_t *) ufs_print },
2641	{ &vop_read_desc,		(vop_t *) ufsfifo_read },
2642	{ &vop_reclaim_desc,		(vop_t *) ufs_reclaim },
2643	{ &vop_setattr_desc,		(vop_t *) ufs_setattr },
2644#ifdef MAC
2645	{ &vop_setlabel_desc,		(vop_t *) vop_stdsetlabel_ea },
2646#endif
2647	{ &vop_write_desc,		(vop_t *) ufsfifo_write },
2648#ifdef UFS_EXTATTR
2649	{ &vop_getextattr_desc,		(vop_t *) ufs_getextattr },
2650	{ &vop_deleteextattr_desc,		(vop_t *) ufs_deleteextattr },
2651	{ &vop_setextattr_desc,		(vop_t *) ufs_setextattr },
2652#endif
2653#ifdef UFS_ACL
2654	{ &vop_getacl_desc,		(vop_t *) ufs_getacl },
2655	{ &vop_setacl_desc,		(vop_t *) ufs_setacl },
2656	{ &vop_aclcheck_desc,		(vop_t *) ufs_aclcheck },
2657#endif
2658	{ NULL, NULL }
2659};
2660static struct vnodeopv_desc ufs_fifoop_opv_desc =
2661	{ &ufs_fifoop_p, ufs_fifoop_entries };
2662
2663VNODEOP_SET(ufs_vnodeop_opv_desc);
2664VNODEOP_SET(ufs_fifoop_opv_desc);
2665
2666int
2667ufs_vnoperate(ap)
2668	struct vop_generic_args /* {
2669		struct vnodeop_desc *a_desc;
2670	} */ *ap;
2671{
2672	return (VOCALL(ufs_vnodeop_p, ap->a_desc->vdesc_offset, ap));
2673}
2674
2675int
2676ufs_vnoperatefifo(ap)
2677	struct vop_generic_args /* {
2678		struct vnodeop_desc *a_desc;
2679	} */ *ap;
2680{
2681	return (VOCALL(ufs_fifoop_p, ap->a_desc->vdesc_offset, ap));
2682}
2683