aboutsummaryrefslogtreecommitdiffstats
path: root/net/9p/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/9p/client.c')
-rw-r--r--net/9p/client.c152
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
138struct 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}
183EXPORT_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
192struct 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}
207EXPORT_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
217static 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;
231error:
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 */
242static 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
123static struct p9_fid *p9_fid_create(struct p9_client *clnt) 271static 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}
290EXPORT_SYMBOL(p9_client_destroy); 442EXPORT_SYMBOL(p9_client_destroy);