1 /* $NetBSD: advnops.c,v 1.35 2009/07/03 21:17:40 elad Exp $ */
4 * Copyright (c) 1994 Christian E. Hopps
5 * Copyright (c) 1996 Matthias Scheler
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: advnops.c,v 1.35 2009/07/03 21:17:40 elad Exp $");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/vnode.h>
40 #include <sys/mount.h>
42 #include <sys/queue.h>
43 #include <sys/namei.h>
45 #include <sys/dirent.h>
46 #include <sys/inttypes.h>
47 #include <sys/malloc.h>
50 #include <sys/unistd.h>
52 #include <sys/kauth.h>
54 #include <miscfs/genfs/genfs.h>
55 #include <miscfs/specfs/specdev.h>
56 #include <fs/adosfs/adosfs.h>
58 extern struct vnodeops adosfs_vnodeops
;
60 #define adosfs_open genfs_nullop
61 int adosfs_getattr(void *);
62 int adosfs_read(void *);
63 int adosfs_write(void *);
64 #define adosfs_fcntl genfs_fcntl
65 #define adosfs_ioctl genfs_enoioctl
66 #define adosfs_poll genfs_poll
67 int adosfs_strategy(void *);
68 int adosfs_link(void *);
69 int adosfs_symlink(void *);
70 #define adosfs_abortop genfs_abortop
71 int adosfs_bmap(void *);
72 int adosfs_print(void *);
73 int adosfs_readdir(void *);
74 int adosfs_access(void *);
75 int adosfs_readlink(void *);
76 int adosfs_inactive(void *);
77 int adosfs_reclaim(void *);
78 int adosfs_pathconf(void *);
80 #define adosfs_close genfs_nullop
81 #define adosfs_fsync genfs_nullop
82 #define adosfs_seek genfs_seek
84 #define adosfs_advlock genfs_einval
85 #define adosfs_bwrite genfs_eopnotsupp
86 #define adosfs_create genfs_eopnotsupp
87 #define adosfs_mkdir genfs_eopnotsupp
88 #define adosfs_mknod genfs_eopnotsupp
89 #define adosfs_revoke genfs_revoke
90 #define adosfs_mmap genfs_mmap
91 #define adosfs_remove genfs_eopnotsupp
92 #define adosfs_rename genfs_eopnotsupp
93 #define adosfs_rmdir genfs_eopnotsupp
94 #define adosfs_setattr genfs_eopnotsupp
96 const struct vnodeopv_entry_desc adosfs_vnodeop_entries
[] = {
97 { &vop_default_desc
, vn_default_error
},
98 { &vop_lookup_desc
, adosfs_lookup
}, /* lookup */
99 { &vop_create_desc
, adosfs_create
}, /* create */
100 { &vop_mknod_desc
, adosfs_mknod
}, /* mknod */
101 { &vop_open_desc
, adosfs_open
}, /* open */
102 { &vop_close_desc
, adosfs_close
}, /* close */
103 { &vop_access_desc
, adosfs_access
}, /* access */
104 { &vop_getattr_desc
, adosfs_getattr
}, /* getattr */
105 { &vop_setattr_desc
, adosfs_setattr
}, /* setattr */
106 { &vop_read_desc
, adosfs_read
}, /* read */
107 { &vop_write_desc
, adosfs_write
}, /* write */
108 { &vop_fcntl_desc
, adosfs_fcntl
}, /* fcntl */
109 { &vop_ioctl_desc
, adosfs_ioctl
}, /* ioctl */
110 { &vop_poll_desc
, adosfs_poll
}, /* poll */
111 { &vop_kqfilter_desc
, genfs_kqfilter
}, /* kqfilter */
112 { &vop_revoke_desc
, adosfs_revoke
}, /* revoke */
113 { &vop_mmap_desc
, adosfs_mmap
}, /* mmap */
114 { &vop_fsync_desc
, adosfs_fsync
}, /* fsync */
115 { &vop_seek_desc
, adosfs_seek
}, /* seek */
116 { &vop_remove_desc
, adosfs_remove
}, /* remove */
117 { &vop_link_desc
, adosfs_link
}, /* link */
118 { &vop_rename_desc
, adosfs_rename
}, /* rename */
119 { &vop_mkdir_desc
, adosfs_mkdir
}, /* mkdir */
120 { &vop_rmdir_desc
, adosfs_rmdir
}, /* rmdir */
121 { &vop_symlink_desc
, adosfs_symlink
}, /* symlink */
122 { &vop_readdir_desc
, adosfs_readdir
}, /* readdir */
123 { &vop_readlink_desc
, adosfs_readlink
}, /* readlink */
124 { &vop_abortop_desc
, adosfs_abortop
}, /* abortop */
125 { &vop_inactive_desc
, adosfs_inactive
}, /* inactive */
126 { &vop_reclaim_desc
, adosfs_reclaim
}, /* reclaim */
127 { &vop_lock_desc
, genfs_lock
}, /* lock */
128 { &vop_unlock_desc
, genfs_unlock
}, /* unlock */
129 { &vop_bmap_desc
, adosfs_bmap
}, /* bmap */
130 { &vop_strategy_desc
, adosfs_strategy
}, /* strategy */
131 { &vop_print_desc
, adosfs_print
}, /* print */
132 { &vop_islocked_desc
, genfs_islocked
}, /* islocked */
133 { &vop_pathconf_desc
, adosfs_pathconf
}, /* pathconf */
134 { &vop_advlock_desc
, adosfs_advlock
}, /* advlock */
135 { &vop_bwrite_desc
, adosfs_bwrite
}, /* bwrite */
136 { &vop_getpages_desc
, genfs_getpages
}, /* getpages */
137 { &vop_putpages_desc
, genfs_putpages
}, /* putpages */
141 const struct vnodeopv_desc adosfs_vnodeop_opv_desc
=
142 { &adosfs_vnodeop_p
, adosfs_vnodeop_entries
};
145 adosfs_getattr(void *v
)
147 struct vop_getattr_args
/* {
153 struct adosfsmount
*amp
;
157 #ifdef ADOSFS_DIAGNOSTIC
164 vap
->va_uid
= ap
->uid
;
165 vap
->va_gid
= ap
->gid
;
166 vap
->va_fsid
= sp
->a_vp
->v_mount
->mnt_stat
.f_fsidx
.__fsid_val
[0];
167 vap
->va_atime
.tv_sec
= vap
->va_mtime
.tv_sec
= vap
->va_ctime
.tv_sec
=
168 ap
->mtime
.days
* 24 * 60 * 60 + ap
->mtime
.mins
* 60 +
169 ap
->mtime
.ticks
/ 50 + (8 * 365 + 2) * 24 * 60 * 60;
170 vap
->va_atime
.tv_nsec
= vap
->va_mtime
.tv_nsec
= vap
->va_ctime
.tv_nsec
= 0;
173 vap
->va_rdev
= NODEV
;
174 vap
->va_fileid
= ap
->block
;
175 vap
->va_type
= sp
->a_vp
->v_type
;
176 vap
->va_mode
= adunixprot(ap
->adprot
) & amp
->mask
;
177 if (sp
->a_vp
->v_type
== VDIR
) {
178 vap
->va_nlink
= 1; /* XXX bogus, oh well */
179 vap
->va_bytes
= amp
->bsize
;
180 vap
->va_size
= amp
->bsize
;
183 * XXX actually we can track this if we were to walk the list
184 * of links if it exists.
185 * XXX for now, just set nlink to 2 if this is a hard link
186 * to a file, or a file with a hard link.
188 vap
->va_nlink
= 1 + (ap
->linkto
!= 0);
190 * round up to nearest blocks add number of file list
191 * blocks needed and mutiply by number of bytes per block.
193 fblks
= howmany(ap
->fsize
, amp
->dbsize
);
194 fblks
+= howmany(fblks
, ANODENDATBLKENT(ap
));
195 vap
->va_bytes
= fblks
* amp
->dbsize
;
196 vap
->va_size
= ap
->fsize
;
198 vap
->va_blocksize
= amp
->dbsize
;
200 #ifdef ADOSFS_DIAGNOSTIC
206 * are things locked??? they need to be to avoid this being
207 * deleted or changed (data block pointer blocks moving about.)
212 struct vop_read_args
/* {
218 struct vnode
*vp
= sp
->a_vp
;
219 struct adosfsmount
*amp
;
224 int size
, diff
, error
;
227 #ifdef ADOSFS_DIAGNOSTIC
235 * Return EOF for character devices, EIO for others
237 if (sp
->a_vp
->v_type
!= VREG
) {
241 if (uio
->uio_resid
== 0)
243 if (uio
->uio_offset
< 0) {
249 * to expensive to let general algorithm figure out that
250 * we are beyond the file. Do it now.
252 if (uio
->uio_offset
>= ap
->fsize
)
256 * taken from ufs_read()
259 if (vp
->v_type
== VREG
&& IS_FFS(amp
)) {
260 const int advice
= IO_ADV_DECODE(sp
->a_ioflag
);
263 while (uio
->uio_resid
> 0) {
264 vsize_t bytelen
= MIN(ap
->fsize
- uio
->uio_offset
,
270 error
= ubc_uiomove(&vp
->v_uobj
, uio
, bytelen
, advice
,
271 UBC_READ
| UBC_PARTIALOK
| UBC_UNMAP_FLAG(vp
));
281 lbn
= uio
->uio_offset
/ size
;
282 on
= uio
->uio_offset
% size
;
283 n
= MIN(size
- on
, uio
->uio_resid
);
284 diff
= ap
->fsize
- uio
->uio_offset
;
293 * read ahead could possibly be worth something
294 * but not much as ados makes little attempt to
295 * make things contigous
297 error
= bread(sp
->a_vp
, lbn
, amp
->bsize
, NOCRED
, 0, &bp
);
304 error
= EIO
; /* OFS needs the complete block */
305 else if (adoswordn(bp
, 0) != BPT_DATA
) {
307 printf("adosfs: bad primary type blk %" PRId64
"\n",
308 bp
->b_blkno
/ (amp
->bsize
/ DEV_BSIZE
));
311 } else if (adoscksum(bp
, ap
->nwords
)) {
313 printf("adosfs: blk %" PRId64
" failed cksum.\n",
314 bp
->b_blkno
/ (amp
->bsize
/ DEV_BSIZE
));
324 #ifdef ADOSFS_DIAGNOSTIC
325 printf(" %" PRId64
"+%ld-%" PRId64
"+%ld", lbn
, on
, lbn
, n
);
327 n
= MIN(n
, size
- bp
->b_resid
);
328 error
= uiomove((char *)bp
->b_data
+ on
+
329 amp
->bsize
- amp
->dbsize
, (int)n
, uio
);
331 } while (error
== 0 && uio
->uio_resid
> 0 && n
!= 0);
335 #ifdef ADOSFS_DIAGNOSTIC
336 printf(" %d)", error
);
342 adosfs_write(void *v
)
344 #ifdef ADOSFS_DIAGNOSTIC
346 struct vop_write_args
/* {
354 printf(" EOPNOTSUPP)");
360 * Just call the device strategy routine
363 adosfs_strategy(void *v
)
365 struct vop_strategy_args
/* {
374 #ifdef ADOSFS_DIAGNOSTIC
378 if (bp
->b_vp
== NULL
) {
386 if (bp
->b_blkno
== bp
->b_lblkno
) {
387 error
= VOP_BMAP(vp
, bp
->b_lblkno
, NULL
, &bp
->b_blkno
, NULL
);
394 if ((long)bp
->b_blkno
== -1) {
400 error
= VOP_STRATEGY(vp
, bp
);
402 #ifdef ADOSFS_DIAGNOSTIC
403 printf(" %d)", error
);
411 struct vop_link_args
/* {
414 struct componentname *a_cnp;
417 VOP_ABORTOP(ap
->a_dvp
, ap
->a_cnp
);
423 adosfs_symlink(void *v
)
425 struct vop_symlink_args
/* {
427 struct vnode **a_vpp;
428 struct componentname *a_cnp;
433 VOP_ABORTOP(ap
->a_dvp
, ap
->a_cnp
);
439 * Wait until the vnode has finished changing state.
444 struct vop_bmap_args
/* {
447 struct vnode **a_vpp;
453 long nb
, flblk
, flblkoff
, fcnt
;
458 #ifdef ADOSFS_DIAGNOSTIC
469 if (sp
->a_vpp
!= NULL
)
470 *sp
->a_vpp
= ap
->amp
->devvp
;
477 if (sp
->a_vp
->v_type
!= VREG
) {
483 * walk the chain of file list blocks until we find
484 * the one that will yield the block pointer we need.
486 if (ap
->type
== AFILE
)
487 nb
= ap
->block
; /* pointer to ourself */
488 else if (ap
->type
== ALFILE
)
489 nb
= ap
->linkto
; /* pointer to real file */
495 flblk
= bn
/ ANODENDATBLKENT(ap
);
499 * check last indirect block cache
501 if (flblk
< ap
->lastlindblk
)
504 flblk
-= ap
->lastlindblk
;
505 fcnt
= ap
->lastlindblk
;
513 printf("adosfs: bad file list chain.\n");
518 error
= bread(ap
->amp
->devvp
, nb
* ap
->amp
->bsize
/ DEV_BSIZE
,
519 ap
->amp
->bsize
, NOCRED
, 0, &flbp
);
524 if (adoscksum(flbp
, ap
->nwords
)) {
526 printf("adosfs: blk %ld failed cksum.\n", nb
);
533 * update last indirect block cache
535 ap
->lastlindblk
= fcnt
++;
538 nb
= adoswordn(flbp
, ap
->nwords
- 2);
542 * calculate offset of block number in table. The table starts
543 * at nwords - 51 and goes to offset 6 or less if indicated by the
544 * valid table entries stored at offset ADBI_NBLKTABENT.
546 flblkoff
= bn
% ANODENDATBLKENT(ap
);
547 if (flblkoff
< adoswordn(flbp
, 2 /* ADBI_NBLKTABENT */)) {
548 flblkoff
= (ap
->nwords
- 51) - flblkoff
;
549 *bnp
= adoswordn(flbp
, flblkoff
) * ap
->amp
->bsize
/ DEV_BSIZE
;
552 printf("flblk offset %ld too large in lblk %ld blk %" PRId64
"\n",
553 flblkoff
, (long)bn
, flbp
->b_blkno
);
559 #ifdef ADOSFS_DIAGNOSTIC
560 if (error
== 0 && bnp
)
561 printf(" %lld => %lld", (long long)bn
, (long long)*bnp
);
562 printf(" %d)\n", error
);
568 * Print out the contents of a adosfs vnode.
572 adosfs_print(void *v
)
575 struct vop_print_args
/* {
583 adosfs_readdir(void *v
)
585 struct vop_readdir_args
/* {
593 int error
, first
, useri
, chainc
, hashi
, scanned
;
595 struct dirent ad
, *adp
;
596 struct anode
*pap
, *ap
;
598 struct uio
*uio
= sp
->a_uio
;
599 off_t uoff
= uio
->uio_offset
;
600 off_t
*cookies
= NULL
;
603 #ifdef ADOSFS_DIAGNOSTIC
607 if (sp
->a_vp
->v_type
!= VDIR
) {
617 pap
= VTOA(sp
->a_vp
);
619 error
= nextbn
= hashi
= chainc
= scanned
= 0;
620 first
= useri
= uoff
/ sizeof ad
;
623 * If offset requested is not on a slot boundary
625 if (uoff
% sizeof ad
) {
631 if (hashi
== pap
->ntabent
) {
635 if (pap
->tab
[hashi
] == 0) {
640 nextbn
= pap
->tab
[hashi
];
643 * First determine if we can skip this chain
648 skip
= useri
- scanned
;
649 if (pap
->tabi
[hashi
] > 0 && pap
->tabi
[hashi
] <= skip
) {
650 scanned
+= pap
->tabi
[hashi
];
658 * Now [continue to] walk the chain
662 error
= VFS_VGET(pap
->amp
->mp
, (ino_t
)nextbn
, &vp
);
671 * check for end of chain.
674 pap
->tabi
[hashi
] = chainc
;
677 } else if (pap
->tabi
[hashi
] <= 0 &&
678 -chainc
< pap
->tabi
[hashi
])
679 pap
->tabi
[hashi
] = -chainc
;
681 if (useri
>= scanned
) {
685 } while (ap
== NULL
&& nextbn
!= 0);
688 * We left the loop but without a result so do main over.
693 * Fill in dirent record
695 memset(adp
, 0, sizeof *adp
);
696 adp
->d_fileno
= ap
->block
;
698 * This deserves a function in kern/vfs_subr.c
700 switch (ATOV(ap
)->v_type
) {
702 adp
->d_type
= DT_REG
;
705 adp
->d_type
= DT_DIR
;
708 adp
->d_type
= DT_LNK
;
711 adp
->d_type
= DT_UNKNOWN
;
714 adp
->d_namlen
= strlen(ap
->name
);
715 memcpy(adp
->d_name
, ap
->name
, adp
->d_namlen
);
716 adp
->d_reclen
= _DIRENT_SIZE(adp
);
719 if (adp
->d_reclen
> uio
->uio_resid
) {
720 if (useri
== first
) /* no room for even one entry */
724 error
= uiomove(adp
, adp
->d_reclen
, uio
);
729 ncookies
= useri
- first
;
730 uio
->uio_offset
= uoff
+ ncookies
* sizeof ad
;
732 #ifdef ADOSFS_DIAGNOSTIC
733 printf(" %d)", error
);
735 if (sp
->a_ncookies
!= NULL
) {
736 *sp
->a_ncookies
= ncookies
;
738 *sp
->a_cookies
= cookies
=
739 malloc(ncookies
* sizeof *cookies
, M_TEMP
, M_WAITOK
);
746 *sp
->a_cookies
= NULL
;
753 adosfs_check_possible(struct vnode
*vp
, struct anode
*ap
, mode_t mode
)
757 * Disallow write attempts unless the file is a socket,
758 * fifo, or a block or character device resident on the
762 switch (vp
->v_type
) {
776 adosfs_check_permitted(struct vnode
*vp
, struct anode
*ap
, mode_t mode
,
780 return genfs_can_access(vp
->v_type
,
781 adunixprot(ap
->adprot
) & ap
->amp
->mask
, ap
->uid
, ap
->gid
, mode
,
786 adosfs_access(void *v
)
788 struct vop_access_args
/* {
794 struct vnode
*vp
= sp
->a_vp
;
797 #ifdef ADOSFS_DIAGNOSTIC
803 if (!VOP_ISLOCKED(vp
)) {
804 vprint("adosfs_access: not locked", sp
->a_vp
);
805 panic("adosfs_access: not locked");
809 error
= adosfs_check_possible(vp
, ap
, sp
->a_mode
);
813 error
= adosfs_check_permitted(vp
, ap
, sp
->a_mode
, sp
->a_cred
);
815 #ifdef ADOSFS_DIAGNOSTIC
816 printf(" %d)", error
);
822 adosfs_readlink(void *v
)
824 struct vop_readlink_args
/* {
832 #ifdef ADOSFS_DIAGNOSTIC
836 error
= uiomove(ap
->slinkto
, strlen(ap
->slinkto
), sp
->a_uio
);
837 #ifdef ADOSFS_DIAGNOSTIC
838 printf(" %d)", error
);
845 adosfs_inactive(void *v
)
847 struct vop_inactive_args
/* {
851 struct vnode
*vp
= sp
->a_vp
;
852 #ifdef ADOSFS_DIAGNOSTIC
856 /* XXX this needs to check if file was deleted */
857 *sp
->a_recycle
= true;
859 #ifdef ADOSFS_DIAGNOSTIC
866 * the kernel wants its vnode back.
867 * no lock needed we are being called from vclean()
870 adosfs_reclaim(void *v
)
872 struct vop_reclaim_args
/* {
878 #ifdef ADOSFS_DIAGNOSTIC
879 printf("(reclaim 0)");
883 LIST_REMOVE(ap
, link
);
885 if (vp
->v_type
== VDIR
&& ap
->tab
)
886 free(ap
->tab
, M_ANODE
);
887 else if (vp
->v_type
== VLNK
&& ap
->slinkto
)
888 free(ap
->slinkto
, M_ANODE
);
889 genfs_node_destroy(vp
);
890 pool_put(&adosfs_node_pool
, ap
);
896 * POSIX pathconf info, grabbed from kern/u fs, probably need to
897 * investigate exactly what each return type means as they are probably
898 * not valid currently
901 adosfs_pathconf(void *v
)
903 struct vop_pathconf_args
/* {
906 register_t *a_retval;
909 switch (ap
->a_name
) {
911 *ap
->a_retval
= LINK_MAX
;
914 *ap
->a_retval
= ap
->a_vp
->v_mount
->mnt_stat
.f_namemax
;
917 *ap
->a_retval
= PATH_MAX
;
920 *ap
->a_retval
= PIPE_BUF
;
922 case _PC_CHOWN_RESTRICTED
:
926 *ap
->a_retval
= _POSIX_VDISABLE
;
931 case _PC_FILESIZEBITS
: