diff options
Diffstat (limited to 'net/9p/client.c')
-rw-r--r-- | net/9p/client.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/net/9p/client.c b/net/9p/client.c index 712d4f336adc..867031934f75 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -120,6 +120,154 @@ static int parse_opts(char *opts, struct p9_client *clnt) | |||
120 | return ret; | 120 | return ret; |
121 | } | 121 | } |
122 | 122 | ||
123 | /** | ||
124 | * p9_tag_alloc - lookup/allocate a request by tag | ||
125 | * @c: client session to lookup tag within | ||
126 | * @tag: numeric id for transaction | ||
127 | * | ||
128 | * this is a simple array lookup, but will grow the | ||
129 | * request_slots as necessary to accomodate transaction | ||
130 | * ids which did not previously have a slot. | ||
131 | * | ||
132 | * this code relies on the client spinlock to manage locks, its | ||
133 | * possible we should switch to something else, but I'd rather | ||
134 | * stick with something low-overhead for the common case. | ||
135 | * | ||
136 | */ | ||
137 | |||
138 | struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | ||
139 | { | ||
140 | unsigned long flags; | ||
141 | int row, col; | ||
142 | |||
143 | /* This looks up the original request by tag so we know which | ||
144 | * buffer to read the data into */ | ||
145 | tag++; | ||
146 | |||
147 | if (tag >= c->max_tag) { | ||
148 | spin_lock_irqsave(&c->lock, flags); | ||
149 | /* check again since original check was outside of lock */ | ||
150 | while (tag >= c->max_tag) { | ||
151 | row = (tag / P9_ROW_MAXTAG); | ||
152 | c->reqs[row] = kcalloc(P9_ROW_MAXTAG, | ||
153 | sizeof(struct p9_req_t), GFP_ATOMIC); | ||
154 | |||
155 | if (!c->reqs[row]) { | ||
156 | printk(KERN_ERR "Couldn't grow tag array\n"); | ||
157 | BUG(); | ||
158 | } | ||
159 | for (col = 0; col < P9_ROW_MAXTAG; col++) { | ||
160 | c->reqs[row][col].status = REQ_STATUS_IDLE; | ||
161 | c->reqs[row][col].flush_tag = P9_NOTAG; | ||
162 | c->reqs[row][col].wq = kmalloc( | ||
163 | sizeof(wait_queue_head_t), GFP_ATOMIC); | ||
164 | if (!c->reqs[row][col].wq) { | ||
165 | printk(KERN_ERR | ||
166 | "Couldn't grow tag array\n"); | ||
167 | BUG(); | ||
168 | } | ||
169 | init_waitqueue_head(c->reqs[row][col].wq); | ||
170 | } | ||
171 | c->max_tag += P9_ROW_MAXTAG; | ||
172 | } | ||
173 | spin_unlock_irqrestore(&c->lock, flags); | ||
174 | } | ||
175 | row = tag / P9_ROW_MAXTAG; | ||
176 | col = tag % P9_ROW_MAXTAG; | ||
177 | |||
178 | c->reqs[row][col].status = REQ_STATUS_ALLOC; | ||
179 | c->reqs[row][col].flush_tag = P9_NOTAG; | ||
180 | |||
181 | return &c->reqs[row][col]; | ||
182 | } | ||
183 | EXPORT_SYMBOL(p9_tag_alloc); | ||
184 | |||
185 | /** | ||
186 | * p9_tag_lookup - lookup a request by tag | ||
187 | * @c: client session to lookup tag within | ||
188 | * @tag: numeric id for transaction | ||
189 | * | ||
190 | */ | ||
191 | |||
192 | struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag) | ||
193 | { | ||
194 | int row, col; | ||
195 | |||
196 | /* This looks up the original request by tag so we know which | ||
197 | * buffer to read the data into */ | ||
198 | tag++; | ||
199 | |||
200 | BUG_ON(tag >= c->max_tag); | ||
201 | |||
202 | row = tag / P9_ROW_MAXTAG; | ||
203 | col = tag % P9_ROW_MAXTAG; | ||
204 | |||
205 | return &c->reqs[row][col]; | ||
206 | } | ||
207 | EXPORT_SYMBOL(p9_tag_lookup); | ||
208 | |||
209 | /** | ||
210 | * p9_tag_init - setup tags structure and contents | ||
211 | * @tags: tags structure from the client struct | ||
212 | * | ||
213 | * This initializes the tags structure for each client instance. | ||
214 | * | ||
215 | */ | ||
216 | |||
217 | static int p9_tag_init(struct p9_client *c) | ||
218 | { | ||
219 | int err = 0; | ||
220 | |||
221 | c->tagpool = p9_idpool_create(); | ||
222 | if (IS_ERR(c->tagpool)) { | ||
223 | err = PTR_ERR(c->tagpool); | ||
224 | c->tagpool = NULL; | ||
225 | goto error; | ||
226 | } | ||
227 | |||
228 | p9_idpool_get(c->tagpool); /* reserve tag 0 */ | ||
229 | |||
230 | c->max_tag = 0; | ||
231 | error: | ||
232 | return err; | ||
233 | } | ||
234 | |||
235 | /** | ||
236 | * p9_tag_cleanup - cleans up tags structure and reclaims resources | ||
237 | * @tags: tags structure from the client struct | ||
238 | * | ||
239 | * This frees resources associated with the tags structure | ||
240 | * | ||
241 | */ | ||
242 | static void p9_tag_cleanup(struct p9_client *c) | ||
243 | { | ||
244 | int row, col; | ||
245 | |||
246 | /* check to insure all requests are idle */ | ||
247 | for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { | ||
248 | for (col = 0; col < P9_ROW_MAXTAG; col++) { | ||
249 | if (c->reqs[row][col].status != REQ_STATUS_IDLE) { | ||
250 | P9_DPRINTK(P9_DEBUG_MUX, | ||
251 | "Attempting to cleanup non-free tag %d,%d\n", | ||
252 | row, col); | ||
253 | /* TODO: delay execution of cleanup */ | ||
254 | return; | ||
255 | } | ||
256 | } | ||
257 | } | ||
258 | |||
259 | if (c->tagpool) | ||
260 | p9_idpool_destroy(c->tagpool); | ||
261 | |||
262 | /* free requests associated with tags */ | ||
263 | for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { | ||
264 | for (col = 0; col < P9_ROW_MAXTAG; col++) | ||
265 | kfree(c->reqs[row][col].wq); | ||
266 | kfree(c->reqs[row]); | ||
267 | } | ||
268 | c->max_tag = 0; | ||
269 | } | ||
270 | |||
123 | static struct p9_fid *p9_fid_create(struct p9_client *clnt) | 271 | static struct p9_fid *p9_fid_create(struct p9_client *clnt) |
124 | { | 272 | { |
125 | int err; | 273 | int err; |
@@ -209,6 +357,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) | |||
209 | goto error; | 357 | goto error; |
210 | } | 358 | } |
211 | 359 | ||
360 | p9_tag_init(clnt); | ||
361 | |||
212 | err = parse_opts(options, clnt); | 362 | err = parse_opts(options, clnt); |
213 | if (err < 0) | 363 | if (err < 0) |
214 | goto error; | 364 | goto error; |
@@ -285,6 +435,8 @@ void p9_client_destroy(struct p9_client *clnt) | |||
285 | if (clnt->fidpool) | 435 | if (clnt->fidpool) |
286 | p9_idpool_destroy(clnt->fidpool); | 436 | p9_idpool_destroy(clnt->fidpool); |
287 | 437 | ||
438 | p9_tag_cleanup(clnt); | ||
439 | |||
288 | kfree(clnt); | 440 | kfree(clnt); |
289 | } | 441 | } |
290 | EXPORT_SYMBOL(p9_client_destroy); | 442 | EXPORT_SYMBOL(p9_client_destroy); |