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