xref: /freebsd/sys/fs/devfs/devfs_vnops.c (revision 09e8dea79366f1e5b3a73e8a271b26e4b6bf2e6a)
1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 2000
5  *	Poul-Henning Kamp.  All rights reserved.
6  *
7  * This code is derived from software donated to Berkeley by
8  * Jan-Simon Pendry.
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. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  *	@(#)kernfs_vnops.c	8.15 (Berkeley) 5/21/95
32  * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43
33  *
34  * $FreeBSD$
35  */
36 
37 /*
38  * TODO:
39  *	remove empty directories
40  *	mknod: hunt down DE_DELETED, compare name, reinstantiate.
41  *	mkdir: want it ?
42  */
43 
44 #include <opt_devfs.h>
45 #ifndef NODEVFS
46 
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/conf.h>
50 #include <sys/dirent.h>
51 #include <sys/kernel.h>
52 #include <sys/lock.h>
53 #include <sys/malloc.h>
54 #include <sys/mount.h>
55 #include <sys/namei.h>
56 #include <sys/proc.h>
57 #include <sys/time.h>
58 #include <sys/unistd.h>
59 #include <sys/vnode.h>
60 
61 #include <fs/devfs/devfs.h>
62 
63 static int	devfs_access(struct vop_access_args *ap);
64 static int	devfs_getattr(struct vop_getattr_args *ap);
65 static int	devfs_lookupx(struct vop_lookup_args *ap);
66 static int	devfs_mknod(struct vop_mknod_args *ap);
67 static int	devfs_pathconf(struct vop_pathconf_args *ap);
68 static int	devfs_print(struct vop_print_args *ap);
69 static int	devfs_read(struct vop_read_args *ap);
70 static int	devfs_readdir(struct vop_readdir_args *ap);
71 static int	devfs_readlink(struct vop_readlink_args *ap);
72 static int	devfs_reclaim(struct vop_reclaim_args *ap);
73 static int	devfs_remove(struct vop_remove_args *ap);
74 static int	devfs_revoke(struct vop_revoke_args *ap);
75 static int	devfs_setattr(struct vop_setattr_args *ap);
76 static int	devfs_symlink(struct vop_symlink_args *ap);
77 
78 /*
79  * Construct the fully qualified path name relative to the mountpoint
80  */
81 static char *
82 devfs_fqpn(char *buf, struct vnode *dvp, struct componentname *cnp)
83 {
84 	int i;
85 	struct devfs_dirent *de, *dd;
86 	struct devfs_mount *dmp;
87 
88 	dmp = VFSTODEVFS(dvp->v_mount);
89 	dd = dvp->v_data;
90 	i = SPECNAMELEN;
91 	buf[i] = '\0';
92 	i -= cnp->cn_namelen;
93 	if (i < 0)
94 		 return (NULL);
95 	bcopy(cnp->cn_nameptr, buf + i, cnp->cn_namelen);
96 	de = dd;
97 	while (de != dmp->dm_basedir) {
98 		i--;
99 		if (i < 0)
100 			 return (NULL);
101 		buf[i] = '/';
102 		i -= de->de_dirent->d_namlen;
103 		if (i < 0)
104 			 return (NULL);
105 		bcopy(de->de_dirent->d_name, buf + i,
106 		    de->de_dirent->d_namlen);
107 		de = TAILQ_FIRST(&de->de_dlist);	/* "." */
108 		de = TAILQ_NEXT(de, de_list);		/* ".." */
109 		de = de->de_dir;
110 	}
111 	return (buf + i);
112 }
113 
114 int
115 devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td)
116 {
117 	int error;
118 	struct vnode *vp;
119 	dev_t dev;
120 
121 	if (td == NULL)
122 		td = curthread; /* XXX */
123 loop:
124 	vp = de->de_vnode;
125 	if (vp != NULL) {
126 		if (vget(vp, LK_EXCLUSIVE, td ? td : curthread))
127 			goto loop;
128 		*vpp = vp;
129 		return (0);
130 	}
131 	if (de->de_dirent->d_type == DT_CHR) {
132 		dev = *devfs_itod(de->de_inode);
133 		if (dev == NULL)
134 			return (ENOENT);
135 	} else {
136 		dev = NODEV;
137 	}
138 	error = getnewvnode(VT_DEVFS, mp, devfs_vnodeop_p, &vp);
139 	if (error != 0) {
140 		printf("devfs_allocv: failed to allocate new vnode\n");
141 		return (error);
142 	}
143 
144 	if (de->de_dirent->d_type == DT_CHR) {
145 		vp->v_type = VCHR;
146 		vp = addaliasu(vp, dev->si_udev);
147 		vp->v_op = devfs_specop_p;
148 	} else if (de->de_dirent->d_type == DT_DIR) {
149 		vp->v_type = VDIR;
150 	} else if (de->de_dirent->d_type == DT_LNK) {
151 		vp->v_type = VLNK;
152 	} else {
153 		vp->v_type = VBAD;
154 	}
155 	vp->v_data = de;
156 	de->de_vnode = vp;
157 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
158 	*vpp = vp;
159 	return (0);
160 }
161 
162 static int
163 devfs_access(ap)
164 	struct vop_access_args /* {
165 		struct vnode *a_vp;
166 		int  a_mode;
167 		struct ucred *a_cred;
168 		struct thread *a_td;
169 	} */ *ap;
170 {
171 	struct vnode *vp = ap->a_vp;
172 	struct devfs_dirent *de;
173 
174 	de = vp->v_data;
175 	if (vp->v_type == VDIR)
176 		de = de->de_dir;
177 
178 	return (vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid,
179 	    ap->a_mode, ap->a_cred, NULL));
180 }
181 
182 static int
183 devfs_getattr(ap)
184 	struct vop_getattr_args /* {
185 		struct vnode *a_vp;
186 		struct vattr *a_vap;
187 		struct ucred *a_cred;
188 		struct thread *a_td;
189 	} */ *ap;
190 {
191 	struct vnode *vp = ap->a_vp;
192 	struct vattr *vap = ap->a_vap;
193 	int error = 0;
194 	struct devfs_dirent *de;
195 	dev_t dev;
196 
197 	de = vp->v_data;
198 	if (vp->v_type == VDIR)
199 		de = de->de_dir;
200 	bzero((caddr_t) vap, sizeof(*vap));
201 	vattr_null(vap);
202 	vap->va_uid = de->de_uid;
203 	vap->va_gid = de->de_gid;
204 	vap->va_mode = de->de_mode;
205 	if (vp->v_type == VLNK)
206 		vap->va_size = de->de_dirent->d_namlen;
207 	else if (vp->v_type == VDIR)
208 		vap->va_size = vap->va_bytes = DEV_BSIZE;
209 	else
210 		vap->va_size = 0;
211 	if (vp->v_type != VDIR)
212 		vap->va_bytes = 0;
213 	vap->va_blocksize = DEV_BSIZE;
214 	vap->va_type = vp->v_type;
215 
216 #define fix(aa)							\
217 	do {							\
218 		if ((aa).tv_sec == 0) {				\
219 			(aa).tv_sec = boottime.tv_sec;		\
220 			(aa).tv_nsec = boottime.tv_usec * 1000; \
221 		}						\
222 	} while (0)
223 
224 	if (vp->v_type != VCHR)  {
225 		fix(de->de_atime);
226 		vap->va_atime = de->de_atime;
227 		fix(de->de_mtime);
228 		vap->va_mtime = de->de_mtime;
229 		fix(de->de_ctime);
230 		vap->va_ctime = de->de_ctime;
231 	} else {
232 		dev = vp->v_rdev;
233 		fix(dev->si_atime);
234 		vap->va_atime = dev->si_atime;
235 		fix(dev->si_mtime);
236 		vap->va_mtime = dev->si_mtime;
237 		fix(dev->si_ctime);
238 		vap->va_ctime = dev->si_ctime;
239 		vap->va_rdev = dev->si_udev;
240 	}
241 	vap->va_gen = 0;
242 	vap->va_flags = 0;
243 	vap->va_nlink = de->de_links;
244 	vap->va_fileid = de->de_inode;
245 
246 	return (error);
247 }
248 
249 static int
250 devfs_lookupx(ap)
251 	struct vop_lookup_args /* {
252 		struct vnode * a_dvp;
253 		struct vnode ** a_vpp;
254 		struct componentname * a_cnp;
255 	} */ *ap;
256 {
257 	struct componentname *cnp;
258 	struct vnode *dvp, **vpp;
259 	struct thread *td;
260 	struct devfs_dirent *de, *dd;
261 	struct devfs_mount *dmp;
262 	dev_t cdev, *cpdev;
263 	int error, cloned, flags, nameiop;
264 	char specname[SPECNAMELEN + 1], *pname;
265 
266 	cnp = ap->a_cnp;
267 	vpp = ap->a_vpp;
268 	dvp = ap->a_dvp;
269 	pname = cnp->cn_nameptr;
270 	td = cnp->cn_thread;
271 	flags = cnp->cn_flags;
272 	nameiop = cnp->cn_nameiop;
273 	dmp = VFSTODEVFS(dvp->v_mount);
274 	cloned = 0;
275 	dd = dvp->v_data;
276 
277 	*vpp = NULLVP;
278 	cnp->cn_flags &= ~PDIRUNLOCK;
279 
280 	if ((flags & ISLASTCN) && nameiop == RENAME)
281 		return (EOPNOTSUPP);
282 
283 	if (dvp->v_type != VDIR)
284 		return (ENOTDIR);
285 
286 	if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT))
287 		return (EIO);
288 
289 	error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td);
290 	if (error)
291 		return (error);
292 
293 	if (cnp->cn_namelen == 1 && *pname == '.') {
294 		if ((flags & ISLASTCN) && nameiop != LOOKUP)
295 			return (EINVAL);
296 		*vpp = dvp;
297 		VREF(dvp);
298 		return (0);
299 	}
300 
301 	if (flags & ISDOTDOT) {
302 		if ((flags & ISLASTCN) && nameiop != LOOKUP)
303 			return (EINVAL);
304 		VOP_UNLOCK(dvp, 0, td);
305 		cnp->cn_flags |= PDIRUNLOCK;
306 		de = TAILQ_FIRST(&dd->de_dlist);	/* "." */
307 		de = TAILQ_NEXT(de, de_list);		/* ".." */
308 		de = de->de_dir;
309 		error = devfs_allocv(de, dvp->v_mount, vpp, td);
310 		if (error || ((flags & LOCKPARENT) && (flags & ISLASTCN))) {
311 			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
312 			cnp->cn_flags &= ~PDIRUNLOCK;
313 		}
314 		return (error);
315 	}
316 
317 	devfs_populate(dmp);
318 	dd = dvp->v_data;
319 	TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
320 		if (cnp->cn_namelen != de->de_dirent->d_namlen)
321 			continue;
322 		if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
323 		    de->de_dirent->d_namlen) != 0)
324 			continue;
325 		if (de->de_flags & DE_WHITEOUT)
326 			goto notfound;
327 		goto found;
328 	}
329 
330 	if (nameiop == DELETE)
331 		goto notfound;
332 
333 	/*
334 	 * OK, we didn't have an entry for the name we were asked for
335 	 * so we try to see if anybody can create it on demand.
336 	 */
337 	pname = devfs_fqpn(specname, dvp, cnp);
338 	if (pname == NULL)
339 		goto notfound;
340 
341 	cdev = NODEV;
342 	EVENTHANDLER_INVOKE(dev_clone, pname, strlen(pname), &cdev);
343 	if (cdev == NODEV)
344 		goto notfound;
345 
346 	devfs_populate(dmp);
347 	dd = dvp->v_data;
348 
349 	TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
350 		cpdev = devfs_itod(de->de_inode);
351 		if (cpdev != NULL && cdev == *cpdev)
352 			goto found;
353 		continue;
354 	}
355 
356 notfound:
357 
358 	if ((nameiop == CREATE || nameiop == RENAME) &&
359 	    (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) {
360 		cnp->cn_flags |= SAVENAME;
361 		if (!(flags & LOCKPARENT)) {
362 			VOP_UNLOCK(dvp, 0, td);
363 			cnp->cn_flags |= PDIRUNLOCK;
364 		}
365 		return (EJUSTRETURN);
366 	}
367 	return (ENOENT);
368 
369 
370 found:
371 
372 	if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) {
373 		error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td);
374 		if (error)
375 			return (error);
376 		if (*vpp == dvp) {
377 			VREF(dvp);
378 			*vpp = dvp;
379 			return (0);
380 		}
381 		error = devfs_allocv(de, dvp->v_mount, vpp, td);
382 		if (error)
383 			return (error);
384 		if (!(flags & LOCKPARENT)) {
385 			VOP_UNLOCK(dvp, 0, td);
386 			cnp->cn_flags |= PDIRUNLOCK;
387 		}
388 		return (0);
389 	}
390 	error = devfs_allocv(de, dvp->v_mount, vpp, td);
391 	if (error)
392 		return (error);
393 	if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) {
394 		VOP_UNLOCK(dvp, 0, td);
395 		cnp->cn_flags |= PDIRUNLOCK;
396 	}
397 	return (0);
398 }
399 
400 static int
401 devfs_lookup(struct vop_lookup_args *ap)
402 {
403 	int j;
404 	struct devfs_mount *dmp;
405 
406 	dmp = VFSTODEVFS(ap->a_dvp->v_mount);
407 	lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread);
408 	j = devfs_lookupx(ap);
409 	lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
410 	return (j);
411 }
412 
413 static int
414 devfs_mknod(struct vop_mknod_args *ap)
415 /*
416 struct vop_mknod_args {
417         struct vnodeop_desc *a_desc;
418         struct vnode *a_dvp;
419         struct vnode **a_vpp;
420         struct componentname *a_cnp;
421         struct vattr *a_vap;
422 };
423 */
424 {
425 	struct componentname *cnp;
426 	struct vnode *dvp, **vpp;
427 	struct thread *td;
428 	struct devfs_dirent *dd, *de;
429 	struct devfs_mount *dmp;
430 	int cloned, flags, nameiop;
431 	int error;
432 
433 	dvp = ap->a_dvp;
434 	dmp = VFSTODEVFS(dvp->v_mount);
435 	lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
436 
437 	cnp = ap->a_cnp;
438 	vpp = ap->a_vpp;
439 	td = cnp->cn_thread;
440 	flags = cnp->cn_flags;
441 	nameiop = cnp->cn_nameiop;
442 	cloned = 0;
443 	dd = dvp->v_data;
444 
445 	error = ENOENT;
446 	TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
447 		if (cnp->cn_namelen != de->de_dirent->d_namlen)
448 			continue;
449 		if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
450 		    de->de_dirent->d_namlen) != 0)
451 			continue;
452 		if (de->de_flags & DE_WHITEOUT)
453 			break;
454 		goto notfound;
455 	}
456 	if (de == NULL)
457 		goto notfound;
458 	de->de_flags &= ~DE_WHITEOUT;
459 	error = devfs_allocv(de, dvp->v_mount, vpp, td);
460 notfound:
461 	lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
462 	return (error);
463 }
464 
465 
466 static int
467 devfs_pathconf(ap)
468 	struct vop_pathconf_args /* {
469 		struct vnode *a_vp;
470 		int a_name;
471 		int *a_retval;
472 	} */ *ap;
473 {
474 
475 	switch (ap->a_name) {
476 	case _PC_NAME_MAX:
477 		*ap->a_retval = NAME_MAX;
478 		return (0);
479 	case _PC_PATH_MAX:
480 		*ap->a_retval = PATH_MAX;
481 		return (0);
482 	default:
483 		return (vop_stdpathconf(ap));
484 	}
485 	/* NOTREACHED */
486 }
487 
488 /* ARGSUSED */
489 static int
490 devfs_print(ap)
491 	struct vop_print_args /* {
492 		struct vnode *a_vp;
493 	} */ *ap;
494 {
495 
496 	printf("tag VT_DEVFS, devfs vnode\n");
497 	return (0);
498 }
499 
500 static int
501 devfs_read(ap)
502 	struct vop_read_args /* {
503 		struct vnode *a_vp;
504 		struct uio *a_uio;
505 		int a_ioflag;
506 		struct ucred *a_cred;
507 	} */ *ap;
508 {
509 
510 	if (ap->a_vp->v_type != VDIR)
511 		return (EINVAL);
512 	return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL));
513 }
514 
515 static int
516 devfs_readdir(ap)
517 	struct vop_readdir_args /* {
518 		struct vnode *a_vp;
519 		struct uio *a_uio;
520 		struct ucred *a_cred;
521 		int *a_eofflag;
522 		int *a_ncookies;
523 		u_long **a_cookies;
524 	} */ *ap;
525 {
526 	int error;
527 	struct uio *uio;
528 	struct dirent *dp;
529 	struct devfs_dirent *dd;
530 	struct devfs_dirent *de;
531 	struct devfs_mount *dmp;
532 	off_t off, oldoff;
533 	int ncookies = 0;
534 	u_long *cookiebuf, *cookiep;
535 	struct dirent *dps, *dpe;
536 
537 	if (ap->a_vp->v_type != VDIR)
538 		return (ENOTDIR);
539 
540 	uio = ap->a_uio;
541 	if (uio->uio_offset < 0)
542 		return (EINVAL);
543 
544 	dmp = VFSTODEVFS(ap->a_vp->v_mount);
545 	lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread);
546 	devfs_populate(dmp);
547 	error = 0;
548 	de = ap->a_vp->v_data;
549 	off = 0;
550 	oldoff = uio->uio_offset;
551 	TAILQ_FOREACH(dd, &de->de_dlist, de_list) {
552 		if (dd->de_flags & DE_WHITEOUT)
553 			continue;
554 		if (dd->de_dirent->d_type == DT_DIR)
555 			de = dd->de_dir;
556 		else
557 			de = dd;
558 		dp = dd->de_dirent;
559 		if (dp->d_reclen > uio->uio_resid)
560 			break;
561 		dp->d_fileno = de->de_inode;
562 		if (off >= uio->uio_offset) {
563 			ncookies++;
564 			error = uiomove((caddr_t)dp, dp->d_reclen, uio);
565 			if (error)
566 				break;
567 		}
568 		off += dp->d_reclen;
569 	}
570 	if( !error && ap->a_ncookies != NULL && ap->a_cookies != NULL ) {
571 		MALLOC(cookiebuf, u_long *, ncookies * sizeof(u_long),
572                        M_TEMP, M_WAITOK);
573 		cookiep = cookiebuf;
574 		dps = (struct dirent *)
575 			(uio->uio_iov->iov_base - (uio->uio_offset - oldoff));
576 		dpe = (struct dirent *) uio->uio_iov->iov_base;
577 		for( dp = dps;
578 			dp < dpe;
579 			dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
580 				oldoff += dp->d_reclen;
581 				*cookiep++ = (u_long) oldoff;
582 		}
583 		*ap->a_ncookies = ncookies;
584 		*ap->a_cookies = cookiebuf;
585     }
586 	lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
587 	uio->uio_offset = off;
588 	return (error);
589 }
590 
591 static int
592 devfs_readlink(ap)
593 	struct vop_readlink_args /* {
594 		struct vnode *a_vp;
595 		struct uio *a_uio;
596 		struct ucred *a_cead;
597 	} */ *ap;
598 {
599 	int error;
600 	struct devfs_dirent *de;
601 
602 	de = ap->a_vp->v_data;
603 	error = uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio);
604 	return (error);
605 }
606 
607 static int
608 devfs_reclaim(ap)
609 	struct vop_reclaim_args /* {
610 		struct vnode *a_vp;
611 	} */ *ap;
612 {
613 	struct vnode *vp = ap->a_vp;
614 	struct devfs_dirent *de;
615 	int i;
616 
617 	de = vp->v_data;
618 	if (de != NULL)
619 		de->de_vnode = NULL;
620 	vp->v_data = NULL;
621 	if (vp->v_rdev != NODEV && vp->v_rdev != NULL) {
622 		i = vcount(vp);
623 		if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0 &&
624 		    (vp->v_rdev->si_flags & SI_NAMED))
625 			destroy_dev(vp->v_rdev);
626 	}
627 	return (0);
628 }
629 
630 static int
631 devfs_remove(ap)
632 	struct vop_remove_args /* {
633 		struct vnode *a_dvp;
634 		struct vnode *a_vp;
635 		struct componentname *a_cnp;
636 	} */ *ap;
637 {
638 	struct vnode *vp = ap->a_vp;
639 	struct devfs_dirent *dd;
640 	struct devfs_dirent *de;
641 	struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount);
642 
643 	lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
644 	dd = ap->a_dvp->v_data;
645 	de = vp->v_data;
646 	if (de->de_dirent->d_type == DT_LNK) {
647 		TAILQ_REMOVE(&dd->de_dlist, de, de_list);
648 		if (de->de_vnode)
649 			de->de_vnode->v_data = NULL;
650 		FREE(de, M_DEVFS);
651 	} else {
652 		de->de_flags |= DE_WHITEOUT;
653 	}
654 	lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
655 	return (0);
656 }
657 
658 /*
659  * Revoke is called on a tty when a terminal session ends.  The vnode
660  * is orphaned by setting v_op to deadfs so we need to let go of it
661  * as well so that we create a new one next time around.
662  */
663 static int
664 devfs_revoke(ap)
665 	struct vop_revoke_args /* {
666 		struct vnode *a_vp;
667 		int a_flags;
668 	} */ *ap;
669 {
670 	struct vnode *vp = ap->a_vp;
671 	struct devfs_dirent *de;
672 
673 	de = vp->v_data;
674 	de->de_vnode = NULL;
675 	vop_revoke(ap);
676 	return (0);
677 }
678 
679 static int
680 devfs_setattr(ap)
681 	struct vop_setattr_args /* {
682 		struct vnode *a_vp;
683 		struct vattr *a_vap;
684 		struct ucred *a_cred;
685 		struct proc *a_p;
686 	} */ *ap;
687 {
688 	struct devfs_dirent *de;
689 	struct vattr *vap;
690 	struct vnode *vp;
691 	int c, error;
692 	uid_t uid;
693 	gid_t gid;
694 
695 	vap = ap->a_vap;
696 	vp = ap->a_vp;
697 	if ((vap->va_type != VNON) ||
698 	    (vap->va_nlink != VNOVAL) ||
699 	    (vap->va_fsid != VNOVAL) ||
700 	    (vap->va_fileid != VNOVAL) ||
701 	    (vap->va_blocksize != VNOVAL) ||
702 	    (vap->va_flags != VNOVAL && vap->va_flags != 0) ||
703 	    (vap->va_rdev != VNOVAL) ||
704 	    ((int)vap->va_bytes != VNOVAL) ||
705 	    (vap->va_gen != VNOVAL)) {
706 		return (EINVAL);
707 	}
708 
709 	de = vp->v_data;
710 	if (vp->v_type == VDIR)
711 		de = de->de_dir;
712 
713 	error = c = 0;
714 	if (vap->va_uid == (uid_t)VNOVAL)
715 		uid = de->de_uid;
716 	else
717 		uid = vap->va_uid;
718 	if (vap->va_gid == (gid_t)VNOVAL)
719 		gid = de->de_gid;
720 	else
721 		gid = vap->va_gid;
722 	if (uid != de->de_uid || gid != de->de_gid) {
723 		if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid ||
724 		    (gid != de->de_gid && !groupmember(gid, ap->a_cred))) &&
725 		    (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT)) != 0)
726 			return (error);
727 		de->de_uid = uid;
728 		de->de_gid = gid;
729 		c = 1;
730 	}
731 
732 	if (vap->va_mode != (mode_t)VNOVAL) {
733 		if ((ap->a_cred->cr_uid != de->de_uid) &&
734 		    (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT)))
735 			return (error);
736 		de->de_mode = vap->va_mode;
737 		c = 1;
738 	}
739 
740 	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
741 		/* See the comment in ufs_vnops::ufs_setattr(). */
742 		if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, ap->a_td)) &&
743 		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
744 		    (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td))))
745 			return (error);
746 		if (vap->va_atime.tv_sec != VNOVAL) {
747 			if (vp->v_type == VCHR)
748 				vp->v_rdev->si_atime = vap->va_atime;
749 			else
750 				de->de_atime = vap->va_atime;
751 		}
752 		if (vap->va_mtime.tv_sec != VNOVAL) {
753 			if (vp->v_type == VCHR)
754 				vp->v_rdev->si_mtime = vap->va_mtime;
755 			else
756 				de->de_mtime = vap->va_mtime;
757 		}
758 		c = 1;
759 	}
760 
761 	if (c) {
762 		if (vp->v_type == VCHR)
763 			vfs_timestamp(&vp->v_rdev->si_ctime);
764 		else
765 			vfs_timestamp(&de->de_mtime);
766 	}
767 	return (0);
768 }
769 
770 static int
771 devfs_symlink(ap)
772 	struct vop_symlink_args /* {
773 		struct vnode *a_dvp;
774 		struct vnode **a_vpp;
775 		struct componentname *a_cnp;
776 		struct vattr *a_vap;
777 		char *a_target;
778 	} */ *ap;
779 {
780 	int i, error;
781 	struct devfs_dirent *dd;
782 	struct devfs_dirent *de;
783 	struct devfs_mount *dmp;
784 
785 	error = suser(ap->a_cnp->cn_thread);
786 	if (error)
787 		return(error);
788 	dmp = VFSTODEVFS(ap->a_dvp->v_mount);
789 	dd = ap->a_dvp->v_data;
790 	de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen);
791 	de->de_uid = 0;
792 	de->de_gid = 0;
793 	de->de_mode = 0755;
794 	de->de_inode = dmp->dm_inode++;
795 	de->de_dirent->d_type = DT_LNK;
796 	i = strlen(ap->a_target) + 1;
797 	MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK);
798 	bcopy(ap->a_target, de->de_symlink, i);
799 	lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
800 	TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
801 	devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0);
802 	lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
803 	return (0);
804 }
805 
806 static vop_t **devfs_vnodeop_p;
807 static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
808 	{ &vop_default_desc,		(vop_t *) vop_defaultop },
809 	{ &vop_access_desc,		(vop_t *) devfs_access },
810 	{ &vop_getattr_desc,		(vop_t *) devfs_getattr },
811 	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
812 	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
813 	{ &vop_lookup_desc,		(vop_t *) devfs_lookup },
814 	{ &vop_mknod_desc,		(vop_t *) devfs_mknod },
815 	{ &vop_pathconf_desc,		(vop_t *) devfs_pathconf },
816 	{ &vop_print_desc,		(vop_t *) devfs_print },
817 	{ &vop_read_desc,		(vop_t *) devfs_read },
818 	{ &vop_readdir_desc,		(vop_t *) devfs_readdir },
819 	{ &vop_readlink_desc,		(vop_t *) devfs_readlink },
820 	{ &vop_reclaim_desc,		(vop_t *) devfs_reclaim },
821 	{ &vop_remove_desc,		(vop_t *) devfs_remove },
822 	{ &vop_revoke_desc,		(vop_t *) devfs_revoke },
823 	{ &vop_setattr_desc,		(vop_t *) devfs_setattr },
824 	{ &vop_symlink_desc,		(vop_t *) devfs_symlink },
825 	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
826 	{ NULL, NULL }
827 };
828 static struct vnodeopv_desc devfs_vnodeop_opv_desc =
829 	{ &devfs_vnodeop_p, devfs_vnodeop_entries };
830 
831 VNODEOP_SET(devfs_vnodeop_opv_desc);
832 
833 static vop_t **devfs_specop_p;
834 static struct vnodeopv_entry_desc devfs_specop_entries[] = {
835 	{ &vop_default_desc,		(vop_t *) spec_vnoperate },
836 	{ &vop_access_desc,		(vop_t *) devfs_access },
837 	{ &vop_getattr_desc,		(vop_t *) devfs_getattr },
838 	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
839 	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
840 	{ &vop_print_desc,		(vop_t *) devfs_print },
841 	{ &vop_reclaim_desc,		(vop_t *) devfs_reclaim },
842 	{ &vop_remove_desc,		(vop_t *) devfs_remove },
843 	{ &vop_revoke_desc,		(vop_t *) devfs_revoke },
844 	{ &vop_setattr_desc,		(vop_t *) devfs_setattr },
845 	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
846 	{ NULL, NULL }
847 };
848 static struct vnodeopv_desc devfs_specop_opv_desc =
849 	{ &devfs_specop_p, devfs_specop_entries };
850 
851 VNODEOP_SET(devfs_specop_opv_desc);
852 #endif
853