From: Chuck Lever Signed-off-by: Chuck Lever Cc: Trond Myklebust Cc: "J. Bruce Fields" Signed-off-by: Andrew Morton --- fs/nfs/super.c | 132 +++++++++++++++++++++++++++++------------------ 1 files changed, 83 insertions(+), 49 deletions(-) diff -puN fs/nfs/super.c~nfs-implement-nfsv2-3-in-kernel-mount-option-parsing fs/nfs/super.c --- a/fs/nfs/super.c~nfs-implement-nfsv2-3-in-kernel-mount-option-parsing +++ a/fs/nfs/super.c @@ -934,8 +934,6 @@ static struct nfs_mount_data *nfs_conver if (args == NULL) return ERR_PTR(-ENOMEM); - args->nmd.version = 7; - args->nmd.flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP); args->nmd.rsize = NFS_MAX_FILE_IO_SIZE; args->nmd.wsize = NFS_MAX_FILE_IO_SIZE; @@ -988,71 +986,74 @@ out_invalid: * Validate the NFS2/NFS3 mount data * - fills in the mount root filehandle */ -static int nfs_validate_mount_data(struct nfs_mount_data *data, - struct nfs_fh *mntfh) -{ - if (data == NULL) { - dprintk("%s: missing data argument\n", __FUNCTION__); - return -EINVAL; - } +static int nfs_validate_mount_data(struct nfs_mount_data **options, + struct nfs_fh *mntfh, + const char *dev_name) +{ + struct nfs_mount_data *data = *options; + unsigned int len; + char *c; + int status; - if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) { - dprintk("%s: bad mount version\n", __FUNCTION__); - return -EINVAL; - } + if (data == NULL) + goto out_no_data; switch (data->version) { - case 1: - data->namlen = 0; - case 2: - data->bsize = 0; - case 3: - if (data->flags & NFS_MOUNT_VER3) { - dprintk("%s: mount structure version %d does not support NFSv3\n", - __FUNCTION__, - data->version); - return -EINVAL; - } - data->root.size = NFS2_FHSIZE; - memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); - case 4: - if (data->flags & NFS_MOUNT_SECFLAVOUR) { - dprintk("%s: mount structure version %d does not support strong security\n", - __FUNCTION__, - data->version); - return -EINVAL; - } - case 5: - memset(data->context, 0, sizeof(data->context)); + case 1: + data->namlen = 0; + case 2: + data->bsize = 0; + case 3: + if (data->flags & NFS_MOUNT_VER3) + goto out_no_v3; + data->root.size = NFS2_FHSIZE; + memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); + case 4: + if (data->flags & NFS_MOUNT_SECFLAVOUR) + goto out_no_sec; + case 5: + memset(data->context, 0, sizeof(data->context)); + case 6: + break; + default: + data = nfs_convert_mount_opts((char *) data); + if (IS_ERR(data)) + return PTR_ERR(data); + *options = data; + + c = strchr(dev_name, ':'); + if (c == NULL) + return -EINVAL; + len = c - dev_name - 1; + if (len > 256) + return -EINVAL; + strncpy(data->hostname, dev_name, len); + + status = nfs_try_mount(data, ++c); + if (status) + return -EINVAL; } - /* Set the pseudoflavor */ if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) data->pseudoflavor = RPC_AUTH_UNIX; #ifndef CONFIG_NFS_V3 - /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */ - if (data->flags & NFS_MOUNT_VER3) { - dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__); - return -EPROTONOSUPPORT; - } -#endif /* CONFIG_NFS_V3 */ + if (data->flags & NFS_MOUNT_VER3) + goto out_v3_not_compiled; +#endif /* !CONFIG_NFS_V3 */ /* We now require that the mount process passes the remote address */ if (!nfs_verify_server_address((struct sockaddr *) &data->addr, sizeof(data->addr))) return -EINVAL; - /* Prepare the root filehandle */ if (data->flags & NFS_MOUNT_VER3) mntfh->size = data->root.size; else mntfh->size = NFS2_FHSIZE; - if (mntfh->size > sizeof(mntfh->data)) { - dprintk("%s: invalid root filehandle\n", __FUNCTION__); - return -EINVAL; - } + if (mntfh->size > sizeof(mntfh->data)) + goto out_invalid_fh; memcpy(mntfh->data, data->root.data, mntfh->size); if (mntfh->size < sizeof(mntfh->data)) @@ -1060,6 +1061,30 @@ static int nfs_validate_mount_data(struc sizeof(mntfh->data) - mntfh->size); return 0; + +out_no_data: + dprintk("NFS: mount program didn't pass any mount data\n"); + return -EINVAL; + +out_no_v3: + dprintk("NFS: nfs_mount_data version %d does not support NFSv3\n", + data->version); + return -EINVAL; + +out_no_sec: + dprintk("NFS: nfs_mount_data version %d supports only AUTH_SYS\n", + data->version); + return -EINVAL; + +#ifndef CONFIG_NFS_V3 +out_v3_not_compiled: + dprintk("NFS: NFSv3 is not compiled into kernel\n"); + return -EPROTONOSUPPORT; +#endif /* !CONFIG_NFS_V3 */ + +out_invalid_fh: + dprintk("NFS: invalid root filehandle\n"); + return -EINVAL; } /* @@ -1206,9 +1231,12 @@ static int nfs_get_sb(struct file_system int error; /* Validate the mount data */ - error = nfs_validate_mount_data(data, &mntfh); - if (error < 0) + error = nfs_validate_mount_data(&data, &mntfh, dev_name); + if (error < 0) { + if (data != raw_data) + kfree(data); return error; + } /* Get a volume representation */ server = nfs_create_server(data, &mntfh); @@ -1250,16 +1278,22 @@ static int nfs_get_sb(struct file_system s->s_flags |= MS_ACTIVE; mnt->mnt_sb = s; mnt->mnt_root = mntroot; + if (data != raw_data) + kfree(data); return 0; out_err_nosb: nfs_free_server(server); out_err_noserver: + if (data != raw_data) + kfree(data); return error; error_splat_super: up_write(&s->s_umount); deactivate_super(s); + if (data != raw_data) + kfree(data); return error; } _