diff options
Diffstat (limited to 'net/sunrpc/rpc_pipe.c')
| -rw-r--r-- | net/sunrpc/rpc_pipe.c | 102 |
1 files changed, 61 insertions, 41 deletions
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; |
