diff options
author | Fred Isaman <iisaman@netapp.com> | 2012-04-20 14:47:46 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-04-27 14:10:37 -0400 |
commit | 4db6e0b74c0f6dfc2f9c0690e8df512e3b635983 (patch) | |
tree | 19d8a2a7051bdab220b0bdcf3da1e350a53ce428 /fs/nfs/pnfs.c | |
parent | 30dd374f6fc1b202db3a1b57b61afff1326bad92 (diff) |
NFS: merge _full and _partial read rpc_ops
Decouple nfs_pgio_header and nfs_read_data, and have (possibly
multiple) nfs_read_datas each take a refcount on nfs_pgio_header.
For the moment keeps nfs_read_header as a way to preallocate a single
nfs_read_data with the nfs_pgio_header. The code doesn't need this,
and would be prettier without, but given the amount of churn I am
already introducing I didn't want to play with tuning new mempools.
This also fixes bug in pnfs_ld_handle_read_error. In the case of
desc->pg_bsize < PAGE_CACHE_SIZE, the pages list was empty, causing
replay attempt to do nothing.
Signed-off-by: Fred Isaman <iisaman@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r-- | fs/nfs/pnfs.c | 55 |
1 files changed, 36 insertions, 19 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index d705da427e6d..d1a91dbe7654 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -1333,7 +1333,9 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data) | |||
1333 | clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); | 1333 | clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); |
1334 | pnfs_return_layout(hdr->inode); | 1334 | pnfs_return_layout(hdr->inode); |
1335 | } | 1335 | } |
1336 | data->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode, &hdr->pages); | 1336 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) |
1337 | data->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode, | ||
1338 | &hdr->pages); | ||
1337 | } | 1339 | } |
1338 | 1340 | ||
1339 | /* | 1341 | /* |
@@ -1348,7 +1350,6 @@ void pnfs_ld_read_done(struct nfs_read_data *data) | |||
1348 | hdr->mds_ops->rpc_call_done(&data->task, data); | 1350 | hdr->mds_ops->rpc_call_done(&data->task, data); |
1349 | } else | 1351 | } else |
1350 | pnfs_ld_handle_read_error(data); | 1352 | pnfs_ld_handle_read_error(data); |
1351 | put_lseg(hdr->lseg); | ||
1352 | hdr->mds_ops->rpc_release(data); | 1353 | hdr->mds_ops->rpc_release(data); |
1353 | } | 1354 | } |
1354 | EXPORT_SYMBOL_GPL(pnfs_ld_read_done); | 1355 | EXPORT_SYMBOL_GPL(pnfs_ld_read_done); |
@@ -1359,11 +1360,11 @@ pnfs_read_through_mds(struct nfs_pageio_descriptor *desc, | |||
1359 | { | 1360 | { |
1360 | struct nfs_pgio_header *hdr = data->header; | 1361 | struct nfs_pgio_header *hdr = data->header; |
1361 | 1362 | ||
1362 | list_splice_tail_init(&hdr->pages, &desc->pg_list); | 1363 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { |
1363 | if (hdr->req && list_empty(&hdr->req->wb_list)) | 1364 | list_splice_tail_init(&hdr->pages, &desc->pg_list); |
1364 | nfs_list_add_request(hdr->req, &desc->pg_list); | 1365 | nfs_pageio_reset_read_mds(desc); |
1365 | nfs_pageio_reset_read_mds(desc); | 1366 | desc->pg_recoalesce = 1; |
1366 | desc->pg_recoalesce = 1; | 1367 | } |
1367 | nfs_readdata_release(data); | 1368 | nfs_readdata_release(data); |
1368 | } | 1369 | } |
1369 | 1370 | ||
@@ -1381,18 +1382,13 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata, | |||
1381 | enum pnfs_try_status trypnfs; | 1382 | enum pnfs_try_status trypnfs; |
1382 | 1383 | ||
1383 | hdr->mds_ops = call_ops; | 1384 | hdr->mds_ops = call_ops; |
1384 | hdr->lseg = get_lseg(lseg); | ||
1385 | 1385 | ||
1386 | dprintk("%s: Reading ino:%lu %u@%llu\n", | 1386 | dprintk("%s: Reading ino:%lu %u@%llu\n", |
1387 | __func__, inode->i_ino, rdata->args.count, rdata->args.offset); | 1387 | __func__, inode->i_ino, rdata->args.count, rdata->args.offset); |
1388 | 1388 | ||
1389 | trypnfs = nfss->pnfs_curr_ld->read_pagelist(rdata); | 1389 | trypnfs = nfss->pnfs_curr_ld->read_pagelist(rdata); |
1390 | if (trypnfs == PNFS_NOT_ATTEMPTED) { | 1390 | if (trypnfs != PNFS_NOT_ATTEMPTED) |
1391 | put_lseg(hdr->lseg); | ||
1392 | hdr->lseg = NULL; | ||
1393 | } else { | ||
1394 | nfs_inc_stats(inode, NFSIOS_PNFS_READ); | 1391 | nfs_inc_stats(inode, NFSIOS_PNFS_READ); |
1395 | } | ||
1396 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); | 1392 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); |
1397 | return trypnfs; | 1393 | return trypnfs; |
1398 | } | 1394 | } |
@@ -1408,7 +1404,7 @@ pnfs_do_multiple_reads(struct nfs_pageio_descriptor *desc, struct list_head *hea | |||
1408 | while (!list_empty(head)) { | 1404 | while (!list_empty(head)) { |
1409 | enum pnfs_try_status trypnfs; | 1405 | enum pnfs_try_status trypnfs; |
1410 | 1406 | ||
1411 | data = list_entry(head->next, struct nfs_read_data, list); | 1407 | data = list_first_entry(head, struct nfs_read_data, list); |
1412 | list_del_init(&data->list); | 1408 | list_del_init(&data->list); |
1413 | 1409 | ||
1414 | trypnfs = pnfs_try_to_read_data(data, call_ops, lseg); | 1410 | trypnfs = pnfs_try_to_read_data(data, call_ops, lseg); |
@@ -1418,20 +1414,41 @@ pnfs_do_multiple_reads(struct nfs_pageio_descriptor *desc, struct list_head *hea | |||
1418 | put_lseg(lseg); | 1414 | put_lseg(lseg); |
1419 | } | 1415 | } |
1420 | 1416 | ||
1417 | static void pnfs_readhdr_free(struct nfs_pgio_header *hdr) | ||
1418 | { | ||
1419 | put_lseg(hdr->lseg); | ||
1420 | nfs_readhdr_free(hdr); | ||
1421 | } | ||
1422 | |||
1421 | int | 1423 | int |
1422 | pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) | 1424 | pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) |
1423 | { | 1425 | { |
1424 | LIST_HEAD(head); | 1426 | struct nfs_read_header *rhdr; |
1427 | struct nfs_pgio_header *hdr; | ||
1425 | int ret; | 1428 | int ret; |
1426 | 1429 | ||
1427 | ret = nfs_generic_pagein(desc, &head); | 1430 | rhdr = nfs_readhdr_alloc(); |
1428 | if (ret != 0) { | 1431 | if (!rhdr) { |
1432 | nfs_async_read_error(&desc->pg_list); | ||
1433 | ret = -ENOMEM; | ||
1429 | put_lseg(desc->pg_lseg); | 1434 | put_lseg(desc->pg_lseg); |
1430 | desc->pg_lseg = NULL; | 1435 | desc->pg_lseg = NULL; |
1431 | return ret; | 1436 | return ret; |
1432 | } | 1437 | } |
1433 | pnfs_do_multiple_reads(desc, &head); | 1438 | hdr = &rhdr->header; |
1434 | return 0; | 1439 | nfs_pgheader_init(desc, hdr, pnfs_readhdr_free); |
1440 | hdr->lseg = get_lseg(desc->pg_lseg); | ||
1441 | atomic_inc(&hdr->refcnt); | ||
1442 | ret = nfs_generic_pagein(desc, hdr); | ||
1443 | if (ret != 0) { | ||
1444 | put_lseg(desc->pg_lseg); | ||
1445 | desc->pg_lseg = NULL; | ||
1446 | set_bit(NFS_IOHDR_REDO, &hdr->flags); | ||
1447 | } else | ||
1448 | pnfs_do_multiple_reads(desc, &hdr->rpc_list); | ||
1449 | if (atomic_dec_and_test(&hdr->refcnt)) | ||
1450 | nfs_read_completion(hdr); | ||
1451 | return ret; | ||
1435 | } | 1452 | } |
1436 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages); | 1453 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages); |
1437 | 1454 | ||