diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-07-12 13:42:02 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-07-15 09:12:17 -0400 |
commit | 275acaafd45fbc8ecc3beabd6367e60b3049606a (patch) | |
tree | 7da9d9a606c274742d41860cb429c7d25a917f1d /fs | |
parent | 3b6091846d5b6113d695c79caec7cc96b62d469b (diff) |
NFS: Clean up: split out the RPC transmission from nfs_pagein_multi/one
...and do the same for nfs_flush_multi/one.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/read.c | 92 | ||||
-rw-r--r-- | fs/nfs/write.c | 93 |
2 files changed, 102 insertions, 83 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 581534a4aed7..0215bac35fc6 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -30,8 +30,6 @@ | |||
30 | 30 | ||
31 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 31 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
32 | 32 | ||
33 | static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc); | ||
34 | static int nfs_pagein_one(struct nfs_pageio_descriptor *desc); | ||
35 | static const struct nfs_pageio_ops nfs_pageio_read_ops; | 33 | static const struct nfs_pageio_ops nfs_pageio_read_ops; |
36 | static const struct rpc_call_ops nfs_read_partial_ops; | 34 | static const struct rpc_call_ops nfs_read_partial_ops; |
37 | static const struct rpc_call_ops nfs_read_full_ops; | 35 | static const struct rpc_call_ops nfs_read_full_ops; |
@@ -253,6 +251,27 @@ static int nfs_do_read(struct nfs_read_data *data, | |||
253 | return nfs_initiate_read(data, NFS_CLIENT(inode), call_ops); | 251 | return nfs_initiate_read(data, NFS_CLIENT(inode), call_ops); |
254 | } | 252 | } |
255 | 253 | ||
254 | static int | ||
255 | nfs_do_multiple_reads(struct list_head *head, | ||
256 | const struct rpc_call_ops *call_ops, | ||
257 | struct pnfs_layout_segment *lseg) | ||
258 | { | ||
259 | struct nfs_read_data *data; | ||
260 | int ret = 0; | ||
261 | |||
262 | while (!list_empty(head)) { | ||
263 | int ret2; | ||
264 | |||
265 | data = list_entry(head->next, struct nfs_read_data, list); | ||
266 | list_del_init(&data->list); | ||
267 | |||
268 | ret2 = nfs_do_read(data, call_ops, lseg); | ||
269 | if (ret == 0) | ||
270 | ret = ret2; | ||
271 | } | ||
272 | return ret; | ||
273 | } | ||
274 | |||
256 | static void | 275 | static void |
257 | nfs_async_read_error(struct list_head *head) | 276 | nfs_async_read_error(struct list_head *head) |
258 | { | 277 | { |
@@ -279,7 +298,7 @@ nfs_async_read_error(struct list_head *head) | |||
279 | * won't see the new data until our attribute cache is updated. This is more | 298 | * won't see the new data until our attribute cache is updated. This is more |
280 | * or less conventional NFS client behavior. | 299 | * or less conventional NFS client behavior. |
281 | */ | 300 | */ |
282 | static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc) | 301 | static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head *res) |
283 | { | 302 | { |
284 | struct nfs_page *req = nfs_list_entry(desc->pg_list.next); | 303 | struct nfs_page *req = nfs_list_entry(desc->pg_list.next); |
285 | struct page *page = req->wb_page; | 304 | struct page *page = req->wb_page; |
@@ -288,11 +307,10 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc) | |||
288 | unsigned int offset; | 307 | unsigned int offset; |
289 | int requests = 0; | 308 | int requests = 0; |
290 | int ret = 0; | 309 | int ret = 0; |
291 | struct pnfs_layout_segment *lseg = desc->pg_lseg; | ||
292 | LIST_HEAD(list); | ||
293 | 310 | ||
294 | nfs_list_remove_request(req); | 311 | nfs_list_remove_request(req); |
295 | 312 | ||
313 | offset = 0; | ||
296 | nbytes = desc->pg_count; | 314 | nbytes = desc->pg_count; |
297 | do { | 315 | do { |
298 | size_t len = min(nbytes,rsize); | 316 | size_t len = min(nbytes,rsize); |
@@ -300,57 +318,33 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc) | |||
300 | data = nfs_readdata_alloc(1); | 318 | data = nfs_readdata_alloc(1); |
301 | if (!data) | 319 | if (!data) |
302 | goto out_bad; | 320 | goto out_bad; |
303 | list_add(&data->list, &list); | 321 | data->pagevec[0] = page; |
322 | nfs_read_rpcsetup(req, data, len, offset); | ||
323 | list_add(&data->list, res); | ||
304 | requests++; | 324 | requests++; |
305 | nbytes -= len; | 325 | nbytes -= len; |
326 | offset += len; | ||
306 | } while(nbytes != 0); | 327 | } while(nbytes != 0); |
307 | atomic_set(&req->wb_complete, requests); | 328 | atomic_set(&req->wb_complete, requests); |
308 | |||
309 | ClearPageError(page); | 329 | ClearPageError(page); |
310 | offset = 0; | ||
311 | nbytes = desc->pg_count; | ||
312 | do { | ||
313 | int ret2; | ||
314 | |||
315 | data = list_entry(list.next, struct nfs_read_data, list); | ||
316 | list_del_init(&data->list); | ||
317 | |||
318 | data->pagevec[0] = page; | ||
319 | |||
320 | if (nbytes < rsize) | ||
321 | rsize = nbytes; | ||
322 | nfs_read_rpcsetup(req, data, rsize, offset); | ||
323 | ret2 = nfs_do_read(data, &nfs_read_partial_ops, lseg); | ||
324 | if (ret == 0) | ||
325 | ret = ret2; | ||
326 | offset += rsize; | ||
327 | nbytes -= rsize; | ||
328 | } while (nbytes != 0); | ||
329 | put_lseg(lseg); | ||
330 | desc->pg_lseg = NULL; | ||
331 | |||
332 | return ret; | 330 | return ret; |
333 | |||
334 | out_bad: | 331 | out_bad: |
335 | while (!list_empty(&list)) { | 332 | while (!list_empty(res)) { |
336 | data = list_entry(list.next, struct nfs_read_data, list); | 333 | data = list_entry(res->next, struct nfs_read_data, list); |
337 | list_del(&data->list); | 334 | list_del(&data->list); |
338 | nfs_readdata_free(data); | 335 | nfs_readdata_free(data); |
339 | } | 336 | } |
340 | SetPageError(page); | 337 | SetPageError(page); |
341 | nfs_readpage_release(req); | 338 | nfs_readpage_release(req); |
342 | put_lseg(lseg); | ||
343 | desc->pg_lseg = NULL; | ||
344 | return -ENOMEM; | 339 | return -ENOMEM; |
345 | } | 340 | } |
346 | 341 | ||
347 | static int nfs_pagein_one(struct nfs_pageio_descriptor *desc) | 342 | static int nfs_pagein_one(struct nfs_pageio_descriptor *desc, struct list_head *res) |
348 | { | 343 | { |
349 | struct nfs_page *req; | 344 | struct nfs_page *req; |
350 | struct page **pages; | 345 | struct page **pages; |
351 | struct nfs_read_data *data; | 346 | struct nfs_read_data *data; |
352 | struct list_head *head = &desc->pg_list; | 347 | struct list_head *head = &desc->pg_list; |
353 | struct pnfs_layout_segment *lseg = desc->pg_lseg; | ||
354 | int ret = 0; | 348 | int ret = 0; |
355 | 349 | ||
356 | data = nfs_readdata_alloc(nfs_page_array_len(desc->pg_base, | 350 | data = nfs_readdata_alloc(nfs_page_array_len(desc->pg_base, |
@@ -372,18 +366,32 @@ static int nfs_pagein_one(struct nfs_pageio_descriptor *desc) | |||
372 | req = nfs_list_entry(data->pages.next); | 366 | req = nfs_list_entry(data->pages.next); |
373 | 367 | ||
374 | nfs_read_rpcsetup(req, data, desc->pg_count, 0); | 368 | nfs_read_rpcsetup(req, data, desc->pg_count, 0); |
375 | ret = nfs_do_read(data, &nfs_read_full_ops, lseg); | 369 | list_add(&data->list, res); |
376 | out: | 370 | out: |
377 | put_lseg(lseg); | ||
378 | desc->pg_lseg = NULL; | ||
379 | return ret; | 371 | return ret; |
380 | } | 372 | } |
381 | 373 | ||
382 | int nfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) | 374 | int nfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) |
383 | { | 375 | { |
384 | if (desc->pg_bsize < PAGE_CACHE_SIZE) | 376 | LIST_HEAD(head); |
385 | return nfs_pagein_multi(desc); | 377 | int ret; |
386 | return nfs_pagein_one(desc); | 378 | |
379 | if (desc->pg_bsize < PAGE_CACHE_SIZE) { | ||
380 | ret = nfs_pagein_multi(desc, &head); | ||
381 | if (ret == 0) | ||
382 | ret = nfs_do_multiple_reads(&head, | ||
383 | &nfs_read_partial_ops, | ||
384 | desc->pg_lseg); | ||
385 | } else { | ||
386 | ret = nfs_pagein_one(desc, &head); | ||
387 | if (ret == 0) | ||
388 | ret = nfs_do_multiple_reads(&head, | ||
389 | &nfs_read_full_ops, | ||
390 | desc->pg_lseg); | ||
391 | } | ||
392 | put_lseg(desc->pg_lseg); | ||
393 | desc->pg_lseg = NULL; | ||
394 | return ret; | ||
387 | } | 395 | } |
388 | EXPORT_SYMBOL_GPL(nfs_generic_pg_readpages); | 396 | EXPORT_SYMBOL_GPL(nfs_generic_pg_readpages); |
389 | 397 | ||
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index d9dd744588d4..bd4b34e5870b 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -903,6 +903,27 @@ static int nfs_do_write(struct nfs_write_data *data, | |||
903 | return nfs_initiate_write(data, NFS_CLIENT(inode), call_ops, how); | 903 | return nfs_initiate_write(data, NFS_CLIENT(inode), call_ops, how); |
904 | } | 904 | } |
905 | 905 | ||
906 | static int nfs_do_multiple_writes(struct list_head *head, | ||
907 | const struct rpc_call_ops *call_ops, | ||
908 | struct pnfs_layout_segment *lseg, | ||
909 | int how) | ||
910 | { | ||
911 | struct nfs_write_data *data; | ||
912 | int ret = 0; | ||
913 | |||
914 | while (!list_empty(head)) { | ||
915 | int ret2; | ||
916 | |||
917 | data = list_entry(head->next, struct nfs_write_data, list); | ||
918 | list_del_init(&data->list); | ||
919 | |||
920 | ret2 = nfs_do_write(data, call_ops, lseg, how); | ||
921 | if (ret == 0) | ||
922 | ret = ret2; | ||
923 | } | ||
924 | return ret; | ||
925 | } | ||
926 | |||
906 | /* If a nfs_flush_* function fails, it should remove reqs from @head and | 927 | /* If a nfs_flush_* function fails, it should remove reqs from @head and |
907 | * call this on each, which will prepare them to be retried on next | 928 | * call this on each, which will prepare them to be retried on next |
908 | * writeback using standard nfs. | 929 | * writeback using standard nfs. |
@@ -920,7 +941,7 @@ static void nfs_redirty_request(struct nfs_page *req) | |||
920 | * Generate multiple small requests to write out a single | 941 | * Generate multiple small requests to write out a single |
921 | * contiguous dirty area on one page. | 942 | * contiguous dirty area on one page. |
922 | */ | 943 | */ |
923 | static int nfs_flush_multi(struct nfs_pageio_descriptor *desc) | 944 | static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head *res) |
924 | { | 945 | { |
925 | struct nfs_page *req = nfs_list_entry(desc->pg_list.next); | 946 | struct nfs_page *req = nfs_list_entry(desc->pg_list.next); |
926 | struct page *page = req->wb_page; | 947 | struct page *page = req->wb_page; |
@@ -929,8 +950,6 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc) | |||
929 | unsigned int offset; | 950 | unsigned int offset; |
930 | int requests = 0; | 951 | int requests = 0; |
931 | int ret = 0; | 952 | int ret = 0; |
932 | struct pnfs_layout_segment *lseg = desc->pg_lseg; | ||
933 | LIST_HEAD(list); | ||
934 | 953 | ||
935 | nfs_list_remove_request(req); | 954 | nfs_list_remove_request(req); |
936 | 955 | ||
@@ -940,6 +959,7 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc) | |||
940 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; | 959 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; |
941 | 960 | ||
942 | 961 | ||
962 | offset = 0; | ||
943 | nbytes = desc->pg_count; | 963 | nbytes = desc->pg_count; |
944 | do { | 964 | do { |
945 | size_t len = min(nbytes, wsize); | 965 | size_t len = min(nbytes, wsize); |
@@ -947,47 +967,23 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc) | |||
947 | data = nfs_writedata_alloc(1); | 967 | data = nfs_writedata_alloc(1); |
948 | if (!data) | 968 | if (!data) |
949 | goto out_bad; | 969 | goto out_bad; |
950 | list_add(&data->list, &list); | 970 | data->pagevec[0] = page; |
971 | nfs_write_rpcsetup(req, data, wsize, offset, desc->pg_ioflags); | ||
972 | list_add(&data->list, res); | ||
951 | requests++; | 973 | requests++; |
952 | nbytes -= len; | 974 | nbytes -= len; |
975 | offset += len; | ||
953 | } while (nbytes != 0); | 976 | } while (nbytes != 0); |
954 | atomic_set(&req->wb_complete, requests); | 977 | atomic_set(&req->wb_complete, requests); |
955 | |||
956 | ClearPageError(page); | ||
957 | offset = 0; | ||
958 | nbytes = desc->pg_count; | ||
959 | do { | ||
960 | int ret2; | ||
961 | |||
962 | data = list_entry(list.next, struct nfs_write_data, list); | ||
963 | list_del_init(&data->list); | ||
964 | |||
965 | data->pagevec[0] = page; | ||
966 | |||
967 | if (nbytes < wsize) | ||
968 | wsize = nbytes; | ||
969 | nfs_write_rpcsetup(req, data, wsize, offset, desc->pg_ioflags); | ||
970 | ret2 = nfs_do_write(data, &nfs_write_partial_ops, lseg, | ||
971 | desc->pg_ioflags); | ||
972 | if (ret == 0) | ||
973 | ret = ret2; | ||
974 | offset += wsize; | ||
975 | nbytes -= wsize; | ||
976 | } while (nbytes != 0); | ||
977 | |||
978 | put_lseg(lseg); | ||
979 | desc->pg_lseg = NULL; | ||
980 | return ret; | 978 | return ret; |
981 | 979 | ||
982 | out_bad: | 980 | out_bad: |
983 | while (!list_empty(&list)) { | 981 | while (!list_empty(res)) { |
984 | data = list_entry(list.next, struct nfs_write_data, list); | 982 | data = list_entry(res->next, struct nfs_write_data, list); |
985 | list_del(&data->list); | 983 | list_del(&data->list); |
986 | nfs_writedata_free(data); | 984 | nfs_writedata_free(data); |
987 | } | 985 | } |
988 | nfs_redirty_request(req); | 986 | nfs_redirty_request(req); |
989 | put_lseg(lseg); | ||
990 | desc->pg_lseg = NULL; | ||
991 | return -ENOMEM; | 987 | return -ENOMEM; |
992 | } | 988 | } |
993 | 989 | ||
@@ -999,13 +995,12 @@ out_bad: | |||
999 | * This is the case if nfs_updatepage detects a conflicting request | 995 | * This is the case if nfs_updatepage detects a conflicting request |
1000 | * that has been written but not committed. | 996 | * that has been written but not committed. |
1001 | */ | 997 | */ |
1002 | static int nfs_flush_one(struct nfs_pageio_descriptor *desc) | 998 | static int nfs_flush_one(struct nfs_pageio_descriptor *desc, struct list_head *res) |
1003 | { | 999 | { |
1004 | struct nfs_page *req; | 1000 | struct nfs_page *req; |
1005 | struct page **pages; | 1001 | struct page **pages; |
1006 | struct nfs_write_data *data; | 1002 | struct nfs_write_data *data; |
1007 | struct list_head *head = &desc->pg_list; | 1003 | struct list_head *head = &desc->pg_list; |
1008 | struct pnfs_layout_segment *lseg = desc->pg_lseg; | ||
1009 | int ret = 0; | 1004 | int ret = 0; |
1010 | 1005 | ||
1011 | data = nfs_writedata_alloc(nfs_page_array_len(desc->pg_base, | 1006 | data = nfs_writedata_alloc(nfs_page_array_len(desc->pg_base, |
@@ -1035,18 +1030,34 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc) | |||
1035 | 1030 | ||
1036 | /* Set up the argument struct */ | 1031 | /* Set up the argument struct */ |
1037 | nfs_write_rpcsetup(req, data, desc->pg_count, 0, desc->pg_ioflags); | 1032 | nfs_write_rpcsetup(req, data, desc->pg_count, 0, desc->pg_ioflags); |
1038 | ret = nfs_do_write(data, &nfs_write_full_ops, lseg, desc->pg_ioflags); | 1033 | list_add(&data->list, res); |
1039 | out: | 1034 | out: |
1040 | put_lseg(lseg); /* Cleans any gotten in ->pg_test */ | ||
1041 | desc->pg_lseg = NULL; | ||
1042 | return ret; | 1035 | return ret; |
1043 | } | 1036 | } |
1044 | 1037 | ||
1045 | int nfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc) | 1038 | int nfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc) |
1046 | { | 1039 | { |
1047 | if (desc->pg_bsize < PAGE_CACHE_SIZE) | 1040 | LIST_HEAD(head); |
1048 | return nfs_flush_multi(desc); | 1041 | int ret; |
1049 | return nfs_flush_one(desc); | 1042 | |
1043 | if (desc->pg_bsize < PAGE_CACHE_SIZE) { | ||
1044 | ret = nfs_flush_multi(desc, &head); | ||
1045 | if (ret == 0) | ||
1046 | ret = nfs_do_multiple_writes(&head, | ||
1047 | &nfs_write_partial_ops, | ||
1048 | desc->pg_lseg, | ||
1049 | desc->pg_ioflags); | ||
1050 | } else { | ||
1051 | ret = nfs_flush_one(desc, &head); | ||
1052 | if (ret == 0) | ||
1053 | ret = nfs_do_multiple_writes(&head, | ||
1054 | &nfs_write_full_ops, | ||
1055 | desc->pg_lseg, | ||
1056 | desc->pg_ioflags); | ||
1057 | } | ||
1058 | put_lseg(desc->pg_lseg); | ||
1059 | desc->pg_lseg = NULL; | ||
1060 | return ret; | ||
1050 | } | 1061 | } |
1051 | EXPORT_SYMBOL_GPL(nfs_generic_pg_writepages); | 1062 | EXPORT_SYMBOL_GPL(nfs_generic_pg_writepages); |
1052 | 1063 | ||