64c6d1d2dc
- remove special treatment of pager_map mappings in pmaps. this is required now, since I've removed the globals that expose the address range. pager_map now uses pmap_kenter_pa() instead of pmap_enter(), so there's no longer any need to special-case it. - eliminate struct uvm_vnode by moving its fields into struct vnode. - rewrite the pageout path. the pager is now responsible for handling the high-level requests instead of only getting control after a bunch of work has already been done on its behalf. this will allow us to UBCify LFS, which needs tighter control over its pages than other filesystems do. writing a page to disk no longer requires making it read-only, which allows us to write wired pages without causing all kinds of havoc. - use a new PG_PAGEOUT flag to indicate that a page should be freed on behalf of the pagedaemon when it's unlocked. this flag is very similar to PG_RELEASED, but unlike PG_RELEASED, PG_PAGEOUT can be cleared if the pageout fails due to eg. an indirect-block buffer being locked. this allows us to remove the "version" field from struct vm_page, and together with shrinking "loan_count" from 32 bits to 16, struct vm_page is now 4 bytes smaller. - no longer use PG_RELEASED for swap-backed pages. if the page is busy because it's being paged out, we can't release the swap slot to be reallocated until that write is complete, but unlike with vnodes we don't keep a count of in-progress writes so there's no good way to know when the write is done. instead, when we need to free a busy swap-backed page, just sleep until we can get it busy ourselves. - implement a fast-path for extending writes which allows us to avoid zeroing new pages. this substantially reduces cpu usage. - encapsulate the data used by the genfs code in a struct genfs_node, which must be the first element of the filesystem-specific vnode data for filesystems which use genfs_{get,put}pages(). - eliminate many of the UVM pagerops, since they aren't needed anymore now that the pager "put" operation is a higher-level operation. - enhance the genfs code to allow NFS to use the genfs_{get,put}pages instead of a modified copy. - clean up struct vnode by removing all the fields that used to be used by the vfs_cluster.c code (which we don't use anymore with UBC). - remove kmem_object and mb_object since they were useless. instead of allocating pages to these objects, we now just allocate pages with no object. such pages are mapped in the kernel until they are freed, so we can use the mapping to find the page to free it. this allows us to remove splvm() protection in several places. The sum of all these changes improves write throughput on my decstation 5000/200 to within 1% of the rate of NetBSD 1.5 and reduces the elapsed time for "make release" of a NetBSD 1.5 source tree on my 128MB pc to 10% less than a 1.5 kernel took.
860 lines
20 KiB
C
860 lines
20 KiB
C
/* $NetBSD: advfsops.c,v 1.48 2001/09/15 20:36:32 chs Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1994 Christian E. Hopps
|
|
* Copyright (c) 1996 Matthias Scheler
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Christian E. Hopps.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#if defined(_KERNEL_OPT)
|
|
#include "opt_compat_netbsd.h"
|
|
#endif
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/vnode.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/time.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/pool.h>
|
|
#include <sys/disklabel.h>
|
|
#include <miscfs/specfs/specdev.h> /* XXX */
|
|
#include <sys/fcntl.h>
|
|
#include <sys/namei.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/queue.h>
|
|
#include <sys/buf.h>
|
|
#include <adosfs/adosfs.h>
|
|
|
|
void adosfs_init __P((void));
|
|
void adosfs_reinit __P((void));
|
|
void adosfs_done __P((void));
|
|
int adosfs_mount __P((struct mount *, const char *, void *, struct nameidata *,
|
|
struct proc *));
|
|
int adosfs_start __P((struct mount *, int, struct proc *));
|
|
int adosfs_unmount __P((struct mount *, int, struct proc *));
|
|
int adosfs_root __P((struct mount *, struct vnode **));
|
|
int adosfs_quotactl __P((struct mount *, int, uid_t, caddr_t, struct proc *));
|
|
int adosfs_statfs __P((struct mount *, struct statfs *, struct proc *));
|
|
int adosfs_sync __P((struct mount *, int, struct ucred *, struct proc *));
|
|
int adosfs_vget __P((struct mount *, ino_t, struct vnode **));
|
|
int adosfs_fhtovp __P((struct mount *, struct fid *, struct vnode **));
|
|
int adosfs_checkexp __P((struct mount *, struct mbuf *, int *,
|
|
struct ucred **));
|
|
int adosfs_vptofh __P((struct vnode *, struct fid *));
|
|
|
|
int adosfs_mountfs __P((struct vnode *, struct mount *, struct proc *));
|
|
int adosfs_loadbitmap __P((struct adosfsmount *));
|
|
int adosfs_sysctl __P((int *, u_int, void *, size_t *, void *, size_t,
|
|
struct proc *));
|
|
|
|
struct simplelock adosfs_hashlock;
|
|
|
|
struct pool adosfs_node_pool;
|
|
|
|
int
|
|
adosfs_mount(mp, path, data, ndp, p)
|
|
struct mount *mp;
|
|
const char *path;
|
|
void *data;
|
|
struct nameidata *ndp;
|
|
struct proc *p;
|
|
{
|
|
struct vnode *devvp;
|
|
struct adosfs_args args;
|
|
struct adosfsmount *amp;
|
|
size_t size;
|
|
int error;
|
|
mode_t accessmode;
|
|
|
|
error = copyin(data, (caddr_t)&args, sizeof(struct adosfs_args));
|
|
if (error)
|
|
return(error);
|
|
|
|
#if 0
|
|
if (mp->mnt_flag & MNT_UPDATE)
|
|
return (EOPNOTSUPP);
|
|
#endif
|
|
if ((mp->mnt_flag & MNT_RDONLY) == 0)
|
|
return (EROFS);
|
|
/*
|
|
* If updating, check whether changing from read-only to
|
|
* read/write; if there is no device name, that's all we do.
|
|
*/
|
|
if (mp->mnt_flag & MNT_UPDATE) {
|
|
amp = VFSTOADOSFS(mp);
|
|
if (args.fspec == 0)
|
|
return (vfs_export(mp, &->export, &args.export));
|
|
}
|
|
/*
|
|
* Not an update, or updating the name: look up the name
|
|
* and verify that it refers to a sensible block device.
|
|
*/
|
|
NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
|
|
if ((error = namei(ndp)) != 0)
|
|
return (error);
|
|
devvp = ndp->ni_vp;
|
|
|
|
if (devvp->v_type != VBLK) {
|
|
vrele(devvp);
|
|
return (ENOTBLK);
|
|
}
|
|
if (major(devvp->v_rdev) >= nblkdev) {
|
|
vrele(devvp);
|
|
return (ENXIO);
|
|
}
|
|
/*
|
|
* If mount by non-root, then verify that user has necessary
|
|
* permissions on the device.
|
|
*/
|
|
if (p->p_ucred->cr_uid != 0) {
|
|
accessmode = VREAD;
|
|
if ((mp->mnt_flag & MNT_RDONLY) == 0)
|
|
accessmode |= VWRITE;
|
|
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
|
|
error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p);
|
|
if (error) {
|
|
vput(devvp);
|
|
return (error);
|
|
}
|
|
VOP_UNLOCK(devvp, 0);
|
|
}
|
|
/* MNT_UPDATE? */
|
|
if ((error = adosfs_mountfs(devvp, mp, p)) != 0) {
|
|
vrele(devvp);
|
|
return (error);
|
|
}
|
|
amp = VFSTOADOSFS(mp);
|
|
amp->uid = args.uid;
|
|
amp->gid = args.gid;
|
|
amp->mask = args.mask;
|
|
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
|
|
memset(mp->mnt_stat.f_mntonname + size, 0, MNAMELEN - size);
|
|
(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
|
|
&size);
|
|
memset(mp->mnt_stat.f_mntfromname + size, 0, MNAMELEN - size);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
adosfs_mountfs(devvp, mp, p)
|
|
struct vnode *devvp;
|
|
struct mount *mp;
|
|
struct proc *p;
|
|
{
|
|
struct disklabel dl;
|
|
struct partition *parp;
|
|
struct adosfsmount *amp;
|
|
struct buf *bp;
|
|
struct vnode *rvp;
|
|
int error, part, i;
|
|
|
|
part = DISKPART(devvp->v_rdev);
|
|
amp = NULL;
|
|
|
|
/*
|
|
* Disallow multiple mounts of the same device.
|
|
* Disallow mounting of a device that is currently in use
|
|
* (except for root, which might share swap device for miniroot).
|
|
* Flush out any old buffers remaining from a previous use.
|
|
*/
|
|
if ((error = vfs_mountedon(devvp)) != 0)
|
|
return (error);
|
|
if (vcount(devvp) > 1 && devvp != rootvp)
|
|
return (EBUSY);
|
|
if ((error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)) != 0)
|
|
return (error);
|
|
|
|
/*
|
|
* open blkdev and read root block
|
|
*/
|
|
if ((error = VOP_OPEN(devvp, FREAD, NOCRED, p)) != 0)
|
|
return (error);
|
|
error = VOP_IOCTL(devvp, DIOCGDINFO,(caddr_t)&dl, FREAD, NOCRED, p);
|
|
if (error)
|
|
goto fail;
|
|
|
|
parp = &dl.d_partitions[part];
|
|
amp = malloc(sizeof(struct adosfsmount), M_ADOSFSMNT, M_WAITOK);
|
|
memset((char *)amp, 0, (u_long)sizeof(struct adosfsmount));
|
|
amp->mp = mp;
|
|
if (dl.d_type == DTYPE_FLOPPY) {
|
|
amp->bsize = dl.d_secsize;
|
|
amp->secsperblk = 1;
|
|
}
|
|
else {
|
|
amp->bsize = parp->p_fsize * parp->p_frag;
|
|
amp->secsperblk = parp->p_frag;
|
|
}
|
|
|
|
/* invalid fs ? */
|
|
if (amp->secsperblk == 0) {
|
|
error = EINVAL;
|
|
goto fail;
|
|
}
|
|
|
|
bp = NULL;
|
|
if ((error = bread(devvp, (daddr_t)BBOFF,
|
|
amp->bsize, NOCRED, &bp)) != 0) {
|
|
brelse(bp);
|
|
goto fail;
|
|
}
|
|
amp->dostype = adoswordn(bp, 0);
|
|
brelse(bp);
|
|
|
|
/* basic sanity checks */
|
|
if (amp->dostype < 0x444f5300 || amp->dostype > 0x444f5305) {
|
|
error = EINVAL;
|
|
goto fail;
|
|
}
|
|
|
|
amp->rootb = (parp->p_size / amp->secsperblk - 1 + parp->p_cpg) >> 1;
|
|
amp->numblks = parp->p_size / amp->secsperblk - parp->p_cpg;
|
|
|
|
amp->nwords = amp->bsize >> 2;
|
|
amp->dbsize = amp->bsize - (IS_FFS(amp) ? 0 : OFS_DATA_OFFSET);
|
|
amp->devvp = devvp;
|
|
|
|
mp->mnt_data = (qaddr_t)amp;
|
|
mp->mnt_stat.f_fsid.val[0] = (long)devvp->v_rdev;
|
|
mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_ADOSFS);
|
|
mp->mnt_fs_bshift = ffs(amp->bsize) - 1;
|
|
mp->mnt_dev_bshift = DEV_BSHIFT; /* XXX */
|
|
mp->mnt_flag |= MNT_LOCAL;
|
|
|
|
/*
|
|
* init anode table.
|
|
*/
|
|
for (i = 0; i < ANODEHASHSZ; i++)
|
|
LIST_INIT(&->anodetab[i]);
|
|
|
|
/*
|
|
* get the root anode, if not a valid fs this will fail.
|
|
*/
|
|
if ((error = VFS_ROOT(mp, &rvp)) != 0)
|
|
goto fail;
|
|
/* allocate and load bitmap, set free space */
|
|
amp->bitmap = malloc(((amp->numblks + 31) / 32) * sizeof(*amp->bitmap),
|
|
M_ADOSFSBITMAP, M_WAITOK);
|
|
if (amp->bitmap)
|
|
adosfs_loadbitmap(amp);
|
|
if (mp->mnt_flag & MNT_RDONLY && amp->bitmap) {
|
|
/*
|
|
* Don't need the bitmap any more if it's read-only.
|
|
*/
|
|
free(amp->bitmap, M_ADOSFSBITMAP);
|
|
amp->bitmap = NULL;
|
|
}
|
|
vput(rvp);
|
|
|
|
return(0);
|
|
|
|
fail:
|
|
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
|
|
(void) VOP_CLOSE(devvp, FREAD, NOCRED, p);
|
|
VOP_UNLOCK(devvp, 0);
|
|
if (amp && amp->bitmap)
|
|
free(amp->bitmap, M_ADOSFSBITMAP);
|
|
if (amp)
|
|
free(amp, M_ADOSFSMNT);
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
adosfs_start(mp, flags, p)
|
|
struct mount *mp;
|
|
int flags;
|
|
struct proc *p;
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
adosfs_unmount(mp, mntflags, p)
|
|
struct mount *mp;
|
|
int mntflags;
|
|
struct proc *p;
|
|
{
|
|
struct adosfsmount *amp;
|
|
int error, flags;
|
|
|
|
flags = 0;
|
|
if (mntflags & MNT_FORCE)
|
|
flags |= FORCECLOSE;
|
|
if ((error = vflush(mp, NULLVP, flags)) != 0)
|
|
return (error);
|
|
amp = VFSTOADOSFS(mp);
|
|
if (amp->devvp->v_type != VBAD)
|
|
amp->devvp->v_specmountpoint = NULL;
|
|
vn_lock(amp->devvp, LK_EXCLUSIVE | LK_RETRY);
|
|
error = VOP_CLOSE(amp->devvp, FREAD, NOCRED, p);
|
|
vput(amp->devvp);
|
|
if (amp->bitmap)
|
|
free(amp->bitmap, M_ADOSFSBITMAP);
|
|
free(amp, M_ADOSFSMNT);
|
|
mp->mnt_data = (qaddr_t)0;
|
|
mp->mnt_flag &= ~MNT_LOCAL;
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
adosfs_root(mp, vpp)
|
|
struct mount *mp;
|
|
struct vnode **vpp;
|
|
{
|
|
struct vnode *nvp;
|
|
int error;
|
|
|
|
if ((error = VFS_VGET(mp, (ino_t)VFSTOADOSFS(mp)->rootb, &nvp)) != 0)
|
|
return (error);
|
|
/* XXX verify it's a root block? */
|
|
*vpp = nvp;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
adosfs_statfs(mp, sbp, p)
|
|
struct mount *mp;
|
|
struct statfs *sbp;
|
|
struct proc *p;
|
|
{
|
|
struct adosfsmount *amp;
|
|
|
|
amp = VFSTOADOSFS(mp);
|
|
#ifdef COMPAT_09
|
|
sbp->f_type = 16;
|
|
#else
|
|
sbp->f_type = 0;
|
|
#endif
|
|
sbp->f_bsize = amp->bsize;
|
|
sbp->f_iosize = amp->dbsize;
|
|
sbp->f_blocks = amp->numblks;
|
|
sbp->f_bfree = amp->freeblks;
|
|
sbp->f_bavail = amp->freeblks;
|
|
sbp->f_files = 0; /* who knows */
|
|
sbp->f_ffree = 0; /* " " */
|
|
if (sbp != &mp->mnt_stat) {
|
|
memcpy(sbp->f_mntonname, mp->mnt_stat.f_mntonname, MNAMELEN);
|
|
memcpy(sbp->f_mntfromname, mp->mnt_stat.f_mntfromname, MNAMELEN);
|
|
}
|
|
strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* lookup an anode, check mount's hash table if not found, create
|
|
* return locked and referenced al la vget(vp, 1);
|
|
*/
|
|
int
|
|
adosfs_vget(mp, an, vpp)
|
|
struct mount *mp;
|
|
ino_t an;
|
|
struct vnode **vpp;
|
|
{
|
|
struct adosfsmount *amp;
|
|
struct vnode *vp;
|
|
struct anode *ap;
|
|
struct buf *bp;
|
|
char *nam, *tmp;
|
|
int namlen, error;
|
|
|
|
error = 0;
|
|
amp = VFSTOADOSFS(mp);
|
|
bp = NULL;
|
|
|
|
/*
|
|
* check hash table. we are done if found
|
|
*/
|
|
if ((*vpp = adosfs_ahashget(mp, an)) != NULL)
|
|
return (0);
|
|
|
|
error = getnewvnode(VT_ADOSFS, mp, adosfs_vnodeop_p, &vp);
|
|
if (error)
|
|
return (error);
|
|
|
|
/*
|
|
* setup, insert in hash, and lock before io.
|
|
*/
|
|
vp->v_data = ap = pool_get(&adosfs_node_pool, PR_WAITOK);
|
|
memset(ap, 0, sizeof(struct anode));
|
|
ap->vp = vp;
|
|
ap->amp = amp;
|
|
ap->block = an;
|
|
ap->nwords = amp->nwords;
|
|
adosfs_ainshash(amp, ap);
|
|
|
|
if ((error = bread(amp->devvp, an * amp->bsize / DEV_BSIZE,
|
|
amp->bsize, NOCRED, &bp)) != 0) {
|
|
brelse(bp);
|
|
vput(vp);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* get type and fill rest in based on that.
|
|
*/
|
|
switch (ap->type = adosfs_getblktype(amp, bp)) {
|
|
case AROOT:
|
|
vp->v_type = VDIR;
|
|
vp->v_flag |= VROOT;
|
|
ap->mtimev.days = adoswordn(bp, ap->nwords - 10);
|
|
ap->mtimev.mins = adoswordn(bp, ap->nwords - 9);
|
|
ap->mtimev.ticks = adoswordn(bp, ap->nwords - 8);
|
|
ap->created.days = adoswordn(bp, ap->nwords - 7);
|
|
ap->created.mins = adoswordn(bp, ap->nwords - 6);
|
|
ap->created.ticks = adoswordn(bp, ap->nwords - 5);
|
|
break;
|
|
case ALDIR:
|
|
case ADIR:
|
|
vp->v_type = VDIR;
|
|
break;
|
|
case ALFILE:
|
|
case AFILE:
|
|
vp->v_type = VREG;
|
|
ap->fsize = adoswordn(bp, ap->nwords - 47);
|
|
break;
|
|
case ASLINK: /* XXX soft link */
|
|
vp->v_type = VLNK;
|
|
/*
|
|
* convert from BCPL string and
|
|
* from: "part:dir/file" to: "/part/dir/file"
|
|
*/
|
|
nam = bp->b_data + (6 * sizeof(long));
|
|
namlen = strlen(nam);
|
|
tmp = nam;
|
|
while (*tmp && *tmp != ':')
|
|
tmp++;
|
|
if (*tmp == 0) {
|
|
ap->slinkto = malloc(namlen + 1, M_ANODE, M_WAITOK);
|
|
memcpy(ap->slinkto, nam, namlen);
|
|
} else if (*nam == ':') {
|
|
ap->slinkto = malloc(namlen + 1, M_ANODE, M_WAITOK);
|
|
memcpy(ap->slinkto, nam, namlen);
|
|
ap->slinkto[0] = '/';
|
|
} else {
|
|
ap->slinkto = malloc(namlen + 2, M_ANODE, M_WAITOK);
|
|
ap->slinkto[0] = '/';
|
|
memcpy(&ap->slinkto[1], nam, namlen);
|
|
ap->slinkto[tmp - nam + 1] = '/';
|
|
namlen++;
|
|
}
|
|
ap->slinkto[namlen] = 0;
|
|
ap->fsize = namlen;
|
|
break;
|
|
default:
|
|
brelse(bp);
|
|
vput(vp);
|
|
return (EINVAL);
|
|
}
|
|
|
|
/*
|
|
* Get appropriate data from this block; hard link needs
|
|
* to get other data from the "real" block.
|
|
*/
|
|
|
|
/*
|
|
* copy in name (from original block)
|
|
*/
|
|
nam = bp->b_data + (ap->nwords - 20) * sizeof(u_int32_t);
|
|
namlen = *(u_char *)nam++;
|
|
if (namlen > 30) {
|
|
#ifdef DIAGNOSTIC
|
|
printf("adosfs: aget: name length too long blk %d\n", an);
|
|
#endif
|
|
brelse(bp);
|
|
vput(vp);
|
|
return (EINVAL);
|
|
}
|
|
memcpy(ap->name, nam, namlen);
|
|
ap->name[namlen] = 0;
|
|
|
|
/*
|
|
* if dir alloc hash table and copy it in
|
|
*/
|
|
if (vp->v_type == VDIR) {
|
|
int i;
|
|
|
|
ap->tab = malloc(ANODETABSZ(ap) * 2, M_ANODE, M_WAITOK);
|
|
ap->ntabent = ANODETABENT(ap);
|
|
ap->tabi = (int *)&ap->tab[ap->ntabent];
|
|
memset(ap->tabi, 0, ANODETABSZ(ap));
|
|
for (i = 0; i < ap->ntabent; i++)
|
|
ap->tab[i] = adoswordn(bp, i + 6);
|
|
}
|
|
|
|
/*
|
|
* misc.
|
|
*/
|
|
ap->pblock = adoswordn(bp, ap->nwords - 3);
|
|
ap->hashf = adoswordn(bp, ap->nwords - 4);
|
|
ap->linknext = adoswordn(bp, ap->nwords - 10);
|
|
ap->linkto = adoswordn(bp, ap->nwords - 11);
|
|
|
|
/*
|
|
* setup last indirect block cache.
|
|
*/
|
|
ap->lastlindblk = 0;
|
|
if (ap->type == AFILE) {
|
|
ap->lastindblk = ap->block;
|
|
if (adoswordn(bp, ap->nwords - 10))
|
|
ap->linkto = ap->block;
|
|
} else if (ap->type == ALFILE) {
|
|
ap->lastindblk = ap->linkto;
|
|
brelse(bp);
|
|
bp = NULL;
|
|
error = bread(amp->devvp, ap->linkto * amp->bsize / DEV_BSIZE,
|
|
amp->bsize, NOCRED, &bp);
|
|
if (error) {
|
|
brelse(bp);
|
|
vput(vp);
|
|
return (error);
|
|
}
|
|
ap->fsize = adoswordn(bp, ap->nwords - 47);
|
|
/*
|
|
* Should ap->block be set to the real file header block?
|
|
*/
|
|
ap->block = ap->linkto;
|
|
}
|
|
|
|
if (ap->type == AROOT) {
|
|
ap->adprot = 15;
|
|
ap->uid = amp->uid;
|
|
ap->gid = amp->gid;
|
|
} else {
|
|
ap->adprot = adoswordn(bp, ap->nwords - 48) ^ 15;
|
|
/*
|
|
* ADOS directories do not have a `x' protection bit as
|
|
* it is known in VFS; this functionality is fulfilled
|
|
* by the ADOS `r' bit.
|
|
*
|
|
* To retain the ADOS behaviour, fake execute permissions
|
|
* in that case.
|
|
*/
|
|
if ((ap->type == ADIR || ap->type == ALDIR) &&
|
|
(ap->adprot & 0x00000008) == 0)
|
|
ap->adprot &= ~0x00000002;
|
|
|
|
/*
|
|
* Get uid/gid from extensions in file header
|
|
* (really need to know if this is a muFS partition)
|
|
*/
|
|
ap->uid = (adoswordn(bp, ap->nwords - 49) >> 16) & 0xffff;
|
|
ap->gid = adoswordn(bp, ap->nwords - 49) & 0xffff;
|
|
if (ap->uid || ap->gid) {
|
|
if (ap->uid == 0xffff)
|
|
ap->uid = 0;
|
|
if (ap->gid == 0xffff)
|
|
ap->gid = 0;
|
|
ap->adprot |= 0x40000000; /* Kludge */
|
|
}
|
|
else {
|
|
/*
|
|
* uid & gid extension don't exist,
|
|
* so use the mount-point uid/gid
|
|
*/
|
|
ap->uid = amp->uid;
|
|
ap->gid = amp->gid;
|
|
}
|
|
}
|
|
ap->mtime.days = adoswordn(bp, ap->nwords - 23);
|
|
ap->mtime.mins = adoswordn(bp, ap->nwords - 22);
|
|
ap->mtime.ticks = adoswordn(bp, ap->nwords - 21);
|
|
|
|
*vpp = vp;
|
|
brelse(bp);
|
|
vp->v_size = ap->fsize;
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Load the bitmap into memory, and count the number of available
|
|
* blocks.
|
|
* The bitmap will be released if the filesystem is read-only; it's
|
|
* only needed to find the free space.
|
|
*/
|
|
int
|
|
adosfs_loadbitmap(amp)
|
|
struct adosfsmount *amp;
|
|
{
|
|
struct buf *bp, *mapbp;
|
|
u_long bn;
|
|
int blkix, endix, mapix;
|
|
int bmsize;
|
|
int error;
|
|
|
|
bp = mapbp = NULL;
|
|
bn = amp->rootb;
|
|
if ((error = bread(amp->devvp, bn * amp->bsize / DEV_BSIZE, amp->bsize,
|
|
NOCRED, &bp)) != 0) {
|
|
brelse(bp);
|
|
return (error);
|
|
}
|
|
blkix = amp->nwords - 49;
|
|
endix = amp->nwords - 24;
|
|
mapix = 0;
|
|
bmsize = (amp->numblks + 31) / 32;
|
|
while (mapix < bmsize) {
|
|
int n;
|
|
u_long bits;
|
|
|
|
if (adoswordn(bp, blkix) == 0)
|
|
break;
|
|
if (mapbp != NULL)
|
|
brelse(mapbp);
|
|
if ((error = bread(amp->devvp,
|
|
adoswordn(bp, blkix) * amp->bsize / DEV_BSIZE, amp->bsize,
|
|
NOCRED, &mapbp)) != 0)
|
|
break;
|
|
if (adoscksum(mapbp, amp->nwords)) {
|
|
#ifdef DIAGNOSTIC
|
|
printf("adosfs: loadbitmap - cksum of blk %d failed\n",
|
|
adoswordn(bp, blkix));
|
|
#endif
|
|
/* XXX Force read-only? Set free space 0? */
|
|
break;
|
|
}
|
|
n = 1;
|
|
while (n < amp->nwords && mapix < bmsize) {
|
|
amp->bitmap[mapix++] = bits = adoswordn(mapbp, n);
|
|
++n;
|
|
if (mapix == bmsize && amp->numblks & 31)
|
|
bits &= ~(0xffffffff << (amp->numblks & 31));
|
|
while (bits) {
|
|
if (bits & 1)
|
|
++amp->freeblks;
|
|
bits >>= 1;
|
|
}
|
|
}
|
|
++blkix;
|
|
if (mapix < bmsize && blkix == endix) {
|
|
bn = adoswordn(bp, blkix);
|
|
brelse(bp);
|
|
if ((error = bread(amp->devvp, bn * amp->bsize / DEV_BSIZE,
|
|
amp->bsize, NOCRED, &bp)) != 0)
|
|
break;
|
|
/*
|
|
* Why is there no checksum on these blocks?
|
|
*/
|
|
blkix = 0;
|
|
endix = amp->nwords - 1;
|
|
}
|
|
}
|
|
if (bp)
|
|
brelse(bp);
|
|
if (mapbp)
|
|
brelse(mapbp);
|
|
return (error);
|
|
}
|
|
|
|
|
|
/*
|
|
* File handle to vnode
|
|
*
|
|
* Have to be really careful about stale file handles:
|
|
* - check that the inode number is in range
|
|
* - call iget() to get the locked inode
|
|
* - check for an unallocated inode (i_mode == 0)
|
|
* - check that the generation number matches
|
|
*/
|
|
|
|
struct ifid {
|
|
ushort ifid_len;
|
|
ushort ifid_pad;
|
|
int ifid_ino;
|
|
long ifid_start;
|
|
};
|
|
|
|
int
|
|
adosfs_fhtovp(mp, fhp, vpp)
|
|
struct mount *mp;
|
|
struct fid *fhp;
|
|
struct vnode **vpp;
|
|
{
|
|
struct ifid *ifhp = (struct ifid *)fhp;
|
|
#if 0
|
|
struct anode *ap;
|
|
#endif
|
|
struct vnode *nvp;
|
|
int error;
|
|
|
|
#ifdef ADOSFS_DIAGNOSTIC
|
|
printf("adfhtovp(%x, %x, %x)\n", mp, fhp, vpp);
|
|
#endif
|
|
|
|
if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) {
|
|
*vpp = NULLVP;
|
|
return (error);
|
|
}
|
|
#if 0
|
|
ap = VTOA(nvp);
|
|
if (ap->inode.iso_mode == 0) {
|
|
vput(nvp);
|
|
*vpp = NULLVP;
|
|
return (ESTALE);
|
|
}
|
|
#endif
|
|
*vpp = nvp;
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
adosfs_checkexp(mp, nam, exflagsp, credanonp)
|
|
struct mount *mp;
|
|
struct mbuf *nam;
|
|
int *exflagsp;
|
|
struct ucred **credanonp;
|
|
{
|
|
struct adosfsmount *amp = VFSTOADOSFS(mp);
|
|
#if 0
|
|
struct anode *ap;
|
|
#endif
|
|
struct netcred *np;
|
|
|
|
#ifdef ADOSFS_DIAGNOSTIC
|
|
printf("adcheckexp(%x, %x, %x)\n", mp, nam, exflagsp);
|
|
#endif
|
|
|
|
/*
|
|
* Get the export permission structure for this <mp, client> tuple.
|
|
*/
|
|
np = vfs_export_lookup(mp, &->export, nam);
|
|
if (np == NULL)
|
|
return (EACCES);
|
|
|
|
*exflagsp = np->netc_exflags;
|
|
*credanonp = &np->netc_anon;
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
adosfs_vptofh(vp, fhp)
|
|
struct vnode *vp;
|
|
struct fid *fhp;
|
|
{
|
|
struct anode *ap = VTOA(vp);
|
|
struct ifid *ifhp;
|
|
|
|
ifhp = (struct ifid *)fhp;
|
|
ifhp->ifid_len = sizeof(struct ifid);
|
|
|
|
ifhp->ifid_ino = ap->block;
|
|
ifhp->ifid_start = ap->block;
|
|
|
|
#ifdef ADOSFS_DIAGNOSTIC
|
|
printf("advptofh(%x, %x)\n", vp, fhp);
|
|
#endif
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
adosfs_quotactl(mp, cmds, uid, arg, p)
|
|
struct mount *mp;
|
|
int cmds;
|
|
uid_t uid;
|
|
caddr_t arg;
|
|
struct proc *p;
|
|
{
|
|
return(EOPNOTSUPP);
|
|
}
|
|
|
|
int
|
|
adosfs_sync(mp, waitfor, uc, p)
|
|
struct mount *mp;
|
|
int waitfor;
|
|
struct ucred *uc;
|
|
struct proc *p;
|
|
{
|
|
#ifdef ADOSFS_DIAGNOSTIC
|
|
printf("ad_sync(%x, %x)\n", mp, waitfor);
|
|
#endif
|
|
return(0);
|
|
}
|
|
|
|
void
|
|
adosfs_init()
|
|
{
|
|
simple_lock_init(&adosfs_hashlock);
|
|
|
|
pool_init(&adosfs_node_pool, sizeof(struct anode), 0, 0, 0,
|
|
"adosndpl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
|
|
M_ANODE);
|
|
}
|
|
|
|
void
|
|
adosfs_done()
|
|
{
|
|
pool_destroy(&adosfs_node_pool);
|
|
}
|
|
|
|
int
|
|
adosfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
|
|
int *name;
|
|
u_int namelen;
|
|
void *oldp;
|
|
size_t *oldlenp;
|
|
void *newp;
|
|
size_t newlen;
|
|
struct proc *p;
|
|
{
|
|
return (EOPNOTSUPP);
|
|
}
|
|
|
|
/*
|
|
* vfs generic function call table
|
|
*/
|
|
|
|
extern const struct vnodeopv_desc adosfs_vnodeop_opv_desc;
|
|
|
|
const struct vnodeopv_desc *adosfs_vnodeopv_descs[] = {
|
|
&adosfs_vnodeop_opv_desc,
|
|
NULL,
|
|
};
|
|
|
|
struct vfsops adosfs_vfsops = {
|
|
MOUNT_ADOSFS,
|
|
adosfs_mount,
|
|
adosfs_start,
|
|
adosfs_unmount,
|
|
adosfs_root,
|
|
adosfs_quotactl,
|
|
adosfs_statfs,
|
|
adosfs_sync,
|
|
adosfs_vget,
|
|
adosfs_fhtovp,
|
|
adosfs_vptofh,
|
|
adosfs_init,
|
|
NULL,
|
|
adosfs_done,
|
|
adosfs_sysctl,
|
|
NULL, /* vfs_mountroot */
|
|
adosfs_checkexp,
|
|
adosfs_vnodeopv_descs,
|
|
};
|