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