diff options
author | Fred Isaman <iisaman@netapp.com> | 2012-04-20 14:47:47 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-04-27 14:10:37 -0400 |
commit | 6c75dc0d498caa402fb17b1bf769835a9db875c8 (patch) | |
tree | b367bb2428c011f20b8fd47a6dd0b8603ee136ba /fs/nfs/pnfs.c | |
parent | 4db6e0b74c0f6dfc2f9c0690e8df512e3b635983 (diff) |
NFS: merge _full and _partial write rpc_ops
Decouple nfs_pgio_header and nfs_write_data, and have (possibly
multiple) nfs_write_datas each take a refcount on nfs_pgio_header.
For the moment keeps nfs_write_header as a way to preallocate a single
nfs_write_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_write_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 | 58 |
1 files changed, 36 insertions, 22 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index d1a91dbe7654..d515f00614cd 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -1199,7 +1199,9 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data) | |||
1199 | clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); | 1199 | clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); |
1200 | pnfs_return_layout(hdr->inode); | 1200 | pnfs_return_layout(hdr->inode); |
1201 | } | 1201 | } |
1202 | data->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode, &hdr->pages); | 1202 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) |
1203 | data->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode, | ||
1204 | &hdr->pages); | ||
1203 | } | 1205 | } |
1204 | 1206 | ||
1205 | /* | 1207 | /* |
@@ -1214,7 +1216,6 @@ void pnfs_ld_write_done(struct nfs_write_data *data) | |||
1214 | hdr->mds_ops->rpc_call_done(&data->task, data); | 1216 | hdr->mds_ops->rpc_call_done(&data->task, data); |
1215 | } else | 1217 | } else |
1216 | pnfs_ld_handle_write_error(data); | 1218 | pnfs_ld_handle_write_error(data); |
1217 | put_lseg(hdr->lseg); | ||
1218 | hdr->mds_ops->rpc_release(data); | 1219 | hdr->mds_ops->rpc_release(data); |
1219 | } | 1220 | } |
1220 | EXPORT_SYMBOL_GPL(pnfs_ld_write_done); | 1221 | EXPORT_SYMBOL_GPL(pnfs_ld_write_done); |
@@ -1225,12 +1226,11 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc, | |||
1225 | { | 1226 | { |
1226 | struct nfs_pgio_header *hdr = data->header; | 1227 | struct nfs_pgio_header *hdr = data->header; |
1227 | 1228 | ||
1228 | list_splice_tail_init(&hdr->pages, &desc->pg_list); | 1229 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { |
1229 | if (hdr->req && list_empty(&hdr->req->wb_list)) | 1230 | list_splice_tail_init(&hdr->pages, &desc->pg_list); |
1230 | nfs_list_add_request(hdr->req, &desc->pg_list); | 1231 | nfs_pageio_reset_write_mds(desc); |
1231 | nfs_pageio_reset_write_mds(desc); | 1232 | desc->pg_recoalesce = 1; |
1232 | desc->pg_recoalesce = 1; | 1233 | } |
1233 | put_lseg(hdr->lseg); | ||
1234 | nfs_writedata_release(data); | 1234 | nfs_writedata_release(data); |
1235 | } | 1235 | } |
1236 | 1236 | ||
@@ -1246,18 +1246,12 @@ pnfs_try_to_write_data(struct nfs_write_data *wdata, | |||
1246 | struct nfs_server *nfss = NFS_SERVER(inode); | 1246 | struct nfs_server *nfss = NFS_SERVER(inode); |
1247 | 1247 | ||
1248 | hdr->mds_ops = call_ops; | 1248 | hdr->mds_ops = call_ops; |
1249 | hdr->lseg = get_lseg(lseg); | ||
1250 | 1249 | ||
1251 | dprintk("%s: Writing ino:%lu %u@%llu (how %d)\n", __func__, | 1250 | dprintk("%s: Writing ino:%lu %u@%llu (how %d)\n", __func__, |
1252 | inode->i_ino, wdata->args.count, wdata->args.offset, how); | 1251 | inode->i_ino, wdata->args.count, wdata->args.offset, how); |
1253 | |||
1254 | trypnfs = nfss->pnfs_curr_ld->write_pagelist(wdata, how); | 1252 | trypnfs = nfss->pnfs_curr_ld->write_pagelist(wdata, how); |
1255 | if (trypnfs == PNFS_NOT_ATTEMPTED) { | 1253 | if (trypnfs != PNFS_NOT_ATTEMPTED) |
1256 | put_lseg(hdr->lseg); | ||
1257 | hdr->lseg = NULL; | ||
1258 | } else | ||
1259 | nfs_inc_stats(inode, NFSIOS_PNFS_WRITE); | 1254 | nfs_inc_stats(inode, NFSIOS_PNFS_WRITE); |
1260 | |||
1261 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); | 1255 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); |
1262 | return trypnfs; | 1256 | return trypnfs; |
1263 | } | 1257 | } |
@@ -1273,7 +1267,7 @@ pnfs_do_multiple_writes(struct nfs_pageio_descriptor *desc, struct list_head *he | |||
1273 | while (!list_empty(head)) { | 1267 | while (!list_empty(head)) { |
1274 | enum pnfs_try_status trypnfs; | 1268 | enum pnfs_try_status trypnfs; |
1275 | 1269 | ||
1276 | data = list_entry(head->next, struct nfs_write_data, list); | 1270 | data = list_first_entry(head, struct nfs_write_data, list); |
1277 | list_del_init(&data->list); | 1271 | list_del_init(&data->list); |
1278 | 1272 | ||
1279 | trypnfs = pnfs_try_to_write_data(data, call_ops, lseg, how); | 1273 | trypnfs = pnfs_try_to_write_data(data, call_ops, lseg, how); |
@@ -1283,20 +1277,40 @@ pnfs_do_multiple_writes(struct nfs_pageio_descriptor *desc, struct list_head *he | |||
1283 | put_lseg(lseg); | 1277 | put_lseg(lseg); |
1284 | } | 1278 | } |
1285 | 1279 | ||
1280 | static void pnfs_writehdr_free(struct nfs_pgio_header *hdr) | ||
1281 | { | ||
1282 | put_lseg(hdr->lseg); | ||
1283 | nfs_writehdr_free(hdr); | ||
1284 | } | ||
1285 | |||
1286 | int | 1286 | int |
1287 | pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc) | 1287 | pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc) |
1288 | { | 1288 | { |
1289 | LIST_HEAD(head); | 1289 | struct nfs_write_header *whdr; |
1290 | struct nfs_pgio_header *hdr; | ||
1290 | int ret; | 1291 | int ret; |
1291 | 1292 | ||
1292 | ret = nfs_generic_flush(desc, &head); | 1293 | whdr = nfs_writehdr_alloc(); |
1293 | if (ret != 0) { | 1294 | if (!whdr) { |
1295 | nfs_async_write_error(&desc->pg_list); | ||
1294 | put_lseg(desc->pg_lseg); | 1296 | put_lseg(desc->pg_lseg); |
1295 | desc->pg_lseg = NULL; | 1297 | desc->pg_lseg = NULL; |
1296 | return ret; | 1298 | return -ENOMEM; |
1297 | } | 1299 | } |
1298 | pnfs_do_multiple_writes(desc, &head, desc->pg_ioflags); | 1300 | hdr = &whdr->header; |
1299 | return 0; | 1301 | nfs_pgheader_init(desc, hdr, pnfs_writehdr_free); |
1302 | hdr->lseg = get_lseg(desc->pg_lseg); | ||
1303 | atomic_inc(&hdr->refcnt); | ||
1304 | ret = nfs_generic_flush(desc, hdr); | ||
1305 | if (ret != 0) { | ||
1306 | put_lseg(desc->pg_lseg); | ||
1307 | desc->pg_lseg = NULL; | ||
1308 | set_bit(NFS_IOHDR_REDO, &hdr->flags); | ||
1309 | } else | ||
1310 | pnfs_do_multiple_writes(desc, &hdr->rpc_list, desc->pg_ioflags); | ||
1311 | if (atomic_dec_and_test(&hdr->refcnt)) | ||
1312 | nfs_write_completion(hdr); | ||
1313 | return ret; | ||
1300 | } | 1314 | } |
1301 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages); | 1315 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages); |
1302 | 1316 | ||