aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/write.c
diff options
context:
space:
mode:
authorFred Isaman <iisaman@netapp.com>2012-04-20 14:47:44 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-04-27 14:10:37 -0400
commitcd841605f7a721878d8a2d1362484723d8abf569 (patch)
treeb5c37db575cd545a183577249909e042fe38d646 /fs/nfs/write.c
parentb5542849764aa56fd3f05c0041195b637b9d2ac2 (diff)
NFS: create common nfs_pgio_header for both read and write
In order to avoid duplicating all the data in nfs_read_data whenever we split it up into multiple RPC calls (either due to a short read result or due to rsize < PAGE_SIZE), we split out the bits that are the same per RPC call into a separate "header" structure. The goal this patch moves towards is to have a single header refcounted by several rpc_data structures. Thus, want to always refer from rpc_data to the header, and not the other way. This patch comes close to that ideal, but the directio code currently needs some special casing, isolated in the nfs_direct_[read_write]hdr_release() functions. This will be dealt with in a future patch. Signed-off-by: Fred Isaman <iisaman@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r--fs/nfs/write.c104
1 files changed, 58 insertions, 46 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 76735dd8c9a7..dbb5c0a613b8 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -69,19 +69,24 @@ void nfs_commit_free(struct nfs_commit_data *p)
69} 69}
70EXPORT_SYMBOL_GPL(nfs_commit_free); 70EXPORT_SYMBOL_GPL(nfs_commit_free);
71 71
72struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) 72struct nfs_write_header *nfs_writehdr_alloc(unsigned int pagecount)
73{ 73{
74 struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); 74 struct nfs_write_header *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS);
75 75
76 if (p) { 76 if (p) {
77 struct nfs_pgio_header *hdr = &p->header;
78 struct nfs_write_data *data = &p->rpc_data;
79
77 memset(p, 0, sizeof(*p)); 80 memset(p, 0, sizeof(*p));
78 INIT_LIST_HEAD(&p->pages); 81 INIT_LIST_HEAD(&hdr->pages);
79 p->npages = pagecount; 82 INIT_LIST_HEAD(&data->list);
80 if (pagecount <= ARRAY_SIZE(p->page_array)) 83 data->npages = pagecount;
81 p->pagevec = p->page_array; 84 data->header = hdr;
85 if (pagecount <= ARRAY_SIZE(data->page_array))
86 data->pagevec = data->page_array;
82 else { 87 else {
83 p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS); 88 data->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
84 if (!p->pagevec) { 89 if (!data->pagevec) {
85 mempool_free(p, nfs_wdata_mempool); 90 mempool_free(p, nfs_wdata_mempool);
86 p = NULL; 91 p = NULL;
87 } 92 }
@@ -90,17 +95,18 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
90 return p; 95 return p;
91} 96}
92 97
93void nfs_writedata_free(struct nfs_write_data *p) 98void nfs_writehdr_free(struct nfs_pgio_header *hdr)
94{ 99{
95 if (p && (p->pagevec != &p->page_array[0])) 100 struct nfs_write_header *whdr = container_of(hdr, struct nfs_write_header, header);
96 kfree(p->pagevec); 101 mempool_free(whdr, nfs_wdata_mempool);
97 mempool_free(p, nfs_wdata_mempool);
98} 102}
99 103
100void nfs_writedata_release(struct nfs_write_data *wdata) 104void nfs_writedata_release(struct nfs_write_data *wdata)
101{ 105{
102 put_nfs_open_context(wdata->args.context); 106 put_nfs_open_context(wdata->args.context);
103 nfs_writedata_free(wdata); 107 if (wdata->pagevec != wdata->page_array)
108 kfree(wdata->pagevec);
109 nfs_writehdr_free(wdata->header);
104} 110}
105 111
106static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error) 112static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
@@ -507,9 +513,8 @@ static inline
507int nfs_write_need_commit(struct nfs_write_data *data) 513int nfs_write_need_commit(struct nfs_write_data *data)
508{ 514{
509 if (data->verf.committed == NFS_DATA_SYNC) 515 if (data->verf.committed == NFS_DATA_SYNC)
510 return data->lseg == NULL; 516 return data->header->lseg == NULL;
511 else 517 return data->verf.committed != NFS_FILE_SYNC;
512 return data->verf.committed != NFS_FILE_SYNC;
513} 518}
514 519
515static inline 520static inline
@@ -517,7 +522,7 @@ int nfs_reschedule_unstable_write(struct nfs_page *req,
517 struct nfs_write_data *data) 522 struct nfs_write_data *data)
518{ 523{
519 if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) { 524 if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) {
520 nfs_mark_request_commit(req, data->lseg); 525 nfs_mark_request_commit(req, data->header->lseg);
521 return 1; 526 return 1;
522 } 527 }
523 if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { 528 if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) {
@@ -841,13 +846,13 @@ int nfs_initiate_write(struct rpc_clnt *clnt,
841 const struct rpc_call_ops *call_ops, 846 const struct rpc_call_ops *call_ops,
842 int how) 847 int how)
843{ 848{
844 struct inode *inode = data->inode; 849 struct inode *inode = data->header->inode;
845 int priority = flush_task_priority(how); 850 int priority = flush_task_priority(how);
846 struct rpc_task *task; 851 struct rpc_task *task;
847 struct rpc_message msg = { 852 struct rpc_message msg = {
848 .rpc_argp = &data->args, 853 .rpc_argp = &data->args,
849 .rpc_resp = &data->res, 854 .rpc_resp = &data->res,
850 .rpc_cred = data->cred, 855 .rpc_cred = data->header->cred,
851 }; 856 };
852 struct rpc_task_setup task_setup_data = { 857 struct rpc_task_setup task_setup_data = {
853 .rpc_client = clnt, 858 .rpc_client = clnt,
@@ -896,14 +901,15 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
896 unsigned int count, unsigned int offset, 901 unsigned int count, unsigned int offset,
897 int how) 902 int how)
898{ 903{
904 struct nfs_pgio_header *hdr = data->header;
899 struct inode *inode = req->wb_context->dentry->d_inode; 905 struct inode *inode = req->wb_context->dentry->d_inode;
900 906
901 /* Set up the RPC argument and reply structs 907 /* Set up the RPC argument and reply structs
902 * NB: take care not to mess about with data->commit et al. */ 908 * NB: take care not to mess about with data->commit et al. */
903 909
904 data->req = req; 910 hdr->req = req;
905 data->inode = inode = req->wb_context->dentry->d_inode; 911 hdr->inode = inode = req->wb_context->dentry->d_inode;
906 data->cred = req->wb_context->cred; 912 hdr->cred = req->wb_context->cred;
907 913
908 data->args.fh = NFS_FH(inode); 914 data->args.fh = NFS_FH(inode);
909 data->args.offset = req_offset(req) + offset; 915 data->args.offset = req_offset(req) + offset;
@@ -935,7 +941,7 @@ static int nfs_do_write(struct nfs_write_data *data,
935 const struct rpc_call_ops *call_ops, 941 const struct rpc_call_ops *call_ops,
936 int how) 942 int how)
937{ 943{
938 struct inode *inode = data->args.context->dentry->d_inode; 944 struct inode *inode = data->header->inode;
939 945
940 return nfs_initiate_write(NFS_CLIENT(inode), data, call_ops, how); 946 return nfs_initiate_write(NFS_CLIENT(inode), data, call_ops, how);
941} 947}
@@ -981,6 +987,7 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head
981{ 987{
982 struct nfs_page *req = nfs_list_entry(desc->pg_list.next); 988 struct nfs_page *req = nfs_list_entry(desc->pg_list.next);
983 struct page *page = req->wb_page; 989 struct page *page = req->wb_page;
990 struct nfs_write_header *whdr;
984 struct nfs_write_data *data; 991 struct nfs_write_data *data;
985 size_t wsize = desc->pg_bsize, nbytes; 992 size_t wsize = desc->pg_bsize, nbytes;
986 unsigned int offset; 993 unsigned int offset;
@@ -1000,9 +1007,10 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head
1000 do { 1007 do {
1001 size_t len = min(nbytes, wsize); 1008 size_t len = min(nbytes, wsize);
1002 1009
1003 data = nfs_writedata_alloc(1); 1010 whdr = nfs_writehdr_alloc(1);
1004 if (!data) 1011 if (!whdr)
1005 goto out_bad; 1012 goto out_bad;
1013 data = &whdr->rpc_data;
1006 data->pagevec[0] = page; 1014 data->pagevec[0] = page;
1007 nfs_write_rpcsetup(req, data, len, offset, desc->pg_ioflags); 1015 nfs_write_rpcsetup(req, data, len, offset, desc->pg_ioflags);
1008 list_add(&data->list, res); 1016 list_add(&data->list, res);
@@ -1036,13 +1044,14 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc, struct list_head *r
1036{ 1044{
1037 struct nfs_page *req; 1045 struct nfs_page *req;
1038 struct page **pages; 1046 struct page **pages;
1047 struct nfs_write_header *whdr;
1039 struct nfs_write_data *data; 1048 struct nfs_write_data *data;
1040 struct list_head *head = &desc->pg_list; 1049 struct list_head *head = &desc->pg_list;
1041 int ret = 0; 1050 int ret = 0;
1042 1051
1043 data = nfs_writedata_alloc(nfs_page_array_len(desc->pg_base, 1052 whdr = nfs_writehdr_alloc(nfs_page_array_len(desc->pg_base,
1044 desc->pg_count)); 1053 desc->pg_count));
1045 if (!data) { 1054 if (!whdr) {
1046 while (!list_empty(head)) { 1055 while (!list_empty(head)) {
1047 req = nfs_list_entry(head->next); 1056 req = nfs_list_entry(head->next);
1048 nfs_list_remove_request(req); 1057 nfs_list_remove_request(req);
@@ -1051,14 +1060,15 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc, struct list_head *r
1051 ret = -ENOMEM; 1060 ret = -ENOMEM;
1052 goto out; 1061 goto out;
1053 } 1062 }
1063 data = &whdr->rpc_data;
1054 pages = data->pagevec; 1064 pages = data->pagevec;
1055 while (!list_empty(head)) { 1065 while (!list_empty(head)) {
1056 req = nfs_list_entry(head->next); 1066 req = nfs_list_entry(head->next);
1057 nfs_list_remove_request(req); 1067 nfs_list_remove_request(req);
1058 nfs_list_add_request(req, &data->pages); 1068 nfs_list_add_request(req, &whdr->header.pages);
1059 *pages++ = req->wb_page; 1069 *pages++ = req->wb_page;
1060 } 1070 }
1061 req = nfs_list_entry(data->pages.next); 1071 req = nfs_list_entry(whdr->header.pages.next);
1062 1072
1063 if ((desc->pg_ioflags & FLUSH_COND_STABLE) && 1073 if ((desc->pg_ioflags & FLUSH_COND_STABLE) &&
1064 (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit)) 1074 (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit))
@@ -1126,10 +1136,11 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
1126 1136
1127 dprintk("NFS: %5u write(%s/%lld %d@%lld)", 1137 dprintk("NFS: %5u write(%s/%lld %d@%lld)",
1128 task->tk_pid, 1138 task->tk_pid,
1129 data->req->wb_context->dentry->d_inode->i_sb->s_id, 1139 data->header->inode->i_sb->s_id,
1130 (long long) 1140 (long long)
1131 NFS_FILEID(data->req->wb_context->dentry->d_inode), 1141 NFS_FILEID(data->header->inode),
1132 data->req->wb_bytes, (long long)req_offset(data->req)); 1142 data->header->req->wb_bytes,
1143 (long long)req_offset(data->header->req));
1133 1144
1134 nfs_writeback_done(task, data); 1145 nfs_writeback_done(task, data);
1135} 1146}
@@ -1137,7 +1148,7 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
1137static void nfs_writeback_release_partial(void *calldata) 1148static void nfs_writeback_release_partial(void *calldata)
1138{ 1149{
1139 struct nfs_write_data *data = calldata; 1150 struct nfs_write_data *data = calldata;
1140 struct nfs_page *req = data->req; 1151 struct nfs_page *req = data->header->req;
1141 struct page *page = req->wb_page; 1152 struct page *page = req->wb_page;
1142 int status = data->task.tk_status; 1153 int status = data->task.tk_status;
1143 1154
@@ -1169,13 +1180,13 @@ static void nfs_writeback_release_partial(void *calldata)
1169out: 1180out:
1170 if (atomic_dec_and_test(&req->wb_complete)) 1181 if (atomic_dec_and_test(&req->wb_complete))
1171 nfs_writepage_release(req, data); 1182 nfs_writepage_release(req, data);
1172 nfs_writedata_release(calldata); 1183 nfs_writedata_release(data);
1173} 1184}
1174 1185
1175void nfs_write_prepare(struct rpc_task *task, void *calldata) 1186void nfs_write_prepare(struct rpc_task *task, void *calldata)
1176{ 1187{
1177 struct nfs_write_data *data = calldata; 1188 struct nfs_write_data *data = calldata;
1178 NFS_PROTO(data->inode)->write_rpc_prepare(task, data); 1189 NFS_PROTO(data->header->inode)->write_rpc_prepare(task, data);
1179} 1190}
1180 1191
1181void nfs_commit_prepare(struct rpc_task *task, void *calldata) 1192void nfs_commit_prepare(struct rpc_task *task, void *calldata)
@@ -1208,11 +1219,12 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata)
1208static void nfs_writeback_release_full(void *calldata) 1219static void nfs_writeback_release_full(void *calldata)
1209{ 1220{
1210 struct nfs_write_data *data = calldata; 1221 struct nfs_write_data *data = calldata;
1222 struct nfs_pgio_header *hdr = data->header;
1211 int status = data->task.tk_status; 1223 int status = data->task.tk_status;
1212 1224
1213 /* Update attributes as result of writeback. */ 1225 /* Update attributes as result of writeback. */
1214 while (!list_empty(&data->pages)) { 1226 while (!list_empty(&hdr->pages)) {
1215 struct nfs_page *req = nfs_list_entry(data->pages.next); 1227 struct nfs_page *req = nfs_list_entry(hdr->pages.next);
1216 struct page *page = req->wb_page; 1228 struct page *page = req->wb_page;
1217 1229
1218 nfs_list_remove_request(req); 1230 nfs_list_remove_request(req);
@@ -1233,7 +1245,7 @@ static void nfs_writeback_release_full(void *calldata)
1233 1245
1234 if (nfs_write_need_commit(data)) { 1246 if (nfs_write_need_commit(data)) {
1235 memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); 1247 memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
1236 nfs_mark_request_commit(req, data->lseg); 1248 nfs_mark_request_commit(req, hdr->lseg);
1237 dprintk(" marked for commit\n"); 1249 dprintk(" marked for commit\n");
1238 goto next; 1250 goto next;
1239 } 1251 }
@@ -1244,7 +1256,7 @@ remove_request:
1244 nfs_unlock_request(req); 1256 nfs_unlock_request(req);
1245 nfs_end_page_writeback(page); 1257 nfs_end_page_writeback(page);
1246 } 1258 }
1247 nfs_writedata_release(calldata); 1259 nfs_writedata_release(data);
1248} 1260}
1249 1261
1250static const struct rpc_call_ops nfs_write_full_ops = { 1262static const struct rpc_call_ops nfs_write_full_ops = {
@@ -1261,6 +1273,7 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
1261{ 1273{
1262 struct nfs_writeargs *argp = &data->args; 1274 struct nfs_writeargs *argp = &data->args;
1263 struct nfs_writeres *resp = &data->res; 1275 struct nfs_writeres *resp = &data->res;
1276 struct inode *inode = data->header->inode;
1264 int status; 1277 int status;
1265 1278
1266 dprintk("NFS: %5u nfs_writeback_done (status %d)\n", 1279 dprintk("NFS: %5u nfs_writeback_done (status %d)\n",
@@ -1273,10 +1286,10 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
1273 * another writer had changed the file, but some applications 1286 * another writer had changed the file, but some applications
1274 * depend on tighter cache coherency when writing. 1287 * depend on tighter cache coherency when writing.
1275 */ 1288 */
1276 status = NFS_PROTO(data->inode)->write_done(task, data); 1289 status = NFS_PROTO(inode)->write_done(task, data);
1277 if (status != 0) 1290 if (status != 0)
1278 return; 1291 return;
1279 nfs_add_stats(data->inode, NFSIOS_SERVERWRITTENBYTES, resp->count); 1292 nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, resp->count);
1280 1293
1281#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) 1294#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
1282 if (resp->verf->committed < argp->stable && task->tk_status >= 0) { 1295 if (resp->verf->committed < argp->stable && task->tk_status >= 0) {
@@ -1294,7 +1307,7 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
1294 if (time_before(complain, jiffies)) { 1307 if (time_before(complain, jiffies)) {
1295 dprintk("NFS: faulty NFS server %s:" 1308 dprintk("NFS: faulty NFS server %s:"
1296 " (committed = %d) != (stable = %d)\n", 1309 " (committed = %d) != (stable = %d)\n",
1297 NFS_SERVER(data->inode)->nfs_client->cl_hostname, 1310 NFS_SERVER(inode)->nfs_client->cl_hostname,
1298 resp->verf->committed, argp->stable); 1311 resp->verf->committed, argp->stable);
1299 complain = jiffies + 300 * HZ; 1312 complain = jiffies + 300 * HZ;
1300 } 1313 }
@@ -1304,7 +1317,7 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
1304 if (task->tk_status >= 0 && resp->count < argp->count) { 1317 if (task->tk_status >= 0 && resp->count < argp->count) {
1305 static unsigned long complain; 1318 static unsigned long complain;
1306 1319
1307 nfs_inc_stats(data->inode, NFSIOS_SHORTWRITE); 1320 nfs_inc_stats(inode, NFSIOS_SHORTWRITE);
1308 1321
1309 /* Has the server at least made some progress? */ 1322 /* Has the server at least made some progress? */
1310 if (resp->count != 0) { 1323 if (resp->count != 0) {
@@ -1333,7 +1346,6 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
1333 /* Can't do anything about it except throw an error. */ 1346 /* Can't do anything about it except throw an error. */
1334 task->tk_status = -EIO; 1347 task->tk_status = -EIO;
1335 } 1348 }
1336 return;
1337} 1349}
1338 1350
1339 1351
@@ -1745,7 +1757,7 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
1745int __init nfs_init_writepagecache(void) 1757int __init nfs_init_writepagecache(void)
1746{ 1758{
1747 nfs_wdata_cachep = kmem_cache_create("nfs_write_data", 1759 nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
1748 sizeof(struct nfs_write_data), 1760 sizeof(struct nfs_write_header),
1749 0, SLAB_HWCACHE_ALIGN, 1761 0, SLAB_HWCACHE_ALIGN,
1750 NULL); 1762 NULL);
1751 if (nfs_wdata_cachep == NULL) 1763 if (nfs_wdata_cachep == NULL)