diff options
Diffstat (limited to 'net/9p/client.c')
-rw-r--r-- | net/9p/client.c | 166 |
1 files changed, 121 insertions, 45 deletions
diff --git a/net/9p/client.c b/net/9p/client.c index a848bca9fbff..347ec0cd2718 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -229,10 +229,23 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | |||
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_KERNEL); | ||
237 | req->tc->capacity = alloc_msize; | ||
238 | req->rc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, | ||
239 | GFP_KERNEL); | ||
240 | req->rc->capacity = alloc_msize; | ||
241 | } else { | ||
242 | req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, | ||
243 | GFP_KERNEL); | ||
244 | req->tc->capacity = c->msize; | ||
245 | req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, | ||
246 | GFP_KERNEL); | ||
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 | 467 | ||
459 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", | 468 | if (!p9_is_proto_dotl(c)) { |
460 | &ename, &ecode); | 469 | char *ename; |
461 | if (err) | 470 | |
462 | goto out_err; | 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; | ||
463 | 493 | ||
464 | if (p9_is_proto_dotu(c)) | 494 | if (p9_is_proto_dotu(c)) |
465 | err = -ecode; | 495 | err = -ecode; |
466 | 496 | ||
467 | if (!err || !IS_ERR_VALUE(err)) { | 497 | if (!err || !IS_ERR_VALUE(err)) { |
468 | err = p9_errstr2errno(ename, strlen(ename)); | 498 | err = p9_errstr2errno(ename, strlen(ename)); |
469 | 499 | ||
470 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); | 500 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, |
501 | ename); | ||
471 | 502 | ||
472 | kfree(ename); | 503 | kfree(ename); |
473 | } | ||
474 | } else { | ||
475 | err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode); | ||
476 | err = -ecode; | ||
477 | |||
478 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); | ||
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 | ||
@@ -1191,6 +1220,27 @@ error: | |||
1191 | } | 1220 | } |
1192 | EXPORT_SYMBOL(p9_client_fsync); | 1221 | EXPORT_SYMBOL(p9_client_fsync); |
1193 | 1222 | ||
1223 | int p9_client_sync_fs(struct p9_fid *fid) | ||
1224 | { | ||
1225 | int err = 0; | ||
1226 | struct p9_req_t *req; | ||
1227 | struct p9_client *clnt; | ||
1228 | |||
1229 | P9_DPRINTK(P9_DEBUG_9P, ">>> TSYNC_FS fid %d\n", fid->fid); | ||
1230 | |||
1231 | clnt = fid->clnt; | ||
1232 | req = p9_client_rpc(clnt, P9_TSYNCFS, "d", fid->fid); | ||
1233 | if (IS_ERR(req)) { | ||
1234 | err = PTR_ERR(req); | ||
1235 | goto error; | ||
1236 | } | ||
1237 | P9_DPRINTK(P9_DEBUG_9P, "<<< RSYNCFS fid %d\n", fid->fid); | ||
1238 | p9_free_req(clnt, req); | ||
1239 | error: | ||
1240 | return err; | ||
1241 | } | ||
1242 | EXPORT_SYMBOL(p9_client_sync_fs); | ||
1243 | |||
1194 | int p9_client_clunk(struct p9_fid *fid) | 1244 | int p9_client_clunk(struct p9_fid *fid) |
1195 | { | 1245 | { |
1196 | int err; | 1246 | int err; |
@@ -1270,7 +1320,15 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
1270 | if (count < rsize) | 1320 | if (count < rsize) |
1271 | rsize = count; | 1321 | rsize = count; |
1272 | 1322 | ||
1273 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize); | 1323 | /* Don't bother zerocopy form small IO (< 1024) */ |
1324 | if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == | ||
1325 | P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) { | ||
1326 | req = p9_client_rpc(clnt, P9_TREAD, "dqE", fid->fid, offset, | ||
1327 | rsize, data, udata); | ||
1328 | } else { | ||
1329 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, | ||
1330 | rsize); | ||
1331 | } | ||
1274 | if (IS_ERR(req)) { | 1332 | if (IS_ERR(req)) { |
1275 | err = PTR_ERR(req); | 1333 | err = PTR_ERR(req); |
1276 | goto error; | 1334 | goto error; |
@@ -1284,13 +1342,15 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
1284 | 1342 | ||
1285 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); | 1343 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); |
1286 | 1344 | ||
1287 | if (data) { | 1345 | if (!req->tc->pbuf_size) { |
1288 | memmove(data, dataptr, count); | 1346 | if (data) { |
1289 | } else { | 1347 | memmove(data, dataptr, count); |
1290 | err = copy_to_user(udata, dataptr, count); | 1348 | } else { |
1291 | if (err) { | 1349 | err = copy_to_user(udata, dataptr, count); |
1292 | err = -EFAULT; | 1350 | if (err) { |
1293 | goto free_and_error; | 1351 | err = -EFAULT; |
1352 | goto free_and_error; | ||
1353 | } | ||
1294 | } | 1354 | } |
1295 | } | 1355 | } |
1296 | p9_free_req(clnt, req); | 1356 | p9_free_req(clnt, req); |
@@ -1323,12 +1383,21 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | |||
1323 | 1383 | ||
1324 | if (count < rsize) | 1384 | if (count < rsize) |
1325 | rsize = count; | 1385 | rsize = count; |
1326 | if (data) | 1386 | |
1327 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset, | 1387 | /* Don't bother zerocopy form small IO (< 1024) */ |
1328 | rsize, data); | 1388 | if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == |
1329 | else | 1389 | P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) { |
1330 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset, | 1390 | req = p9_client_rpc(clnt, P9_TWRITE, "dqE", fid->fid, offset, |
1331 | rsize, udata); | 1391 | rsize, data, udata); |
1392 | } else { | ||
1393 | |||
1394 | if (data) | ||
1395 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, | ||
1396 | offset, rsize, data); | ||
1397 | else | ||
1398 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, | ||
1399 | offset, rsize, udata); | ||
1400 | } | ||
1332 | if (IS_ERR(req)) { | 1401 | if (IS_ERR(req)) { |
1333 | err = PTR_ERR(req); | 1402 | err = PTR_ERR(req); |
1334 | goto error; | 1403 | goto error; |
@@ -1716,7 +1785,14 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
1716 | if (count < rsize) | 1785 | if (count < rsize) |
1717 | rsize = count; | 1786 | rsize = count; |
1718 | 1787 | ||
1719 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, offset, rsize); | 1788 | if ((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == |
1789 | P9_TRANS_PREF_PAYLOAD_SEP) { | ||
1790 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqF", fid->fid, | ||
1791 | offset, rsize, data); | ||
1792 | } else { | ||
1793 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, | ||
1794 | offset, rsize); | ||
1795 | } | ||
1720 | if (IS_ERR(req)) { | 1796 | if (IS_ERR(req)) { |
1721 | err = PTR_ERR(req); | 1797 | err = PTR_ERR(req); |
1722 | goto error; | 1798 | goto error; |
@@ -1730,7 +1806,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
1730 | 1806 | ||
1731 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); | 1807 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); |
1732 | 1808 | ||
1733 | if (data) | 1809 | if (!req->tc->pbuf_size && data) |
1734 | memmove(data, dataptr, count); | 1810 | memmove(data, dataptr, count); |
1735 | 1811 | ||
1736 | p9_free_req(clnt, req); | 1812 | p9_free_req(clnt, req); |