xref: /freebsd/sys/fs/devfs/devfs_vnops.c (revision d37ea99837e6ad50837fd9fe1771ddf1c3ba6002)
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 #include <opt_mac.h>
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/mac.h>
54 #include <sys/malloc.h>
55 #include <sys/mount.h>
56 #include <sys/namei.h>
57 #include <sys/proc.h>
58 #include <sys/time.h>
59 #include <sys/unistd.h>
60 #include <sys/vnode.h>
61 
62 #include <fs/devfs/devfs.h>
63 
64 static int	devfs_access(struct vop_access_args *ap);
65 static int	devfs_getattr(struct vop_getattr_args *ap);
66 static int	devfs_ioctl(struct vop_ioctl_args *ap);
67 static int	devfs_lookupx(struct vop_lookup_args *ap);
68 static int	devfs_mknod(struct vop_mknod_args *ap);
69 static int	devfs_pathconf(struct vop_pathconf_args *ap);
70 static int	devfs_read(struct vop_read_args *ap);
71 static int	devfs_readdir(struct vop_readdir_args *ap);
72 static int	devfs_readlink(struct vop_readlink_args *ap);
73 static int	devfs_reclaim(struct vop_reclaim_args *ap);
74 static int	devfs_remove(struct vop_remove_args *ap);
75 static int	devfs_revoke(struct vop_revoke_args *ap);
76 static int	devfs_setattr(struct vop_setattr_args *ap);
77 #ifdef MAC
78 static int	devfs_setlabel(struct vop_setlabel_args *ap);
79 #endif
80 static int	devfs_symlink(struct vop_symlink_args *ap);
81 
82 static vop_t **devfs_vnodeop_p;
83 static vop_t **devfs_specop_p;
84 
85 /*
86  * Construct the fully qualified path name relative to the mountpoint
87  */
88 static char *
89 devfs_fqpn(char *buf, struct vnode *dvp, struct componentname *cnp)
90 {
91 	int i;
92 	struct devfs_dirent *de, *dd;
93 	struct devfs_mount *dmp;
94 
95 	dmp = VFSTODEVFS(dvp->v_mount);
96 	dd = dvp->v_data;
97 	i = SPECNAMELEN;
98 	buf[i] = '\0';
99 	i -= cnp->cn_namelen;
100 	if (i < 0)
101 		 return (NULL);
102 	bcopy(cnp->cn_nameptr, buf + i, cnp->cn_namelen);
103 	de = dd;
104 	while (de != dmp->dm_basedir) {
105 		i--;
106 		if (i < 0)
107 			 return (NULL);
108 		buf[i] = '/';
109 		i -= de->de_dirent->d_namlen;
110 		if (i < 0)
111 			 return (NULL);
112 		bcopy(de->de_dirent->d_name, buf + i,
113 		    de->de_dirent->d_namlen);
114 		de = TAILQ_FIRST(&de->de_dlist);	/* "." */
115 		de = TAILQ_NEXT(de, de_list);		/* ".." */
116 		de = de->de_dir;
117 	}
118 	return (buf + i);
119 }
120 
121 int
122 devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td)
123 {
124 	int error;
125 	struct vnode *vp;
126 	struct cdev *dev;
127 
128 	if (td == NULL)
129 		td = curthread; /* XXX */
130 loop:
131 	vp = de->de_vnode;
132 	if (vp != NULL) {
133 		if (vget(vp, LK_EXCLUSIVE, td ? td : curthread))
134 			goto loop;
135 		*vpp = vp;
136 		return (0);
137 	}
138 	if (de->de_dirent->d_type == DT_CHR) {
139 		dev = *devfs_itod(de->de_inode);
140 		if (dev == NULL)
141 			return (ENOENT);
142 	} else {
143 		dev = NULL;
144 	}
145 	error = getnewvnode("devfs", mp, devfs_vnodeop_p, &vp);
146 	if (error != 0) {
147 		printf("devfs_allocv: failed to allocate new vnode\n");
148 		return (error);
149 	}
150 
151 	if (de->de_dirent->d_type == DT_CHR) {
152 		vp->v_type = VCHR;
153 		vp = addaliasu(vp, dev->si_udev);
154 		vp->v_op = devfs_specop_p;
155 	} else if (de->de_dirent->d_type == DT_DIR) {
156 		vp->v_type = VDIR;
157 	} else if (de->de_dirent->d_type == DT_LNK) {
158 		vp->v_type = VLNK;
159 	} else {
160 		vp->v_type = VBAD;
161 	}
162 	vp->v_data = de;
163 	de->de_vnode = vp;
164 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
165 #ifdef MAC
166 	mac_associate_vnode_devfs(mp, de, vp);
167 #endif
168 	*vpp = vp;
169 	return (0);
170 }
171 
172 static int
173 devfs_access(ap)
174 	struct vop_access_args /* {
175 		struct vnode *a_vp;
176 		int  a_mode;
177 		struct ucred *a_cred;
178 		struct thread *a_td;
179 	} */ *ap;
180 {
181 	struct vnode *vp = ap->a_vp;
182 	struct devfs_dirent *de;
183 	int error;
184 
185 	de = vp->v_data;
186 	if (vp->v_type == VDIR)
187 		de = de->de_dir;
188 
189 	error = vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid,
190 	    ap->a_mode, ap->a_cred, NULL);
191 	if (!error)
192 		return (error);
193 	if (error != EACCES)
194 		return (error);
195 	/* We do, however, allow access to the controlling terminal */
196 	if (!(ap->a_td->td_proc->p_flag & P_CONTROLT))
197 		return (error);
198 	if (ap->a_td->td_proc->p_session->s_ttyvp == de->de_vnode)
199 		return (0);
200 	return (error);
201 }
202 
203 static int
204 devfs_getattr(ap)
205 	struct vop_getattr_args /* {
206 		struct vnode *a_vp;
207 		struct vattr *a_vap;
208 		struct ucred *a_cred;
209 		struct thread *a_td;
210 	} */ *ap;
211 {
212 	struct vnode *vp = ap->a_vp;
213 	struct vattr *vap = ap->a_vap;
214 	int error = 0;
215 	struct devfs_dirent *de;
216 	struct cdev *dev;
217 
218 	de = vp->v_data;
219 	if (vp->v_type == VDIR)
220 		de = de->de_dir;
221 	bzero((caddr_t) vap, sizeof(*vap));
222 	vattr_null(vap);
223 	vap->va_uid = de->de_uid;
224 	vap->va_gid = de->de_gid;
225 	vap->va_mode = de->de_mode;
226 	if (vp->v_type == VLNK)
227 		vap->va_size = strlen(de->de_symlink);
228 	else if (vp->v_type == VDIR)
229 		vap->va_size = vap->va_bytes = DEV_BSIZE;
230 	else
231 		vap->va_size = 0;
232 	if (vp->v_type != VDIR)
233 		vap->va_bytes = 0;
234 	vap->va_blocksize = DEV_BSIZE;
235 	vap->va_type = vp->v_type;
236 
237 #define fix(aa)							\
238 	do {							\
239 		if ((aa).tv_sec == 0) {				\
240 			(aa).tv_sec = boottime.tv_sec;		\
241 			(aa).tv_nsec = boottime.tv_usec * 1000; \
242 		}						\
243 	} while (0)
244 
245 	if (vp->v_type != VCHR)  {
246 		fix(de->de_atime);
247 		vap->va_atime = de->de_atime;
248 		fix(de->de_mtime);
249 		vap->va_mtime = de->de_mtime;
250 		fix(de->de_ctime);
251 		vap->va_ctime = de->de_ctime;
252 	} else {
253 		dev = vp->v_rdev;
254 		fix(dev->si_atime);
255 		vap->va_atime = dev->si_atime;
256 		fix(dev->si_mtime);
257 		vap->va_mtime = dev->si_mtime;
258 		fix(dev->si_ctime);
259 		vap->va_ctime = dev->si_ctime;
260 		vap->va_rdev = dev->si_udev;
261 	}
262 	vap->va_gen = 0;
263 	vap->va_flags = 0;
264 	vap->va_nlink = de->de_links;
265 	vap->va_fileid = de->de_inode;
266 
267 	return (error);
268 }
269 
270 static int
271 devfs_ioctl(ap)
272 	struct vop_ioctl_args /* {
273 		struct vnode *a_vp;
274 		u_long  a_command;
275 		caddr_t  a_data;
276 		int  a_fflag;
277 		struct ucred *a_cred;
278 		struct thread *a_td;
279 	} */ *ap;
280 {
281 	int error;
282 	struct devfs_mount *dmp;
283 
284 	dmp = VFSTODEVFS(ap->a_vp->v_mount);
285 	lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread);
286 	devfs_populate(dmp);
287 	lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
288 	error = devfs_rules_ioctl(ap->a_vp->v_mount, ap->a_command, ap->a_data,
289 	    ap->a_td);
290 	return (error);
291 }
292 
293 static int
294 devfs_lookupx(ap)
295 	struct vop_lookup_args /* {
296 		struct vnode * a_dvp;
297 		struct vnode ** a_vpp;
298 		struct componentname * a_cnp;
299 	} */ *ap;
300 {
301 	struct componentname *cnp;
302 	struct vnode *dvp, **vpp;
303 	struct thread *td;
304 	struct devfs_dirent *de, *dd;
305 	struct devfs_dirent **dde;
306 	struct devfs_mount *dmp;
307 	struct cdev *cdev;
308 	int error, flags, nameiop;
309 	char specname[SPECNAMELEN + 1], *pname;
310 
311 	cnp = ap->a_cnp;
312 	vpp = ap->a_vpp;
313 	dvp = ap->a_dvp;
314 	pname = cnp->cn_nameptr;
315 	td = cnp->cn_thread;
316 	flags = cnp->cn_flags;
317 	nameiop = cnp->cn_nameiop;
318 	dmp = VFSTODEVFS(dvp->v_mount);
319 	dd = dvp->v_data;
320 
321 	*vpp = NULLVP;
322 	cnp->cn_flags &= ~PDIRUNLOCK;
323 
324 	if ((flags & ISLASTCN) && nameiop == RENAME)
325 		return (EOPNOTSUPP);
326 
327 	if (dvp->v_type != VDIR)
328 		return (ENOTDIR);
329 
330 	if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT))
331 		return (EIO);
332 
333 	error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td);
334 	if (error)
335 		return (error);
336 
337 	if (cnp->cn_namelen == 1 && *pname == '.') {
338 		if ((flags & ISLASTCN) && nameiop != LOOKUP)
339 			return (EINVAL);
340 		*vpp = dvp;
341 		VREF(dvp);
342 		return (0);
343 	}
344 
345 	if (flags & ISDOTDOT) {
346 		if ((flags & ISLASTCN) && nameiop != LOOKUP)
347 			return (EINVAL);
348 		VOP_UNLOCK(dvp, 0, td);
349 		cnp->cn_flags |= PDIRUNLOCK;
350 		de = TAILQ_FIRST(&dd->de_dlist);	/* "." */
351 		de = TAILQ_NEXT(de, de_list);		/* ".." */
352 		de = de->de_dir;
353 		error = devfs_allocv(de, dvp->v_mount, vpp, td);
354 		if (error || ((flags & LOCKPARENT) && (flags & ISLASTCN))) {
355 			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
356 			cnp->cn_flags &= ~PDIRUNLOCK;
357 		}
358 		return (error);
359 	}
360 
361 	devfs_populate(dmp);
362 	dd = dvp->v_data;
363 	TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
364 		if (cnp->cn_namelen != de->de_dirent->d_namlen)
365 			continue;
366 		if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
367 		    de->de_dirent->d_namlen) != 0)
368 			continue;
369 		if (de->de_flags & DE_WHITEOUT)
370 			goto notfound;
371 		goto found;
372 	}
373 
374 	if (nameiop == DELETE)
375 		goto notfound;
376 
377 	/*
378 	 * OK, we didn't have an entry for the name we were asked for
379 	 * so we try to see if anybody can create it on demand.
380 	 */
381 	pname = devfs_fqpn(specname, dvp, cnp);
382 	if (pname == NULL)
383 		goto notfound;
384 
385 	cdev = NULL;
386 	EVENTHANDLER_INVOKE(dev_clone, pname, strlen(pname), &cdev);
387 	if (cdev == NULL)
388 		goto notfound;
389 
390 	devfs_populate(dmp);
391 
392 	dde = devfs_itode(dmp, cdev->si_inode);
393 
394 	if (dde == NULL || *dde == NULL || *dde == DE_DELETED)
395 		goto notfound;
396 
397 	if ((*dde)->de_flags & DE_WHITEOUT)
398 		goto notfound;
399 
400 	de = *dde;
401 	goto found;
402 
403 notfound:
404 
405 	if ((nameiop == CREATE || nameiop == RENAME) &&
406 	    (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) {
407 		cnp->cn_flags |= SAVENAME;
408 		if (!(flags & LOCKPARENT)) {
409 			VOP_UNLOCK(dvp, 0, td);
410 			cnp->cn_flags |= PDIRUNLOCK;
411 		}
412 		return (EJUSTRETURN);
413 	}
414 	return (ENOENT);
415 
416 
417 found:
418 
419 	if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) {
420 		error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td);
421 		if (error)
422 			return (error);
423 		if (*vpp == dvp) {
424 			VREF(dvp);
425 			*vpp = dvp;
426 			return (0);
427 		}
428 		error = devfs_allocv(de, dvp->v_mount, vpp, td);
429 		if (error)
430 			return (error);
431 		if (!(flags & LOCKPARENT)) {
432 			VOP_UNLOCK(dvp, 0, td);
433 			cnp->cn_flags |= PDIRUNLOCK;
434 		}
435 		return (0);
436 	}
437 	error = devfs_allocv(de, dvp->v_mount, vpp, td);
438 	if (error)
439 		return (error);
440 	if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) {
441 		VOP_UNLOCK(dvp, 0, td);
442 		cnp->cn_flags |= PDIRUNLOCK;
443 	}
444 	return (0);
445 }
446 
447 static int
448 devfs_lookup(struct vop_lookup_args *ap)
449 {
450 	int j;
451 	struct devfs_mount *dmp;
452 
453 	dmp = VFSTODEVFS(ap->a_dvp->v_mount);
454 	lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread);
455 	j = devfs_lookupx(ap);
456 	lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
457 	return (j);
458 }
459 
460 static int
461 devfs_mknod(struct vop_mknod_args *ap)
462 /*
463 struct vop_mknod_args {
464 	struct vnodeop_desc *a_desc;
465 	struct vnode *a_dvp;
466 	struct vnode **a_vpp;
467 	struct componentname *a_cnp;
468 	struct vattr *a_vap;
469 };
470 */
471 {
472 	struct componentname *cnp;
473 	struct vnode *dvp, **vpp;
474 	struct thread *td;
475 	struct devfs_dirent *dd, *de;
476 	struct devfs_mount *dmp;
477 	int error;
478 
479 	dvp = ap->a_dvp;
480 	dmp = VFSTODEVFS(dvp->v_mount);
481 	lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
482 
483 	cnp = ap->a_cnp;
484 	vpp = ap->a_vpp;
485 	td = cnp->cn_thread;
486 	dd = dvp->v_data;
487 
488 	error = ENOENT;
489 	TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
490 		if (cnp->cn_namelen != de->de_dirent->d_namlen)
491 			continue;
492 		if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
493 		    de->de_dirent->d_namlen) != 0)
494 			continue;
495 		if (de->de_flags & DE_WHITEOUT)
496 			break;
497 		goto notfound;
498 	}
499 	if (de == NULL)
500 		goto notfound;
501 	de->de_flags &= ~DE_WHITEOUT;
502 	error = devfs_allocv(de, dvp->v_mount, vpp, td);
503 notfound:
504 	lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
505 	return (error);
506 }
507 
508 
509 static int
510 devfs_pathconf(ap)
511 	struct vop_pathconf_args /* {
512 		struct vnode *a_vp;
513 		int a_name;
514 		int *a_retval;
515 	} */ *ap;
516 {
517 
518 	switch (ap->a_name) {
519 	case _PC_NAME_MAX:
520 		*ap->a_retval = NAME_MAX;
521 		return (0);
522 	case _PC_PATH_MAX:
523 		*ap->a_retval = PATH_MAX;
524 		return (0);
525 	case _PC_MAC_PRESENT:
526 #ifdef MAC
527 		/*
528 		 * If MAC is enabled, devfs automatically supports
529 		 * trivial non-persistant label storage.
530 		 */
531 		*ap->a_retval = 1;
532 #else
533 		*ap->a_retval = 0;
534 #endif
535 		return (0);
536 	default:
537 		return (vop_stdpathconf(ap));
538 	}
539 	/* NOTREACHED */
540 }
541 
542 static int
543 devfs_read(ap)
544 	struct vop_read_args /* {
545 		struct vnode *a_vp;
546 		struct uio *a_uio;
547 		int a_ioflag;
548 		struct ucred *a_cred;
549 	} */ *ap;
550 {
551 
552 	if (ap->a_vp->v_type != VDIR)
553 		return (EINVAL);
554 	return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL));
555 }
556 
557 static int
558 devfs_readdir(ap)
559 	struct vop_readdir_args /* {
560 		struct vnode *a_vp;
561 		struct uio *a_uio;
562 		struct ucred *a_cred;
563 		int *a_eofflag;
564 		int *a_ncookies;
565 		u_long **a_cookies;
566 	} */ *ap;
567 {
568 	int error;
569 	struct uio *uio;
570 	struct dirent *dp;
571 	struct devfs_dirent *dd;
572 	struct devfs_dirent *de;
573 	struct devfs_mount *dmp;
574 	off_t off, oldoff;
575 	int ncookies = 0;
576 	u_long *cookiebuf, *cookiep;
577 	struct dirent *dps, *dpe;
578 
579 	if (ap->a_vp->v_type != VDIR)
580 		return (ENOTDIR);
581 
582 	uio = ap->a_uio;
583 	if (uio->uio_offset < 0)
584 		return (EINVAL);
585 
586 	dmp = VFSTODEVFS(ap->a_vp->v_mount);
587 	lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread);
588 	devfs_populate(dmp);
589 	error = 0;
590 	de = ap->a_vp->v_data;
591 	off = 0;
592 	oldoff = uio->uio_offset;
593 	TAILQ_FOREACH(dd, &de->de_dlist, de_list) {
594 		if (dd->de_flags & DE_WHITEOUT)
595 			continue;
596 		if (dd->de_dirent->d_type == DT_DIR)
597 			de = dd->de_dir;
598 		else
599 			de = dd;
600 		dp = dd->de_dirent;
601 		if (dp->d_reclen > uio->uio_resid)
602 			break;
603 		dp->d_fileno = de->de_inode;
604 		if (off >= uio->uio_offset) {
605 			ncookies++;
606 			error = uiomove(dp, dp->d_reclen, uio);
607 			if (error)
608 				break;
609 		}
610 		off += dp->d_reclen;
611 	}
612 	if( !error && ap->a_ncookies != NULL && ap->a_cookies != NULL ) {
613 		MALLOC(cookiebuf, u_long *, ncookies * sizeof(u_long),
614 		       M_TEMP, M_WAITOK);
615 		cookiep = cookiebuf;
616 		dps = (struct dirent *)((char *)uio->uio_iov->iov_base -
617 		    (uio->uio_offset - oldoff));
618 		dpe = (struct dirent *) uio->uio_iov->iov_base;
619 		for( dp = dps;
620 			dp < dpe;
621 			dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
622 				oldoff += dp->d_reclen;
623 				*cookiep++ = (u_long) oldoff;
624 		}
625 		*ap->a_ncookies = ncookies;
626 		*ap->a_cookies = cookiebuf;
627 	}
628 	lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
629 	uio->uio_offset = off;
630 	return (error);
631 }
632 
633 static int
634 devfs_readlink(ap)
635 	struct vop_readlink_args /* {
636 		struct vnode *a_vp;
637 		struct uio *a_uio;
638 		struct ucred *a_cead;
639 	} */ *ap;
640 {
641 	int error;
642 	struct devfs_dirent *de;
643 
644 	de = ap->a_vp->v_data;
645 	error = uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio);
646 	return (error);
647 }
648 
649 static int
650 devfs_reclaim(ap)
651 	struct vop_reclaim_args /* {
652 		struct vnode *a_vp;
653 	} */ *ap;
654 {
655 	struct vnode *vp = ap->a_vp;
656 	struct devfs_dirent *de;
657 	int i;
658 
659 	de = vp->v_data;
660 	if (de != NULL)
661 		de->de_vnode = NULL;
662 	vp->v_data = NULL;
663 	if (vp->v_rdev != NULL && vp->v_rdev != NULL) {
664 		i = vcount(vp);
665 		if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0 &&
666 		    (vp->v_rdev->si_flags & SI_NAMED))
667 			destroy_dev(vp->v_rdev);
668 	}
669 	return (0);
670 }
671 
672 static int
673 devfs_remove(ap)
674 	struct vop_remove_args /* {
675 		struct vnode *a_dvp;
676 		struct vnode *a_vp;
677 		struct componentname *a_cnp;
678 	} */ *ap;
679 {
680 	struct vnode *vp = ap->a_vp;
681 	struct devfs_dirent *dd;
682 	struct devfs_dirent *de;
683 	struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount);
684 
685 	lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
686 	dd = ap->a_dvp->v_data;
687 	de = vp->v_data;
688 	if (de->de_dirent->d_type == DT_LNK) {
689 		TAILQ_REMOVE(&dd->de_dlist, de, de_list);
690 		if (de->de_vnode)
691 			de->de_vnode->v_data = NULL;
692 #ifdef MAC
693 		mac_destroy_devfsdirent(de);
694 #endif
695 		FREE(de, M_DEVFS);
696 	} else {
697 		de->de_flags |= DE_WHITEOUT;
698 	}
699 	lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
700 	return (0);
701 }
702 
703 /*
704  * Revoke is called on a tty when a terminal session ends.  The vnode
705  * is orphaned by setting v_op to deadfs so we need to let go of it
706  * as well so that we create a new one next time around.
707  */
708 static int
709 devfs_revoke(ap)
710 	struct vop_revoke_args /* {
711 		struct vnode *a_vp;
712 		int a_flags;
713 	} */ *ap;
714 {
715 	struct vnode *vp = ap->a_vp;
716 	struct devfs_dirent *de;
717 
718 	de = vp->v_data;
719 	de->de_vnode = NULL;
720 	vop_revoke(ap);
721 	return (0);
722 }
723 
724 static int
725 devfs_setattr(ap)
726 	struct vop_setattr_args /* {
727 		struct vnode *a_vp;
728 		struct vattr *a_vap;
729 		struct ucred *a_cred;
730 		struct proc *a_p;
731 	} */ *ap;
732 {
733 	struct devfs_dirent *de;
734 	struct vattr *vap;
735 	struct vnode *vp;
736 	int c, error;
737 	uid_t uid;
738 	gid_t gid;
739 
740 	vap = ap->a_vap;
741 	vp = ap->a_vp;
742 	if ((vap->va_type != VNON) ||
743 	    (vap->va_nlink != VNOVAL) ||
744 	    (vap->va_fsid != VNOVAL) ||
745 	    (vap->va_fileid != VNOVAL) ||
746 	    (vap->va_blocksize != VNOVAL) ||
747 	    (vap->va_flags != VNOVAL && vap->va_flags != 0) ||
748 	    (vap->va_rdev != VNOVAL) ||
749 	    ((int)vap->va_bytes != VNOVAL) ||
750 	    (vap->va_gen != VNOVAL)) {
751 		return (EINVAL);
752 	}
753 
754 	de = vp->v_data;
755 	if (vp->v_type == VDIR)
756 		de = de->de_dir;
757 
758 	error = c = 0;
759 	if (vap->va_uid == (uid_t)VNOVAL)
760 		uid = de->de_uid;
761 	else
762 		uid = vap->va_uid;
763 	if (vap->va_gid == (gid_t)VNOVAL)
764 		gid = de->de_gid;
765 	else
766 		gid = vap->va_gid;
767 	if (uid != de->de_uid || gid != de->de_gid) {
768 		if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid ||
769 		    (gid != de->de_gid && !groupmember(gid, ap->a_cred))) &&
770 		    (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT)) != 0)
771 			return (error);
772 		de->de_uid = uid;
773 		de->de_gid = gid;
774 		c = 1;
775 	}
776 
777 	if (vap->va_mode != (mode_t)VNOVAL) {
778 		if ((ap->a_cred->cr_uid != de->de_uid) &&
779 		    (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT)))
780 			return (error);
781 		de->de_mode = vap->va_mode;
782 		c = 1;
783 	}
784 
785 	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
786 		/* See the comment in ufs_vnops::ufs_setattr(). */
787 		if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, ap->a_td)) &&
788 		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
789 		    (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td))))
790 			return (error);
791 		if (vap->va_atime.tv_sec != VNOVAL) {
792 			if (vp->v_type == VCHR)
793 				vp->v_rdev->si_atime = vap->va_atime;
794 			else
795 				de->de_atime = vap->va_atime;
796 		}
797 		if (vap->va_mtime.tv_sec != VNOVAL) {
798 			if (vp->v_type == VCHR)
799 				vp->v_rdev->si_mtime = vap->va_mtime;
800 			else
801 				de->de_mtime = vap->va_mtime;
802 		}
803 		c = 1;
804 	}
805 
806 	if (c) {
807 		if (vp->v_type == VCHR)
808 			vfs_timestamp(&vp->v_rdev->si_ctime);
809 		else
810 			vfs_timestamp(&de->de_mtime);
811 	}
812 	return (0);
813 }
814 
815 #ifdef MAC
816 static int
817 devfs_setlabel(ap)
818 	struct vop_setlabel_args /* {
819 		struct vnode *a_vp;
820 		struct mac *a_label;
821 		struct ucred *a_cred;
822 		struct thread *a_td;
823 	} */ *ap;
824 {
825 	struct vnode *vp;
826 	struct devfs_dirent *de;
827 
828 	vp = ap->a_vp;
829 	de = vp->v_data;
830 
831 	mac_relabel_vnode(ap->a_cred, vp, ap->a_label);
832 	mac_update_devfsdirent(vp->v_mount, de, vp);
833 
834 	return (0);
835 }
836 #endif
837 
838 static int
839 devfs_symlink(ap)
840 	struct vop_symlink_args /* {
841 		struct vnode *a_dvp;
842 		struct vnode **a_vpp;
843 		struct componentname *a_cnp;
844 		struct vattr *a_vap;
845 		char *a_target;
846 	} */ *ap;
847 {
848 	int i, error;
849 	struct devfs_dirent *dd;
850 	struct devfs_dirent *de;
851 	struct devfs_mount *dmp;
852 
853 	error = suser(ap->a_cnp->cn_thread);
854 	if (error)
855 		return(error);
856 	dmp = VFSTODEVFS(ap->a_dvp->v_mount);
857 	dd = ap->a_dvp->v_data;
858 	de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen);
859 	de->de_uid = 0;
860 	de->de_gid = 0;
861 	de->de_mode = 0755;
862 	de->de_inode = dmp->dm_inode++;
863 	de->de_dirent->d_type = DT_LNK;
864 	i = strlen(ap->a_target) + 1;
865 	MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK);
866 	bcopy(ap->a_target, de->de_symlink, i);
867 	lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
868 #ifdef MAC
869 	mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de);
870 #endif
871 	TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
872 	devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0);
873 	lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
874 	return (0);
875 }
876 
877 static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
878 	{ &vop_default_desc,		(vop_t *) vop_defaultop },
879 	{ &vop_access_desc,		(vop_t *) devfs_access },
880 	{ &vop_getattr_desc,		(vop_t *) devfs_getattr },
881 	{ &vop_ioctl_desc,		(vop_t *) devfs_ioctl },
882 	{ &vop_lookup_desc,		(vop_t *) devfs_lookup },
883 	{ &vop_mknod_desc,		(vop_t *) devfs_mknod },
884 	{ &vop_pathconf_desc,		(vop_t *) devfs_pathconf },
885 	{ &vop_read_desc,		(vop_t *) devfs_read },
886 	{ &vop_readdir_desc,		(vop_t *) devfs_readdir },
887 	{ &vop_readlink_desc,		(vop_t *) devfs_readlink },
888 	{ &vop_reclaim_desc,		(vop_t *) devfs_reclaim },
889 	{ &vop_remove_desc,		(vop_t *) devfs_remove },
890 	{ &vop_revoke_desc,		(vop_t *) devfs_revoke },
891 	{ &vop_setattr_desc,		(vop_t *) devfs_setattr },
892 #ifdef MAC
893 	{ &vop_setlabel_desc,		(vop_t *) devfs_setlabel },
894 #endif
895 	{ &vop_symlink_desc,		(vop_t *) devfs_symlink },
896 	{ NULL, NULL }
897 };
898 static struct vnodeopv_desc devfs_vnodeop_opv_desc =
899 	{ &devfs_vnodeop_p, devfs_vnodeop_entries };
900 
901 VNODEOP_SET(devfs_vnodeop_opv_desc);
902 
903 static struct vnodeopv_entry_desc devfs_specop_entries[] = {
904 	{ &vop_default_desc,		(vop_t *) spec_vnoperate },
905 	{ &vop_access_desc,		(vop_t *) devfs_access },
906 	{ &vop_getattr_desc,		(vop_t *) devfs_getattr },
907 	{ &vop_pathconf_desc,		(vop_t *) devfs_pathconf },
908 	{ &vop_reclaim_desc,		(vop_t *) devfs_reclaim },
909 	{ &vop_remove_desc,		(vop_t *) devfs_remove },
910 	{ &vop_revoke_desc,		(vop_t *) devfs_revoke },
911 	{ &vop_setattr_desc,		(vop_t *) devfs_setattr },
912 #ifdef MAC
913 	{ &vop_setlabel_desc,		(vop_t *) devfs_setlabel },
914 #endif
915 	{ NULL, NULL }
916 };
917 static struct vnodeopv_desc devfs_specop_opv_desc =
918 	{ &devfs_specop_p, devfs_specop_entries };
919 
920 VNODEOP_SET(devfs_specop_opv_desc);
921