From d813e119cd6c679612501334a33729686df556cc Mon Sep 17 00:00:00 2001 From: dillon Date: Sun, 19 Sep 1999 06:24:21 +0000 Subject: [PATCH] Fix BOOTP root FS mounts. Also cleanup vfs_getnewfsid() and collapse addaliasu() into addalias() (no operational change) and clarify comments relating to a trick that vclean() uses. The fix to BOOTP is yet another hack. Actually, rootfsid handling is already a major hack. The whole thing needs to be cleaned up. Reviewed by: David Greenman , Alan Cox --- sys/kern/vfs_conf.c | 22 +++++++++++++++- sys/kern/vfs_export.c | 58 +++++++++++++++++++++++++++---------------- sys/kern/vfs_mount.c | 22 +++++++++++++++- sys/kern/vfs_subr.c | 58 +++++++++++++++++++++++++++---------------- sys/sys/mount.h | 1 + 5 files changed, 117 insertions(+), 44 deletions(-) diff --git a/sys/kern/vfs_conf.c b/sys/kern/vfs_conf.c index 87f3e4a7bc93..7c11af72172f 100644 --- a/sys/kern/vfs_conf.c +++ b/sys/kern/vfs_conf.c @@ -136,7 +136,27 @@ vfs_mountrootfs(void *unused) mp->mnt_flag |= MNT_ROOTFS; /* - * Attempt the mount + * If we have no idea what the device is because the VFS root mount + * initialization code couldn't figure it out, take a guess by + * assuming that vfs_getnewfsid() will be called when we try the + * mount. For the moment this is necessary for NFS-baesd BOOTP + * boots. Ultimately we would like to get rid of 'rootdev' entirely + * and go with a linked list of possible roots and device-specific + * auxillary data that we do not try to interpret ourselves. + */ + if (rootdev == NODEV && rootdevs[0] == NODEV) + rootdev = vfs_getrootfsid(mp); + + /* + * Attempt the mount. This is rather messy due to many historical + * layers. Basically what it comes down to is that 'rootdev' is an + * override to the rootdevs[] array. The rootdevs[] array itself + * cannot normally be accessed directly by other modules, but FFS + * plays with it. NFS, on the otherhand, has no clue what the + * device assignment for a mount will be until it actually does it. + * + * During the loop we set rootdev to rootdevs[i]. This is used + * by FFS and a few other modules. It is ignored by NFS. */ err = ENXIO; orootdev = rootdev; diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c index 757e4aa5255c..6737312c436e 100644 --- a/sys/kern/vfs_export.c +++ b/sys/kern/vfs_export.c @@ -333,35 +333,54 @@ vfs_getvfs(fsid) /* * Get a new unique fsid + * + * Keep in mind that several mounts may be running in parallel, + * so always increment mntid_base even if lower numbers are available. */ + +static u_short mntid_base; + void vfs_getnewfsid(mp) struct mount *mp; { - static u_short xxxfs_mntid; - fsid_t tfsid; int mtype; simple_lock(&mntid_slock); + mtype = mp->mnt_vfc->vfc_typenum; - mp->mnt_stat.f_fsid.val[0] = makeudev(255, mtype); - mp->mnt_stat.f_fsid.val[1] = mtype; - if (xxxfs_mntid == 0) - ++xxxfs_mntid; - tfsid.val[0] = makeudev(255, mtype + (xxxfs_mntid << 16)); - tfsid.val[1] = mtype; - if (mountlist.cqh_first != (void *)&mountlist) { - while (vfs_getvfs(&tfsid)) { - xxxfs_mntid++; - tfsid.val[0] = makeudev(255, - mtype + (xxxfs_mntid << 16)); - } + for (;;) { + tfsid.val[0] = makeudev(255, mtype + (mntid_base << 16)); + tfsid.val[1] = mtype; + ++mntid_base; + if (vfs_getvfs(&tfsid) == NULL) + break; } + mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; + mp->mnt_stat.f_fsid.val[1] = tfsid.val[1]; + simple_unlock(&mntid_slock); } +/* + * Get what should become the root fsid. + * + * This is somewhat of a hack. If the rootdev is not known we + * assume that vfs_getnewfsid() will be called momentarily to + * allocate it, and we return what vfs_getnewfsid() will return. + */ + +dev_t +vfs_getrootfsid(struct mount *mp) +{ + int mtype; + + mtype = mp->mnt_vfc->vfc_typenum; + return(makedev(255, mtype + (mntid_base << 16))); +} + /* * Knob to control the precision of file timestamps: * @@ -1303,11 +1322,7 @@ addaliasu(nvp, nvp_rdev) if (nvp->v_type != VBLK && nvp->v_type != VCHR) panic("addaliasu on non-special vnode"); - - nvp->v_rdev = udev2dev(nvp_rdev, nvp->v_type == VBLK ? 1 : 0); - simple_lock(&spechash_slock); - SLIST_INSERT_HEAD(&nvp->v_rdev->si_hlist, nvp, v_specnext); - simple_unlock(&spechash_slock); + addalias(nvp, udev2dev(nvp_rdev, nvp->v_type == VBLK ? 1 : 0)); } void @@ -1650,8 +1665,9 @@ vclean(vp, flags, p) if ((obj = vp->v_object) != NULL) { if (obj->ref_count == 0) { /* - * This is a normal way of shutting down the object/vnode - * association. + * vclean() may be called twice. The first time removes the + * primary reference to the object, the second time goes + * one further and is a special-case to terminate the object. */ vm_object_terminate(obj); } else { diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 87f3e4a7bc93..7c11af72172f 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -136,7 +136,27 @@ vfs_mountrootfs(void *unused) mp->mnt_flag |= MNT_ROOTFS; /* - * Attempt the mount + * If we have no idea what the device is because the VFS root mount + * initialization code couldn't figure it out, take a guess by + * assuming that vfs_getnewfsid() will be called when we try the + * mount. For the moment this is necessary for NFS-baesd BOOTP + * boots. Ultimately we would like to get rid of 'rootdev' entirely + * and go with a linked list of possible roots and device-specific + * auxillary data that we do not try to interpret ourselves. + */ + if (rootdev == NODEV && rootdevs[0] == NODEV) + rootdev = vfs_getrootfsid(mp); + + /* + * Attempt the mount. This is rather messy due to many historical + * layers. Basically what it comes down to is that 'rootdev' is an + * override to the rootdevs[] array. The rootdevs[] array itself + * cannot normally be accessed directly by other modules, but FFS + * plays with it. NFS, on the otherhand, has no clue what the + * device assignment for a mount will be until it actually does it. + * + * During the loop we set rootdev to rootdevs[i]. This is used + * by FFS and a few other modules. It is ignored by NFS. */ err = ENXIO; orootdev = rootdev; diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 757e4aa5255c..6737312c436e 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -333,35 +333,54 @@ vfs_getvfs(fsid) /* * Get a new unique fsid + * + * Keep in mind that several mounts may be running in parallel, + * so always increment mntid_base even if lower numbers are available. */ + +static u_short mntid_base; + void vfs_getnewfsid(mp) struct mount *mp; { - static u_short xxxfs_mntid; - fsid_t tfsid; int mtype; simple_lock(&mntid_slock); + mtype = mp->mnt_vfc->vfc_typenum; - mp->mnt_stat.f_fsid.val[0] = makeudev(255, mtype); - mp->mnt_stat.f_fsid.val[1] = mtype; - if (xxxfs_mntid == 0) - ++xxxfs_mntid; - tfsid.val[0] = makeudev(255, mtype + (xxxfs_mntid << 16)); - tfsid.val[1] = mtype; - if (mountlist.cqh_first != (void *)&mountlist) { - while (vfs_getvfs(&tfsid)) { - xxxfs_mntid++; - tfsid.val[0] = makeudev(255, - mtype + (xxxfs_mntid << 16)); - } + for (;;) { + tfsid.val[0] = makeudev(255, mtype + (mntid_base << 16)); + tfsid.val[1] = mtype; + ++mntid_base; + if (vfs_getvfs(&tfsid) == NULL) + break; } + mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; + mp->mnt_stat.f_fsid.val[1] = tfsid.val[1]; + simple_unlock(&mntid_slock); } +/* + * Get what should become the root fsid. + * + * This is somewhat of a hack. If the rootdev is not known we + * assume that vfs_getnewfsid() will be called momentarily to + * allocate it, and we return what vfs_getnewfsid() will return. + */ + +dev_t +vfs_getrootfsid(struct mount *mp) +{ + int mtype; + + mtype = mp->mnt_vfc->vfc_typenum; + return(makedev(255, mtype + (mntid_base << 16))); +} + /* * Knob to control the precision of file timestamps: * @@ -1303,11 +1322,7 @@ addaliasu(nvp, nvp_rdev) if (nvp->v_type != VBLK && nvp->v_type != VCHR) panic("addaliasu on non-special vnode"); - - nvp->v_rdev = udev2dev(nvp_rdev, nvp->v_type == VBLK ? 1 : 0); - simple_lock(&spechash_slock); - SLIST_INSERT_HEAD(&nvp->v_rdev->si_hlist, nvp, v_specnext); - simple_unlock(&spechash_slock); + addalias(nvp, udev2dev(nvp_rdev, nvp->v_type == VBLK ? 1 : 0)); } void @@ -1650,8 +1665,9 @@ vclean(vp, flags, p) if ((obj = vp->v_object) != NULL) { if (obj->ref_count == 0) { /* - * This is a normal way of shutting down the object/vnode - * association. + * vclean() may be called twice. The first time removes the + * primary reference to the object, the second time goes + * one further and is a special-case to terminate the object. */ vm_object_terminate(obj); } else { diff --git a/sys/sys/mount.h b/sys/sys/mount.h index bb4b490b3171..2da7a1e43908 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -391,6 +391,7 @@ struct netcred *vfs_export_lookup /* lookup host in fs export list */ __P((struct mount *, struct netexport *, struct sockaddr *)); int vfs_allocate_syncvnode __P((struct mount *)); void vfs_getnewfsid __P((struct mount *)); +dev_t vfs_getrootfsid __P((struct mount *)); struct mount *vfs_getvfs __P((fsid_t *)); /* return vfs given fsid */ int vfs_modevent __P((module_t, int, void *)); int vfs_mountedon __P((struct vnode *)); /* is a vfs mounted on vp */