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