diff options
Diffstat (limited to 'net/sunrpc')
| -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 |
4 files changed, 111 insertions, 62 deletions
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) | |||
| 184 | */ | 184 | */ |
| 185 | struct rpc_cred * | 185 | struct rpc_cred * |
| 186 | rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | 186 | rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, |
| 187 | int taskflags) | 187 | int flags) |
| 188 | { | 188 | { |
| 189 | struct rpc_cred_cache *cache = auth->au_credcache; | 189 | struct rpc_cred_cache *cache = auth->au_credcache; |
| 190 | HLIST_HEAD(free); | 190 | HLIST_HEAD(free); |
| @@ -193,7 +193,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
| 193 | *cred = NULL; | 193 | *cred = NULL; |
| 194 | int nr = 0; | 194 | int nr = 0; |
| 195 | 195 | ||
| 196 | if (!(taskflags & RPC_TASK_ROOTCREDS)) | 196 | if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) |
| 197 | nr = acred->uid & RPC_CREDCACHE_MASK; | 197 | nr = acred->uid & RPC_CREDCACHE_MASK; |
| 198 | retry: | 198 | retry: |
| 199 | spin_lock(&rpc_credcache_lock); | 199 | spin_lock(&rpc_credcache_lock); |
| @@ -202,7 +202,7 @@ retry: | |||
| 202 | hlist_for_each_safe(pos, next, &cache->hashtable[nr]) { | 202 | hlist_for_each_safe(pos, next, &cache->hashtable[nr]) { |
| 203 | struct rpc_cred *entry; | 203 | struct rpc_cred *entry; |
| 204 | entry = hlist_entry(pos, struct rpc_cred, cr_hash); | 204 | entry = hlist_entry(pos, struct rpc_cred, cr_hash); |
| 205 | if (entry->cr_ops->crmatch(acred, entry, taskflags)) { | 205 | if (entry->cr_ops->crmatch(acred, entry, flags)) { |
| 206 | hlist_del(&entry->cr_hash); | 206 | hlist_del(&entry->cr_hash); |
| 207 | cred = entry; | 207 | cred = entry; |
| 208 | break; | 208 | break; |
| @@ -224,7 +224,7 @@ retry: | |||
| 224 | rpcauth_destroy_credlist(&free); | 224 | rpcauth_destroy_credlist(&free); |
| 225 | 225 | ||
| 226 | if (!cred) { | 226 | if (!cred) { |
| 227 | new = auth->au_ops->crcreate(auth, acred, taskflags); | 227 | new = auth->au_ops->crcreate(auth, acred, flags); |
| 228 | if (!IS_ERR(new)) { | 228 | if (!IS_ERR(new)) { |
| 229 | #ifdef RPC_DEBUG | 229 | #ifdef RPC_DEBUG |
| 230 | new->cr_magic = RPCAUTH_CRED_MAGIC; | 230 | new->cr_magic = RPCAUTH_CRED_MAGIC; |
| @@ -232,13 +232,21 @@ retry: | |||
| 232 | goto retry; | 232 | goto retry; |
| 233 | } else | 233 | } else |
| 234 | cred = new; | 234 | cred = new; |
| 235 | } else if ((cred->cr_flags & RPCAUTH_CRED_NEW) | ||
| 236 | && cred->cr_ops->cr_init != NULL | ||
| 237 | && !(flags & RPCAUTH_LOOKUP_NEW)) { | ||
| 238 | int res = cred->cr_ops->cr_init(auth, cred); | ||
| 239 | if (res < 0) { | ||
| 240 | put_rpccred(cred); | ||
| 241 | cred = ERR_PTR(res); | ||
| 242 | } | ||
| 235 | } | 243 | } |
| 236 | 244 | ||
| 237 | return (struct rpc_cred *) cred; | 245 | return (struct rpc_cred *) cred; |
| 238 | } | 246 | } |
| 239 | 247 | ||
| 240 | struct rpc_cred * | 248 | struct rpc_cred * |
| 241 | rpcauth_lookupcred(struct rpc_auth *auth, int taskflags) | 249 | rpcauth_lookupcred(struct rpc_auth *auth, int flags) |
| 242 | { | 250 | { |
| 243 | struct auth_cred acred = { | 251 | struct auth_cred acred = { |
| 244 | .uid = current->fsuid, | 252 | .uid = current->fsuid, |
| @@ -250,7 +258,7 @@ rpcauth_lookupcred(struct rpc_auth *auth, int taskflags) | |||
| 250 | dprintk("RPC: looking up %s cred\n", | 258 | dprintk("RPC: looking up %s cred\n", |
| 251 | auth->au_ops->au_name); | 259 | auth->au_ops->au_name); |
| 252 | get_group_info(acred.group_info); | 260 | get_group_info(acred.group_info); |
| 253 | ret = auth->au_ops->lookup_cred(auth, &acred, taskflags); | 261 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); |
| 254 | put_group_info(acred.group_info); | 262 | put_group_info(acred.group_info); |
| 255 | return ret; | 263 | return ret; |
| 256 | } | 264 | } |
| @@ -265,11 +273,14 @@ rpcauth_bindcred(struct rpc_task *task) | |||
| 265 | .group_info = current->group_info, | 273 | .group_info = current->group_info, |
| 266 | }; | 274 | }; |
| 267 | struct rpc_cred *ret; | 275 | struct rpc_cred *ret; |
| 276 | int flags = 0; | ||
| 268 | 277 | ||
| 269 | dprintk("RPC: %4d looking up %s cred\n", | 278 | dprintk("RPC: %4d looking up %s cred\n", |
| 270 | task->tk_pid, task->tk_auth->au_ops->au_name); | 279 | task->tk_pid, task->tk_auth->au_ops->au_name); |
| 271 | get_group_info(acred.group_info); | 280 | get_group_info(acred.group_info); |
| 272 | ret = auth->au_ops->lookup_cred(auth, &acred, task->tk_flags); | 281 | if (task->tk_flags & RPC_TASK_ROOTCREDS) |
| 282 | flags |= RPCAUTH_LOOKUP_ROOTCREDS; | ||
| 283 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); | ||
| 273 | if (!IS_ERR(ret)) | 284 | if (!IS_ERR(ret)) |
| 274 | task->tk_msg.rpc_cred = ret; | 285 | task->tk_msg.rpc_cred = ret; |
| 275 | else | 286 | 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) | |||
| 158 | old = gss_cred->gc_ctx; | 158 | old = gss_cred->gc_ctx; |
| 159 | gss_cred->gc_ctx = ctx; | 159 | gss_cred->gc_ctx = ctx; |
| 160 | cred->cr_flags |= RPCAUTH_CRED_UPTODATE; | 160 | cred->cr_flags |= RPCAUTH_CRED_UPTODATE; |
| 161 | cred->cr_flags &= ~RPCAUTH_CRED_NEW; | ||
| 161 | write_unlock(&gss_ctx_lock); | 162 | write_unlock(&gss_ctx_lock); |
| 162 | if (old) | 163 | if (old) |
| 163 | gss_put_ctx(old); | 164 | gss_put_ctx(old); |
| @@ -580,7 +581,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
| 580 | } else { | 581 | } else { |
| 581 | struct auth_cred acred = { .uid = uid }; | 582 | struct auth_cred acred = { .uid = uid }; |
| 582 | spin_unlock(&gss_auth->lock); | 583 | spin_unlock(&gss_auth->lock); |
| 583 | cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, 0); | 584 | cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, RPCAUTH_LOOKUP_NEW); |
| 584 | if (IS_ERR(cred)) { | 585 | if (IS_ERR(cred)) { |
| 585 | err = PTR_ERR(cred); | 586 | err = PTR_ERR(cred); |
| 586 | goto err_put_ctx; | 587 | goto err_put_ctx; |
| @@ -758,13 +759,13 @@ gss_destroy_cred(struct rpc_cred *rc) | |||
| 758 | * Lookup RPCSEC_GSS cred for the current process | 759 | * Lookup RPCSEC_GSS cred for the current process |
| 759 | */ | 760 | */ |
| 760 | static struct rpc_cred * | 761 | static struct rpc_cred * |
| 761 | gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) | 762 | gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) |
| 762 | { | 763 | { |
| 763 | return rpcauth_lookup_credcache(auth, acred, taskflags); | 764 | return rpcauth_lookup_credcache(auth, acred, flags); |
| 764 | } | 765 | } |
| 765 | 766 | ||
| 766 | static struct rpc_cred * | 767 | static struct rpc_cred * |
| 767 | gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) | 768 | gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) |
| 768 | { | 769 | { |
| 769 | struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth); | 770 | struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth); |
| 770 | struct gss_cred *cred = NULL; | 771 | struct gss_cred *cred = NULL; |
| @@ -785,13 +786,8 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) | |||
| 785 | */ | 786 | */ |
| 786 | cred->gc_flags = 0; | 787 | cred->gc_flags = 0; |
| 787 | cred->gc_base.cr_ops = &gss_credops; | 788 | cred->gc_base.cr_ops = &gss_credops; |
| 789 | cred->gc_base.cr_flags = RPCAUTH_CRED_NEW; | ||
| 788 | cred->gc_service = gss_auth->service; | 790 | cred->gc_service = gss_auth->service; |
| 789 | do { | ||
| 790 | err = gss_create_upcall(gss_auth, cred); | ||
| 791 | } while (err == -EAGAIN); | ||
| 792 | if (err < 0) | ||
| 793 | goto out_err; | ||
| 794 | |||
| 795 | return &cred->gc_base; | 791 | return &cred->gc_base; |
| 796 | 792 | ||
| 797 | out_err: | 793 | out_err: |
| @@ -801,13 +797,34 @@ out_err: | |||
| 801 | } | 797 | } |
| 802 | 798 | ||
| 803 | static int | 799 | static int |
| 804 | gss_match(struct auth_cred *acred, struct rpc_cred *rc, int taskflags) | 800 | gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred) |
| 801 | { | ||
| 802 | struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth); | ||
| 803 | struct gss_cred *gss_cred = container_of(cred,struct gss_cred, gc_base); | ||
| 804 | int err; | ||
| 805 | |||
| 806 | do { | ||
| 807 | err = gss_create_upcall(gss_auth, gss_cred); | ||
| 808 | } while (err == -EAGAIN); | ||
| 809 | return err; | ||
| 810 | } | ||
| 811 | |||
| 812 | static int | ||
| 813 | gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) | ||
| 805 | { | 814 | { |
| 806 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); | 815 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); |
| 807 | 816 | ||
| 817 | /* | ||
| 818 | * If the searchflags have set RPCAUTH_LOOKUP_NEW, then | ||
| 819 | * we don't really care if the credential has expired or not, | ||
| 820 | * since the caller should be prepared to reinitialise it. | ||
| 821 | */ | ||
| 822 | if ((flags & RPCAUTH_LOOKUP_NEW) && (rc->cr_flags & RPCAUTH_CRED_NEW)) | ||
| 823 | goto out; | ||
| 808 | /* Don't match with creds that have expired. */ | 824 | /* Don't match with creds that have expired. */ |
| 809 | if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) | 825 | if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) |
| 810 | return 0; | 826 | return 0; |
| 827 | out: | ||
| 811 | return (rc->cr_uid == acred->uid); | 828 | return (rc->cr_uid == acred->uid); |
| 812 | } | 829 | } |
| 813 | 830 | ||
| @@ -1241,6 +1258,7 @@ static struct rpc_authops authgss_ops = { | |||
| 1241 | static struct rpc_credops gss_credops = { | 1258 | static struct rpc_credops gss_credops = { |
| 1242 | .cr_name = "AUTH_GSS", | 1259 | .cr_name = "AUTH_GSS", |
| 1243 | .crdestroy = gss_destroy_cred, | 1260 | .crdestroy = gss_destroy_cred, |
| 1261 | .cr_init = gss_cred_init, | ||
| 1244 | .crmatch = gss_match, | 1262 | .crmatch = gss_match, |
| 1245 | .crmarshal = gss_marshal, | 1263 | .crmarshal = gss_marshal, |
| 1246 | .crrefresh = gss_refresh, | 1264 | .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) | |||
| 75 | 75 | ||
| 76 | atomic_set(&cred->uc_count, 1); | 76 | atomic_set(&cred->uc_count, 1); |
| 77 | cred->uc_flags = RPCAUTH_CRED_UPTODATE; | 77 | cred->uc_flags = RPCAUTH_CRED_UPTODATE; |
| 78 | if (flags & RPC_TASK_ROOTCREDS) { | 78 | if (flags & RPCAUTH_LOOKUP_ROOTCREDS) { |
| 79 | cred->uc_uid = 0; | 79 | cred->uc_uid = 0; |
| 80 | cred->uc_gid = 0; | 80 | cred->uc_gid = 0; |
| 81 | cred->uc_gids[0] = NOGROUP; | 81 | cred->uc_gids[0] = NOGROUP; |
| @@ -108,12 +108,12 @@ unx_destroy_cred(struct rpc_cred *cred) | |||
| 108 | * request root creds (e.g. for NFS swapping). | 108 | * request root creds (e.g. for NFS swapping). |
| 109 | */ | 109 | */ |
| 110 | static int | 110 | static int |
| 111 | unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags) | 111 | unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags) |
| 112 | { | 112 | { |
| 113 | struct unx_cred *cred = (struct unx_cred *) rcred; | 113 | struct unx_cred *cred = (struct unx_cred *) rcred; |
| 114 | int i; | 114 | int i; |
| 115 | 115 | ||
| 116 | if (!(taskflags & RPC_TASK_ROOTCREDS)) { | 116 | if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) { |
| 117 | int groups; | 117 | int groups; |
| 118 | 118 | ||
| 119 | if (cred->uc_uid != acred->uid | 119 | 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; | |||
| 38 | 38 | ||
| 39 | #define RPC_UPCALL_TIMEOUT (30*HZ) | 39 | #define RPC_UPCALL_TIMEOUT (30*HZ) |
| 40 | 40 | ||
| 41 | static void | 41 | static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, |
| 42 | __rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, int err) | 42 | void (*destroy_msg)(struct rpc_pipe_msg *), int err) |
| 43 | { | 43 | { |
| 44 | struct rpc_pipe_msg *msg; | 44 | struct rpc_pipe_msg *msg; |
| 45 | void (*destroy_msg)(struct rpc_pipe_msg *); | ||
| 46 | 45 | ||
| 47 | destroy_msg = rpci->ops->destroy_msg; | 46 | if (list_empty(head)) |
| 48 | while (!list_empty(head)) { | 47 | return; |
| 48 | do { | ||
| 49 | msg = list_entry(head->next, struct rpc_pipe_msg, list); | 49 | msg = list_entry(head->next, struct rpc_pipe_msg, list); |
| 50 | list_del_init(&msg->list); | 50 | list_del(&msg->list); |
| 51 | msg->errno = err; | 51 | msg->errno = err; |
| 52 | destroy_msg(msg); | 52 | destroy_msg(msg); |
| 53 | } | 53 | } while (!list_empty(head)); |
| 54 | } | ||
| 55 | |||
| 56 | static void | ||
| 57 | __rpc_purge_upcall(struct inode *inode, int err) | ||
| 58 | { | ||
| 59 | struct rpc_inode *rpci = RPC_I(inode); | ||
| 60 | |||
| 61 | __rpc_purge_list(rpci, &rpci->pipe, err); | ||
| 62 | rpci->pipelen = 0; | ||
| 63 | wake_up(&rpci->waitq); | 54 | wake_up(&rpci->waitq); |
| 64 | } | 55 | } |
| 65 | 56 | ||
| 66 | static void | 57 | static void |
| 67 | rpc_timeout_upcall_queue(void *data) | 58 | rpc_timeout_upcall_queue(void *data) |
| 68 | { | 59 | { |
| 60 | LIST_HEAD(free_list); | ||
| 69 | struct rpc_inode *rpci = (struct rpc_inode *)data; | 61 | struct rpc_inode *rpci = (struct rpc_inode *)data; |
| 70 | struct inode *inode = &rpci->vfs_inode; | 62 | struct inode *inode = &rpci->vfs_inode; |
| 63 | void (*destroy_msg)(struct rpc_pipe_msg *); | ||
| 71 | 64 | ||
| 72 | mutex_lock(&inode->i_mutex); | 65 | spin_lock(&inode->i_lock); |
| 73 | if (rpci->ops == NULL) | 66 | if (rpci->ops == NULL) { |
| 74 | goto out; | 67 | spin_unlock(&inode->i_lock); |
| 75 | if (rpci->nreaders == 0 && !list_empty(&rpci->pipe)) | 68 | return; |
| 76 | __rpc_purge_upcall(inode, -ETIMEDOUT); | 69 | } |
| 77 | out: | 70 | destroy_msg = rpci->ops->destroy_msg; |
| 78 | mutex_unlock(&inode->i_mutex); | 71 | if (rpci->nreaders == 0) { |
| 72 | list_splice_init(&rpci->pipe, &free_list); | ||
| 73 | rpci->pipelen = 0; | ||
| 74 | } | ||
| 75 | spin_unlock(&inode->i_lock); | ||
| 76 | rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT); | ||
| 79 | } | 77 | } |
| 80 | 78 | ||
| 81 | int | 79 | int |
| @@ -84,7 +82,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) | |||
| 84 | struct rpc_inode *rpci = RPC_I(inode); | 82 | struct rpc_inode *rpci = RPC_I(inode); |
| 85 | int res = -EPIPE; | 83 | int res = -EPIPE; |
| 86 | 84 | ||
| 87 | mutex_lock(&inode->i_mutex); | 85 | spin_lock(&inode->i_lock); |
| 88 | if (rpci->ops == NULL) | 86 | if (rpci->ops == NULL) |
| 89 | goto out; | 87 | goto out; |
| 90 | if (rpci->nreaders) { | 88 | if (rpci->nreaders) { |
| @@ -100,7 +98,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) | |||
| 100 | res = 0; | 98 | res = 0; |
| 101 | } | 99 | } |
| 102 | out: | 100 | out: |
| 103 | mutex_unlock(&inode->i_mutex); | 101 | spin_unlock(&inode->i_lock); |
| 104 | wake_up(&rpci->waitq); | 102 | wake_up(&rpci->waitq); |
| 105 | return res; | 103 | return res; |
| 106 | } | 104 | } |
| @@ -115,21 +113,29 @@ static void | |||
| 115 | rpc_close_pipes(struct inode *inode) | 113 | rpc_close_pipes(struct inode *inode) |
| 116 | { | 114 | { |
| 117 | struct rpc_inode *rpci = RPC_I(inode); | 115 | struct rpc_inode *rpci = RPC_I(inode); |
| 116 | struct rpc_pipe_ops *ops; | ||
| 118 | 117 | ||
| 119 | mutex_lock(&inode->i_mutex); | 118 | mutex_lock(&inode->i_mutex); |
| 120 | if (rpci->ops != NULL) { | 119 | ops = rpci->ops; |
| 120 | if (ops != NULL) { | ||
| 121 | LIST_HEAD(free_list); | ||
| 122 | |||
| 123 | spin_lock(&inode->i_lock); | ||
| 121 | rpci->nreaders = 0; | 124 | rpci->nreaders = 0; |
| 122 | __rpc_purge_list(rpci, &rpci->in_upcall, -EPIPE); | 125 | list_splice_init(&rpci->in_upcall, &free_list); |
| 123 | __rpc_purge_upcall(inode, -EPIPE); | 126 | list_splice_init(&rpci->pipe, &free_list); |
| 124 | rpci->nwriters = 0; | 127 | rpci->pipelen = 0; |
| 125 | if (rpci->ops->release_pipe) | ||
| 126 | rpci->ops->release_pipe(inode); | ||
| 127 | rpci->ops = NULL; | 128 | rpci->ops = NULL; |
| 129 | spin_unlock(&inode->i_lock); | ||
| 130 | rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE); | ||
| 131 | rpci->nwriters = 0; | ||
| 132 | if (ops->release_pipe) | ||
| 133 | ops->release_pipe(inode); | ||
| 134 | cancel_delayed_work(&rpci->queue_timeout); | ||
| 135 | flush_scheduled_work(); | ||
| 128 | } | 136 | } |
| 129 | rpc_inode_setowner(inode, NULL); | 137 | rpc_inode_setowner(inode, NULL); |
| 130 | mutex_unlock(&inode->i_mutex); | 138 | mutex_unlock(&inode->i_mutex); |
| 131 | cancel_delayed_work(&rpci->queue_timeout); | ||
| 132 | flush_scheduled_work(); | ||
| 133 | } | 139 | } |
| 134 | 140 | ||
| 135 | static struct inode * | 141 | static struct inode * |
| @@ -177,16 +183,26 @@ rpc_pipe_release(struct inode *inode, struct file *filp) | |||
| 177 | goto out; | 183 | goto out; |
| 178 | msg = (struct rpc_pipe_msg *)filp->private_data; | 184 | msg = (struct rpc_pipe_msg *)filp->private_data; |
| 179 | if (msg != NULL) { | 185 | if (msg != NULL) { |
| 186 | spin_lock(&inode->i_lock); | ||
| 180 | msg->errno = -EAGAIN; | 187 | msg->errno = -EAGAIN; |
| 181 | list_del_init(&msg->list); | 188 | list_del(&msg->list); |
| 189 | spin_unlock(&inode->i_lock); | ||
| 182 | rpci->ops->destroy_msg(msg); | 190 | rpci->ops->destroy_msg(msg); |
| 183 | } | 191 | } |
| 184 | if (filp->f_mode & FMODE_WRITE) | 192 | if (filp->f_mode & FMODE_WRITE) |
| 185 | rpci->nwriters --; | 193 | rpci->nwriters --; |
| 186 | if (filp->f_mode & FMODE_READ) | 194 | if (filp->f_mode & FMODE_READ) { |
| 187 | rpci->nreaders --; | 195 | rpci->nreaders --; |
| 188 | if (!rpci->nreaders) | 196 | if (rpci->nreaders == 0) { |
| 189 | __rpc_purge_upcall(inode, -EAGAIN); | 197 | LIST_HEAD(free_list); |
| 198 | spin_lock(&inode->i_lock); | ||
| 199 | list_splice_init(&rpci->pipe, &free_list); | ||
| 200 | rpci->pipelen = 0; | ||
| 201 | spin_unlock(&inode->i_lock); | ||
| 202 | rpc_purge_list(rpci, &free_list, | ||
| 203 | rpci->ops->destroy_msg, -EAGAIN); | ||
| 204 | } | ||
| 205 | } | ||
| 190 | if (rpci->ops->release_pipe) | 206 | if (rpci->ops->release_pipe) |
| 191 | rpci->ops->release_pipe(inode); | 207 | rpci->ops->release_pipe(inode); |
| 192 | out: | 208 | out: |
| @@ -209,6 +225,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) | |||
| 209 | } | 225 | } |
| 210 | msg = filp->private_data; | 226 | msg = filp->private_data; |
| 211 | if (msg == NULL) { | 227 | if (msg == NULL) { |
| 228 | spin_lock(&inode->i_lock); | ||
| 212 | if (!list_empty(&rpci->pipe)) { | 229 | if (!list_empty(&rpci->pipe)) { |
| 213 | msg = list_entry(rpci->pipe.next, | 230 | msg = list_entry(rpci->pipe.next, |
| 214 | struct rpc_pipe_msg, | 231 | struct rpc_pipe_msg, |
| @@ -218,6 +235,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) | |||
| 218 | filp->private_data = msg; | 235 | filp->private_data = msg; |
| 219 | msg->copied = 0; | 236 | msg->copied = 0; |
| 220 | } | 237 | } |
| 238 | spin_unlock(&inode->i_lock); | ||
| 221 | if (msg == NULL) | 239 | if (msg == NULL) |
| 222 | goto out_unlock; | 240 | goto out_unlock; |
| 223 | } | 241 | } |
| @@ -225,7 +243,9 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) | |||
| 225 | res = rpci->ops->upcall(filp, msg, buf, len); | 243 | res = rpci->ops->upcall(filp, msg, buf, len); |
| 226 | if (res < 0 || msg->len == msg->copied) { | 244 | if (res < 0 || msg->len == msg->copied) { |
| 227 | filp->private_data = NULL; | 245 | filp->private_data = NULL; |
| 228 | list_del_init(&msg->list); | 246 | spin_lock(&inode->i_lock); |
| 247 | list_del(&msg->list); | ||
| 248 | spin_unlock(&inode->i_lock); | ||
| 229 | rpci->ops->destroy_msg(msg); | 249 | rpci->ops->destroy_msg(msg); |
| 230 | } | 250 | } |
| 231 | out_unlock: | 251 | out_unlock: |
| @@ -610,7 +630,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd) | |||
| 610 | return ERR_PTR(error); | 630 | return ERR_PTR(error); |
| 611 | dir = nd->dentry->d_inode; | 631 | dir = nd->dentry->d_inode; |
| 612 | mutex_lock(&dir->i_mutex); | 632 | mutex_lock(&dir->i_mutex); |
| 613 | dentry = lookup_hash(nd); | 633 | dentry = lookup_one_len(nd->last.name, nd->dentry, nd->last.len); |
| 614 | if (IS_ERR(dentry)) | 634 | if (IS_ERR(dentry)) |
| 615 | goto out_err; | 635 | goto out_err; |
| 616 | if (dentry->d_inode) { | 636 | if (dentry->d_inode) { |
| @@ -672,7 +692,7 @@ rpc_rmdir(char *path) | |||
| 672 | return error; | 692 | return error; |
| 673 | dir = nd.dentry->d_inode; | 693 | dir = nd.dentry->d_inode; |
| 674 | mutex_lock(&dir->i_mutex); | 694 | mutex_lock(&dir->i_mutex); |
| 675 | dentry = lookup_hash(&nd); | 695 | dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len); |
| 676 | if (IS_ERR(dentry)) { | 696 | if (IS_ERR(dentry)) { |
| 677 | error = PTR_ERR(dentry); | 697 | error = PTR_ERR(dentry); |
| 678 | goto out_release; | 698 | goto out_release; |
| @@ -733,7 +753,7 @@ rpc_unlink(char *path) | |||
| 733 | return error; | 753 | return error; |
| 734 | dir = nd.dentry->d_inode; | 754 | dir = nd.dentry->d_inode; |
| 735 | mutex_lock(&dir->i_mutex); | 755 | mutex_lock(&dir->i_mutex); |
| 736 | dentry = lookup_hash(&nd); | 756 | dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len); |
| 737 | if (IS_ERR(dentry)) { | 757 | if (IS_ERR(dentry)) { |
| 738 | error = PTR_ERR(dentry); | 758 | error = PTR_ERR(dentry); |
| 739 | goto out_release; | 759 | goto out_release; |
