From: Andy Adamson Date: Fri, 18 May 2007 16:52:46 -0400 NFSv4: Handle NFS4ERR_WRONGSEC in nfs4_proc_lookup The first time through the wrongsec handler, setup the ex_list via a secinfo call. The existance of ex_list signals to skip setup and try the next flavor on the list, which will only occur if the server secinfo list is incorret, or if we are trying a list of flavors (from mount) on a PUTROOTFH/PUTFH WRONGSEC. Free the wrongsec handler resources upon success. NOTE: future patches will pass a successful flavor to nfs_clone_server() for new fsid nfs_server setup. Signed-off-by: Andy Adamson Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 3 +++ fs/nfs/nfs4proc.c | 42 ++++++++++++++++++++++++++++++++++++++++++ fs/nfs/nfs4xdr.c | 4 ---- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 3ff47de..f85f2b2 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -168,6 +168,9 @@ extern ssize_t nfs4_getxattr(struct dentry *, const char *, void *, size_t); extern int nfs4_setxattr(struct dentry *, const char *, const void *, size_t, int); extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); +/* client.c */ +extern void nfs4_shutdown_wrongsec(struct nfs4_exception *); +extern int nfs4_clnt_try_next_flavor(struct nfs_server *, struct nfs4_exception *); /* nfs4proc.c */ extern int nfs4_map_errors(int err); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8df5c0e..afeb5bf 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -65,6 +65,8 @@ static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *) static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); +int nfs4_proc_secinfo(struct nfs_server *, struct nfs_fh *, struct qstr *, struct nfs4_secinfo_res *); + /* Prevent leaks of NFSv4 errors into userland */ int nfs4_map_errors(int err) @@ -1601,6 +1603,8 @@ static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, .rpc_resp = &res, }; + if (exc->ex_cred) + msg.rpc_cred = exc->ex_cred; nfs_fattr_init(fattr); dprintk("NFS call lookup %s\n", name->name); @@ -2752,6 +2756,37 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) return res; } +static int nfs4_wrongsec(struct nfs4_exception *exc, struct nfs_server *server) +{ + int err = -EACCES; + + dprintk("--> nfs4_wrongsec\n"); + + if (exc->ex_list) + goto try; + switch(exc->ex_info.op) { + case OP_LOOKUP: + err = -ENOMEM; + exc->ex_list = kzalloc(sizeof(*exc->ex_list), GFP_KERNEL); + if (!exc->ex_list) + goto out; + err = nfs4_proc_secinfo(server, exc->ex_info.fh, + exc->ex_info.name, + exc->ex_list); + break; + default: + printk("ERROR: %s() don't know what to do for op=%d\n", __FUNCTION__, exc->ex_info.op); + break; + } + if (err != 0) + goto out; +try: + err = nfs4_clnt_try_next_flavor(server, exc); +out: + dprintk("<-- nfs4_wrongsec error %d\n", err); + return err; +} + /* This is the error handling routine for processes that are allowed * to sleep. */ @@ -2763,6 +2798,8 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, exception->retry = 0; switch(errorcode) { case 0: + if (exception->ex_list) + nfs4_shutdown_wrongsec(exception); return 0; case -NFS4ERR_STALE_CLIENTID: case -NFS4ERR_STALE_STATEID: @@ -2780,6 +2817,11 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, break; case -NFS4ERR_OLD_STATEID: exception->retry = 1; + break; + case -NFS4ERR_WRONGSEC: + ret = nfs4_wrongsec(exception, (struct nfs_server *)server); + if (ret == 0) + exception->retry = 1; } /* We failed to handle the error */ return nfs4_map_errors(ret); diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index e561cc8..4eb8a59 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -4636,10 +4636,6 @@ static struct { { NFS4ERR_SYMLINK, ELOOP }, { NFS4ERR_OP_ILLEGAL, EOPNOTSUPP }, { NFS4ERR_DEADLOCK, EDEADLK }, - { NFS4ERR_WRONGSEC, EPERM }, /* FIXME: this needs - * to be handled by a - * middle-layer. - */ { -1, EIO } };