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