diff options
Diffstat (limited to 'net/9p/client.c')
-rw-r--r-- | net/9p/client.c | 157 |
1 files changed, 106 insertions, 51 deletions
diff --git a/net/9p/client.c b/net/9p/client.c index a848bca9fbff..77367745be9b 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -178,7 +178,7 @@ free_and_return: | |||
178 | * @tag: numeric id for transaction | 178 | * @tag: numeric id for transaction |
179 | * | 179 | * |
180 | * this is a simple array lookup, but will grow the | 180 | * this is a simple array lookup, but will grow the |
181 | * request_slots as necessary to accomodate transaction | 181 | * request_slots as necessary to accommodate transaction |
182 | * ids which did not previously have a slot. | 182 | * ids which did not previously have a slot. |
183 | * | 183 | * |
184 | * this code relies on the client spinlock to manage locks, its | 184 | * this code relies on the client spinlock to manage locks, its |
@@ -223,16 +223,29 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | |||
223 | 223 | ||
224 | req = &c->reqs[row][col]; | 224 | req = &c->reqs[row][col]; |
225 | if (!req->tc) { | 225 | if (!req->tc) { |
226 | req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); | 226 | req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_NOFS); |
227 | if (!req->wq) { | 227 | if (!req->wq) { |
228 | printk(KERN_ERR "Couldn't grow tag array\n"); | 228 | printk(KERN_ERR "Couldn't grow tag array\n"); |
229 | return ERR_PTR(-ENOMEM); | 229 | return ERR_PTR(-ENOMEM); |
230 | } | 230 | } |
231 | init_waitqueue_head(req->wq); | 231 | init_waitqueue_head(req->wq); |
232 | req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, | 232 | if ((c->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == |
233 | GFP_KERNEL); | 233 | P9_TRANS_PREF_PAYLOAD_SEP) { |
234 | req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, | 234 | int alloc_msize = min(c->msize, 4096); |
235 | GFP_KERNEL); | 235 | req->tc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, |
236 | GFP_NOFS); | ||
237 | req->tc->capacity = alloc_msize; | ||
238 | req->rc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, | ||
239 | GFP_NOFS); | ||
240 | req->rc->capacity = alloc_msize; | ||
241 | } else { | ||
242 | req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, | ||
243 | GFP_NOFS); | ||
244 | req->tc->capacity = c->msize; | ||
245 | req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, | ||
246 | GFP_NOFS); | ||
247 | req->rc->capacity = c->msize; | ||
248 | } | ||
236 | if ((!req->tc) || (!req->rc)) { | 249 | if ((!req->tc) || (!req->rc)) { |
237 | printk(KERN_ERR "Couldn't grow tag array\n"); | 250 | printk(KERN_ERR "Couldn't grow tag array\n"); |
238 | kfree(req->tc); | 251 | kfree(req->tc); |
@@ -243,9 +256,7 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | |||
243 | return ERR_PTR(-ENOMEM); | 256 | return ERR_PTR(-ENOMEM); |
244 | } | 257 | } |
245 | req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); | 258 | req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); |
246 | req->tc->capacity = c->msize; | ||
247 | req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); | 259 | req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); |
248 | req->rc->capacity = c->msize; | ||
249 | } | 260 | } |
250 | 261 | ||
251 | p9pdu_reset(req->tc); | 262 | p9pdu_reset(req->tc); |
@@ -443,6 +454,7 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) | |||
443 | { | 454 | { |
444 | int8_t type; | 455 | int8_t type; |
445 | int err; | 456 | int err; |
457 | int ecode; | ||
446 | 458 | ||
447 | err = p9_parse_header(req->rc, NULL, &type, NULL, 0); | 459 | err = p9_parse_header(req->rc, NULL, &type, NULL, 0); |
448 | if (err) { | 460 | if (err) { |
@@ -450,36 +462,53 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) | |||
450 | return err; | 462 | return err; |
451 | } | 463 | } |
452 | 464 | ||
453 | if (type == P9_RERROR || type == P9_RLERROR) { | 465 | if (type != P9_RERROR && type != P9_RLERROR) |
454 | int ecode; | 466 | return 0; |
455 | |||
456 | if (!p9_is_proto_dotl(c)) { | ||
457 | char *ename; | ||
458 | |||
459 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", | ||
460 | &ename, &ecode); | ||
461 | if (err) | ||
462 | goto out_err; | ||
463 | 467 | ||
464 | if (p9_is_proto_dotu(c)) | 468 | if (!p9_is_proto_dotl(c)) { |
465 | err = -ecode; | 469 | char *ename; |
470 | |||
471 | if (req->tc->pbuf_size) { | ||
472 | /* Handle user buffers */ | ||
473 | size_t len = req->rc->size - req->rc->offset; | ||
474 | if (req->tc->pubuf) { | ||
475 | /* User Buffer */ | ||
476 | err = copy_from_user( | ||
477 | &req->rc->sdata[req->rc->offset], | ||
478 | req->tc->pubuf, len); | ||
479 | if (err) { | ||
480 | err = -EFAULT; | ||
481 | goto out_err; | ||
482 | } | ||
483 | } else { | ||
484 | /* Kernel Buffer */ | ||
485 | memmove(&req->rc->sdata[req->rc->offset], | ||
486 | req->tc->pkbuf, len); | ||
487 | } | ||
488 | } | ||
489 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", | ||
490 | &ename, &ecode); | ||
491 | if (err) | ||
492 | goto out_err; | ||
466 | 493 | ||
467 | if (!err || !IS_ERR_VALUE(err)) { | 494 | if (p9_is_proto_dotu(c)) |
468 | err = p9_errstr2errno(ename, strlen(ename)); | 495 | err = -ecode; |
469 | 496 | ||
470 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); | 497 | if (!err || !IS_ERR_VALUE(err)) { |
498 | err = p9_errstr2errno(ename, strlen(ename)); | ||
471 | 499 | ||
472 | kfree(ename); | 500 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, |
473 | } | 501 | ename); |
474 | } else { | ||
475 | err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode); | ||
476 | err = -ecode; | ||
477 | 502 | ||
478 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); | 503 | kfree(ename); |
479 | } | 504 | } |
505 | } else { | ||
506 | err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode); | ||
507 | err = -ecode; | ||
508 | |||
509 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); | ||
510 | } | ||
480 | 511 | ||
481 | } else | ||
482 | err = 0; | ||
483 | 512 | ||
484 | return err; | 513 | return err; |
485 | 514 | ||
@@ -900,15 +929,15 @@ error: | |||
900 | } | 929 | } |
901 | EXPORT_SYMBOL(p9_client_attach); | 930 | EXPORT_SYMBOL(p9_client_attach); |
902 | 931 | ||
903 | struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, | 932 | struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname, |
904 | int clone) | 933 | char **wnames, int clone) |
905 | { | 934 | { |
906 | int err; | 935 | int err; |
907 | struct p9_client *clnt; | 936 | struct p9_client *clnt; |
908 | struct p9_fid *fid; | 937 | struct p9_fid *fid; |
909 | struct p9_qid *wqids; | 938 | struct p9_qid *wqids; |
910 | struct p9_req_t *req; | 939 | struct p9_req_t *req; |
911 | int16_t nwqids, count; | 940 | uint16_t nwqids, count; |
912 | 941 | ||
913 | err = 0; | 942 | err = 0; |
914 | wqids = NULL; | 943 | wqids = NULL; |
@@ -926,7 +955,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, | |||
926 | fid = oldfid; | 955 | fid = oldfid; |
927 | 956 | ||
928 | 957 | ||
929 | P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n", | 958 | P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %ud wname[0] %s\n", |
930 | oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL); | 959 | oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL); |
931 | 960 | ||
932 | req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, | 961 | req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, |
@@ -1270,7 +1299,15 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
1270 | if (count < rsize) | 1299 | if (count < rsize) |
1271 | rsize = count; | 1300 | rsize = count; |
1272 | 1301 | ||
1273 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize); | 1302 | /* Don't bother zerocopy form small IO (< 1024) */ |
1303 | if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == | ||
1304 | P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) { | ||
1305 | req = p9_client_rpc(clnt, P9_TREAD, "dqE", fid->fid, offset, | ||
1306 | rsize, data, udata); | ||
1307 | } else { | ||
1308 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, | ||
1309 | rsize); | ||
1310 | } | ||
1274 | if (IS_ERR(req)) { | 1311 | if (IS_ERR(req)) { |
1275 | err = PTR_ERR(req); | 1312 | err = PTR_ERR(req); |
1276 | goto error; | 1313 | goto error; |
@@ -1284,13 +1321,15 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
1284 | 1321 | ||
1285 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); | 1322 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); |
1286 | 1323 | ||
1287 | if (data) { | 1324 | if (!req->tc->pbuf_size) { |
1288 | memmove(data, dataptr, count); | 1325 | if (data) { |
1289 | } else { | 1326 | memmove(data, dataptr, count); |
1290 | err = copy_to_user(udata, dataptr, count); | 1327 | } else { |
1291 | if (err) { | 1328 | err = copy_to_user(udata, dataptr, count); |
1292 | err = -EFAULT; | 1329 | if (err) { |
1293 | goto free_and_error; | 1330 | err = -EFAULT; |
1331 | goto free_and_error; | ||
1332 | } | ||
1294 | } | 1333 | } |
1295 | } | 1334 | } |
1296 | p9_free_req(clnt, req); | 1335 | p9_free_req(clnt, req); |
@@ -1323,12 +1362,21 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | |||
1323 | 1362 | ||
1324 | if (count < rsize) | 1363 | if (count < rsize) |
1325 | rsize = count; | 1364 | rsize = count; |
1326 | if (data) | 1365 | |
1327 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset, | 1366 | /* Don't bother zerocopy form small IO (< 1024) */ |
1328 | rsize, data); | 1367 | if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == |
1329 | else | 1368 | P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) { |
1330 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset, | 1369 | req = p9_client_rpc(clnt, P9_TWRITE, "dqE", fid->fid, offset, |
1331 | rsize, udata); | 1370 | rsize, data, udata); |
1371 | } else { | ||
1372 | |||
1373 | if (data) | ||
1374 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, | ||
1375 | offset, rsize, data); | ||
1376 | else | ||
1377 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, | ||
1378 | offset, rsize, udata); | ||
1379 | } | ||
1332 | if (IS_ERR(req)) { | 1380 | if (IS_ERR(req)) { |
1333 | err = PTR_ERR(req); | 1381 | err = PTR_ERR(req); |
1334 | goto error; | 1382 | goto error; |
@@ -1716,7 +1764,14 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
1716 | if (count < rsize) | 1764 | if (count < rsize) |
1717 | rsize = count; | 1765 | rsize = count; |
1718 | 1766 | ||
1719 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, offset, rsize); | 1767 | if ((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == |
1768 | P9_TRANS_PREF_PAYLOAD_SEP) { | ||
1769 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqF", fid->fid, | ||
1770 | offset, rsize, data); | ||
1771 | } else { | ||
1772 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, | ||
1773 | offset, rsize); | ||
1774 | } | ||
1720 | if (IS_ERR(req)) { | 1775 | if (IS_ERR(req)) { |
1721 | err = PTR_ERR(req); | 1776 | err = PTR_ERR(req); |
1722 | goto error; | 1777 | goto error; |
@@ -1730,7 +1785,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
1730 | 1785 | ||
1731 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); | 1786 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); |
1732 | 1787 | ||
1733 | if (data) | 1788 | if (!req->tc->pbuf_size && data) |
1734 | memmove(data, dataptr, count); | 1789 | memmove(data, dataptr, count); |
1735 | 1790 | ||
1736 | p9_free_req(clnt, req); | 1791 | p9_free_req(clnt, req); |