diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-02-01 12:18:44 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-02-01 12:52:24 -0500 |
commit | 9842ef3557abf5ec2fd92bfa6e29ce0e271b3f6e (patch) | |
tree | 03c5059d866eb40956fe01094d9bc1b811d9c4f0 /net/sunrpc/rpc_pipe.c | |
parent | 8a3177604b729ec3b80e43790ee978863ac7551b (diff) |
SUNRPC: rpc_timeout_upcall_queue should not sleep
The function rpc_timeout_upcall_queue runs from a workqueue, and hence
sleeping is not recommended. Convert the protection of the upcall queue
from being mutex-based to being spinlock-based.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/rpc_pipe.c')
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 96 |
1 files changed, 58 insertions, 38 deletions
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 9764c80ab0b2..7281746e6532 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: |