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