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