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