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