Deleted Added
full compact
devfs_vnops.c (76320) devfs_vnops.c (76554)
1#define DEBUG 1
2/*
3 * Copyright (c) 1992, 1993
4 * The Regents of the University of California. All rights reserved.
5 * Copyright (c) 2000
6 * Poul-Henning Kamp. All rights reserved.
7 *
8 * This code is derived from software donated to Berkeley by
9 * Jan-Simon Pendry.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95
33 * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43
34 *
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 *
35 * $FreeBSD: head/sys/fs/devfs/devfs_vnops.c 76320 2001-05-06 17:40:34Z phk $
34 * $FreeBSD: head/sys/fs/devfs/devfs_vnops.c 76554 2001-05-13 20:52:40Z phk $
36 */
37
35 */
36
37#include <opt_devfs.h>
38#ifndef NODEVFS
39
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/conf.h>
41#include <sys/dirent.h>
42#include <sys/kernel.h>
43#include <sys/lock.h>
44#include <sys/malloc.h>
45#include <sys/mount.h>
46#include <sys/namei.h>
47#include <sys/proc.h>
48#include <sys/socket.h>
49#include <sys/time.h>
50#include <sys/vnode.h>
51
52#include <fs/devfs/devfs.h>
53
54static int devfs_access __P((struct vop_access_args *ap));
55static int devfs_getattr __P((struct vop_getattr_args *ap));
56static int devfs_lookupx __P((struct vop_lookup_args *ap));
57static int devfs_print __P((struct vop_print_args *ap));
58static int devfs_read __P((struct vop_read_args *ap));
59static int devfs_readdir __P((struct vop_readdir_args *ap));
60static int devfs_readlink __P((struct vop_readlink_args *ap));
61static int devfs_reclaim __P((struct vop_reclaim_args *ap));
62static int devfs_remove __P((struct vop_remove_args *ap));
63static int devfs_revoke __P((struct vop_revoke_args *ap));
64static int devfs_setattr __P((struct vop_setattr_args *ap));
65static int devfs_symlink __P((struct vop_symlink_args *ap));
66
67int
68devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct proc *p)
69{
70 int error;
71 struct vnode *vp;
72 dev_t dev;
73
74 if (p == NULL)
75 p = curproc; /* XXX */
76loop:
77 vp = de->de_vnode;
78 if (vp != NULL) {
79 if (vget(vp, LK_EXCLUSIVE, p ? p : curproc))
80 goto loop;
81 *vpp = vp;
82 return (0);
83 }
84 if (de->de_dirent->d_type == DT_CHR) {
85 dev = *devfs_itod(de->de_inode);
86 if (dev == NULL)
87 return (ENOENT);
88 } else {
89 dev = NODEV;
90 }
91 error = getnewvnode(VT_DEVFS, mp, devfs_vnodeop_p, &vp);
92 if (error != 0) {
93 printf("devfs_allocv: failed to allocate new vnode\n");
94 return (error);
95 }
96
97 if (de->de_dirent->d_type == DT_CHR) {
98 vp->v_type = VCHR;
99 vp = addaliasu(vp, dev->si_udev);
100 vp->v_op = devfs_specop_p;
101 } else if (de->de_dirent->d_type == DT_DIR) {
102 vp->v_type = VDIR;
103 } else if (de->de_dirent->d_type == DT_LNK) {
104 vp->v_type = VLNK;
105 } else {
106 vp->v_type = VBAD;
107 }
108 vp->v_data = de;
109 de->de_vnode = vp;
110 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
111 *vpp = vp;
112 return (0);
113}
114
115static int
116devfs_access(ap)
117 struct vop_access_args /* {
118 struct vnode *a_vp;
119 int a_mode;
120 struct ucred *a_cred;
121 struct proc *a_p;
122 } */ *ap;
123{
124 struct vnode *vp = ap->a_vp;
125 struct devfs_dirent *de;
126
127 de = vp->v_data;
128 if (vp->v_type == VDIR)
129 de = de->de_dir;
130
131 return (vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid,
132 ap->a_mode, ap->a_cred, NULL));
133}
134
135static int
136devfs_getattr(ap)
137 struct vop_getattr_args /* {
138 struct vnode *a_vp;
139 struct vattr *a_vap;
140 struct ucred *a_cred;
141 struct proc *a_p;
142 } */ *ap;
143{
144 struct vnode *vp = ap->a_vp;
145 struct vattr *vap = ap->a_vap;
146 int error = 0;
147 struct devfs_dirent *de;
148 dev_t dev;
149
150 de = vp->v_data;
151 if (vp->v_type == VDIR)
152 de = de->de_dir;
153 bzero((caddr_t) vap, sizeof(*vap));
154 vattr_null(vap);
155 vap->va_uid = de->de_uid;
156 vap->va_gid = de->de_gid;
157 vap->va_mode = de->de_mode;
158 if (vp->v_type == VLNK)
159 vap->va_size = de->de_dirent->d_namlen;
160 else
161 vap->va_size = 0;
162 vap->va_blocksize = DEV_BSIZE;
163 vap->va_type = vp->v_type;
164
165#define fix(aa) \
166 do { \
167 if ((aa).tv_sec == 0) { \
168 (aa).tv_sec = boottime.tv_sec; \
169 (aa).tv_nsec = boottime.tv_usec * 1000; \
170 } \
171 } while (0)
172
173 if (vp->v_type != VCHR) {
174 fix(de->de_atime);
175 vap->va_atime = de->de_atime;
176 fix(de->de_mtime);
177 vap->va_mtime = de->de_mtime;
178 fix(de->de_ctime);
179 vap->va_ctime = de->de_ctime;
180 } else {
181 dev = vp->v_rdev;
182 fix(dev->si_atime);
183 vap->va_atime = dev->si_atime;
184 fix(dev->si_mtime);
185 vap->va_mtime = dev->si_mtime;
186 fix(dev->si_ctime);
187 vap->va_ctime = dev->si_ctime;
188 vap->va_rdev = dev->si_udev;
189 }
190 vap->va_gen = 0;
191 vap->va_flags = 0;
192 vap->va_bytes = 0;
193 vap->va_nlink = de->de_links;
194 vap->va_fileid = de->de_inode;
195
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/conf.h>
43#include <sys/dirent.h>
44#include <sys/kernel.h>
45#include <sys/lock.h>
46#include <sys/malloc.h>
47#include <sys/mount.h>
48#include <sys/namei.h>
49#include <sys/proc.h>
50#include <sys/socket.h>
51#include <sys/time.h>
52#include <sys/vnode.h>
53
54#include <fs/devfs/devfs.h>
55
56static int devfs_access __P((struct vop_access_args *ap));
57static int devfs_getattr __P((struct vop_getattr_args *ap));
58static int devfs_lookupx __P((struct vop_lookup_args *ap));
59static int devfs_print __P((struct vop_print_args *ap));
60static int devfs_read __P((struct vop_read_args *ap));
61static int devfs_readdir __P((struct vop_readdir_args *ap));
62static int devfs_readlink __P((struct vop_readlink_args *ap));
63static int devfs_reclaim __P((struct vop_reclaim_args *ap));
64static int devfs_remove __P((struct vop_remove_args *ap));
65static int devfs_revoke __P((struct vop_revoke_args *ap));
66static int devfs_setattr __P((struct vop_setattr_args *ap));
67static int devfs_symlink __P((struct vop_symlink_args *ap));
68
69int
70devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct proc *p)
71{
72 int error;
73 struct vnode *vp;
74 dev_t dev;
75
76 if (p == NULL)
77 p = curproc; /* XXX */
78loop:
79 vp = de->de_vnode;
80 if (vp != NULL) {
81 if (vget(vp, LK_EXCLUSIVE, p ? p : curproc))
82 goto loop;
83 *vpp = vp;
84 return (0);
85 }
86 if (de->de_dirent->d_type == DT_CHR) {
87 dev = *devfs_itod(de->de_inode);
88 if (dev == NULL)
89 return (ENOENT);
90 } else {
91 dev = NODEV;
92 }
93 error = getnewvnode(VT_DEVFS, mp, devfs_vnodeop_p, &vp);
94 if (error != 0) {
95 printf("devfs_allocv: failed to allocate new vnode\n");
96 return (error);
97 }
98
99 if (de->de_dirent->d_type == DT_CHR) {
100 vp->v_type = VCHR;
101 vp = addaliasu(vp, dev->si_udev);
102 vp->v_op = devfs_specop_p;
103 } else if (de->de_dirent->d_type == DT_DIR) {
104 vp->v_type = VDIR;
105 } else if (de->de_dirent->d_type == DT_LNK) {
106 vp->v_type = VLNK;
107 } else {
108 vp->v_type = VBAD;
109 }
110 vp->v_data = de;
111 de->de_vnode = vp;
112 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
113 *vpp = vp;
114 return (0);
115}
116
117static int
118devfs_access(ap)
119 struct vop_access_args /* {
120 struct vnode *a_vp;
121 int a_mode;
122 struct ucred *a_cred;
123 struct proc *a_p;
124 } */ *ap;
125{
126 struct vnode *vp = ap->a_vp;
127 struct devfs_dirent *de;
128
129 de = vp->v_data;
130 if (vp->v_type == VDIR)
131 de = de->de_dir;
132
133 return (vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid,
134 ap->a_mode, ap->a_cred, NULL));
135}
136
137static int
138devfs_getattr(ap)
139 struct vop_getattr_args /* {
140 struct vnode *a_vp;
141 struct vattr *a_vap;
142 struct ucred *a_cred;
143 struct proc *a_p;
144 } */ *ap;
145{
146 struct vnode *vp = ap->a_vp;
147 struct vattr *vap = ap->a_vap;
148 int error = 0;
149 struct devfs_dirent *de;
150 dev_t dev;
151
152 de = vp->v_data;
153 if (vp->v_type == VDIR)
154 de = de->de_dir;
155 bzero((caddr_t) vap, sizeof(*vap));
156 vattr_null(vap);
157 vap->va_uid = de->de_uid;
158 vap->va_gid = de->de_gid;
159 vap->va_mode = de->de_mode;
160 if (vp->v_type == VLNK)
161 vap->va_size = de->de_dirent->d_namlen;
162 else
163 vap->va_size = 0;
164 vap->va_blocksize = DEV_BSIZE;
165 vap->va_type = vp->v_type;
166
167#define fix(aa) \
168 do { \
169 if ((aa).tv_sec == 0) { \
170 (aa).tv_sec = boottime.tv_sec; \
171 (aa).tv_nsec = boottime.tv_usec * 1000; \
172 } \
173 } while (0)
174
175 if (vp->v_type != VCHR) {
176 fix(de->de_atime);
177 vap->va_atime = de->de_atime;
178 fix(de->de_mtime);
179 vap->va_mtime = de->de_mtime;
180 fix(de->de_ctime);
181 vap->va_ctime = de->de_ctime;
182 } else {
183 dev = vp->v_rdev;
184 fix(dev->si_atime);
185 vap->va_atime = dev->si_atime;
186 fix(dev->si_mtime);
187 vap->va_mtime = dev->si_mtime;
188 fix(dev->si_ctime);
189 vap->va_ctime = dev->si_ctime;
190 vap->va_rdev = dev->si_udev;
191 }
192 vap->va_gen = 0;
193 vap->va_flags = 0;
194 vap->va_bytes = 0;
195 vap->va_nlink = de->de_links;
196 vap->va_fileid = de->de_inode;
197
196#ifdef DEBUG
197 if (error)
198 printf("devfs_getattr: return error %d\n", error);
199#endif
200 return (error);
201}
202
203static int
204devfs_lookupx(ap)
205 struct vop_lookup_args /* {
206 struct vnode * a_dvp;
207 struct vnode ** a_vpp;
208 struct componentname * a_cnp;
209 } */ *ap;
210{
211 struct componentname *cnp;
212 struct vnode *dvp, **vpp;
213 struct proc *p;
214 struct devfs_dirent *de, *dd;
215 struct devfs_mount *dmp;
216 dev_t cdev;
217 int error, cloned, i, flags, nameiop;
218 char specname[SPECNAMELEN + 1], *pname;
219
220 cnp = ap->a_cnp;
221 vpp = ap->a_vpp;
222 dvp = ap->a_dvp;
223 pname = cnp->cn_nameptr;
224 p = cnp->cn_proc;
225 flags = cnp->cn_flags;
226 nameiop = cnp->cn_nameiop;
227 dmp = VFSTODEVFS(dvp->v_mount);
228 cloned = 0;
229 dd = dvp->v_data;
230
231 *vpp = NULLVP;
232
233 if (nameiop == RENAME)
234 return (EOPNOTSUPP);
235
236 if (dvp->v_type != VDIR)
237 return (ENOTDIR);
238
239 if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT))
240 return (EIO);
241
242 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc);
243 if (error)
244 return (error);
245
246 if (cnp->cn_namelen == 1 && *pname == '.') {
247 if (nameiop != LOOKUP)
248 return (EINVAL);
249 *vpp = dvp;
250 VREF(dvp);
251 return (0);
252 }
253
254 if (flags & ISDOTDOT) {
255 if (nameiop != LOOKUP)
256 return (EINVAL);
257 VOP_UNLOCK(dvp, 0, p);
258 de = TAILQ_FIRST(&dd->de_dlist); /* "." */
259 de = TAILQ_NEXT(de, de_list); /* ".." */
260 de = de->de_dir;
261 error = devfs_allocv(de, dvp->v_mount, vpp, p);
262 if (error) {
263 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
264 return (error);
265 }
266 if ((flags & LOCKPARENT) && (flags & ISLASTCN))
267 error = vn_lock(dvp, LK_EXCLUSIVE, p);
268 if (error)
269 vput(*vpp);
270 return (error);
271 }
272
273 devfs_populate(dmp);
274 dd = dvp->v_data;
275 TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
276 if (cnp->cn_namelen != de->de_dirent->d_namlen)
277 continue;
278 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
279 de->de_dirent->d_namlen) != 0)
280 continue;
281 goto found;
282 }
283
284 /*
285 * OK, we didn't have an entry for the name we were asked for
286 * so we try to see if anybody can create it on demand.
287 * We need to construct the full "devname" for this device
288 * relative to "basedir" or the clone functions would not
289 * be able to tell "/dev/foo" from "/dev/bar/foo"
290 */
291 i = SPECNAMELEN;
292 specname[i] = '\0';
293 i -= cnp->cn_namelen;
294 if (i < 0)
295 goto notfound;
296 bcopy(cnp->cn_nameptr, specname + i, cnp->cn_namelen);
297 de = dd;
298 while (de != dmp->dm_basedir) {
299 i--;
300 if (i < 0)
301 goto notfound;
302 specname[i] = '/';
303 i -= de->de_dirent->d_namlen;
304 if (i < 0)
305 goto notfound;
306 bcopy(de->de_dirent->d_name, specname + i,
307 de->de_dirent->d_namlen);
308 de = TAILQ_FIRST(&de->de_dlist); /* "." */
309 de = TAILQ_NEXT(de, de_list); /* ".." */
310 de = de->de_dir;
311 }
312
313#if 0
314 printf("Finished specname: %d \"%s\"\n", i, specname + i);
315#endif
316 cdev = NODEV;
317 EVENTHANDLER_INVOKE(dev_clone, specname + i,
318 strlen(specname + i), &cdev);
319#if 0
320 printf("cloned %s -> %p %s\n", specname + i, cdev,
321 cdev == NODEV ? "NODEV" : cdev->si_name);
322#endif
323 if (cdev == NODEV)
324 goto notfound;
325
326 devfs_populate(dmp);
327 dd = dvp->v_data;
328 TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
329 if (cnp->cn_namelen != de->de_dirent->d_namlen)
330 continue;
331 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
332 de->de_dirent->d_namlen) != 0)
333 continue;
334 goto found;
335 }
336
337notfound:
338
339 if ((nameiop == CREATE || nameiop == RENAME) &&
340 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) {
341 cnp->cn_flags |= SAVENAME;
342 if (!(flags & LOCKPARENT))
343 VOP_UNLOCK(dvp, 0, p);
344 return (EJUSTRETURN);
345 }
346 return (ENOENT);
347
348
349found:
350
351 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) {
352 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, p);
353 if (error)
354 return (error);
355 if (*vpp == dvp) {
356 VREF(dvp);
357 *vpp = dvp;
358 return (0);
359 }
360 error = devfs_allocv(de, dvp->v_mount, vpp, p);
361 if (error)
362 return (error);
363 if (!(flags & LOCKPARENT))
364 VOP_UNLOCK(dvp, 0, p);
365 return (0);
366 }
367 error = devfs_allocv(de, dvp->v_mount, vpp, p);
368 if (error)
369 return (error);
370 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN))
371 VOP_UNLOCK(dvp, 0, p);
372 return (0);
373}
374
375static int
376devfs_lookup(struct vop_lookup_args *ap)
377{
378 int j;
379 struct devfs_mount *dmp;
380
381 dmp = VFSTODEVFS(ap->a_dvp->v_mount);
382 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curproc);
383 j = devfs_lookupx(ap);
384 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc);
385 return (j);
386}
387
388/* ARGSUSED */
389static int
390devfs_print(ap)
391 struct vop_print_args /* {
392 struct vnode *a_vp;
393 } */ *ap;
394{
395
396 printf("tag VT_DEVFS, devfs vnode\n");
397 return (0);
398}
399
400static int
401devfs_read(ap)
402 struct vop_read_args /* {
403 struct vnode *a_vp;
404 struct uio *a_uio;
405 int a_ioflag;
406 struct ucred *a_cred;
407 } */ *ap;
408{
409
410 if (ap->a_vp->v_type != VDIR)
411 return (EINVAL);
412 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL));
413}
414
415static int
416devfs_readdir(ap)
417 struct vop_readdir_args /* {
418 struct vnode *a_vp;
419 struct uio *a_uio;
420 struct ucred *a_cred;
421 int *a_eofflag;
422 int *a_ncookies;
423 u_long **a_cookies;
424 } */ *ap;
425{
426 int error;
427 struct uio *uio;
428 struct dirent *dp;
429 struct devfs_dirent *dd;
430 struct devfs_dirent *de;
431 struct devfs_mount *dmp;
432 off_t off;
433
434 if (ap->a_vp->v_type != VDIR)
435 return (ENOTDIR);
436
437 if (ap->a_ncookies)
438 return (EOPNOTSUPP);
439
440 uio = ap->a_uio;
441 if (uio->uio_offset < 0)
442 return (EINVAL);
443
444 dmp = VFSTODEVFS(ap->a_vp->v_mount);
445 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curproc);
446 devfs_populate(dmp);
447 error = 0;
448 de = ap->a_vp->v_data;
449 dd = TAILQ_FIRST(&de->de_dlist);
450 off = 0;
451 while (dd != NULL) {
452 if (dd->de_dirent->d_type == DT_DIR)
453 de = dd->de_dir;
454 else
455 de = dd;
456 dp = dd->de_dirent;
457 if (dp->d_reclen > uio->uio_resid)
458 break;
459 dp->d_fileno = de->de_inode;
460 if (off >= uio->uio_offset) {
461 error = uiomove((caddr_t)dp, dp->d_reclen, uio);
462 if (error)
463 break;
464 }
465 off += dp->d_reclen;
466 dd = TAILQ_NEXT(dd, de_list);
467 }
468 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc);
469 uio->uio_offset = off;
470 return (error);
471}
472
473static int
474devfs_readlink(ap)
475 struct vop_readlink_args /* {
476 struct vnode *a_vp;
477 struct uio *a_uio;
478 struct ucred *a_cead;
479 } */ *ap;
480{
481 int error;
482 struct devfs_dirent *de;
483
484 de = ap->a_vp->v_data;
485 error = uiomove(de->de_symlink, strlen(de->de_symlink) + 1, ap->a_uio);
486 return (error);
487}
488
489static int
490devfs_reclaim(ap)
491 struct vop_reclaim_args /* {
492 struct vnode *a_vp;
493 } */ *ap;
494{
495 struct vnode *vp = ap->a_vp;
496 struct devfs_dirent *de;
497 int i;
498
499 de = vp->v_data;
500 if (de != NULL)
501 de->de_vnode = NULL;
502 if (de != NULL && de->de_flags & DE_ORPHAN) {
503 if (de->de_symlink)
504 FREE(de->de_symlink, M_DEVFS);
505 FREE(de, M_DEVFS);
506 }
507 vp->v_data = NULL;
508 if (vp->v_rdev != NODEV && vp->v_rdev != NULL) {
509 i = vcount(vp);
510 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0)
511 destroy_dev(vp->v_rdev);
512 }
513 return (0);
514}
515
516static int
517devfs_remove(ap)
518 struct vop_remove_args /* {
519 struct vnode *a_dvp;
520 struct vnode *a_vp;
521 struct componentname *a_cnp;
522 } */ *ap;
523{
524 struct vnode *vp = ap->a_vp;
525 struct devfs_dirent *dd;
526 struct devfs_dirent *de, **dep;
527 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount);
528
529 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curproc);
530 dd = ap->a_dvp->v_data;
531 de = vp->v_data;
532 TAILQ_REMOVE(&dd->de_dlist, de, de_list);
533 dep = devfs_itode(dmp, de->de_inode);
534 if (dep != NULL)
535 *dep = DE_DELETED;
536 de->de_flags |= DE_ORPHAN;
537 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc);
538 return (0);
539}
540
541/*
542 * Revoke is called on a tty when a terminal session ends. The vnode
543 * is orphaned by setting v_op to deadfs so we need to let go of it
544 * as well so that we create a new one next time around.
545 */
546static int
547devfs_revoke(ap)
548 struct vop_revoke_args /* {
549 struct vnode *a_vp;
550 int a_flags;
551 } */ *ap;
552{
553 struct vnode *vp = ap->a_vp;
554 struct devfs_dirent *de;
555
556 de = vp->v_data;
557 de->de_vnode = NULL;
558 vop_revoke(ap);
559 return (0);
560}
561
562static int
563devfs_setattr(ap)
564 struct vop_setattr_args /* {
565 struct vnode *a_vp;
566 struct vattr *a_vap;
567 struct ucred *a_cred;
568 struct proc *a_p;
569 } */ *ap;
570{
571 struct devfs_dirent *de;
572 struct vattr *vap;
573 int c, error;
574 uid_t uid;
575 gid_t gid;
576
577 vap = ap->a_vap;
578 if ((vap->va_type != VNON) ||
579 (vap->va_nlink != VNOVAL) ||
580 (vap->va_fsid != VNOVAL) ||
581 (vap->va_fileid != VNOVAL) ||
582 (vap->va_blocksize != VNOVAL) ||
583 (vap->va_flags != VNOVAL && vap->va_flags != 0) ||
584 (vap->va_rdev != VNOVAL) ||
585 ((int)vap->va_bytes != VNOVAL) ||
586 (vap->va_gen != VNOVAL)) {
587 return (EINVAL);
588 }
589
590 de = ap->a_vp->v_data;
591 if (ap->a_vp->v_type == VDIR)
592 de = de->de_dir;
593
594 error = c = 0;
595 if (vap->va_uid == (uid_t)VNOVAL)
596 uid = de->de_uid;
597 else
598 uid = vap->va_uid;
599 if (vap->va_gid == (gid_t)VNOVAL)
600 gid = de->de_gid;
601 else
602 gid = vap->va_gid;
603 if (uid != de->de_uid || gid != de->de_gid) {
604 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid ||
605 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) &&
606 (error = suser(ap->a_p)) != 0)
607 return (error);
608 de->de_uid = uid;
609 de->de_gid = gid;
610 c = 1;
611 }
612 if (vap->va_mode != (mode_t)VNOVAL) {
613 if ((ap->a_cred->cr_uid != de->de_uid) &&
614 (error = suser(ap->a_p)))
615 return (error);
616 de->de_mode = vap->va_mode;
617 c = 1;
618 }
619 if (vap->va_atime.tv_sec != VNOVAL) {
620 if ((ap->a_cred->cr_uid != de->de_uid) &&
621 (error = suser(ap->a_p)))
622 return (error);
623 de->de_atime = vap->va_atime;
624 c = 1;
625 }
626 if (vap->va_mtime.tv_sec != VNOVAL) {
627 if ((ap->a_cred->cr_uid != de->de_uid) &&
628 (error = suser(ap->a_p)))
629 return (error);
630 de->de_mtime = vap->va_mtime;
631 c = 1;
632 }
633
634 if (c)
635 getnanotime(&de->de_ctime);
636 return (0);
637}
638
639static int
640devfs_symlink(ap)
641 struct vop_symlink_args /* {
642 struct vnode *a_dvp;
643 struct vnode **a_vpp;
644 struct componentname *a_cnp;
645 struct vattr *a_vap;
646 char *a_target;
647 } */ *ap;
648{
649 int i, error;
650 struct devfs_dirent *dd;
651 struct devfs_dirent *de;
652 struct devfs_mount *dmp;
653
654 error = suser(ap->a_cnp->cn_proc);
655 if (error)
656 return(error);
657 dmp = VFSTODEVFS(ap->a_dvp->v_mount);
658 dd = ap->a_dvp->v_data;
659 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen);
660 de->de_uid = 0;
661 de->de_gid = 0;
662 de->de_mode = 0755;
663 de->de_inode = dmp->dm_inode++;
664 de->de_dirent->d_type = DT_LNK;
665 i = strlen(ap->a_target) + 1;
666 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK);
667 bcopy(ap->a_target, de->de_symlink, i);
668 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curproc);
669 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
670 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0);
671 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc);
672 return (0);
673}
674
675static vop_t **devfs_vnodeop_p;
676static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
677 { &vop_default_desc, (vop_t *) vop_defaultop },
678 { &vop_access_desc, (vop_t *) devfs_access },
679 { &vop_getattr_desc, (vop_t *) devfs_getattr },
680 { &vop_lookup_desc, (vop_t *) devfs_lookup },
681 { &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
682 { &vop_print_desc, (vop_t *) devfs_print },
683 { &vop_read_desc, (vop_t *) devfs_read },
684 { &vop_readdir_desc, (vop_t *) devfs_readdir },
685 { &vop_readlink_desc, (vop_t *) devfs_readlink },
686 { &vop_reclaim_desc, (vop_t *) devfs_reclaim },
687 { &vop_remove_desc, (vop_t *) devfs_remove },
688 { &vop_revoke_desc, (vop_t *) devfs_revoke },
689 { &vop_setattr_desc, (vop_t *) devfs_setattr },
690 { &vop_symlink_desc, (vop_t *) devfs_symlink },
691 { NULL, NULL }
692};
693static struct vnodeopv_desc devfs_vnodeop_opv_desc =
694 { &devfs_vnodeop_p, devfs_vnodeop_entries };
695
696VNODEOP_SET(devfs_vnodeop_opv_desc);
697
698static vop_t **devfs_specop_p;
699static struct vnodeopv_entry_desc devfs_specop_entries[] = {
700 { &vop_default_desc, (vop_t *) spec_vnoperate },
701 { &vop_access_desc, (vop_t *) devfs_access },
702 { &vop_getattr_desc, (vop_t *) devfs_getattr },
703 { &vop_print_desc, (vop_t *) devfs_print },
704 { &vop_reclaim_desc, (vop_t *) devfs_reclaim },
705 { &vop_remove_desc, (vop_t *) devfs_remove },
706 { &vop_revoke_desc, (vop_t *) devfs_revoke },
707 { &vop_setattr_desc, (vop_t *) devfs_setattr },
708 { NULL, NULL }
709};
710static struct vnodeopv_desc devfs_specop_opv_desc =
711 { &devfs_specop_p, devfs_specop_entries };
712
713VNODEOP_SET(devfs_specop_opv_desc);
198 return (error);
199}
200
201static int
202devfs_lookupx(ap)
203 struct vop_lookup_args /* {
204 struct vnode * a_dvp;
205 struct vnode ** a_vpp;
206 struct componentname * a_cnp;
207 } */ *ap;
208{
209 struct componentname *cnp;
210 struct vnode *dvp, **vpp;
211 struct proc *p;
212 struct devfs_dirent *de, *dd;
213 struct devfs_mount *dmp;
214 dev_t cdev;
215 int error, cloned, i, flags, nameiop;
216 char specname[SPECNAMELEN + 1], *pname;
217
218 cnp = ap->a_cnp;
219 vpp = ap->a_vpp;
220 dvp = ap->a_dvp;
221 pname = cnp->cn_nameptr;
222 p = cnp->cn_proc;
223 flags = cnp->cn_flags;
224 nameiop = cnp->cn_nameiop;
225 dmp = VFSTODEVFS(dvp->v_mount);
226 cloned = 0;
227 dd = dvp->v_data;
228
229 *vpp = NULLVP;
230
231 if (nameiop == RENAME)
232 return (EOPNOTSUPP);
233
234 if (dvp->v_type != VDIR)
235 return (ENOTDIR);
236
237 if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT))
238 return (EIO);
239
240 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc);
241 if (error)
242 return (error);
243
244 if (cnp->cn_namelen == 1 && *pname == '.') {
245 if (nameiop != LOOKUP)
246 return (EINVAL);
247 *vpp = dvp;
248 VREF(dvp);
249 return (0);
250 }
251
252 if (flags & ISDOTDOT) {
253 if (nameiop != LOOKUP)
254 return (EINVAL);
255 VOP_UNLOCK(dvp, 0, p);
256 de = TAILQ_FIRST(&dd->de_dlist); /* "." */
257 de = TAILQ_NEXT(de, de_list); /* ".." */
258 de = de->de_dir;
259 error = devfs_allocv(de, dvp->v_mount, vpp, p);
260 if (error) {
261 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
262 return (error);
263 }
264 if ((flags & LOCKPARENT) && (flags & ISLASTCN))
265 error = vn_lock(dvp, LK_EXCLUSIVE, p);
266 if (error)
267 vput(*vpp);
268 return (error);
269 }
270
271 devfs_populate(dmp);
272 dd = dvp->v_data;
273 TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
274 if (cnp->cn_namelen != de->de_dirent->d_namlen)
275 continue;
276 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
277 de->de_dirent->d_namlen) != 0)
278 continue;
279 goto found;
280 }
281
282 /*
283 * OK, we didn't have an entry for the name we were asked for
284 * so we try to see if anybody can create it on demand.
285 * We need to construct the full "devname" for this device
286 * relative to "basedir" or the clone functions would not
287 * be able to tell "/dev/foo" from "/dev/bar/foo"
288 */
289 i = SPECNAMELEN;
290 specname[i] = '\0';
291 i -= cnp->cn_namelen;
292 if (i < 0)
293 goto notfound;
294 bcopy(cnp->cn_nameptr, specname + i, cnp->cn_namelen);
295 de = dd;
296 while (de != dmp->dm_basedir) {
297 i--;
298 if (i < 0)
299 goto notfound;
300 specname[i] = '/';
301 i -= de->de_dirent->d_namlen;
302 if (i < 0)
303 goto notfound;
304 bcopy(de->de_dirent->d_name, specname + i,
305 de->de_dirent->d_namlen);
306 de = TAILQ_FIRST(&de->de_dlist); /* "." */
307 de = TAILQ_NEXT(de, de_list); /* ".." */
308 de = de->de_dir;
309 }
310
311#if 0
312 printf("Finished specname: %d \"%s\"\n", i, specname + i);
313#endif
314 cdev = NODEV;
315 EVENTHANDLER_INVOKE(dev_clone, specname + i,
316 strlen(specname + i), &cdev);
317#if 0
318 printf("cloned %s -> %p %s\n", specname + i, cdev,
319 cdev == NODEV ? "NODEV" : cdev->si_name);
320#endif
321 if (cdev == NODEV)
322 goto notfound;
323
324 devfs_populate(dmp);
325 dd = dvp->v_data;
326 TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
327 if (cnp->cn_namelen != de->de_dirent->d_namlen)
328 continue;
329 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
330 de->de_dirent->d_namlen) != 0)
331 continue;
332 goto found;
333 }
334
335notfound:
336
337 if ((nameiop == CREATE || nameiop == RENAME) &&
338 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) {
339 cnp->cn_flags |= SAVENAME;
340 if (!(flags & LOCKPARENT))
341 VOP_UNLOCK(dvp, 0, p);
342 return (EJUSTRETURN);
343 }
344 return (ENOENT);
345
346
347found:
348
349 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) {
350 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, p);
351 if (error)
352 return (error);
353 if (*vpp == dvp) {
354 VREF(dvp);
355 *vpp = dvp;
356 return (0);
357 }
358 error = devfs_allocv(de, dvp->v_mount, vpp, p);
359 if (error)
360 return (error);
361 if (!(flags & LOCKPARENT))
362 VOP_UNLOCK(dvp, 0, p);
363 return (0);
364 }
365 error = devfs_allocv(de, dvp->v_mount, vpp, p);
366 if (error)
367 return (error);
368 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN))
369 VOP_UNLOCK(dvp, 0, p);
370 return (0);
371}
372
373static int
374devfs_lookup(struct vop_lookup_args *ap)
375{
376 int j;
377 struct devfs_mount *dmp;
378
379 dmp = VFSTODEVFS(ap->a_dvp->v_mount);
380 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curproc);
381 j = devfs_lookupx(ap);
382 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc);
383 return (j);
384}
385
386/* ARGSUSED */
387static int
388devfs_print(ap)
389 struct vop_print_args /* {
390 struct vnode *a_vp;
391 } */ *ap;
392{
393
394 printf("tag VT_DEVFS, devfs vnode\n");
395 return (0);
396}
397
398static int
399devfs_read(ap)
400 struct vop_read_args /* {
401 struct vnode *a_vp;
402 struct uio *a_uio;
403 int a_ioflag;
404 struct ucred *a_cred;
405 } */ *ap;
406{
407
408 if (ap->a_vp->v_type != VDIR)
409 return (EINVAL);
410 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL));
411}
412
413static int
414devfs_readdir(ap)
415 struct vop_readdir_args /* {
416 struct vnode *a_vp;
417 struct uio *a_uio;
418 struct ucred *a_cred;
419 int *a_eofflag;
420 int *a_ncookies;
421 u_long **a_cookies;
422 } */ *ap;
423{
424 int error;
425 struct uio *uio;
426 struct dirent *dp;
427 struct devfs_dirent *dd;
428 struct devfs_dirent *de;
429 struct devfs_mount *dmp;
430 off_t off;
431
432 if (ap->a_vp->v_type != VDIR)
433 return (ENOTDIR);
434
435 if (ap->a_ncookies)
436 return (EOPNOTSUPP);
437
438 uio = ap->a_uio;
439 if (uio->uio_offset < 0)
440 return (EINVAL);
441
442 dmp = VFSTODEVFS(ap->a_vp->v_mount);
443 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curproc);
444 devfs_populate(dmp);
445 error = 0;
446 de = ap->a_vp->v_data;
447 dd = TAILQ_FIRST(&de->de_dlist);
448 off = 0;
449 while (dd != NULL) {
450 if (dd->de_dirent->d_type == DT_DIR)
451 de = dd->de_dir;
452 else
453 de = dd;
454 dp = dd->de_dirent;
455 if (dp->d_reclen > uio->uio_resid)
456 break;
457 dp->d_fileno = de->de_inode;
458 if (off >= uio->uio_offset) {
459 error = uiomove((caddr_t)dp, dp->d_reclen, uio);
460 if (error)
461 break;
462 }
463 off += dp->d_reclen;
464 dd = TAILQ_NEXT(dd, de_list);
465 }
466 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc);
467 uio->uio_offset = off;
468 return (error);
469}
470
471static int
472devfs_readlink(ap)
473 struct vop_readlink_args /* {
474 struct vnode *a_vp;
475 struct uio *a_uio;
476 struct ucred *a_cead;
477 } */ *ap;
478{
479 int error;
480 struct devfs_dirent *de;
481
482 de = ap->a_vp->v_data;
483 error = uiomove(de->de_symlink, strlen(de->de_symlink) + 1, ap->a_uio);
484 return (error);
485}
486
487static int
488devfs_reclaim(ap)
489 struct vop_reclaim_args /* {
490 struct vnode *a_vp;
491 } */ *ap;
492{
493 struct vnode *vp = ap->a_vp;
494 struct devfs_dirent *de;
495 int i;
496
497 de = vp->v_data;
498 if (de != NULL)
499 de->de_vnode = NULL;
500 if (de != NULL && de->de_flags & DE_ORPHAN) {
501 if (de->de_symlink)
502 FREE(de->de_symlink, M_DEVFS);
503 FREE(de, M_DEVFS);
504 }
505 vp->v_data = NULL;
506 if (vp->v_rdev != NODEV && vp->v_rdev != NULL) {
507 i = vcount(vp);
508 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0)
509 destroy_dev(vp->v_rdev);
510 }
511 return (0);
512}
513
514static int
515devfs_remove(ap)
516 struct vop_remove_args /* {
517 struct vnode *a_dvp;
518 struct vnode *a_vp;
519 struct componentname *a_cnp;
520 } */ *ap;
521{
522 struct vnode *vp = ap->a_vp;
523 struct devfs_dirent *dd;
524 struct devfs_dirent *de, **dep;
525 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount);
526
527 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curproc);
528 dd = ap->a_dvp->v_data;
529 de = vp->v_data;
530 TAILQ_REMOVE(&dd->de_dlist, de, de_list);
531 dep = devfs_itode(dmp, de->de_inode);
532 if (dep != NULL)
533 *dep = DE_DELETED;
534 de->de_flags |= DE_ORPHAN;
535 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc);
536 return (0);
537}
538
539/*
540 * Revoke is called on a tty when a terminal session ends. The vnode
541 * is orphaned by setting v_op to deadfs so we need to let go of it
542 * as well so that we create a new one next time around.
543 */
544static int
545devfs_revoke(ap)
546 struct vop_revoke_args /* {
547 struct vnode *a_vp;
548 int a_flags;
549 } */ *ap;
550{
551 struct vnode *vp = ap->a_vp;
552 struct devfs_dirent *de;
553
554 de = vp->v_data;
555 de->de_vnode = NULL;
556 vop_revoke(ap);
557 return (0);
558}
559
560static int
561devfs_setattr(ap)
562 struct vop_setattr_args /* {
563 struct vnode *a_vp;
564 struct vattr *a_vap;
565 struct ucred *a_cred;
566 struct proc *a_p;
567 } */ *ap;
568{
569 struct devfs_dirent *de;
570 struct vattr *vap;
571 int c, error;
572 uid_t uid;
573 gid_t gid;
574
575 vap = ap->a_vap;
576 if ((vap->va_type != VNON) ||
577 (vap->va_nlink != VNOVAL) ||
578 (vap->va_fsid != VNOVAL) ||
579 (vap->va_fileid != VNOVAL) ||
580 (vap->va_blocksize != VNOVAL) ||
581 (vap->va_flags != VNOVAL && vap->va_flags != 0) ||
582 (vap->va_rdev != VNOVAL) ||
583 ((int)vap->va_bytes != VNOVAL) ||
584 (vap->va_gen != VNOVAL)) {
585 return (EINVAL);
586 }
587
588 de = ap->a_vp->v_data;
589 if (ap->a_vp->v_type == VDIR)
590 de = de->de_dir;
591
592 error = c = 0;
593 if (vap->va_uid == (uid_t)VNOVAL)
594 uid = de->de_uid;
595 else
596 uid = vap->va_uid;
597 if (vap->va_gid == (gid_t)VNOVAL)
598 gid = de->de_gid;
599 else
600 gid = vap->va_gid;
601 if (uid != de->de_uid || gid != de->de_gid) {
602 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid ||
603 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) &&
604 (error = suser(ap->a_p)) != 0)
605 return (error);
606 de->de_uid = uid;
607 de->de_gid = gid;
608 c = 1;
609 }
610 if (vap->va_mode != (mode_t)VNOVAL) {
611 if ((ap->a_cred->cr_uid != de->de_uid) &&
612 (error = suser(ap->a_p)))
613 return (error);
614 de->de_mode = vap->va_mode;
615 c = 1;
616 }
617 if (vap->va_atime.tv_sec != VNOVAL) {
618 if ((ap->a_cred->cr_uid != de->de_uid) &&
619 (error = suser(ap->a_p)))
620 return (error);
621 de->de_atime = vap->va_atime;
622 c = 1;
623 }
624 if (vap->va_mtime.tv_sec != VNOVAL) {
625 if ((ap->a_cred->cr_uid != de->de_uid) &&
626 (error = suser(ap->a_p)))
627 return (error);
628 de->de_mtime = vap->va_mtime;
629 c = 1;
630 }
631
632 if (c)
633 getnanotime(&de->de_ctime);
634 return (0);
635}
636
637static int
638devfs_symlink(ap)
639 struct vop_symlink_args /* {
640 struct vnode *a_dvp;
641 struct vnode **a_vpp;
642 struct componentname *a_cnp;
643 struct vattr *a_vap;
644 char *a_target;
645 } */ *ap;
646{
647 int i, error;
648 struct devfs_dirent *dd;
649 struct devfs_dirent *de;
650 struct devfs_mount *dmp;
651
652 error = suser(ap->a_cnp->cn_proc);
653 if (error)
654 return(error);
655 dmp = VFSTODEVFS(ap->a_dvp->v_mount);
656 dd = ap->a_dvp->v_data;
657 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen);
658 de->de_uid = 0;
659 de->de_gid = 0;
660 de->de_mode = 0755;
661 de->de_inode = dmp->dm_inode++;
662 de->de_dirent->d_type = DT_LNK;
663 i = strlen(ap->a_target) + 1;
664 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK);
665 bcopy(ap->a_target, de->de_symlink, i);
666 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curproc);
667 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
668 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0);
669 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc);
670 return (0);
671}
672
673static vop_t **devfs_vnodeop_p;
674static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
675 { &vop_default_desc, (vop_t *) vop_defaultop },
676 { &vop_access_desc, (vop_t *) devfs_access },
677 { &vop_getattr_desc, (vop_t *) devfs_getattr },
678 { &vop_lookup_desc, (vop_t *) devfs_lookup },
679 { &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
680 { &vop_print_desc, (vop_t *) devfs_print },
681 { &vop_read_desc, (vop_t *) devfs_read },
682 { &vop_readdir_desc, (vop_t *) devfs_readdir },
683 { &vop_readlink_desc, (vop_t *) devfs_readlink },
684 { &vop_reclaim_desc, (vop_t *) devfs_reclaim },
685 { &vop_remove_desc, (vop_t *) devfs_remove },
686 { &vop_revoke_desc, (vop_t *) devfs_revoke },
687 { &vop_setattr_desc, (vop_t *) devfs_setattr },
688 { &vop_symlink_desc, (vop_t *) devfs_symlink },
689 { NULL, NULL }
690};
691static struct vnodeopv_desc devfs_vnodeop_opv_desc =
692 { &devfs_vnodeop_p, devfs_vnodeop_entries };
693
694VNODEOP_SET(devfs_vnodeop_opv_desc);
695
696static vop_t **devfs_specop_p;
697static struct vnodeopv_entry_desc devfs_specop_entries[] = {
698 { &vop_default_desc, (vop_t *) spec_vnoperate },
699 { &vop_access_desc, (vop_t *) devfs_access },
700 { &vop_getattr_desc, (vop_t *) devfs_getattr },
701 { &vop_print_desc, (vop_t *) devfs_print },
702 { &vop_reclaim_desc, (vop_t *) devfs_reclaim },
703 { &vop_remove_desc, (vop_t *) devfs_remove },
704 { &vop_revoke_desc, (vop_t *) devfs_revoke },
705 { &vop_setattr_desc, (vop_t *) devfs_setattr },
706 { NULL, NULL }
707};
708static struct vnodeopv_desc devfs_specop_opv_desc =
709 { &devfs_specop_p, devfs_specop_entries };
710
711VNODEOP_SET(devfs_specop_opv_desc);
712#endif