]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/devfs/devfs_vnops.c
Slightly change the semantics of vnode labels for MAC: rather than
[FreeBSD/FreeBSD.git] / sys / fs / devfs / devfs_vnops.c
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