]> git.saurik.com Git - apple/xnu.git/blame - bsd/miscfs/devfs/devfs_vnops.c
xnu-792.6.56.tar.gz
[apple/xnu.git] / bsd / miscfs / devfs / devfs_vnops.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
ff6e181a
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
1c79356b 12 *
ff6e181a
A
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
ff6e181a
A
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
1c79356b
A
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * Copyright 1997,1998 Julian Elischer. All rights reserved.
25 * julian@freebsd.org
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions are
29 * met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright notice,
33 * this list of conditions and the following disclaimer in the documentation
34 * and/or other materials provided with the distribution.
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
37 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR
40 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
42 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
43 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 *
48 * devfs_vnops.c
49 */
50
51/*
52 * HISTORY
53 * Clark Warner (warner_c@apple.com) Tue Feb 10 2000
54 * - Added err_copyfile to the vnode operations table
55 * Dieter Siegmund (dieter@apple.com) Thu Apr 8 14:08:19 PDT 1999
56 * - instead of duplicating specfs here, created a vnode-ops table
57 * that redirects most operations to specfs (as is done with ufs);
58 * - removed routines that made no sense
59 * - cleaned up reclaim: replaced devfs_vntodn() with a macro VTODN()
60 * - cleaned up symlink, link locking
61 * - added the devfs_lock to protect devfs data structures against
62 * driver's calling devfs_add_devswf()/etc.
63 * Dieter Siegmund (dieter@apple.com) Wed Jul 14 13:37:59 PDT 1999
64 * - free the devfs devnode in devfs_inactive(), not just in devfs_reclaim()
65 * to free up kernel memory as soon as it's available
66 * - got rid of devfsspec_{read, write}
67 * Dieter Siegmund (dieter@apple.com) Fri Sep 17 09:58:38 PDT 1999
68 * - update the mod/access times
69 */
70
71#include <sys/param.h>
72#include <sys/systm.h>
1c79356b
A
73#include <sys/namei.h>
74#include <sys/kernel.h>
75#include <sys/fcntl.h>
76#include <sys/conf.h>
77#include <sys/disklabel.h>
78#include <sys/lock.h>
79#include <sys/stat.h>
91447636 80#include <sys/mount_internal.h>
1c79356b 81#include <sys/proc.h>
91447636 82#include <sys/kauth.h>
1c79356b 83#include <sys/time.h>
91447636 84#include <sys/vnode_internal.h>
1c79356b
A
85#include <miscfs/specfs/specdev.h>
86#include <sys/dirent.h>
87#include <sys/vmmeter.h>
88#include <sys/vm.h>
91447636 89#include <sys/uio_internal.h>
1c79356b
A
90
91#include "devfsdefs.h"
92
91447636
A
93static int devfs_update(struct vnode *vp, struct timeval *access,
94 struct timeval *modify);
95
96
1c79356b
A
97/*
98 * Convert a component of a pathname into a pointer to a locked node.
99 * This is a very central and rather complicated routine.
100 * If the file system is not maintained in a strict tree hierarchy,
101 * this can result in a deadlock situation (see comments in code below).
102 *
103 * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
104 * whether the name is to be looked up, created, renamed, or deleted.
105 * When CREATE, RENAME, or DELETE is specified, information usable in
106 * creating, renaming, or deleting a directory entry may be calculated.
107 * If flag has LOCKPARENT or'ed into it and the target of the pathname
108 * exists, lookup returns both the target and its parent directory locked.
109 * When creating or renaming and LOCKPARENT is specified, the target may
110 * not be ".". When deleting and LOCKPARENT is specified, the target may
111 * be "."., but the caller must check to ensure it does an vrele and DNUNLOCK
112 * instead of two DNUNLOCKs.
113 *
114 * Overall outline of devfs_lookup:
115 *
116 * check accessibility of directory
117 * null terminate the component (lookup leaves the whole string alone)
118 * look for name in cache, if found, then if at end of path
119 * and deleting or creating, drop it, else return name
120 * search for name in directory, to found or notfound
121 * notfound:
122 * if creating, return locked directory,
123 * else return error
124 * found:
125 * if at end of path and deleting, return information to allow delete
126 * if at end of path and rewriting (RENAME and LOCKPARENT), lock target
127 * node and return info to allow rewrite
128 * if not at end, add name to cache; if at end and neither creating
129 * nor deleting, add name to cache
130 * On return to lookup, remove the null termination we put in at the start.
131 *
132 * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent node unlocked.
133 */
134static int
91447636
A
135devfs_lookup(struct vnop_lookup_args *ap)
136 /*struct vnop_lookup_args {
1c79356b
A
137 struct vnode * a_dvp; directory vnode ptr
138 struct vnode ** a_vpp; where to put the result
139 struct componentname * a_cnp; the name we want
91447636 140 vfs_context_t a_context;
1c79356b
A
141 };*/
142{
143 struct componentname *cnp = ap->a_cnp;
91447636
A
144 vfs_context_t ctx = cnp->cn_context;
145 struct proc *p = vfs_context_proc(ctx);
1c79356b
A
146 struct vnode *dir_vnode = ap->a_dvp;
147 struct vnode **result_vnode = ap->a_vpp;
148 devnode_t * dir_node; /* the directory we are searching */
149 devnode_t * node = NULL; /* the node we are searching for */
150 devdirent_t * nodename;
151 int flags = cnp->cn_flags;
152 int op = cnp->cn_nameiop; /* LOOKUP, CREATE, RENAME, or DELETE */
1c79356b
A
153 int wantparent = flags & (LOCKPARENT|WANTPARENT);
154 int error = 0;
1c79356b
A
155 char heldchar; /* the char at the end of the name componet */
156
91447636
A
157retry:
158
1c79356b
A
159 *result_vnode = NULL; /* safe not sorry */ /*XXX*/
160
91447636
A
161 //if (dir_vnode->v_usecount == 0)
162 //printf("devfs_lookup: dir had no refs ");
1c79356b
A
163 dir_node = VTODN(dir_vnode);
164
165 /*
91447636 166 * Make sure that our node is a directory as well.
1c79356b
A
167 */
168 if (dir_node->dn_type != DEV_DIR) {
169 return (ENOTDIR);
170 }
171
91447636
A
172 DEVFS_LOCK();
173 /*
174 * temporarily terminate string component
175 */
1c79356b
A
176 heldchar = cnp->cn_nameptr[cnp->cn_namelen];
177 cnp->cn_nameptr[cnp->cn_namelen] = '\0';
91447636
A
178
179 nodename = dev_findname(dir_node, cnp->cn_nameptr);
180 /*
181 * restore saved character
182 */
1c79356b
A
183 cnp->cn_nameptr[cnp->cn_namelen] = heldchar;
184
91447636
A
185 if (nodename) {
186 /* entry exists */
187 node = nodename->de_dnp;
1c79356b 188
91447636
A
189 /* Do potential vnode allocation here inside the lock
190 * to make sure that our device node has a non-NULL dn_vn
191 * associated with it. The device node might otherwise
192 * get deleted out from under us (see devfs_dn_free()).
193 */
194 error = devfs_dntovn(node, result_vnode, p);
195 }
196 DEVFS_UNLOCK();
197
198 if (error) {
199 if (error == EAGAIN)
200 goto retry;
201 return error;
202 }
203 if (!nodename) {
204 /*
205 * we haven't called devfs_dntovn if we get here
206 * we have not taken a reference on the node.. no
207 * vnode_put is necessary on these error returns
208 *
209 * If it doesn't exist and we're not the last component,
1c79356b
A
210 * or we're at the last component, but we're not creating
211 * or renaming, return ENOENT.
212 */
213 if (!(flags & ISLASTCN) || !(op == CREATE || op == RENAME)) {
214 return ENOENT;
215 }
1c79356b
A
216 /*
217 * We return with the directory locked, so that
218 * the parameters we set up above will still be
219 * valid if we actually decide to add a new entry.
220 * We return ni_vp == NULL to indicate that the entry
221 * does not currently exist; we leave a pointer to
222 * the (locked) directory vnode in namei_data->ni_dvp.
1c79356b
A
223 *
224 * NB - if the directory is unlocked, then this
225 * information cannot be used.
226 */
1c79356b
A
227 return (EJUSTRETURN);
228 }
91447636
A
229 /*
230 * from this point forward, we need to vnode_put the reference
231 * picked up in devfs_dntovn if we decide to return an error
232 */
1c79356b
A
233
234 /*
235 * If deleting, and at end of pathname, return
236 * parameters which can be used to remove file.
237 * If the wantparent flag isn't set, we return only
238 * the directory (in namei_data->ni_dvp), otherwise we go
239 * on and lock the node, being careful with ".".
240 */
241 if (op == DELETE && (flags & ISLASTCN)) {
91447636 242
1c79356b
A
243 /*
244 * we are trying to delete '.'. What does this mean? XXX
245 */
246 if (dir_node == node) {
91447636
A
247 if (*result_vnode) {
248 vnode_put(*result_vnode);
249 *result_vnode = NULL;
250 }
251 if ( ((error = vnode_get(dir_vnode)) == 0) ) {
252 *result_vnode = dir_vnode;
253 }
254 return (error);
1c79356b 255 }
1c79356b
A
256 return (0);
257 }
258
259 /*
260 * If rewriting (RENAME), return the vnode and the
261 * information required to rewrite the present directory
262 * Must get node of directory entry to verify it's a
263 * regular file, or empty directory.
264 */
265 if (op == RENAME && wantparent && (flags & ISLASTCN)) {
91447636 266
1c79356b
A
267 /*
268 * Careful about locking second node.
269 * This can only occur if the target is ".".
270 */
91447636
A
271 if (dir_node == node) {
272 error = EISDIR;
273 goto drop_ref;
274 }
1c79356b
A
275 return (0);
276 }
277
278 /*
279 * Step through the translation in the name. We do not unlock the
280 * directory because we may need it again if a symbolic link
281 * is relative to the current directory. Instead we save it
282 * unlocked as "saved_dir_node" XXX. We must get the target
283 * node before unlocking
284 * the directory to insure that the node will not be removed
285 * before we get it. We prevent deadlock by always fetching
286 * nodes from the root, moving down the directory tree. Thus
287 * when following backward pointers ".." we must unlock the
288 * parent directory before getting the requested directory.
289 * There is a potential race condition here if both the current
290 * and parent directories are removed before the lock for the
291 * node associated with ".." returns. We hope that this occurs
292 * infrequently since we cannot avoid this race condition without
293 * implementing a sophisticated deadlock detection algorithm.
294 * Note also that this simple deadlock detection scheme will not
295 * work if the file system has any hard links other than ".."
296 * that point backwards in the directory structure.
297 */
91447636
A
298 if ((flags & ISDOTDOT) == 0 && dir_node == node) {
299 if (*result_vnode) {
300 vnode_put(*result_vnode);
301 *result_vnode = NULL;
302 }
303 if ( (error = vnode_get(dir_vnode)) ) {
304 return (error);
305 }
1c79356b 306 *result_vnode = dir_vnode;
1c79356b 307 }
1c79356b 308 return (0);
91447636
A
309
310drop_ref:
311 if (*result_vnode) {
312 vnode_put(*result_vnode);
313 *result_vnode = NULL;
314 }
315 return (error);
1c79356b
A
316}
317
318static int
91447636
A
319devfs_getattr(struct vnop_getattr_args *ap)
320 /*struct vnop_getattr_args {
1c79356b 321 struct vnode *a_vp;
91447636
A
322 struct vnode_attr *a_vap;
323 kauth_cred_t a_cred;
1c79356b
A
324 struct proc *a_p;
325 } */
326{
1c79356b 327 struct vnode *vp = ap->a_vp;
91447636 328 struct vnode_attr *vap = ap->a_vap;
1c79356b 329 devnode_t * file_node;
91447636 330 struct timeval now;
1c79356b
A
331
332 file_node = VTODN(vp);
1c79356b 333
91447636 334 DEVFS_LOCK();
1c79356b 335
91447636
A
336 microtime(&now);
337 dn_times(file_node, &now, &now, &now);
338
339 VATTR_RETURN(vap, va_mode, file_node->dn_mode);
1c79356b 340
1c79356b
A
341 switch (file_node->dn_type)
342 {
343 case DEV_DIR:
91447636 344 VATTR_RETURN(vap, va_rdev, (dev_t)file_node->dn_dvm);
1c79356b
A
345 vap->va_mode |= (S_IFDIR);
346 break;
347 case DEV_CDEV:
91447636 348 VATTR_RETURN(vap, va_rdev, file_node->dn_typeinfo.dev);
1c79356b
A
349 vap->va_mode |= (S_IFCHR);
350 break;
351 case DEV_BDEV:
91447636 352 VATTR_RETURN(vap, va_rdev, file_node->dn_typeinfo.dev);
1c79356b
A
353 vap->va_mode |= (S_IFBLK);
354 break;
355 case DEV_SLNK:
91447636 356 VATTR_RETURN(vap, va_rdev, 0);
1c79356b
A
357 vap->va_mode |= (S_IFLNK);
358 break;
91447636
A
359 default:
360 VATTR_RETURN(vap, va_rdev, 0); /* default value only */
1c79356b 361 }
91447636
A
362 VATTR_RETURN(vap, va_type, vp->v_type);
363 VATTR_RETURN(vap, va_nlink, file_node->dn_links);
364 VATTR_RETURN(vap, va_uid, file_node->dn_uid);
365 VATTR_RETURN(vap, va_gid, file_node->dn_gid);
366 VATTR_RETURN(vap, va_fsid, (uintptr_t)file_node->dn_dvm);
367 VATTR_RETURN(vap, va_fileid, (uintptr_t)file_node);
368 VATTR_RETURN(vap, va_data_size, file_node->dn_len);
369
370 /* return an override block size (advisory) */
1c79356b 371 if (vp->v_type == VBLK)
91447636 372 VATTR_RETURN(vap, va_iosize, BLKDEV_IOSIZE);
1c79356b 373 else if (vp->v_type == VCHR)
91447636 374 VATTR_RETURN(vap, va_iosize, MAXPHYSIO);
1c79356b 375 else
91447636 376 VATTR_RETURN(vap, va_iosize, vp->v_mount->mnt_vfsstat.f_iosize);
1c79356b 377 /* if the time is bogus, set it to the boot time */
91447636
A
378 if (file_node->dn_ctime.tv_sec == 0) {
379 file_node->dn_ctime.tv_sec = boottime_sec();
380 file_node->dn_ctime.tv_nsec = 0;
381 }
1c79356b 382 if (file_node->dn_mtime.tv_sec == 0)
91447636 383 file_node->dn_mtime = file_node->dn_ctime;
1c79356b 384 if (file_node->dn_atime.tv_sec == 0)
91447636
A
385 file_node->dn_atime = file_node->dn_ctime;
386 VATTR_RETURN(vap, va_change_time, file_node->dn_ctime);
387 VATTR_RETURN(vap, va_modify_time, file_node->dn_mtime);
388 VATTR_RETURN(vap, va_access_time, file_node->dn_atime);
389 VATTR_RETURN(vap, va_gen, 0);
390 VATTR_RETURN(vap, va_flags, 0);
391 VATTR_RETURN(vap, va_filerev, 0);
392 VATTR_RETURN(vap, va_acl, NULL);
393
394 DEVFS_UNLOCK();
395
1c79356b
A
396 return 0;
397}
398
399static int
91447636
A
400devfs_setattr(struct vnop_setattr_args *ap)
401 /*struct vnop_setattr_args {
402 struct vnode *a_vp;
403 struct vnode_attr *a_vap;
404 vfs_context_t a_context;
405 } */
1c79356b 406{
91447636
A
407 struct vnode *vp = ap->a_vp;
408 struct vnode_attr *vap = ap->a_vap;
409 kauth_cred_t cred = vfs_context_ucred(ap->a_context);
410 struct proc *p = vfs_context_proc(ap->a_context);
411 int error = 0;
412 devnode_t * file_node;
413 struct timeval atimeval, mtimeval;
414
415 file_node = VTODN(vp);
416
417 DEVFS_LOCK();
418 /*
419 * Go through the fields and update if set.
420 */
421 if (VATTR_IS_ACTIVE(vap, va_access_time) || VATTR_IS_ACTIVE(vap, va_modify_time)) {
422
423
424 if (VATTR_IS_ACTIVE(vap, va_access_time))
425 file_node->dn_access = 1;
426 if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
427 file_node->dn_change = 1;
428 file_node->dn_update = 1;
1c79356b 429 }
91447636
A
430 atimeval.tv_sec = vap->va_access_time.tv_sec;
431 atimeval.tv_usec = vap->va_access_time.tv_nsec / 1000;
432 mtimeval.tv_sec = vap->va_modify_time.tv_sec;
433 mtimeval.tv_usec = vap->va_modify_time.tv_nsec / 1000;
434
435 if ( (error = devfs_update(vp, &atimeval, &mtimeval)) )
436 goto exit;
437 }
438 VATTR_SET_SUPPORTED(vap, va_access_time);
439 VATTR_SET_SUPPORTED(vap, va_change_time);
440
441 /*
442 * Change the permissions.
443 */
444 if (VATTR_IS_ACTIVE(vap, va_mode)) {
445 file_node->dn_mode &= ~07777;
446 file_node->dn_mode |= vap->va_mode & 07777;
447 }
448 VATTR_SET_SUPPORTED(vap, va_mode);
449
450 /*
451 * Change the owner.
452 */
453 if (VATTR_IS_ACTIVE(vap, va_uid))
454 file_node->dn_uid = vap->va_uid;
455 VATTR_SET_SUPPORTED(vap, va_uid);
456
457 /*
458 * Change the group.
459 */
460 if (VATTR_IS_ACTIVE(vap, va_gid))
461 file_node->dn_gid = vap->va_gid;
462 VATTR_SET_SUPPORTED(vap, va_gid);
463 exit:
464 DEVFS_UNLOCK();
465
1c79356b
A
466 return error;
467}
468
469static int
91447636
A
470devfs_read(struct vnop_read_args *ap)
471 /* struct vnop_read_args {
1c79356b
A
472 struct vnode *a_vp;
473 struct uio *a_uio;
474 int a_ioflag;
91447636 475 vfs_context_t a_context;
1c79356b
A
476 } */
477{
478 devnode_t * dn_p = VTODN(ap->a_vp);
479
480 switch (ap->a_vp->v_type) {
481 case VDIR: {
91447636
A
482 dn_p->dn_access = 1;
483
484 return VNOP_READDIR(ap->a_vp, ap->a_uio, 0, NULL, NULL, ap->a_context);
1c79356b
A
485 }
486 default: {
487 printf("devfs_read(): bad file type %d", ap->a_vp->v_type);
488 return(EINVAL);
489 break;
490 }
491 }
492 return (0); /* not reached */
493}
494
495static int
91447636
A
496devfs_close(struct vnop_close_args *ap)
497 /* struct vnop_close_args {
1c79356b
A
498 struct vnode *a_vp;
499 int a_fflag;
91447636
A
500 vfs_context_t a_context;
501 } */
1c79356b
A
502{
503 struct vnode * vp = ap->a_vp;
504 register devnode_t * dnp = VTODN(vp);
91447636 505 struct timeval now;
1c79356b 506
91447636
A
507 if (vnode_isinuse(vp, 1)) {
508 DEVFS_LOCK();
509 microtime(&now);
510 dn_times(dnp, &now, &now, &now);
511 DEVFS_UNLOCK();
512 }
1c79356b
A
513 return (0);
514}
515
516static int
91447636
A
517devfsspec_close(struct vnop_close_args *ap)
518 /* struct vnop_close_args {
1c79356b
A
519 struct vnode *a_vp;
520 int a_fflag;
91447636
A
521 vfs_context_t a_context;
522 } */
1c79356b
A
523{
524 struct vnode * vp = ap->a_vp;
525 register devnode_t * dnp = VTODN(vp);
91447636 526 struct timeval now;
1c79356b 527
91447636
A
528 if (vnode_isinuse(vp, 1)) {
529 DEVFS_LOCK();
530 microtime(&now);
531 dn_times(dnp, &now, &now, &now);
532 DEVFS_UNLOCK();
533 }
534 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_close), ap));
1c79356b
A
535}
536
537static int
91447636
A
538devfsspec_read(struct vnop_read_args *ap)
539 /* struct vnop_read_args {
1c79356b
A
540 struct vnode *a_vp;
541 struct uio *a_uio;
542 int a_ioflag;
91447636 543 kauth_cred_t a_cred;
1c79356b
A
544 } */
545{
91447636
A
546 register devnode_t * dnp = VTODN(ap->a_vp);
547
548 dnp->dn_access = 1;
549
550 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_read), ap));
1c79356b
A
551}
552
553static int
91447636
A
554devfsspec_write(struct vnop_write_args *ap)
555 /* struct vnop_write_args {
1c79356b
A
556 struct vnode *a_vp;
557 struct uio *a_uio;
558 int a_ioflag;
91447636 559 vfs_context_t a_context;
1c79356b
A
560 } */
561{
91447636
A
562 register devnode_t * dnp = VTODN(ap->a_vp);
563
564 dnp->dn_change = 1;
565 dnp->dn_update = 1;
566
567 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_write), ap));
1c79356b
A
568}
569
570/*
571 * Write data to a file or directory.
572 */
573static int
91447636
A
574devfs_write(struct vnop_write_args *ap)
575 /* struct vnop_write_args {
1c79356b
A
576 struct vnode *a_vp;
577 struct uio *a_uio;
578 int a_ioflag;
91447636 579 kauth_cred_t a_cred;
1c79356b
A
580 } */
581{
582 switch (ap->a_vp->v_type) {
583 case VDIR:
584 return(EISDIR);
585 default:
586 printf("devfs_write(): bad file type %d", ap->a_vp->v_type);
587 return (EINVAL);
588 }
589 return 0; /* not reached */
590}
591
592static int
91447636
A
593devfs_remove(struct vnop_remove_args *ap)
594 /* struct vnop_remove_args {
1c79356b
A
595 struct vnode *a_dvp;
596 struct vnode *a_vp;
597 struct componentname *a_cnp;
598 } */
599{
600 struct vnode *vp = ap->a_vp;
601 struct vnode *dvp = ap->a_dvp;
602 struct componentname *cnp = ap->a_cnp;
91447636 603 vfs_context_t ctx = cnp->cn_context;
1c79356b
A
604 devnode_t * tp;
605 devnode_t * tdp;
606 devdirent_t * tnp;
607 int doingdirectory = 0;
608 int error = 0;
91447636 609 uid_t ouruid = kauth_cred_getuid(vfs_context_ucred(ctx));
1c79356b
A
610
611 /*
91447636 612 * assume that the name is null terminated as they
1c79356b
A
613 * are the end of the path. Get pointers to all our
614 * devfs structures.
615 */
616 tp = VTODN(vp);
617 tdp = VTODN(dvp);
1c79356b 618
91447636
A
619 DEVFS_LOCK();
620
621 tnp = dev_findname(tdp, cnp->cn_nameptr);
622
623 if (tnp == NULL) {
624 error = ENOENT;
625 goto abort;
1c79356b
A
626 }
627
628 /*
629 * Make sure that we don't try do something stupid
630 */
631 if ((tp->dn_type) == DEV_DIR) {
632 /*
633 * Avoid ".", "..", and aliases of "." for obvious reasons.
634 */
635 if ( (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')
636 || (cnp->cn_flags&ISDOTDOT) ) {
637 error = EINVAL;
638 goto abort;
639 }
640 doingdirectory++;
641 }
642
643 /***********************************
644 * Start actually doing things.... *
645 ***********************************/
91447636
A
646 tdp->dn_change = 1;
647 tdp->dn_update = 1;
1c79356b 648
1c79356b
A
649 /*
650 * Target must be empty if a directory and have no links
651 * to it. Also, ensure source and target are compatible
652 * (both directories, or both not directories).
653 */
654 if (( doingdirectory) && (tp->dn_links > 2)) {
655 error = ENOTEMPTY;
656 goto abort;
657 }
1c79356b 658 dev_free_name(tnp);
91447636
A
659abort:
660 DEVFS_UNLOCK();
661
1c79356b
A
662 return (error);
663}
664
665/*
666 */
667static int
91447636
A
668devfs_link(struct vnop_link_args *ap)
669 /*struct vnop_link_args {
1c79356b
A
670 struct vnode *a_tdvp;
671 struct vnode *a_vp;
672 struct componentname *a_cnp;
91447636 673 vfs_context_t a_context;
1c79356b
A
674 } */
675{
676 struct vnode *vp = ap->a_vp;
677 struct vnode *tdvp = ap->a_tdvp;
678 struct componentname *cnp = ap->a_cnp;
1c79356b
A
679 devnode_t * fp;
680 devnode_t * tdp;
681 devdirent_t * tnp;
682 int error = 0;
91447636 683 struct timeval now;
1c79356b
A
684
685 /*
686 * First catch an arbitrary restriction for this FS
687 */
688 if (cnp->cn_namelen > DEVMAXNAMESIZE) {
689 error = ENAMETOOLONG;
690 goto out1;
691 }
692
693 /*
694 * Lock our directories and get our name pointers
695 * assume that the names are null terminated as they
696 * are the end of the path. Get pointers to all our
697 * devfs structures.
698 */
699 tdp = VTODN(tdvp);
700 fp = VTODN(vp);
701
702 if (tdvp->v_mount != vp->v_mount) {
91447636 703 return (EXDEV);
1c79356b 704 }
91447636 705 DEVFS_LOCK();
1c79356b 706
1c79356b
A
707
708 /***********************************
709 * Start actually doing things.... *
710 ***********************************/
91447636
A
711 fp->dn_change = 1;
712
713 microtime(&now);
714 error = devfs_update(vp, &now, &now);
715
1c79356b 716 if (!error) {
1c79356b 717 error = dev_add_name(cnp->cn_nameptr, tdp, NULL, fp, &tnp);
1c79356b
A
718 }
719out1:
91447636 720 DEVFS_UNLOCK();
1c79356b 721
91447636 722 return (error);
1c79356b
A
723}
724
725/*
726 * Rename system call. Seems overly complicated to me...
727 * rename("foo", "bar");
728 * is essentially
729 * unlink("bar");
730 * link("foo", "bar");
731 * unlink("foo");
732 * but ``atomically''.
733 *
734 * When the target exists, both the directory
735 * and target vnodes are locked.
736 * the source and source-parent vnodes are referenced
737 *
738 *
739 * Basic algorithm is:
740 *
741 * 1) Bump link count on source while we're linking it to the
742 * target. This also ensure the inode won't be deleted out
743 * from underneath us while we work (it may be truncated by
744 * a concurrent `trunc' or `open' for creation).
745 * 2) Link source to destination. If destination already exists,
746 * delete it first.
747 * 3) Unlink source reference to node if still around. If a
748 * directory was moved and the parent of the destination
749 * is different from the source, patch the ".." entry in the
750 * directory.
751 */
752static int
91447636
A
753devfs_rename(struct vnop_rename_args *ap)
754 /*struct vnop_rename_args {
1c79356b
A
755 struct vnode *a_fdvp;
756 struct vnode *a_fvp;
757 struct componentname *a_fcnp;
758 struct vnode *a_tdvp;
759 struct vnode *a_tvp;
760 struct componentname *a_tcnp;
91447636 761 vfs_context_t a_context;
1c79356b
A
762 } */
763{
764 struct vnode *tvp = ap->a_tvp;
765 struct vnode *tdvp = ap->a_tdvp;
766 struct vnode *fvp = ap->a_fvp;
767 struct vnode *fdvp = ap->a_fdvp;
768 struct componentname *tcnp = ap->a_tcnp;
769 struct componentname *fcnp = ap->a_fcnp;
1c79356b
A
770 devnode_t *fp, *fdp, *tp, *tdp;
771 devdirent_t *fnp,*tnp;
772 int doingdirectory = 0;
773 int error = 0;
91447636 774 struct timeval now;
1c79356b 775
91447636 776 DEVFS_LOCK();
1c79356b
A
777 /*
778 * First catch an arbitrary restriction for this FS
779 */
91447636 780 if (tcnp->cn_namelen > DEVMAXNAMESIZE) {
1c79356b 781 error = ENAMETOOLONG;
91447636 782 goto out;
1c79356b
A
783 }
784
785 /*
1c79356b
A
786 * assume that the names are null terminated as they
787 * are the end of the path. Get pointers to all our
788 * devfs structures.
789 */
790 tdp = VTODN(tdvp);
791 fdp = VTODN(fdvp);
792 fp = VTODN(fvp);
91447636
A
793
794 fnp = dev_findname(fdp, fcnp->cn_nameptr);
795
796 if (fnp == NULL) {
797 error = ENOENT;
798 goto out;
799 }
1c79356b
A
800 tp = NULL;
801 tnp = NULL;
91447636 802
1c79356b 803 if (tvp) {
91447636 804 tnp = dev_findname(tdp, tcnp->cn_nameptr);
1c79356b 805
91447636
A
806 if (tnp == NULL) {
807 error = ENOENT;
808 goto out;
809 }
810 tp = VTODN(tvp);
1c79356b 811 }
91447636 812
1c79356b
A
813 /*
814 * Make sure that we don't try do something stupid
815 */
816 if ((fp->dn_type) == DEV_DIR) {
817 /*
818 * Avoid ".", "..", and aliases of "." for obvious reasons.
819 */
820 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')
821 || (fcnp->cn_flags&ISDOTDOT)
822 || (tcnp->cn_namelen == 1 && tcnp->cn_nameptr[0] == '.')
823 || (tcnp->cn_flags&ISDOTDOT)
824 || (tdp == fp )) {
825 error = EINVAL;
91447636 826 goto out;
1c79356b
A
827 }
828 doingdirectory++;
829 }
830
831 /*
832 * If ".." must be changed (ie the directory gets a new
833 * parent) then the source directory must not be in the
834 * directory hierarchy above the target, as this would
835 * orphan everything below the source directory. Also
836 * the user must have write permission in the source so
837 * as to be able to change "..".
838 */
839 if (doingdirectory && (tdp != fdp)) {
840 devnode_t * tmp, *ntmp;
1c79356b
A
841 tmp = tdp;
842 do {
843 if(tmp == fp) {
844 /* XXX unlock stuff here probably */
845 error = EINVAL;
846 goto out;
847 }
848 ntmp = tmp;
849 } while ((tmp = tmp->dn_typeinfo.Dir.parent) != ntmp);
850 }
851
852 /***********************************
853 * Start actually doing things.... *
854 ***********************************/
91447636
A
855 fp->dn_change = 1;
856 microtime(&now);
857
858 if ( (error = devfs_update(fvp, &now, &now)) ) {
859 goto out;
1c79356b
A
860 }
861 /*
862 * Check if just deleting a link name.
863 */
864 if (fvp == tvp) {
865 if (fvp->v_type == VDIR) {
866 error = EINVAL;
91447636 867 goto out;
1c79356b 868 }
1c79356b 869 /* Release destination completely. */
1c79356b 870 dev_free_name(fnp);
91447636
A
871
872 DEVFS_UNLOCK();
1c79356b
A
873 return 0;
874 }
1c79356b
A
875 /*
876 * 1) Bump link count while we're moving stuff
877 * around. If we crash somewhere before
878 * completing our work, too bad :)
879 */
880 fp->dn_links++;
881 /*
882 * If the target exists zap it (unless it's a non-empty directory)
883 * We could do that as well but won't
884 */
885 if (tp) {
91447636 886 int ouruid = kauth_cred_getuid(vfs_context_ucred(tcnp->cn_context));
1c79356b
A
887 /*
888 * Target must be empty if a directory and have no links
889 * to it. Also, ensure source and target are compatible
890 * (both directories, or both not directories).
891 */
892 if (( doingdirectory) && (tp->dn_links > 2)) {
91447636
A
893 error = ENOTEMPTY;
894 goto bad;
1c79356b
A
895 }
896 dev_free_name(tnp);
897 tp = NULL;
898 }
899 dev_add_name(tcnp->cn_nameptr,tdp,NULL,fp,&tnp);
900 fnp->de_dnp = NULL;
901 fp->dn_links--; /* one less link to it.. */
1c79356b 902
91447636 903 dev_free_name(fnp);
1c79356b 904bad:
91447636 905 fp->dn_links--; /* we added one earlier*/
1c79356b 906out:
91447636 907 DEVFS_UNLOCK();
1c79356b
A
908 return (error);
909}
910
911static int
91447636
A
912devfs_symlink(struct vnop_symlink_args *ap)
913 /*struct vnop_symlink_args {
1c79356b
A
914 struct vnode *a_dvp;
915 struct vnode **a_vpp;
916 struct componentname *a_cnp;
91447636 917 struct vnode_attr *a_vap;
1c79356b 918 char *a_target;
91447636 919 vfs_context_t a_context;
1c79356b
A
920 } */
921{
55e303ae 922 struct componentname * cnp = ap->a_cnp;
91447636
A
923 vfs_context_t ctx = cnp->cn_context;
924 struct proc *p = vfs_context_proc(ctx);
1c79356b
A
925 int error = 0;
926 devnode_t * dir_p;
927 devnode_type_t typeinfo;
928 devdirent_t * nm_p;
929 devnode_t * dev_p;
91447636 930 struct vnode_attr * vap = ap->a_vap;
1c79356b 931 struct vnode * * vpp = ap->a_vpp;
1c79356b
A
932
933 dir_p = VTODN(ap->a_dvp);
934 typeinfo.Slnk.name = ap->a_target;
935 typeinfo.Slnk.namelen = strlen(ap->a_target);
91447636
A
936
937 DEVFS_LOCK();
1c79356b
A
938 error = dev_add_entry(cnp->cn_nameptr, dir_p, DEV_SLNK,
939 &typeinfo, NULL, NULL, &nm_p);
1c79356b
A
940 if (error) {
941 goto failure;
942 }
1c79356b
A
943 dev_p = nm_p->de_dnp;
944 dev_p->dn_uid = dir_p->dn_uid;
945 dev_p->dn_gid = dir_p->dn_gid;
946 dev_p->dn_mode = vap->va_mode;
947 dn_copy_times(dev_p, dir_p);
91447636 948
1c79356b 949 error = devfs_dntovn(dev_p, vpp, p);
55e303ae 950failure:
91447636
A
951 DEVFS_UNLOCK();
952
1c79356b
A
953 return error;
954}
955
956/*
957 * Mknod vnode call
958 */
91447636
A
959static int
960devfs_mknod(struct vnop_mknod_args *ap)
961 /* struct vnop_mknod_args {
1c79356b
A
962 struct vnode *a_dvp;
963 struct vnode **a_vpp;
964 struct componentname *a_cnp;
91447636
A
965 struct vnode_attr *a_vap;
966 vfs_context_t a_context;
967 } */
1c79356b
A
968{
969 struct componentname * cnp = ap->a_cnp;
91447636
A
970 vfs_context_t ctx = cnp->cn_context;
971 struct proc *p = vfs_context_proc(ctx);
1c79356b
A
972 devnode_t * dev_p;
973 devdirent_t * devent;
974 devnode_t * dir_p; /* devnode for parent directory */
975 struct vnode * dvp = ap->a_dvp;
976 int error = 0;
977 devnode_type_t typeinfo;
91447636 978 struct vnode_attr * vap = ap->a_vap;
1c79356b 979 struct vnode ** vpp = ap->a_vpp;
1c79356b
A
980
981 *vpp = NULL;
91447636
A
982 if (!(vap->va_type == VBLK) && !(vap->va_type == VCHR)) {
983 return (EINVAL); /* only support mknod of special files */
1c79356b
A
984 }
985 dir_p = VTODN(dvp);
986 typeinfo.dev = vap->va_rdev;
91447636
A
987
988 DEVFS_LOCK();
1c79356b
A
989 error = dev_add_entry(cnp->cn_nameptr, dir_p,
990 (vap->va_type == VBLK) ? DEV_BDEV : DEV_CDEV,
991 &typeinfo, NULL, NULL, &devent);
1c79356b 992 if (error) {
91447636 993 goto failure;
1c79356b
A
994 }
995 dev_p = devent->de_dnp;
996 error = devfs_dntovn(dev_p, vpp, p);
997 if (error)
91447636
A
998 goto failure;
999 dev_p->dn_uid = vap->va_uid;
1000 dev_p->dn_gid = vap->va_gid;
1c79356b 1001 dev_p->dn_mode = vap->va_mode;
91447636
A
1002 VATTR_SET_SUPPORTED(vap, va_uid);
1003 VATTR_SET_SUPPORTED(vap, va_gid);
1004 VATTR_SET_SUPPORTED(vap, va_mode);
55e303ae 1005failure:
91447636
A
1006 DEVFS_UNLOCK();
1007
1c79356b
A
1008 return (error);
1009}
1010
1011/*
1012 * Vnode op for readdir
1013 */
1014static int
91447636
A
1015devfs_readdir(struct vnop_readdir_args *ap)
1016 /*struct vnop_readdir_args {
1c79356b
A
1017 struct vnode *a_vp;
1018 struct uio *a_uio;
91447636
A
1019 int a_flags;
1020 int *a_eofflag;
1021 int *a_numdirent;
1022 vfs_context_t a_context;
1c79356b
A
1023 } */
1024{
1025 struct vnode *vp = ap->a_vp;
1026 struct uio *uio = ap->a_uio;
1027 struct dirent dirent;
1028 devnode_t * dir_node;
1029 devdirent_t * name_node;
1030 char *name;
1031 int error = 0;
1032 int reclen;
1033 int nodenumber;
1034 int startpos,pos;
91447636
A
1035
1036 if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF))
1037 return (EINVAL);
1c79356b
A
1038
1039 /* set up refs to dir */
1040 dir_node = VTODN(vp);
91447636 1041 if (dir_node->dn_type != DEV_DIR)
1c79356b 1042 return(ENOTDIR);
1c79356b
A
1043 pos = 0;
1044 startpos = uio->uio_offset;
91447636
A
1045
1046 DEVFS_LOCK();
1047
1c79356b
A
1048 name_node = dir_node->dn_typeinfo.Dir.dirlist;
1049 nodenumber = 0;
1c79356b 1050
91447636
A
1051 dir_node->dn_access = 1;
1052
1053 while ((name_node || (nodenumber < 2)) && (uio_resid(uio) > 0))
1c79356b
A
1054 {
1055 switch(nodenumber)
1056 {
1057 case 0:
1058 dirent.d_fileno = (int32_t)(void *)dir_node;
1059 name = ".";
1060 dirent.d_namlen = 1;
1061 dirent.d_type = DT_DIR;
1062 break;
1063 case 1:
1064 if(dir_node->dn_typeinfo.Dir.parent)
1065 dirent.d_fileno
1066 = (int32_t)dir_node->dn_typeinfo.Dir.parent;
1067 else
1068 dirent.d_fileno = (u_int32_t)dir_node;
1069 name = "..";
1070 dirent.d_namlen = 2;
1071 dirent.d_type = DT_DIR;
1072 break;
1073 default:
1074 dirent.d_fileno = (int32_t)(void *)name_node->de_dnp;
1075 dirent.d_namlen = strlen(name_node->de_name);
1076 name = name_node->de_name;
1077 switch(name_node->de_dnp->dn_type) {
1078 case DEV_BDEV:
1079 dirent.d_type = DT_BLK;
1080 break;
1081 case DEV_CDEV:
1082 dirent.d_type = DT_CHR;
1083 break;
1084 case DEV_DIR:
1085 dirent.d_type = DT_DIR;
1086 break;
1087 case DEV_SLNK:
1088 dirent.d_type = DT_LNK;
1089 break;
1090 default:
1091 dirent.d_type = DT_UNKNOWN;
1092 }
1093 }
1094#define GENERIC_DIRSIZ(dp) \
1095 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
1096
1097 reclen = dirent.d_reclen = GENERIC_DIRSIZ(&dirent);
1098
1099 if(pos >= startpos) /* made it to the offset yet? */
1100 {
91447636 1101 if (uio_resid(uio) < reclen) /* will it fit? */
1c79356b
A
1102 break;
1103 strcpy( dirent.d_name,name);
1104 if ((error = uiomove ((caddr_t)&dirent,
1105 dirent.d_reclen, uio)) != 0)
1106 break;
1107 }
1108 pos += reclen;
1109 if((nodenumber >1) && name_node)
1110 name_node = name_node->de_next;
1111 nodenumber++;
1112 }
91447636 1113 DEVFS_UNLOCK();
1c79356b
A
1114 uio->uio_offset = pos;
1115
1116 return (error);
1117}
1118
1119
1120/*
1121 */
1122static int
91447636
A
1123devfs_readlink(struct vnop_readlink_args *ap)
1124 /*struct vnop_readlink_args {
1c79356b
A
1125 struct vnode *a_vp;
1126 struct uio *a_uio;
91447636 1127 vfs_context_t a_context;
1c79356b
A
1128 } */
1129{
1130 struct vnode *vp = ap->a_vp;
1131 struct uio *uio = ap->a_uio;
1132 devnode_t * lnk_node;
1133 int error = 0;
1134
1135 /* set up refs to dir */
1136 lnk_node = VTODN(vp);
91447636
A
1137
1138 if (lnk_node->dn_type != DEV_SLNK) {
1139 error = EINVAL;
1140 goto out;
1c79356b
A
1141 }
1142 error = uiomove(lnk_node->dn_typeinfo.Slnk.name,
1143 lnk_node->dn_typeinfo.Slnk.namelen, uio);
91447636 1144out:
1c79356b
A
1145 return error;
1146}
1147
1c79356b 1148static int
91447636
A
1149devfs_reclaim(struct vnop_reclaim_args *ap)
1150 /*struct vnop_reclaim_args {
1c79356b
A
1151 struct vnode *a_vp;
1152 } */
1153{
1154 struct vnode * vp = ap->a_vp;
1155 devnode_t * dnp = VTODN(vp);
1156
91447636
A
1157 DEVFS_LOCK();
1158
1c79356b
A
1159 if (dnp) {
1160 /*
1161 * do the same as devfs_inactive in case it is not called
1162 * before us (can that ever happen?)
1163 */
1164 dnp->dn_vn = NULL;
1165 vp->v_data = NULL;
91447636 1166
1c79356b
A
1167 if (dnp->dn_delete) {
1168 devnode_free(dnp);
1169 }
1170 }
91447636
A
1171 DEVFS_UNLOCK();
1172
1c79356b
A
1173 return(0);
1174}
1175
91447636 1176
1c79356b 1177/*
91447636 1178 * Get configurable pathname variables.
1c79356b
A
1179 */
1180static int
91447636
A
1181devs_vnop_pathconf(
1182 struct vnop_pathconf_args /* {
1c79356b 1183 struct vnode *a_vp;
91447636
A
1184 int a_name;
1185 int *a_retval;
1186 vfs_context_t a_context;
1187 } */ *ap)
1c79356b 1188{
91447636
A
1189 switch (ap->a_name) {
1190 case _PC_LINK_MAX:
1191 /* arbitrary limit matching HFS; devfs has no hard limit */
1192 *ap->a_retval = 32767;
1193 break;
1194 case _PC_NAME_MAX:
1195 *ap->a_retval = DEVMAXNAMESIZE - 1; /* includes NUL */
1196 break;
1197 case _PC_PATH_MAX:
1198 *ap->a_retval = DEVMAXPATHSIZE - 1; /* XXX nonconformant */
1199 break;
1200 case _PC_CHOWN_RESTRICTED:
1201 *ap->a_retval = 1;
1202 break;
1203 case _PC_NO_TRUNC:
1204 *ap->a_retval = 0;
1205 break;
1206 case _PC_CASE_SENSITIVE:
1207 *ap->a_retval = 1;
1208 break;
1209 case _PC_CASE_PRESERVING:
1210 *ap->a_retval = 1;
1211 break;
1212 default:
1213 return (EINVAL);
1214 }
1c79356b
A
1215
1216 return (0);
1217}
1218
91447636
A
1219
1220
1c79356b
A
1221/**************************************************************************\
1222* pseudo ops *
1223\**************************************************************************/
1224
1225/*
1226 *
91447636 1227 * struct vnop_inactive_args {
1c79356b 1228 * struct vnode *a_vp;
91447636 1229 * vfs_context_t a_context;
1c79356b
A
1230 * }
1231 */
1232
1233static int
91447636 1234devfs_inactive(__unused struct vnop_inactive_args *ap)
1c79356b 1235{
1c79356b
A
1236 return (0);
1237}
1238
91447636
A
1239/*
1240 * called with DEVFS_LOCK held
1241 */
1242static int
1243devfs_update(struct vnode *vp, struct timeval *access, struct timeval *modify)
1c79356b 1244{
1c79356b 1245 devnode_t * ip;
91447636
A
1246 struct timeval now;
1247
1248 ip = VTODN(vp);
1249 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
1250 ip->dn_access = 0;
1251 ip->dn_change = 0;
1252 ip->dn_update = 0;
1c79356b 1253
1c79356b
A
1254 return (0);
1255 }
91447636
A
1256 microtime(&now);
1257 dn_times(ip, access, modify, &now);
1258
1c79356b
A
1259 return (0);
1260}
1261
1262#define VOPFUNC int (*)(void *)
1263
1264/* The following ops are used by directories and symlinks */
1265int (**devfs_vnodeop_p)(void *);
1266static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
91447636
A
1267 { &vnop_default_desc, (VOPFUNC)vn_default_error },
1268 { &vnop_lookup_desc, (VOPFUNC)devfs_lookup }, /* lookup */
1269 { &vnop_create_desc, (VOPFUNC)err_create }, /* create */
1270 { &vnop_whiteout_desc, (VOPFUNC)err_whiteout }, /* whiteout */
1271 { &vnop_mknod_desc, (VOPFUNC)devfs_mknod }, /* mknod */
1272 { &vnop_open_desc, (VOPFUNC)nop_open }, /* open */
1273 { &vnop_close_desc, (VOPFUNC)devfs_close }, /* close */
1274 { &vnop_getattr_desc, (VOPFUNC)devfs_getattr }, /* getattr */
1275 { &vnop_setattr_desc, (VOPFUNC)devfs_setattr }, /* setattr */
1276 { &vnop_read_desc, (VOPFUNC)devfs_read }, /* read */
1277 { &vnop_write_desc, (VOPFUNC)devfs_write }, /* write */
1278 { &vnop_ioctl_desc, (VOPFUNC)err_ioctl }, /* ioctl */
1279 { &vnop_select_desc, (VOPFUNC)err_select }, /* select */
1280 { &vnop_revoke_desc, (VOPFUNC)err_revoke }, /* revoke */
1281 { &vnop_mmap_desc, (VOPFUNC)err_mmap }, /* mmap */
1282 { &vnop_fsync_desc, (VOPFUNC)nop_fsync }, /* fsync */
1283 { &vnop_remove_desc, (VOPFUNC)devfs_remove }, /* remove */
1284 { &vnop_link_desc, (VOPFUNC)devfs_link }, /* link */
1285 { &vnop_rename_desc, (VOPFUNC)devfs_rename }, /* rename */
1286 { &vnop_mkdir_desc, (VOPFUNC)err_mkdir }, /* mkdir */
1287 { &vnop_rmdir_desc, (VOPFUNC)err_rmdir }, /* rmdir */
1288 { &vnop_symlink_desc, (VOPFUNC)devfs_symlink }, /* symlink */
1289 { &vnop_readdir_desc, (VOPFUNC)devfs_readdir }, /* readdir */
1290 { &vnop_readlink_desc, (VOPFUNC)devfs_readlink }, /* readlink */
1291 { &vnop_inactive_desc, (VOPFUNC)devfs_inactive }, /* inactive */
1292 { &vnop_reclaim_desc, (VOPFUNC)devfs_reclaim }, /* reclaim */
1293 { &vnop_strategy_desc, (VOPFUNC)err_strategy }, /* strategy */
1294 { &vnop_pathconf_desc, (VOPFUNC)devs_vnop_pathconf }, /* pathconf */
1295 { &vnop_advlock_desc, (VOPFUNC)err_advlock }, /* advlock */
1296 { &vnop_bwrite_desc, (VOPFUNC)err_bwrite },
1297 { &vnop_pagein_desc, (VOPFUNC)err_pagein }, /* Pagein */
1298 { &vnop_pageout_desc, (VOPFUNC)err_pageout }, /* Pageout */
1299 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */
1300 { &vnop_blktooff_desc, (VOPFUNC)err_blktooff }, /* blktooff */
1301 { &vnop_offtoblk_desc, (VOPFUNC)err_offtoblk }, /* offtoblk */
1302 { &vnop_blockmap_desc, (VOPFUNC)err_blockmap }, /* blockmap */
1c79356b
A
1303 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
1304};
1305struct vnodeopv_desc devfs_vnodeop_opv_desc =
1306 { &devfs_vnodeop_p, devfs_vnodeop_entries };
1307
1308/* The following ops are used by the device nodes */
1309int (**devfs_spec_vnodeop_p)(void *);
1310static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries[] = {
91447636
A
1311 { &vnop_default_desc, (VOPFUNC)vn_default_error },
1312 { &vnop_lookup_desc, (VOPFUNC)spec_lookup }, /* lookup */
1313 { &vnop_create_desc, (VOPFUNC)spec_create }, /* create */
1314 { &vnop_mknod_desc, (VOPFUNC)spec_mknod }, /* mknod */
1315 { &vnop_open_desc, (VOPFUNC)spec_open }, /* open */
1316 { &vnop_close_desc, (VOPFUNC)devfsspec_close }, /* close */
1317 { &vnop_getattr_desc, (VOPFUNC)devfs_getattr }, /* getattr */
1318 { &vnop_setattr_desc, (VOPFUNC)devfs_setattr }, /* setattr */
1319 { &vnop_read_desc, (VOPFUNC)devfsspec_read }, /* read */
1320 { &vnop_write_desc, (VOPFUNC)devfsspec_write }, /* write */
1321 { &vnop_ioctl_desc, (VOPFUNC)spec_ioctl }, /* ioctl */
1322 { &vnop_select_desc, (VOPFUNC)spec_select }, /* select */
1323 { &vnop_revoke_desc, (VOPFUNC)spec_revoke }, /* revoke */
1324 { &vnop_mmap_desc, (VOPFUNC)spec_mmap }, /* mmap */
1325 { &vnop_fsync_desc, (VOPFUNC)spec_fsync }, /* fsync */
1326 { &vnop_remove_desc, (VOPFUNC)devfs_remove }, /* remove */
1327 { &vnop_link_desc, (VOPFUNC)devfs_link }, /* link */
1328 { &vnop_rename_desc, (VOPFUNC)spec_rename }, /* rename */
1329 { &vnop_mkdir_desc, (VOPFUNC)spec_mkdir }, /* mkdir */
1330 { &vnop_rmdir_desc, (VOPFUNC)spec_rmdir }, /* rmdir */
1331 { &vnop_symlink_desc, (VOPFUNC)spec_symlink }, /* symlink */
1332 { &vnop_readdir_desc, (VOPFUNC)spec_readdir }, /* readdir */
1333 { &vnop_readlink_desc, (VOPFUNC)spec_readlink }, /* readlink */
1334 { &vnop_inactive_desc, (VOPFUNC)devfs_inactive }, /* inactive */
1335 { &vnop_reclaim_desc, (VOPFUNC)devfs_reclaim }, /* reclaim */
1336 { &vnop_strategy_desc, (VOPFUNC)spec_strategy }, /* strategy */
1337 { &vnop_pathconf_desc, (VOPFUNC)spec_pathconf }, /* pathconf */
1338 { &vnop_advlock_desc, (VOPFUNC)spec_advlock }, /* advlock */
1339 { &vnop_bwrite_desc, (VOPFUNC)vn_bwrite },
1340 { &vnop_devblocksize_desc, (VOPFUNC)spec_devblocksize }, /* devblocksize */
1341 { &vnop_pagein_desc, (VOPFUNC)err_pagein }, /* Pagein */
1342 { &vnop_pageout_desc, (VOPFUNC)err_pageout }, /* Pageout */
1343 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */
1344 { &vnop_blktooff_desc, (VOPFUNC)spec_blktooff }, /* blktooff */
1345 { &vnop_blktooff_desc, (VOPFUNC)spec_offtoblk }, /* blkofftoblk */
1346 { &vnop_blockmap_desc, (VOPFUNC)spec_blockmap }, /* blockmap */
1c79356b
A
1347 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
1348};
1349struct vnodeopv_desc devfs_spec_vnodeop_opv_desc =
1350 { &devfs_spec_vnodeop_p, devfs_spec_vnodeop_entries };
1351