advnops.c revision 1.20 1 /* $NetBSD: advnops.c,v 1.20 2006/05/15 01:29:02 christos Exp $ */
2
3 /*
4 * Copyright (c) 1994 Christian E. Hopps
5 * Copyright (c) 1996 Matthias Scheler
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Christian E. Hopps.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: advnops.c,v 1.20 2006/05/15 01:29:02 christos Exp $");
36
37 #if defined(_KERNEL_OPT)
38 #include "opt_quota.h"
39 #endif
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/vnode.h>
44 #include <sys/mount.h>
45 #include <sys/time.h>
46 #include <sys/queue.h>
47 #include <sys/namei.h>
48 #include <sys/buf.h>
49 #include <sys/dirent.h>
50 #include <sys/malloc.h>
51 #include <sys/pool.h>
52 #include <sys/stat.h>
53 #include <sys/unistd.h>
54 #include <sys/proc.h>
55 #include <sys/kauth.h>
56
57 #include <miscfs/genfs/genfs.h>
58 #include <miscfs/specfs/specdev.h>
59 #include <fs/adosfs/adosfs.h>
60
61 extern struct vnodeops adosfs_vnodeops;
62
63 #define adosfs_open genfs_nullop
64 int adosfs_getattr __P((void *));
65 int adosfs_read __P((void *));
66 int adosfs_write __P((void *));
67 #define adosfs_fcntl genfs_fcntl
68 #define adosfs_ioctl genfs_enoioctl
69 #define adosfs_poll genfs_poll
70 int adosfs_strategy __P((void *));
71 int adosfs_link __P((void *));
72 int adosfs_symlink __P((void *));
73 #define adosfs_abortop genfs_abortop
74 int adosfs_bmap __P((void *));
75 int adosfs_print __P((void *));
76 int adosfs_readdir __P((void *));
77 int adosfs_access __P((void *));
78 int adosfs_readlink __P((void *));
79 int adosfs_inactive __P((void *));
80 int adosfs_reclaim __P((void *));
81 int adosfs_pathconf __P((void *));
82
83 #define adosfs_close genfs_nullop
84 #define adosfs_fsync genfs_nullop
85 #define adosfs_lease_check genfs_lease_check
86 #define adosfs_seek genfs_seek
87
88 #define adosfs_advlock genfs_einval
89 #define adosfs_bwrite genfs_eopnotsupp
90 #define adosfs_create genfs_eopnotsupp
91 #define adosfs_mkdir genfs_eopnotsupp
92 #define adosfs_mknod genfs_eopnotsupp
93 #define adosfs_revoke genfs_revoke
94 #define adosfs_mmap genfs_mmap
95 #define adosfs_remove genfs_eopnotsupp
96 #define adosfs_rename genfs_eopnotsupp
97 #define adosfs_rmdir genfs_eopnotsupp
98 #define adosfs_setattr genfs_eopnotsupp
99
100 const struct vnodeopv_entry_desc adosfs_vnodeop_entries[] = {
101 { &vop_default_desc, vn_default_error },
102 { &vop_lookup_desc, adosfs_lookup }, /* lookup */
103 { &vop_create_desc, adosfs_create }, /* create */
104 { &vop_mknod_desc, adosfs_mknod }, /* mknod */
105 { &vop_open_desc, adosfs_open }, /* open */
106 { &vop_close_desc, adosfs_close }, /* close */
107 { &vop_access_desc, adosfs_access }, /* access */
108 { &vop_getattr_desc, adosfs_getattr }, /* getattr */
109 { &vop_setattr_desc, adosfs_setattr }, /* setattr */
110 { &vop_read_desc, adosfs_read }, /* read */
111 { &vop_write_desc, adosfs_write }, /* write */
112 { &vop_lease_desc, adosfs_lease_check }, /* lease */
113 { &vop_fcntl_desc, adosfs_fcntl }, /* fcntl */
114 { &vop_ioctl_desc, adosfs_ioctl }, /* ioctl */
115 { &vop_poll_desc, adosfs_poll }, /* poll */
116 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */
117 { &vop_revoke_desc, adosfs_revoke }, /* revoke */
118 { &vop_mmap_desc, adosfs_mmap }, /* mmap */
119 { &vop_fsync_desc, adosfs_fsync }, /* fsync */
120 { &vop_seek_desc, adosfs_seek }, /* seek */
121 { &vop_remove_desc, adosfs_remove }, /* remove */
122 { &vop_link_desc, adosfs_link }, /* link */
123 { &vop_rename_desc, adosfs_rename }, /* rename */
124 { &vop_mkdir_desc, adosfs_mkdir }, /* mkdir */
125 { &vop_rmdir_desc, adosfs_rmdir }, /* rmdir */
126 { &vop_symlink_desc, adosfs_symlink }, /* symlink */
127 { &vop_readdir_desc, adosfs_readdir }, /* readdir */
128 { &vop_readlink_desc, adosfs_readlink }, /* readlink */
129 { &vop_abortop_desc, adosfs_abortop }, /* abortop */
130 { &vop_inactive_desc, adosfs_inactive }, /* inactive */
131 { &vop_reclaim_desc, adosfs_reclaim }, /* reclaim */
132 { &vop_lock_desc, genfs_lock }, /* lock */
133 { &vop_unlock_desc, genfs_unlock }, /* unlock */
134 { &vop_bmap_desc, adosfs_bmap }, /* bmap */
135 { &vop_strategy_desc, adosfs_strategy }, /* strategy */
136 { &vop_print_desc, adosfs_print }, /* print */
137 { &vop_islocked_desc, genfs_islocked }, /* islocked */
138 { &vop_pathconf_desc, adosfs_pathconf }, /* pathconf */
139 { &vop_advlock_desc, adosfs_advlock }, /* advlock */
140 { &vop_bwrite_desc, adosfs_bwrite }, /* bwrite */
141 { &vop_getpages_desc, genfs_getpages }, /* getpages */
142 { &vop_putpages_desc, genfs_putpages }, /* putpages */
143 { NULL, NULL }
144 };
145
146 const struct vnodeopv_desc adosfs_vnodeop_opv_desc =
147 { &adosfs_vnodeop_p, adosfs_vnodeop_entries };
148
149 int
150 adosfs_getattr(v)
151 void *v;
152 {
153 struct vop_getattr_args /* {
154 struct vnode *a_vp;
155 struct vattr *a_vap;
156 kauth_cred_t a_cred;
157 struct lwp *a_l;
158 } */ *sp = v;
159 struct vattr *vap;
160 struct adosfsmount *amp;
161 struct anode *ap;
162 u_long fblks;
163
164 #ifdef ADOSFS_DIAGNOSTIC
165 advopprint(sp);
166 #endif
167 vap = sp->a_vap;
168 ap = VTOA(sp->a_vp);
169 amp = ap->amp;
170 vattr_null(vap);
171 vap->va_uid = ap->uid;
172 vap->va_gid = ap->gid;
173 vap->va_fsid = sp->a_vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
174 vap->va_atime.tv_sec = vap->va_mtime.tv_sec = vap->va_ctime.tv_sec =
175 ap->mtime.days * 24 * 60 * 60 + ap->mtime.mins * 60 +
176 ap->mtime.ticks / 50 + (8 * 365 + 2) * 24 * 60 * 60;
177 vap->va_atime.tv_nsec = vap->va_mtime.tv_nsec = vap->va_ctime.tv_nsec = 0;
178 vap->va_gen = 0;
179 vap->va_flags = 0;
180 vap->va_rdev = NODEV;
181 vap->va_fileid = ap->block;
182 vap->va_type = sp->a_vp->v_type;
183 vap->va_mode = adunixprot(ap->adprot) & amp->mask;
184 if (sp->a_vp->v_type == VDIR) {
185 vap->va_nlink = 1; /* XXX bogus, oh well */
186 vap->va_bytes = amp->bsize;
187 vap->va_size = amp->bsize;
188 } else {
189 /*
190 * XXX actually we can track this if we were to walk the list
191 * of links if it exists.
192 * XXX for now, just set nlink to 2 if this is a hard link
193 * to a file, or a file with a hard link.
194 */
195 vap->va_nlink = 1 + (ap->linkto != 0);
196 /*
197 * round up to nearest blocks add number of file list
198 * blocks needed and mutiply by number of bytes per block.
199 */
200 fblks = howmany(ap->fsize, amp->dbsize);
201 fblks += howmany(fblks, ANODENDATBLKENT(ap));
202 vap->va_bytes = fblks * amp->dbsize;
203 vap->va_size = ap->fsize;
204
205 vap->va_blocksize = amp->dbsize;
206 }
207 #ifdef ADOSFS_DIAGNOSTIC
208 printf(" 0)");
209 #endif
210 return(0);
211 }
212 /*
213 * are things locked??? they need to be to avoid this being
214 * deleted or changed (data block pointer blocks moving about.)
215 */
216 int
217 adosfs_read(v)
218 void *v;
219 {
220 struct vop_read_args /* {
221 struct vnode *a_vp;
222 struct uio *a_uio;
223 int a_ioflag;
224 kauth_cred_t a_cred;
225 } */ *sp = v;
226 struct vnode *vp = sp->a_vp;
227 struct adosfsmount *amp;
228 struct anode *ap;
229 struct uio *uio;
230 struct buf *bp;
231 daddr_t lbn;
232 int size, diff, error;
233 long n, on;
234
235 #ifdef ADOSFS_DIAGNOSTIC
236 advopprint(sp);
237 #endif
238 error = 0;
239 uio = sp->a_uio;
240 ap = VTOA(sp->a_vp);
241 amp = ap->amp;
242 /*
243 * Return EOF for character devices, EIO for others
244 */
245 if (sp->a_vp->v_type != VREG) {
246 error = EIO;
247 goto reterr;
248 }
249 if (uio->uio_resid == 0)
250 goto reterr;
251 if (uio->uio_offset < 0) {
252 error = EINVAL;
253 goto reterr;
254 }
255
256 /*
257 * to expensive to let general algorithm figure out that
258 * we are beyond the file. Do it now.
259 */
260 if (uio->uio_offset >= ap->fsize)
261 goto reterr;
262
263 /*
264 * taken from ufs_read()
265 */
266
267 if (vp->v_type == VREG && IS_FFS(amp)) {
268 const int advice = IO_ADV_DECODE(sp->a_ioflag);
269 error = 0;
270
271 while (uio->uio_resid > 0) {
272 void *win;
273 int flags;
274 vsize_t bytelen = MIN(ap->fsize - uio->uio_offset,
275 uio->uio_resid);
276
277 if (bytelen == 0) {
278 break;
279 }
280 win = ubc_alloc(&vp->v_uobj, uio->uio_offset,
281 &bytelen, advice, UBC_READ);
282 error = uiomove(win, bytelen, uio);
283 flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0;
284 ubc_release(win, flags);
285 if (error) {
286 break;
287 }
288 }
289 goto out;
290 }
291
292 do {
293 size = amp->dbsize;
294 lbn = uio->uio_offset / size;
295 on = uio->uio_offset % size;
296 n = MIN(size - on, uio->uio_resid);
297 diff = ap->fsize - uio->uio_offset;
298 /*
299 * check for EOF
300 */
301 if (diff <= 0)
302 return(0);
303 if (diff < n)
304 n = diff;
305 /*
306 * read ahead could possibly be worth something
307 * but not much as ados makes little attempt to
308 * make things contigous
309 */
310 error = bread(sp->a_vp, lbn, amp->bsize, NOCRED, &bp);
311 if (error) {
312 brelse(bp);
313 goto reterr;
314 }
315 if (!IS_FFS(amp)) {
316 if (bp->b_resid > 0)
317 error = EIO; /* OFS needs the complete block */
318 else if (adoswordn(bp, 0) != BPT_DATA) {
319 #ifdef DIAGNOSTIC
320 printf("adosfs: bad primary type blk %" PRId64 "\n",
321 bp->b_blkno / (amp->bsize / DEV_BSIZE));
322 #endif
323 error = EINVAL;
324 } else if (adoscksum(bp, ap->nwords)) {
325 #ifdef DIAGNOSTIC
326 printf("adosfs: blk %" PRId64 " failed cksum.\n",
327 bp->b_blkno / (amp->bsize / DEV_BSIZE));
328 #endif
329 error = EINVAL;
330 }
331 }
332
333 if (error) {
334 brelse(bp);
335 goto reterr;
336 }
337 #ifdef ADOSFS_DIAGNOSTIC
338 printf(" %d+%d-%d+%d", lbn, on, lbn, n);
339 #endif
340 n = MIN(n, size - bp->b_resid);
341 error = uiomove(bp->b_data + on +
342 amp->bsize - amp->dbsize, (int)n, uio);
343 brelse(bp);
344 } while (error == 0 && uio->uio_resid > 0 && n != 0);
345
346 out:
347 reterr:
348 #ifdef ADOSFS_DIAGNOSTIC
349 printf(" %d)", error);
350 #endif
351 return(error);
352 }
353
354 int
355 adosfs_write(v)
356 void *v;
357 {
358 #ifdef ADOSFS_DIAGNOSTIC
359 struct vop_write_args /* {
360 struct vnode *a_vp;
361 struct uio *a_uio;
362 int a_ioflag;
363 kauth_cred_t a_cred;
364 } */ *sp = v;
365 advopprint(sp);
366 printf(" EOPNOTSUPP)");
367 #endif
368 return(EOPNOTSUPP);
369 }
370
371 /*
372 * Just call the device strategy routine
373 */
374 int
375 adosfs_strategy(v)
376 void *v;
377 {
378 struct vop_strategy_args /* {
379 struct vnode *a_vp;
380 struct buf *a_bp;
381 } */ *sp = v;
382 struct buf *bp;
383 struct anode *ap;
384 struct vnode *vp;
385 int error;
386
387 #ifdef ADOSFS_DIAGNOSTIC
388 advopprint(sp);
389 #endif
390 bp = sp->a_bp;
391 if (bp->b_vp == NULL) {
392 bp->b_flags |= B_ERROR;
393 biodone(bp);
394 error = EIO;
395 goto reterr;
396 }
397 vp = sp->a_vp;
398 ap = VTOA(vp);
399 if (bp->b_blkno == bp->b_lblkno) {
400 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL);
401 if (error) {
402 bp->b_flags |= B_ERROR;
403 biodone(bp);
404 goto reterr;
405 }
406 }
407 if ((long)bp->b_blkno == -1) {
408 biodone(bp);
409 error = 0;
410 goto reterr;
411 }
412 vp = ap->amp->devvp;
413 error = VOP_STRATEGY(vp, bp);
414 reterr:
415 #ifdef ADOSFS_DIAGNOSTIC
416 printf(" %d)", error);
417 #endif
418 return(error);
419 }
420
421 int
422 adosfs_link(v)
423 void *v;
424 {
425 struct vop_link_args /* {
426 struct vnode *a_dvp;
427 struct vnode *a_vp;
428 struct componentname *a_cnp;
429 } */ *ap = v;
430
431 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
432 vput(ap->a_dvp);
433 return (EROFS);
434 }
435
436 int
437 adosfs_symlink(v)
438 void *v;
439 {
440 struct vop_symlink_args /* {
441 struct vnode *a_dvp;
442 struct vnode **a_vpp;
443 struct componentname *a_cnp;
444 struct vattr *a_vap;
445 char *a_target;
446 } */ *ap = v;
447
448 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
449 vput(ap->a_dvp);
450 return (EROFS);
451 }
452
453 /*
454 * Wait until the vnode has finished changing state.
455 */
456 int
457 adosfs_bmap(v)
458 void *v;
459 {
460 struct vop_bmap_args /* {
461 struct vnode *a_vp;
462 daddr_t a_bn;
463 struct vnode **a_vpp;
464 daddr_t *a_bnp;
465 int *a_runp;
466 } */ *sp = v;
467 struct anode *ap;
468 struct buf *flbp;
469 long nb, flblk, flblkoff, fcnt;
470 daddr_t *bnp;
471 daddr_t bn;
472 int error;
473
474 #ifdef ADOSFS_DIAGNOSTIC
475 advopprint(sp);
476 #endif
477 ap = VTOA(sp->a_vp);
478 bn = sp->a_bn;
479 bnp = sp->a_bnp;
480 if (sp->a_runp) {
481 *sp->a_runp = 0;
482 }
483 error = 0;
484
485 if (sp->a_vpp != NULL)
486 *sp->a_vpp = ap->amp->devvp;
487 if (bnp == NULL)
488 goto reterr;
489 if (bn < 0) {
490 error = EFBIG;
491 goto reterr;
492 }
493 if (sp->a_vp->v_type != VREG) {
494 error = EINVAL;
495 goto reterr;
496 }
497
498 /*
499 * walk the chain of file list blocks until we find
500 * the one that will yield the block pointer we need.
501 */
502 if (ap->type == AFILE)
503 nb = ap->block; /* pointer to ourself */
504 else if (ap->type == ALFILE)
505 nb = ap->linkto; /* pointer to real file */
506 else {
507 error = EINVAL;
508 goto reterr;
509 }
510
511 flblk = bn / ANODENDATBLKENT(ap);
512 flbp = NULL;
513
514 /*
515 * check last indirect block cache
516 */
517 if (flblk < ap->lastlindblk)
518 fcnt = 0;
519 else {
520 flblk -= ap->lastlindblk;
521 fcnt = ap->lastlindblk;
522 nb = ap->lastindblk;
523 }
524 while (flblk >= 0) {
525 if (flbp)
526 brelse(flbp);
527 if (nb == 0) {
528 #ifdef DIAGNOSTIC
529 printf("adosfs: bad file list chain.\n");
530 #endif
531 error = EINVAL;
532 goto reterr;
533 }
534 error = bread(ap->amp->devvp, nb * ap->amp->bsize / DEV_BSIZE,
535 ap->amp->bsize, NOCRED, &flbp);
536 if (error) {
537 brelse(flbp);
538 goto reterr;
539 }
540 if (adoscksum(flbp, ap->nwords)) {
541 #ifdef DIAGNOSTIC
542 printf("adosfs: blk %ld failed cksum.\n", nb);
543 #endif
544 brelse(flbp);
545 error = EINVAL;
546 goto reterr;
547 }
548 /*
549 * update last indirect block cache
550 */
551 ap->lastlindblk = fcnt++;
552 ap->lastindblk = nb;
553
554 nb = adoswordn(flbp, ap->nwords - 2);
555 flblk--;
556 }
557 /*
558 * calculate offset of block number in table. The table starts
559 * at nwords - 51 and goes to offset 6 or less if indicated by the
560 * valid table entries stored at offset ADBI_NBLKTABENT.
561 */
562 flblkoff = bn % ANODENDATBLKENT(ap);
563 if (flblkoff < adoswordn(flbp, 2 /* ADBI_NBLKTABENT */)) {
564 flblkoff = (ap->nwords - 51) - flblkoff;
565 *bnp = adoswordn(flbp, flblkoff) * ap->amp->bsize / DEV_BSIZE;
566 } else {
567 #ifdef DIAGNOSTIC
568 printf("flblk offset %ld too large in lblk %ld blk %" PRId64 "\n",
569 flblkoff, (long)bn, flbp->b_blkno);
570 #endif
571 error = EINVAL;
572 }
573 brelse(flbp);
574 reterr:
575 #ifdef ADOSFS_DIAGNOSTIC
576 if (error == 0 && bnp)
577 printf(" %lld => %lld", (long long)bn, (long long)*bnp);
578 printf(" %d)\n", error);
579 #endif
580 return(error);
581 }
582
583 /*
584 * Print out the contents of a adosfs vnode.
585 */
586 /* ARGSUSED */
587 int
588 adosfs_print(v)
589 void *v;
590 {
591 #if 0
592 struct vop_print_args /* {
593 struct vnode *a_vp;
594 } */ *sp = v;
595 #endif
596 return(0);
597 }
598
599 struct adirent {
600 u_long fileno;
601 u_short reclen;
602 char type;
603 char namlen;
604 char name[ADMAXNAMELEN+2]; /* maxlen plus 2 NUL's */
605 };
606
607 int
608 adosfs_readdir(v)
609 void *v;
610 {
611 struct vop_readdir_args /* {
612 struct vnode *a_vp;
613 struct uio *a_uio;
614 kauth_cred_t a_cred;
615 int *a_eofflag;
616 off_t **a_cookies;
617 int *a_ncookies;
618 } */ *sp = v;
619 int error, useri, chainc, hashi, scanned, uavail;
620 struct adirent ad, *adp;
621 struct anode *pap, *ap;
622 struct adosfsmount *amp;
623 struct vnode *vp;
624 struct uio *uio;
625 u_long nextbn;
626 off_t uoff, *cookies = NULL;
627 int ncookies = 0;
628
629 #ifdef ADOSFS_DIAGNOSTIC
630 advopprint(sp);
631 #endif
632 if (sp->a_vp->v_type != VDIR) {
633 error = ENOTDIR;
634 goto reterr;
635 }
636
637 uio = sp->a_uio;
638 uoff = uio->uio_offset;
639 if (uoff < 0) {
640 error = EINVAL;
641 goto reterr;
642 }
643
644 pap = VTOA(sp->a_vp);
645 amp = pap->amp;
646 adp = &ad;
647 error = nextbn = hashi = chainc = scanned = 0;
648 uavail = uio->uio_resid / sizeof(ad);
649 useri = uoff / sizeof(ad);
650
651 /*
652 * if no slots available or offset requested is not on a slot boundry
653 */
654 if (uavail < 1 || uoff % sizeof(ad)) {
655 error = EINVAL;
656 goto reterr;
657 }
658
659 if (sp->a_ncookies) {
660 ncookies = 0;
661 cookies = malloc(sizeof (off_t) * uavail, M_TEMP, M_WAITOK);
662 *sp->a_cookies = cookies;
663 }
664
665 while (uavail) {
666 if (hashi == pap->ntabent) {
667 *sp->a_eofflag = 1;
668 break;
669 }
670 if (pap->tab[hashi] == 0) {
671 hashi++;
672 continue;
673 }
674 if (nextbn == 0)
675 nextbn = pap->tab[hashi];
676
677 /*
678 * first determine if we can skip this chain
679 */
680 if (chainc == 0) {
681 int skip;
682
683 skip = useri - scanned;
684 if (pap->tabi[hashi] > 0 && pap->tabi[hashi] <= skip) {
685 scanned += pap->tabi[hashi];
686 hashi++;
687 nextbn = 0;
688 continue;
689 }
690 }
691
692 /*
693 * now [continue to] walk the chain
694 */
695 ap = NULL;
696 do {
697 error = VFS_VGET(amp->mp, (ino_t)nextbn, &vp);
698 if (error)
699 goto reterr;
700 ap = VTOA(vp);
701 scanned++;
702 chainc++;
703 nextbn = ap->hashf;
704
705 /*
706 * check for end of chain.
707 */
708 if (nextbn == 0) {
709 pap->tabi[hashi] = chainc;
710 hashi++;
711 chainc = 0;
712 } else if (pap->tabi[hashi] <= 0 &&
713 -chainc < pap->tabi[hashi])
714 pap->tabi[hashi] = -chainc;
715
716 if (useri >= scanned) {
717 vput(vp);
718 ap = NULL;
719 }
720 } while (ap == NULL && nextbn != 0);
721
722 /*
723 * we left the loop but without a result so do main over.
724 */
725 if (ap == NULL)
726 continue;
727 /*
728 * Fill in dirent record
729 */
730 memset(adp, 0, sizeof(struct adirent));
731 adp->fileno = ap->block;
732 /*
733 * this deserves an function in kern/vfs_subr.c
734 */
735 switch (ATOV(ap)->v_type) {
736 case VREG:
737 adp->type = DT_REG;
738 break;
739 case VDIR:
740 adp->type = DT_DIR;
741 break;
742 case VLNK:
743 adp->type = DT_LNK;
744 break;
745 default:
746 adp->type = DT_UNKNOWN;
747 break;
748 }
749 adp->reclen = sizeof(struct adirent);
750 adp->namlen = strlen(ap->name);
751 memcpy(adp->name, ap->name, adp->namlen);
752 vput(vp);
753
754 error = uiomove(adp, sizeof(struct adirent), uio);
755 if (error)
756 break;
757 if (sp->a_ncookies) {
758 *cookies++ = uoff;
759 ncookies++;
760 }
761 uoff += sizeof(struct adirent);
762 useri++;
763 uavail--;
764 }
765 #if doesnt_uiomove_handle_this
766 uio->uio_offset = uoff;
767 #endif
768 reterr:
769 #ifdef ADOSFS_DIAGNOSTIC
770 printf(" %d)", error);
771 #endif
772 if (sp->a_ncookies) {
773 if (error) {
774 free(*sp->a_cookies, M_TEMP);
775 *sp->a_ncookies = 0;
776 *sp->a_cookies = NULL;
777 } else
778 *sp->a_ncookies = ncookies;
779 }
780 return(error);
781 }
782
783
784 int
785 adosfs_access(v)
786 void *v;
787 {
788 struct vop_access_args /* {
789 struct vnode *a_vp;
790 int a_mode;
791 kauth_cred_t a_cred;
792 struct lwp *a_l;
793 } */ *sp = v;
794 struct anode *ap;
795 struct vnode *vp = sp->a_vp;
796 int error;
797
798 #ifdef ADOSFS_DIAGNOSTIC
799 advopprint(sp);
800 #endif
801
802 ap = VTOA(vp);
803 #ifdef DIAGNOSTIC
804 if (!VOP_ISLOCKED(vp)) {
805 vprint("adosfs_access: not locked", sp->a_vp);
806 panic("adosfs_access: not locked");
807 }
808 #endif
809 /*
810 * Disallow write attempts unless the file is a socket,
811 * fifo, or a block or character device resident on the
812 * file system.
813 */
814 if (sp->a_mode & VWRITE) {
815 switch (vp->v_type) {
816 case VDIR:
817 case VLNK:
818 case VREG:
819 return (EROFS);
820 default:
821 break;
822 }
823 }
824 #ifdef QUOTA
825 #endif
826 error = vaccess(sp->a_vp->v_type, adunixprot(ap->adprot) & ap->amp->mask,
827 ap->uid, ap->gid, sp->a_mode, sp->a_cred);
828 #ifdef ADOSFS_DIAGNOSTIC
829 printf(" %d)", error);
830 #endif
831 return(error);
832 }
833
834 int
835 adosfs_readlink(v)
836 void *v;
837 {
838 struct vop_readlink_args /* {
839 struct vnode *a_vp;
840 struct uio *a_uio;
841 kauth_cred_t a_cred;
842 } */ *sp = v;
843 struct anode *ap;
844 int error;
845
846 #ifdef ADOSFS_DIAGNOSTIC
847 advopprint(sp);
848 #endif
849 ap = VTOA(sp->a_vp);
850 error = uiomove(ap->slinkto, strlen(ap->slinkto), sp->a_uio);
851 #ifdef ADOSFS_DIAGNOSTIC
852 printf(" %d)", error);
853 #endif
854 return (error);
855 }
856
857 /*ARGSUSED*/
858 int
859 adosfs_inactive(v)
860 void *v;
861 {
862 struct vop_inactive_args /* {
863 struct vnode *a_vp;
864 struct lwp *a_l;
865 } */ *sp = v;
866 struct vnode *vp = sp->a_vp;
867 struct lwp *l = sp->a_l;
868 #ifdef ADOSFS_DIAGNOSTIC
869 advopprint(sp);
870 #endif
871 VOP_UNLOCK(vp, 0);
872 /* XXX this needs to check if file was deleted */
873 vrecycle(vp, NULL, l);
874
875 #ifdef ADOSFS_DIAGNOSTIC
876 printf(" 0)");
877 #endif
878 return(0);
879 }
880
881 /*
882 * the kernel wants its vnode back.
883 * no lock needed we are being called from vclean()
884 */
885 int
886 adosfs_reclaim(v)
887 void *v;
888 {
889 struct vop_reclaim_args /* {
890 struct vnode *a_vp;
891 } */ *sp = v;
892 struct vnode *vp;
893 struct anode *ap;
894
895 #ifdef ADOSFS_DIAGNOSTIC
896 printf("(reclaim 0)");
897 #endif
898 vp = sp->a_vp;
899 ap = VTOA(vp);
900 LIST_REMOVE(ap, link);
901 cache_purge(vp);
902 if (vp->v_type == VDIR && ap->tab)
903 free(ap->tab, M_ANODE);
904 else if (vp->v_type == VLNK && ap->slinkto)
905 free(ap->slinkto, M_ANODE);
906 pool_put(&adosfs_node_pool, ap);
907 vp->v_data = NULL;
908 return(0);
909 }
910
911 /*
912 * POSIX pathconf info, grabbed from kern/u fs, probably need to
913 * investigate exactly what each return type means as they are probably
914 * not valid currently
915 */
916 int
917 adosfs_pathconf(v)
918 void *v;
919 {
920 struct vop_pathconf_args /* {
921 struct vnode *a_vp;
922 int a_name;
923 register_t *a_retval;
924 } */ *ap = v;
925
926 switch (ap->a_name) {
927 case _PC_LINK_MAX:
928 *ap->a_retval = LINK_MAX;
929 return (0);
930 case _PC_NAME_MAX:
931 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_namemax;
932 return (0);
933 case _PC_PATH_MAX:
934 *ap->a_retval = PATH_MAX;
935 return (0);
936 case _PC_PIPE_BUF:
937 *ap->a_retval = PIPE_BUF;
938 return (0);
939 case _PC_CHOWN_RESTRICTED:
940 *ap->a_retval = 1;
941 return (0);
942 case _PC_VDISABLE:
943 *ap->a_retval = _POSIX_VDISABLE;
944 return (0);
945 case _PC_SYNC_IO:
946 *ap->a_retval = 1;
947 return (0);
948 case _PC_FILESIZEBITS:
949 *ap->a_retval = 32;
950 return (0);
951 default:
952 return (EINVAL);
953 }
954 /* NOTREACHED */
955 }
956