Index: kern/vfs_mount.c =================================================================== RCS file: /home/ncvs/src/sys/kern/vfs_mount.c,v retrieving revision 1.112 diff -u -r1.112 vfs_mount.c --- kern/vfs_mount.c 5 Nov 2003 04:30:07 -0000 1.112 +++ kern/vfs_mount.c 11 Nov 2003 04:38:50 -0000 @@ -103,6 +103,10 @@ static int vfs_nmount(struct thread *td, int, struct uio *); static int vfs_mountroot_try(char *mountfrom); static int vfs_mountroot_ask(void); +static int vfs_mount_alloc(struct vnode *, struct vfsconf *, + const char *, struct thread *, struct mount **); +static int vfs_domount(struct thread *, const char *, char *, + int fsflags, void *fsdata, int compat); static void gets(char *cp); static int usermount = 0; /* if 1, non-root can mount fs. */ @@ -236,6 +240,8 @@ /* * Build a linked list of mount options from a struct uio. */ +#define VFS_MOUNTARG_SIZE_MAX (1024*64) + static int vfs_buildopts(struct uio *auio, struct vfsoptlist **options) { @@ -243,6 +249,7 @@ struct vfsopt *opt; unsigned int i, iovcnt; int error, namelen, optlen; + size_t memused = 0; iovcnt = auio->uio_iovcnt; opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK); @@ -253,6 +260,26 @@ optlen = auio->uio_iov[i + 1].iov_len; opt->name = malloc(namelen, M_MOUNT, M_WAITOK); opt->value = NULL; + opt->len = optlen; + + /* + * Do this early, so jumps to "bad" will free the current + * option + */ + TAILQ_INSERT_TAIL(opts, opt, link); + memused += sizeof (struct vfsopt) + optlen + namelen; + + /* + * Avoid consuming too much memory, and attempts to overflow + * memused + */ + if (memused > VFS_MOUNTARG_SIZE_MAX || + optlen > VFS_MOUNTARG_SIZE_MAX || + namelen > VFS_MOUNTARG_SIZE_MAX) { + error = EINVAL; + goto bad; + } + if (auio->uio_segflg == UIO_SYSSPACE) { bcopy(auio->uio_iov[i].iov_base, opt->name, namelen); } else { @@ -261,7 +288,11 @@ if (error) goto bad; } - opt->len = optlen; + /* Ensure names are null-terminated strings */ + if (opt->name[namelen - 1] != '\0') { + error = EINVAL; + goto bad; + } if (optlen != 0) { opt->value = malloc(optlen, M_MOUNT, M_WAITOK); if (auio->uio_segflg == UIO_SYSSPACE) { @@ -274,7 +305,6 @@ goto bad; } } - TAILQ_INSERT_TAIL(opts, opt, link); } vfs_sanitizeopts(opts); *options = opts; @@ -451,24 +481,68 @@ } /* - * vfs_nmount(): actually attempt a filesystem mount. + * Allocate and initialize the mount point struct. */ static int -vfs_nmount(td, fsflags, fsoptions) - struct thread *td; - int fsflags; /* Flags common to all filesystems. */ - struct uio *fsoptions; /* Options local to the filesystem. */ +vfs_mount_alloc(struct vnode *vp, struct vfsconf *vfsp, + const char *fspath, struct thread *td, struct mount **mpp) { - linker_file_t lf; - struct vnode *vp; struct mount *mp; - struct vfsconf *vfsp; + + mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO); + TAILQ_INIT(&mp->mnt_nvnodelist); + TAILQ_INIT(&mp->mnt_reservedvnlist); + mp->mnt_nvnodelistsize = 0; + mtx_init(&mp->mnt_mtx, "struct mount mtx", NULL, MTX_DEF); + lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE); + vfs_busy(mp, LK_NOWAIT, 0, td); + mp->mnt_op = vfsp->vfc_vfsops; + mp->mnt_vfc = vfsp; + vfsp->vfc_refcount++; + mp->mnt_stat.f_type = vfsp->vfc_typenum; + mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; + strlcpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); + mp->mnt_vnodecovered = vp; + mp->mnt_cred = crdup(td->td_ucred); + mp->mnt_stat.f_owner = td->td_ucred->cr_uid; + strlcpy(mp->mnt_stat.f_mntonname, fspath, MNAMELEN); + mp->mnt_iosize_max = DFLTPHYS; +#ifdef MAC + mac_init_mount(mp); + mac_create_mount(td->td_ucred, mp); +#endif + *mpp = mp; + return (0); +} + +void +vfs_mount_destroy(struct mount *mp, struct thread *td) +{ + + mp->mnt_vfc->vfc_refcount--; + if (!TAILQ_EMPTY(&mp->mnt_nvnodelist)) + panic("unmount: dangling vnode"); + vfs_unbusy(mp,td); + lockdestroy(&mp->mnt_lock); + mtx_destroy(&mp->mnt_mtx); + if (mp->mnt_kern_flag & MNTK_MWAIT) + wakeup(mp); +#ifdef MAC + mac_destroy_mount(mp); +#endif + if (mp->mnt_op->vfs_mount == NULL) + vfs_freeopts(mp->mnt_opt); + crfree(mp->mnt_cred); + free(mp, M_MOUNT); +} + +static int +vfs_nmount(struct thread *td, int fsflags, struct uio *fsoptions) +{ struct vfsoptlist *optlist; char *fstype, *fspath; - int error, flag = 0, kern_flag = 0; int fstypelen, fspathlen; - struct vattr va; - struct nameidata nd; + int error; error = vfs_buildopts(fsoptions, &optlist); if (error) @@ -483,13 +557,13 @@ error = vfs_getopt(optlist, "fstype", (void **)&fstype, &fstypelen); if (error || fstype[fstypelen - 1] != '\0') { error = EINVAL; - goto bad; + goto bail; } fspathlen = 0; error = vfs_getopt(optlist, "fspath", (void **)&fspath, &fspathlen); if (error || fspath[fspathlen - 1] != '\0') { error = EINVAL; - goto bad; + goto bail; } /* @@ -499,13 +573,49 @@ */ if (fstypelen >= MFSNAMELEN - 1 || fspathlen >= MNAMELEN - 1) { error = ENAMETOOLONG; - goto bad; + goto bail; } + error = vfs_domount(td, fstype, fspath, fsflags, optlist, 0); +bail: + if (error) + vfs_freeopts(optlist); + return (error); +} + + +/* + * vfs_domount(): actually attempt a filesystem mount. + */ +static int +vfs_domount( + struct thread *td, + const char *fstype, + char *fspath, + int fsflags, + void *fsdata, + int compat) +{ + linker_file_t lf; + struct vnode *vp; + struct mount *mp; + struct vfsconf *vfsp; + int error, flag = 0, kern_flag = 0; + struct vattr va; + struct nameidata nd; + + /* + * Be ultra-paranoid about making sure the type and fspath + * variables will fit in our mp buffers, including the + * terminating NUL. + */ + if (strlen(fstype) >= MFSNAMELEN || strlen(fspath) >= MNAMELEN) + return (ENAMETOOLONG); + if (usermount == 0) { error = suser(td); if (error) - goto bad; + return (error); } /* * Do not allow NFS export by non-root users. @@ -513,26 +623,25 @@ if (fsflags & MNT_EXPORTED) { error = suser(td); if (error) - goto bad; + return (error); } /* * Silently enforce MNT_NOSUID and MNT_NODEV for non-root users. */ - if (suser(td)) + if (suser(td)) fsflags |= MNT_NOSUID | MNT_NODEV; /* * Get vnode to be covered */ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, td); if ((error = namei(&nd)) != 0) - goto bad; + return (error); NDFREE(&nd, NDF_ONLY_PNBUF); vp = nd.ni_vp; if (fsflags & MNT_UPDATE) { if ((vp->v_vflag & VV_ROOT) == 0) { vput(vp); - error = EINVAL; - goto bad; + return (EINVAL); } mp = vp->v_mount; flag = mp->mnt_flag; @@ -544,8 +653,7 @@ if ((fsflags & MNT_RELOAD) && ((mp->mnt_flag & MNT_RDONLY) == 0)) { vput(vp); - error = EOPNOTSUPP; /* Needs translation */ - goto bad; + return (EOPNOTSUPP); /* Needs translation */ } /* * Only root, or the user that did the original mount is @@ -555,13 +663,12 @@ error = suser(td); if (error) { vput(vp); - goto bad; + return (error); } } if (vfs_busy(mp, LK_NOWAIT, 0, td)) { vput(vp); - error = EBUSY; - goto bad; + return (EBUSY); } VI_LOCK(vp); if ((vp->v_iflag & VI_MOUNT) != 0 || @@ -569,16 +676,17 @@ VI_UNLOCK(vp); vfs_unbusy(mp, td); vput(vp); - error = EBUSY; - goto bad; + return (EBUSY); } vp->v_iflag |= VI_MOUNT; VI_UNLOCK(vp); mp->mnt_flag |= fsflags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT); VOP_UNLOCK(vp, 0, td); - mp->mnt_optnew = optlist; - vfs_mergeopts(mp->mnt_optnew, mp->mnt_opt); + if (compat == 0) { + mp->mnt_optnew = fsdata; + vfs_mergeopts(mp->mnt_optnew, mp->mnt_opt); + } goto update; } /* @@ -588,23 +696,22 @@ error = VOP_GETATTR(vp, &va, td->td_ucred, td); if (error) { vput(vp); - goto bad; + return (error); } if (va.va_uid != td->td_ucred->cr_uid) { error = suser(td); if (error) { vput(vp); - goto bad; + return (error); } } if ((error = vinvalbuf(vp, V_SAVE, td->td_ucred, td, 0, 0)) != 0) { vput(vp); - goto bad; + return (error); } if (vp->v_type != VDIR) { vput(vp); - error = ENOTDIR; - goto bad; + return (ENOTDIR); } for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) if (!strcmp(vfsp->vfc_name, fstype)) @@ -614,19 +721,19 @@ error = suser(td); if (error) { vput(vp); - goto bad; + return (error); } error = securelevel_gt(td->td_ucred, 0); if (error) { vput(vp); - goto bad; + return (error); } error = linker_load_module(NULL, fstype, NULL, NULL, &lf); if (error || lf == NULL) { vput(vp); if (lf == NULL) error = ENODEV; - goto bad; + return (error); } lf->userrefs++; /* Look up again to see if the VFS was loaded. */ @@ -637,8 +744,7 @@ lf->userrefs--; linker_file_unload(lf); vput(vp); - error = ENODEV; - goto bad; + return (ENODEV); } } VI_LOCK(vp); @@ -646,8 +752,7 @@ vp->v_mountedhere != NULL) { VI_UNLOCK(vp); vput(vp); - error = EBUSY; - goto bad; + return (EBUSY); } vp->v_iflag |= VI_MOUNT; VI_UNLOCK(vp); @@ -655,56 +760,33 @@ /* * Allocate and initialize the filesystem. */ - mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO); - TAILQ_INIT(&mp->mnt_nvnodelist); - TAILQ_INIT(&mp->mnt_reservedvnlist); - mp->mnt_nvnodelistsize = 0; - mtx_init(&mp->mnt_mtx, "struct mount mtx", NULL, MTX_DEF); - lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE); - (void)vfs_busy(mp, LK_NOWAIT, 0, td); - mp->mnt_op = vfsp->vfc_vfsops; - mp->mnt_vfc = vfsp; - vfsp->vfc_refcount++; - mp->mnt_stat.f_type = vfsp->vfc_typenum; - mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; - strlcpy(mp->mnt_stat.f_fstypename, fstype, MFSNAMELEN); - mp->mnt_vnodecovered = vp; - mp->mnt_cred = crdup(td->td_ucred); - mp->mnt_stat.f_owner = td->td_ucred->cr_uid; - strlcpy(mp->mnt_stat.f_mntonname, fspath, MNAMELEN); - mp->mnt_iosize_max = DFLTPHYS; -#ifdef MAC - mac_init_mount(mp); - mac_create_mount(td->td_ucred, mp); -#endif + error = vfs_mount_alloc(vp, vfsp, fspath, td, &mp); + if (error) { + vput(vp); + return (error); + } VOP_UNLOCK(vp, 0, td); - mp->mnt_optnew = optlist; /* XXXMAC: should this be above? */ + /* XXXMAC: pass to vfs_mount_alloc? */ + if (compat == 0) + mp->mnt_optnew = fsdata; update: /* - * Check if the fs implements the new VFS_NMOUNT() - * function, since the new system call was used. + * Check if the fs implements the type VFS_[N]MOUNT() + * function we are looking for. */ - if (mp->mnt_op->vfs_mount != NULL) { - printf("%s doesn't support the new mount syscall\n", - mp->mnt_vfc->vfc_name); + if ((compat == 0) == (mp->mnt_op->vfs_mount != NULL)) { + printf("%s doesn't support the %s mount syscall\n", + mp->mnt_vfc->vfc_name, compat? "old" : "new"); VI_LOCK(vp); vp->v_iflag &= ~VI_MOUNT; VI_UNLOCK(vp); if (mp->mnt_flag & MNT_UPDATE) vfs_unbusy(mp, td); - else { - mp->mnt_vfc->vfc_refcount--; - vfs_unbusy(mp, td); -#ifdef MAC - mac_destroy_mount(mp); -#endif - crfree(mp->mnt_cred); - free(mp, M_MOUNT); - } + else + vfs_mount_destroy(mp, td); vrele(vp); - error = EOPNOTSUPP; - goto bad; + return (EOPNOTSUPP); } /* @@ -721,7 +803,8 @@ * XXX The final recipients of VFS_MOUNT just overwrite the ndp they * get. No freeing of cn_pnbuf. */ - error = VFS_NMOUNT(mp, &nd, td); + error = compat? VFS_MOUNT(mp, fspath, fsdata, &nd, td) : + VFS_NMOUNT(mp, &nd, td); if (!error) { if (mp->mnt_opt != NULL) vfs_freeopts(mp->mnt_opt); @@ -780,27 +863,16 @@ if ((mp->mnt_flag & MNT_RDONLY) == 0) error = vfs_allocate_syncvnode(mp); vfs_unbusy(mp, td); - if ((error = VFS_START(mp, 0, td)) != 0) { + if ((error = VFS_START(mp, 0, td)) != 0) vrele(vp); - goto bad; - } } else { VI_LOCK(vp); vp->v_iflag &= ~VI_MOUNT; VI_UNLOCK(vp); - mp->mnt_vfc->vfc_refcount--; - vfs_unbusy(mp, td); -#ifdef MAC - mac_destroy_mount(mp); -#endif - crfree(mp->mnt_cred); - free(mp, M_MOUNT); + + vfs_mount_destroy(mp, td); vput(vp); - goto bad; } - return (0); -bad: - vfs_freeopts(optlist); return (error); } @@ -841,7 +913,8 @@ if (error == 0) error = copyinstr(uap->path, fspath, MNAMELEN, NULL); if (error == 0) - error = vfs_mount(td, fstype, fspath, uap->flags, uap->data); + error = vfs_domount(td, fstype, fspath, uap->flags, + uap->data, 1); free(fstype, M_TEMP); free(fspath, M_TEMP); return (error); @@ -857,302 +930,14 @@ */ int vfs_mount(td, fstype, fspath, fsflags, fsdata) - struct thread *td; - const char *fstype; - char *fspath; - int fsflags; - void *fsdata; + struct thread *td; + const char *fstype; + char *fspath; + int fsflags; + void *fsdata; { - linker_file_t lf; - struct vnode *vp; - struct mount *mp; - struct vfsconf *vfsp; - int error, flag = 0, kern_flag = 0; - struct vattr va; - struct nameidata nd; - - /* - * Be ultra-paranoid about making sure the type and fspath - * variables will fit in our mp buffers, including the - * terminating NUL. - */ - if (strlen(fstype) >= MFSNAMELEN || strlen(fspath) >= MNAMELEN) - return (ENAMETOOLONG); - - if (usermount == 0) { - error = suser(td); - if (error) - return (error); - } - /* - * Do not allow NFS export by non-root users. - */ - if (fsflags & MNT_EXPORTED) { - error = suser(td); - if (error) - return (error); - } - /* - * Silently enforce MNT_NOSUID and MNT_NODEV for non-root users. - */ - if (suser(td)) - fsflags |= MNT_NOSUID | MNT_NODEV; - /* - * Get vnode to be covered - */ - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, td); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - vp = nd.ni_vp; - if (fsflags & MNT_UPDATE) { - if ((vp->v_vflag & VV_ROOT) == 0) { - vput(vp); - return (EINVAL); - } - mp = vp->v_mount; - flag = mp->mnt_flag; - kern_flag = mp->mnt_kern_flag; - /* - * We only allow the filesystem to be reloaded if it - * is currently mounted read-only. - */ - if ((fsflags & MNT_RELOAD) && - ((mp->mnt_flag & MNT_RDONLY) == 0)) { - vput(vp); - return (EOPNOTSUPP); /* Needs translation */ - } - /* - * Only root, or the user that did the original mount is - * permitted to update it. - */ - if (mp->mnt_cred->cr_uid != td->td_ucred->cr_uid) { - error = suser(td); - if (error) { - vput(vp); - return (error); - } - } - if (vfs_busy(mp, LK_NOWAIT, 0, td)) { - vput(vp); - return (EBUSY); - } - VI_LOCK(vp); - if ((vp->v_iflag & VI_MOUNT) != 0 || - vp->v_mountedhere != NULL) { - VI_UNLOCK(vp); - vfs_unbusy(mp, td); - vput(vp); - return (EBUSY); - } - vp->v_iflag |= VI_MOUNT; - VI_UNLOCK(vp); - mp->mnt_flag |= fsflags & - (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT); - VOP_UNLOCK(vp, 0, td); - goto update; - } - /* - * If the user is not root, ensure that they own the directory - * onto which we are attempting to mount. - */ - error = VOP_GETATTR(vp, &va, td->td_ucred, td); - if (error) { - vput(vp); - return (error); - } - if (va.va_uid != td->td_ucred->cr_uid) { - error = suser(td); - if (error) { - vput(vp); - return (error); - } - } - if ((error = vinvalbuf(vp, V_SAVE, td->td_ucred, td, 0, 0)) != 0) { - vput(vp); - return (error); - } - if (vp->v_type != VDIR) { - vput(vp); - return (ENOTDIR); - } - for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) - if (!strcmp(vfsp->vfc_name, fstype)) - break; - if (vfsp == NULL) { - /* Only load modules for root (very important!). */ - error = suser(td); - if (error) { - vput(vp); - return (error); - } - error = securelevel_gt(td->td_ucred, 0); - if (error) { - vput(vp); - return (error); - } - error = linker_load_module(NULL, fstype, NULL, NULL, &lf); - if (error || lf == NULL) { - vput(vp); - if (lf == NULL) - error = ENODEV; - return (error); - } - lf->userrefs++; - /* Look up again to see if the VFS was loaded. */ - for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) - if (!strcmp(vfsp->vfc_name, fstype)) - break; - if (vfsp == NULL) { - lf->userrefs--; - linker_file_unload(lf); - vput(vp); - return (ENODEV); - } - } - VI_LOCK(vp); - if ((vp->v_iflag & VI_MOUNT) != 0 || - vp->v_mountedhere != NULL) { - VI_UNLOCK(vp); - vput(vp); - return (EBUSY); - } - vp->v_iflag |= VI_MOUNT; - VI_UNLOCK(vp); - - /* - * Allocate and initialize the filesystem. - */ - mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO); - TAILQ_INIT(&mp->mnt_nvnodelist); - TAILQ_INIT(&mp->mnt_reservedvnlist); - mp->mnt_nvnodelistsize = 0; - mtx_init(&mp->mnt_mtx, "struct mount mtx", NULL, MTX_DEF); - lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE); - (void)vfs_busy(mp, LK_NOWAIT, 0, td); - mp->mnt_op = vfsp->vfc_vfsops; - mp->mnt_vfc = vfsp; - vfsp->vfc_refcount++; - mp->mnt_stat.f_type = vfsp->vfc_typenum; - mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; - strlcpy(mp->mnt_stat.f_fstypename, fstype, MFSNAMELEN); - mp->mnt_vnodecovered = vp; - mp->mnt_cred = crdup(td->td_ucred); - mp->mnt_stat.f_owner = td->td_ucred->cr_uid; - strlcpy(mp->mnt_stat.f_mntonname, fspath, MNAMELEN); - mp->mnt_iosize_max = DFLTPHYS; -#ifdef MAC - mac_init_mount(mp); - mac_create_mount(td->td_ucred, mp); -#endif - VOP_UNLOCK(vp, 0, td); -update: - /* - * Check if the fs implements the old VFS_MOUNT() - * function, since the old system call was used. - */ - if (mp->mnt_op->vfs_mount == NULL) { - printf("%s doesn't support the old mount syscall\n", - mp->mnt_vfc->vfc_name); - VI_LOCK(vp); - vp->v_iflag &= ~VI_MOUNT; - VI_UNLOCK(vp); - if (mp->mnt_flag & MNT_UPDATE) - vfs_unbusy(mp, td); - else { - mp->mnt_vfc->vfc_refcount--; - vfs_unbusy(mp, td); -#ifdef MAC - mac_destroy_mount(mp); -#endif - crfree(mp->mnt_cred); - free(mp, M_MOUNT); - } - vrele(vp); - return (EOPNOTSUPP); - } - - /* - * Set the mount level flags. - */ - if (fsflags & MNT_RDONLY) - mp->mnt_flag |= MNT_RDONLY; - else if (mp->mnt_flag & MNT_RDONLY) - mp->mnt_kern_flag |= MNTK_WANTRDWR; - mp->mnt_flag &=~ MNT_UPDATEMASK; - mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE); - /* - * Mount the filesystem. - * XXX The final recipients of VFS_MOUNT just overwrite the ndp they - * get. No freeing of cn_pnbuf. - */ - error = VFS_MOUNT(mp, fspath, fsdata, &nd, td); - if (mp->mnt_flag & MNT_UPDATE) { - if (mp->mnt_kern_flag & MNTK_WANTRDWR) - mp->mnt_flag &= ~MNT_RDONLY; - mp->mnt_flag &=~ - (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_SNAPSHOT); - mp->mnt_kern_flag &=~ MNTK_WANTRDWR; - if (error) { - mp->mnt_flag = flag; - mp->mnt_kern_flag = kern_flag; - } - if ((mp->mnt_flag & MNT_RDONLY) == 0) { - if (mp->mnt_syncer == NULL) - error = vfs_allocate_syncvnode(mp); - } else { - if (mp->mnt_syncer != NULL) - vrele(mp->mnt_syncer); - mp->mnt_syncer = NULL; - } - vfs_unbusy(mp, td); - VI_LOCK(vp); - vp->v_iflag &= ~VI_MOUNT; - VI_UNLOCK(vp); - vrele(vp); - return (error); - } - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - /* - * Put the new filesystem on the mount list after root. - */ - cache_purge(vp); - if (!error) { - struct vnode *newdp; - - VI_LOCK(vp); - vp->v_iflag &= ~VI_MOUNT; - VI_UNLOCK(vp); - vp->v_mountedhere = mp; - mtx_lock(&mountlist_mtx); - TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); - mtx_unlock(&mountlist_mtx); - if (VFS_ROOT(mp, &newdp)) - panic("mount: lost mount"); - checkdirs(vp, newdp); - vput(newdp); - VOP_UNLOCK(vp, 0, td); - if ((mp->mnt_flag & MNT_RDONLY) == 0) - error = vfs_allocate_syncvnode(mp); - vfs_unbusy(mp, td); - if ((error = VFS_START(mp, 0, td)) != 0) - vrele(vp); - } else { - VI_LOCK(vp); - vp->v_iflag &= ~VI_MOUNT; - VI_UNLOCK(vp); - mp->mnt_vfc->vfc_refcount--; - vfs_unbusy(mp, td); -#ifdef MAC - mac_destroy_mount(mp); -#endif - crfree(mp->mnt_cred); - free(mp, M_MOUNT); - vput(vp); - } - return (error); + return (vfs_domount(td,fstype, fspath, fsflags, fsdata, 1)); } - /* * Scan all active processes to see if any of them have a current * or root directory of `olddp'. If so, replace them with the new @@ -1360,27 +1145,14 @@ wakeup(mp); return (error); } - crfree(mp->mnt_cred); mtx_lock(&mountlist_mtx); TAILQ_REMOVE(&mountlist, mp, mnt_list); if ((coveredvp = mp->mnt_vnodecovered) != NULL) - coveredvp->v_mountedhere = NULL; - mp->mnt_vfc->vfc_refcount--; - if (!TAILQ_EMPTY(&mp->mnt_nvnodelist)) - panic("unmount: dangling vnode"); - lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_mtx, td); - lockdestroy(&mp->mnt_lock); - mtx_destroy(&mp->mnt_mtx); + coveredvp->v_mountedhere = NULL; + mtx_unlock(&mountlist_mtx); + vfs_mount_destroy(mp, td); if (coveredvp != NULL) vrele(coveredvp); - if (mp->mnt_kern_flag & MNTK_MWAIT) - wakeup(mp); -#ifdef MAC - mac_destroy_mount(mp); -#endif - if (mp->mnt_op->vfs_mount == NULL) - vfs_freeopts(mp->mnt_opt); - free(mp, M_MOUNT); return (0); } @@ -1399,6 +1171,7 @@ struct thread *td = curthread; /* XXX */ struct vfsconf *vfsp; struct mount *mp; + int error; if (fstypename == NULL) return (ENODEV); @@ -1407,30 +1180,14 @@ break; if (vfsp == NULL) return (ENODEV); - mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO); - mtx_init(&mp->mnt_mtx, "struct mount mtx", NULL, MTX_DEF); - lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE); - (void)vfs_busy(mp, LK_NOWAIT, 0, td); - TAILQ_INIT(&mp->mnt_nvnodelist); - TAILQ_INIT(&mp->mnt_reservedvnlist); - mp->mnt_nvnodelistsize = 0; - mp->mnt_vfc = vfsp; - mp->mnt_op = vfsp->vfc_vfsops; - mp->mnt_flag = MNT_RDONLY; - mp->mnt_vnodecovered = NULLVP; - mp->mnt_cred = crdup(td->td_ucred); - vfsp->vfc_refcount++; - mp->mnt_iosize_max = DFLTPHYS; - mp->mnt_stat.f_type = vfsp->vfc_typenum; - mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; - strlcpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); - mp->mnt_stat.f_mntonname[0] = '/'; - mp->mnt_stat.f_mntonname[1] = 0; + + error = vfs_mount_alloc(NULLVP, vfsp, "/", td, &mp); + if (error) + return (error); + + mp->mnt_flag |= MNT_RDONLY; strlcpy(mp->mnt_stat.f_mntfromname, devname, MNAMELEN); -#ifdef MAC - mac_init_mount(mp); - mac_create_mount(td->td_ucred, mp); -#endif + *mpp = mp; return (0); } @@ -1444,18 +1201,18 @@ char *cp; int i, error; - g_waitidle(); + g_waitidle(); - /* + /* * The root filesystem information is compiled in, and we are * booted with instructions to use it. */ #ifdef ROOTDEVNAME - if ((boothowto & RB_DFLTROOT) && + if ((boothowto & RB_DFLTROOT) && !vfs_mountroot_try(ROOTDEVNAME)) return; #endif - /* + /* * We are booted with instructions to prompt for the root filesystem, * or to use the compiled-in default when it doesn't exist. */ @@ -1478,7 +1235,7 @@ /* * Try to use the value read by the loader from /etc/fstab, or - * supplied via some other means. This is the preferred + * supplied via some other means. This is the preferred * mechanism. */ if ((cp = getenv("vfs.root.mountfrom")) != NULL) { @@ -1488,7 +1245,7 @@ return; } - /* + /* * Try values that may have been computed by the machine-dependant * legacy code. */ @@ -1507,7 +1264,7 @@ return; #endif - /* + /* * Everything so far has failed, prompt on the console if we haven't * already tried that. */ @@ -1570,7 +1327,7 @@ mp->mnt_flag &= ~MNT_RDONLY; } - /* + /* * Set the mount path to be something useful, because the * filesystem code isn't responsible now for initialising * f_mntonname unless they want to override the default @@ -1586,14 +1343,8 @@ if (path != NULL) free(path, M_MOUNT); if (error != 0) { - if (mp != NULL) { - vfs_unbusy(mp, curthread); -#ifdef MAC - mac_destroy_mount(mp); -#endif - crfree(mp->mnt_cred); - free(mp, M_MOUNT); - } + if (mp != NULL) + vfs_mount_destroy(mp, curthread); printf("Root mount failed: %d\n", error); } else { Index: nfsclient/nfs_vfsops.c =================================================================== RCS file: /home/ncvs/src/sys/nfsclient/nfs_vfsops.c,v retrieving revision 1.142 diff -u -r1.142 nfs_vfsops.c --- nfsclient/nfs_vfsops.c 7 Nov 2003 22:57:09 -0000 1.142 +++ nfsclient/nfs_vfsops.c 11 Nov 2003 04:38:57 -0000 @@ -492,16 +492,10 @@ struct mount *mp; struct sockaddr *nam; int error; - int didalloc = 0; - mp = *mpp; - - if (mp == NULL) { - if ((error = vfs_rootmountalloc("nfs", path, &mp)) != 0) { - printf("nfs_mountroot: NFS not configured"); - return (error); - } - didalloc = 1; + if ((error = vfs_rootmountalloc("nfs", path, &mp)) != 0) { + printf("nfs_mountroot: NFS not configured"); + return (error); } mp->mnt_kern_flag = 0; @@ -510,10 +504,7 @@ if ((error = mountnfs(args, mp, nam, which, path, vpp, td->td_ucred)) != 0) { printf("nfs_mountroot: mount %s on %s: %d", path, which, error); - mp->mnt_vfc->vfc_refcount--; - vfs_unbusy(mp, td); - if (didalloc) - free(mp, M_MOUNT); + vfs_mount_destroy(mp, td); FREE(nam, M_SONAME); return (error); } Index: sys/mount.h =================================================================== RCS file: /home/ncvs/src/sys/sys/mount.h,v retrieving revision 1.149 diff -u -r1.149 mount.h --- sys/mount.h 5 Nov 2003 04:30:07 -0000 1.149 +++ sys/mount.h 11 Nov 2003 04:39:00 -0000 @@ -485,6 +485,7 @@ int vfs_mountedon(struct vnode *); /* is a vfs mounted on vp */ void vfs_mountroot(void); /* mount our root filesystem */ int vfs_rootmountalloc(char *, char *, struct mount **); +void vfs_mount_destroy(struct mount *, struct thread *); void vfs_unbusy(struct mount *, struct thread *td); void vfs_unmountall(void); int vfs_register(struct vfsconf *);