diff options
-rw-r--r-- | fs/lockd/clntproc.c | 11 | ||||
-rw-r--r-- | fs/nfs/direct.c | 2 | ||||
-rw-r--r-- | include/linux/lockd/lockd.h | 2 | ||||
-rw-r--r-- | include/linux/sunrpc/auth.h | 10 | ||||
-rw-r--r-- | net/sunrpc/auth.c | 25 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 40 | ||||
-rw-r--r-- | net/sunrpc/auth_unix.c | 6 | ||||
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 102 |
8 files changed, 127 insertions, 71 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 145524039577..220058d8616d 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -22,12 +22,14 @@ #define NLMDBG_FACILITY NLMDBG_CLIENT #define NLMCLNT_GRACE_WAIT (5*HZ) #define NLMCLNT_POLL_TIMEOUT (30*HZ) +#define NLMCLNT_MAX_RETRIES 3 static int nlmclnt_test(struct nlm_rqst *, struct file_lock *); static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *); static int nlmclnt_unlock(struct nlm_rqst *, struct file_lock *); static int nlm_stat_to_errno(u32 stat); static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host); +static int nlmclnt_cancel(struct nlm_host *, int , struct file_lock *); static const struct rpc_call_ops nlmclnt_unlock_ops; static const struct rpc_call_ops nlmclnt_cancel_ops; @@ -598,7 +600,7 @@ out_unblock: nlmclnt_finish_block(req); /* Cancel the blocked request if it is still pending */ if (resp->status == NLM_LCK_BLOCKED) - nlmclnt_cancel(host, fl); + nlmclnt_cancel(host, req->a_args.block, fl); out: nlmclnt_release_lockargs(req); return status; @@ -728,8 +730,7 @@ static const struct rpc_call_ops nlmclnt_unlock_ops = { * We always use an async RPC call for this in order not to hang a * process that has been Ctrl-C'ed. */ -int -nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl) +static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl) { struct nlm_rqst *req; unsigned long flags; @@ -750,6 +751,7 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl) req->a_flags = RPC_TASK_ASYNC; nlmclnt_setlockargs(req, fl); + req->a_args.block = block; status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops); if (status < 0) { @@ -801,6 +803,9 @@ die: return; retry_cancel: + /* Don't ever retry more than 3 times */ + if (req->a_retries++ >= NLMCLNT_MAX_RETRIES) + goto die; nlm_rebind_host(req->a_host); rpc_restart_call(task); rpc_delay(task, 30 * HZ); diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 10ae377e68ff..04ab2fc360e7 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -481,7 +481,7 @@ retry: if (wdata->verf.committed != NFS_FILE_SYNC) { need_commit = 1; if (memcmp(&first_verf.verifier, &wdata->verf.verifier, - sizeof(first_verf.verifier))); + sizeof(first_verf.verifier))) goto sync_retry; } diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 95c8fea293ba..920766cea79c 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -84,6 +84,7 @@ struct nlm_rqst { struct nlm_args a_args; /* arguments */ struct nlm_res a_res; /* result */ struct nlm_wait * a_block; + unsigned int a_retries; /* Retry count */ char a_owner[NLMCLNT_OHSIZE]; }; @@ -148,7 +149,6 @@ struct nlm_rqst * nlmclnt_alloc_call(void); int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl); void nlmclnt_finish_block(struct nlm_rqst *req); long nlmclnt_block(struct nlm_rqst *req, long timeout); -int nlmclnt_cancel(struct nlm_host *, struct file_lock *); u32 nlmclnt_grant(struct nlm_lock *); void nlmclnt_recovery(struct nlm_host *, u32); int nlmclnt_reclaim(struct nlm_host *, struct file_lock *); diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index b68c11a2d6dd..be4772ed43c0 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -48,7 +48,7 @@ struct rpc_cred { /* per-flavor data */ }; -#define RPCAUTH_CRED_LOCKED 0x0001 +#define RPCAUTH_CRED_NEW 0x0001 #define RPCAUTH_CRED_UPTODATE 0x0002 #define RPCAUTH_CRED_MAGIC 0x0f4aa4f0 @@ -83,9 +83,10 @@ struct rpc_auth { struct rpc_cred_cache * au_credcache; /* per-flavor data */ }; -#define RPC_AUTH_PROC_CREDS 0x0010 /* process creds (including - * uid/gid, fs[ug]id, gids) - */ + +/* Flags for rpcauth_lookupcred() */ +#define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */ +#define RPCAUTH_LOOKUP_ROOTCREDS 0x02 /* This really ought to go! */ /* * Client authentication ops @@ -105,6 +106,7 @@ struct rpc_authops { struct rpc_credops { const char * cr_name; /* Name of the auth flavour */ + int (*cr_init)(struct rpc_auth *, struct rpc_cred *); void (*crdestroy)(struct rpc_cred *); int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 9ac1b8c26c01..8d6f1a176b15 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -184,7 +184,7 @@ rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free) */ struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, - int taskflags) + int flags) { struct rpc_cred_cache *cache = auth->au_credcache; HLIST_HEAD(free); @@ -193,7 +193,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, *cred = NULL; int nr = 0; - if (!(taskflags & RPC_TASK_ROOTCREDS)) + if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) nr = acred->uid & RPC_CREDCACHE_MASK; retry: spin_lock(&rpc_credcache_lock); @@ -202,7 +202,7 @@ retry: hlist_for_each_safe(pos, next, &cache->hashtable[nr]) { struct rpc_cred *entry; entry = hlist_entry(pos, struct rpc_cred, cr_hash); - if (entry->cr_ops->crmatch(acred, entry, taskflags)) { + if (entry->cr_ops->crmatch(acred, entry, flags)) { hlist_del(&entry->cr_hash); cred = entry; break; @@ -224,7 +224,7 @@ retry: rpcauth_destroy_credlist(&free); if (!cred) { - new = auth->au_ops->crcreate(auth, acred, taskflags); + new = auth->au_ops->crcreate(auth, acred, flags); if (!IS_ERR(new)) { #ifdef RPC_DEBUG new->cr_magic = RPCAUTH_CRED_MAGIC; @@ -232,13 +232,21 @@ retry: goto retry; } else cred = new; + } else if ((cred->cr_flags & RPCAUTH_CRED_NEW) + && cred->cr_ops->cr_init != NULL + && !(flags & RPCAUTH_LOOKUP_NEW)) { + int res = cred->cr_ops->cr_init(auth, cred); + if (res < 0) { + put_rpccred(cred); + cred = ERR_PTR(res); + } } return (struct rpc_cred *) cred; } struct rpc_cred * -rpcauth_lookupcred(struct rpc_auth *auth, int taskflags) +rpcauth_lookupcred(struct rpc_auth *auth, int flags) { struct auth_cred acred = { .uid = current->fsuid, @@ -250,7 +258,7 @@ rpcauth_lookupcred(struct rpc_auth *auth, int taskflags) dprintk("RPC: looking up %s cred\n", auth->au_ops->au_name); get_group_info(acred.group_info); - ret = auth->au_ops->lookup_cred(auth, &acred, taskflags); + ret = auth->au_ops->lookup_cred(auth, &acred, flags); put_group_info(acred.group_info); return ret; } @@ -265,11 +273,14 @@ rpcauth_bindcred(struct rpc_task *task) .group_info = current->group_info, }; struct rpc_cred *ret; + int flags = 0; dprintk("RPC: %4d looking up %s cred\n", task->tk_pid, task->tk_auth->au_ops->au_name); get_group_info(acred.group_info); - ret = auth->au_ops->lookup_cred(auth, &acred, task->tk_flags); + if (task->tk_flags & RPC_TASK_ROOTCREDS) + flags |= RPCAUTH_LOOKUP_ROOTCREDS; + ret = auth->au_ops->lookup_cred(auth, &acred, flags); if (!IS_ERR(ret)) task->tk_msg.rpc_cred = ret; else diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 8d782282ec19..bb46efd92e57 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -158,6 +158,7 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) old = gss_cred->gc_ctx; gss_cred->gc_ctx = ctx; cred->cr_flags |= RPCAUTH_CRED_UPTODATE; + cred->cr_flags &= ~RPCAUTH_CRED_NEW; write_unlock(&gss_ctx_lock); if (old) gss_put_ctx(old); @@ -580,7 +581,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) } else { struct auth_cred acred = { .uid = uid }; spin_unlock(&gss_auth->lock); - cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, 0); + cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, RPCAUTH_LOOKUP_NEW); if (IS_ERR(cred)) { err = PTR_ERR(cred); goto err_put_ctx; @@ -758,13 +759,13 @@ gss_destroy_cred(struct rpc_cred *rc) * Lookup RPCSEC_GSS cred for the current process */ static struct rpc_cred * -gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) +gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) { - return rpcauth_lookup_credcache(auth, acred, taskflags); + return rpcauth_lookup_credcache(auth, acred, flags); } static struct rpc_cred * -gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) +gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) { struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth); struct gss_cred *cred = NULL; @@ -785,13 +786,8 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) */ cred->gc_flags = 0; cred->gc_base.cr_ops = &gss_credops; + cred->gc_base.cr_flags = RPCAUTH_CRED_NEW; cred->gc_service = gss_auth->service; - do { - err = gss_create_upcall(gss_auth, cred); - } while (err == -EAGAIN); - if (err < 0) - goto out_err; - return &cred->gc_base; out_err: @@ -801,13 +797,34 @@ out_err: } static int -gss_match(struct auth_cred *acred, struct rpc_cred *rc, int taskflags) +gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred) +{ + struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth); + struct gss_cred *gss_cred = container_of(cred,struct gss_cred, gc_base); + int err; + + do { + err = gss_create_upcall(gss_auth, gss_cred); + } while (err == -EAGAIN); + return err; +} + +static int +gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) { struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); + /* + * If the searchflags have set RPCAUTH_LOOKUP_NEW, then + * we don't really care if the credential has expired or not, + * since the caller should be prepared to reinitialise it. + */ + if ((flags & RPCAUTH_LOOKUP_NEW) && (rc->cr_flags & RPCAUTH_CRED_NEW)) + goto out; /* Don't match with creds that have expired. */ if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) return 0; +out: return (rc->cr_uid == acred->uid); } @@ -1241,6 +1258,7 @@ static struct rpc_authops authgss_ops = { static struct rpc_credops gss_credops = { .cr_name = "AUTH_GSS", .crdestroy = gss_destroy_cred, + .cr_init = gss_cred_init, .crmatch = gss_match, .crmarshal = gss_marshal, .crrefresh = gss_refresh, diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index 1b3ed4fd1987..df14b6bfbf10 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c @@ -75,7 +75,7 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) atomic_set(&cred->uc_count, 1); cred->uc_flags = RPCAUTH_CRED_UPTODATE; - if (flags & RPC_TASK_ROOTCREDS) { + if (flags & RPCAUTH_LOOKUP_ROOTCREDS) { cred->uc_uid = 0; cred->uc_gid = 0; cred->uc_gids[0] = NOGROUP; @@ -108,12 +108,12 @@ unx_destroy_cred(struct rpc_cred *cred) * request root creds (e.g. for NFS swapping). */ static int -unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags) +unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags) { struct unx_cred *cred = (struct unx_cred *) rcred; int i; - if (!(taskflags & RPC_TASK_ROOTCREDS)) { + if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) { int groups; if (cred->uc_uid != acred->uid diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 9764c80ab0b2..a5c0c7b6e151 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -38,44 +38,42 @@ static kmem_cache_t *rpc_inode_cachep __read_mostly; #define RPC_UPCALL_TIMEOUT (30*HZ) -static void -__rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, int err) +static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, + void (*destroy_msg)(struct rpc_pipe_msg *), int err) { struct rpc_pipe_msg *msg; - void (*destroy_msg)(struct rpc_pipe_msg *); - destroy_msg = rpci->ops->destroy_msg; - while (!list_empty(head)) { + if (list_empty(head)) + return; + do { msg = list_entry(head->next, struct rpc_pipe_msg, list); - list_del_init(&msg->list); + list_del(&msg->list); msg->errno = err; destroy_msg(msg); - } -} - -static void -__rpc_purge_upcall(struct inode *inode, int err) -{ - struct rpc_inode *rpci = RPC_I(inode); - - __rpc_purge_list(rpci, &rpci->pipe, err); - rpci->pipelen = 0; + } while (!list_empty(head)); wake_up(&rpci->waitq); } static void rpc_timeout_upcall_queue(void *data) { + LIST_HEAD(free_list); struct rpc_inode *rpci = (struct rpc_inode *)data; struct inode *inode = &rpci->vfs_inode; + void (*destroy_msg)(struct rpc_pipe_msg *); - mutex_lock(&inode->i_mutex); - if (rpci->ops == NULL) - goto out; - if (rpci->nreaders == 0 && !list_empty(&rpci->pipe)) - __rpc_purge_upcall(inode, -ETIMEDOUT); -out: - mutex_unlock(&inode->i_mutex); + spin_lock(&inode->i_lock); + if (rpci->ops == NULL) { + spin_unlock(&inode->i_lock); + return; + } + destroy_msg = rpci->ops->destroy_msg; + if (rpci->nreaders == 0) { + list_splice_init(&rpci->pipe, &free_list); + rpci->pipelen = 0; + } + spin_unlock(&inode->i_lock); + rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT); } int @@ -84,7 +82,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) struct rpc_inode *rpci = RPC_I(inode); int res = -EPIPE; - mutex_lock(&inode->i_mutex); + spin_lock(&inode->i_lock); if (rpci->ops == NULL) goto out; if (rpci->nreaders) { @@ -100,7 +98,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) res = 0; } out: - mutex_unlock(&inode->i_mutex); + spin_unlock(&inode->i_lock); wake_up(&rpci->waitq); return res; } @@ -115,21 +113,29 @@ static void rpc_close_pipes(struct inode *inode) { struct rpc_inode *rpci = RPC_I(inode); + struct rpc_pipe_ops *ops; mutex_lock(&inode->i_mutex); - if (rpci->ops != NULL) { + ops = rpci->ops; + if (ops != NULL) { + LIST_HEAD(free_list); + + spin_lock(&inode->i_lock); rpci->nreaders = 0; - __rpc_purge_list(rpci, &rpci->in_upcall, -EPIPE); - __rpc_purge_upcall(inode, -EPIPE); - rpci->nwriters = 0; - if (rpci->ops->release_pipe) - rpci->ops->release_pipe(inode); + list_splice_init(&rpci->in_upcall, &free_list); + list_splice_init(&rpci->pipe, &free_list); + rpci->pipelen = 0; rpci->ops = NULL; + spin_unlock(&inode->i_lock); + rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE); + rpci->nwriters = 0; + if (ops->release_pipe) + ops->release_pipe(inode); + cancel_delayed_work(&rpci->queue_timeout); + flush_scheduled_work(); } rpc_inode_setowner(inode, NULL); mutex_unlock(&inode->i_mutex); - cancel_delayed_work(&rpci->queue_timeout); - flush_scheduled_work(); } static struct inode * @@ -177,16 +183,26 @@ rpc_pipe_release(struct inode *inode, struct file *filp) goto out; msg = (struct rpc_pipe_msg *)filp->private_data; if (msg != NULL) { + spin_lock(&inode->i_lock); msg->errno = -EAGAIN; - list_del_init(&msg->list); + list_del(&msg->list); + spin_unlock(&inode->i_lock); rpci->ops->destroy_msg(msg); } if (filp->f_mode & FMODE_WRITE) rpci->nwriters --; - if (filp->f_mode & FMODE_READ) + if (filp->f_mode & FMODE_READ) { rpci->nreaders --; - if (!rpci->nreaders) - __rpc_purge_upcall(inode, -EAGAIN); + if (rpci->nreaders == 0) { + LIST_HEAD(free_list); + spin_lock(&inode->i_lock); + list_splice_init(&rpci->pipe, &free_list); + rpci->pipelen = 0; + spin_unlock(&inode->i_lock); + rpc_purge_list(rpci, &free_list, + rpci->ops->destroy_msg, -EAGAIN); + } + } if (rpci->ops->release_pipe) rpci->ops->release_pipe(inode); out: @@ -209,6 +225,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) } msg = filp->private_data; if (msg == NULL) { + spin_lock(&inode->i_lock); if (!list_empty(&rpci->pipe)) { msg = list_entry(rpci->pipe.next, struct rpc_pipe_msg, @@ -218,6 +235,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) filp->private_data = msg; msg->copied = 0; } + spin_unlock(&inode->i_lock); if (msg == NULL) goto out_unlock; } @@ -225,7 +243,9 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) res = rpci->ops->upcall(filp, msg, buf, len); if (res < 0 || msg->len == msg->copied) { filp->private_data = NULL; - list_del_init(&msg->list); + spin_lock(&inode->i_lock); + list_del(&msg->list); + spin_unlock(&inode->i_lock); rpci->ops->destroy_msg(msg); } out_unlock: @@ -610,7 +630,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd) return ERR_PTR(error); dir = nd->dentry->d_inode; mutex_lock(&dir->i_mutex); - dentry = lookup_hash(nd); + dentry = lookup_one_len(nd->last.name, nd->dentry, nd->last.len); if (IS_ERR(dentry)) goto out_err; if (dentry->d_inode) { @@ -672,7 +692,7 @@ rpc_rmdir(char *path) return error; dir = nd.dentry->d_inode; mutex_lock(&dir->i_mutex); - dentry = lookup_hash(&nd); + dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len); if (IS_ERR(dentry)) { error = PTR_ERR(dentry); goto out_release; @@ -733,7 +753,7 @@ rpc_unlink(char *path) return error; dir = nd.dentry->d_inode; mutex_lock(&dir->i_mutex); - dentry = lookup_hash(&nd); + dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len); if (IS_ERR(dentry)) { error = PTR_ERR(dentry); goto out_release; |