diff options
| -rw-r--r-- | fs/nfs/pagelist.c | 71 | ||||
| -rw-r--r-- | fs/nfs/read.c | 62 | ||||
| -rw-r--r-- | fs/nfs/write.c | 53 | ||||
| -rw-r--r-- | include/linux/nfs_page.h | 14 |
4 files changed, 125 insertions, 75 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 7017eb0e0bc8..528128545d66 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
| @@ -225,14 +225,26 @@ out: | |||
| 225 | /** | 225 | /** |
| 226 | * nfs_pageio_init - initialise a page io descriptor | 226 | * nfs_pageio_init - initialise a page io descriptor |
| 227 | * @desc: pointer to descriptor | 227 | * @desc: pointer to descriptor |
| 228 | * @iosize: io block size | 228 | * @inode: pointer to inode |
| 229 | * @doio: pointer to io function | ||
| 230 | * @bsize: io block size | ||
| 231 | * @io_flags: extra parameters for the io function | ||
| 229 | */ | 232 | */ |
| 230 | void nfs_pageio_init(struct nfs_pageio_descriptor *desc, unsigned int bsize) | 233 | void nfs_pageio_init(struct nfs_pageio_descriptor *desc, |
| 234 | struct inode *inode, | ||
| 235 | int (*doio)(struct inode *, struct list_head *, size_t, int), | ||
| 236 | unsigned int bsize, | ||
| 237 | int io_flags) | ||
| 231 | { | 238 | { |
| 232 | INIT_LIST_HEAD(&desc->pg_list); | 239 | INIT_LIST_HEAD(&desc->pg_list); |
| 240 | desc->pg_bytes_written = 0; | ||
| 233 | desc->pg_count = 0; | 241 | desc->pg_count = 0; |
| 234 | desc->pg_bsize = bsize; | 242 | desc->pg_bsize = bsize; |
| 235 | desc->pg_base = 0; | 243 | desc->pg_base = 0; |
| 244 | desc->pg_inode = inode; | ||
| 245 | desc->pg_doio = doio; | ||
| 246 | desc->pg_ioflags = io_flags; | ||
| 247 | desc->pg_error = 0; | ||
| 236 | } | 248 | } |
| 237 | 249 | ||
| 238 | /** | 250 | /** |
| @@ -265,15 +277,15 @@ static int nfs_can_coalesce_requests(struct nfs_page *prev, | |||
| 265 | } | 277 | } |
| 266 | 278 | ||
| 267 | /** | 279 | /** |
| 268 | * nfs_pageio_add_request - Attempt to coalesce a request into a page list. | 280 | * nfs_pageio_do_add_request - Attempt to coalesce a request into a page list. |
| 269 | * @desc: destination io descriptor | 281 | * @desc: destination io descriptor |
| 270 | * @req: request | 282 | * @req: request |
| 271 | * | 283 | * |
| 272 | * Returns true if the request 'req' was successfully coalesced into the | 284 | * Returns true if the request 'req' was successfully coalesced into the |
| 273 | * existing list of pages 'desc'. | 285 | * existing list of pages 'desc'. |
| 274 | */ | 286 | */ |
| 275 | static int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | 287 | static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc, |
| 276 | struct nfs_page *req) | 288 | struct nfs_page *req) |
| 277 | { | 289 | { |
| 278 | size_t newlen = req->wb_bytes; | 290 | size_t newlen = req->wb_bytes; |
| 279 | 291 | ||
| @@ -301,6 +313,46 @@ static int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
| 301 | return 1; | 313 | return 1; |
| 302 | } | 314 | } |
| 303 | 315 | ||
| 316 | /* | ||
| 317 | * Helper for nfs_pageio_add_request and nfs_pageio_complete | ||
| 318 | */ | ||
| 319 | static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc) | ||
| 320 | { | ||
| 321 | if (!list_empty(&desc->pg_list)) { | ||
| 322 | int error = desc->pg_doio(desc->pg_inode, | ||
| 323 | &desc->pg_list, | ||
| 324 | desc->pg_count, | ||
| 325 | desc->pg_ioflags); | ||
| 326 | if (error < 0) | ||
| 327 | desc->pg_error = error; | ||
| 328 | else | ||
| 329 | desc->pg_bytes_written += desc->pg_count; | ||
| 330 | } | ||
| 331 | if (list_empty(&desc->pg_list)) { | ||
| 332 | desc->pg_count = 0; | ||
| 333 | desc->pg_base = 0; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | /** | ||
| 338 | * nfs_pageio_add_request - Attempt to coalesce a request into a page list. | ||
| 339 | * @desc: destination io descriptor | ||
| 340 | * @req: request | ||
| 341 | * | ||
| 342 | * Returns true if the request 'req' was successfully coalesced into the | ||
| 343 | * existing list of pages 'desc'. | ||
| 344 | */ | ||
| 345 | static int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | ||
| 346 | struct nfs_page *req) | ||
| 347 | { | ||
| 348 | while (!nfs_pageio_do_add_request(desc, req)) { | ||
| 349 | nfs_pageio_doio(desc); | ||
| 350 | if (desc->pg_error < 0) | ||
| 351 | return 0; | ||
| 352 | } | ||
| 353 | return 1; | ||
| 354 | } | ||
| 355 | |||
| 304 | /** | 356 | /** |
| 305 | * nfs_pageio_add_list - Split coalesced requests out from a list. | 357 | * nfs_pageio_add_list - Split coalesced requests out from a list. |
| 306 | * @desc: destination io descriptor | 358 | * @desc: destination io descriptor |
| @@ -320,6 +372,15 @@ void nfs_pageio_add_list(struct nfs_pageio_descriptor *desc, | |||
| 320 | } | 372 | } |
| 321 | } | 373 | } |
| 322 | 374 | ||
| 375 | /** | ||
| 376 | * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor | ||
| 377 | * @desc: pointer to io descriptor | ||
| 378 | */ | ||
| 379 | void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) | ||
| 380 | { | ||
| 381 | nfs_pageio_doio(desc); | ||
| 382 | } | ||
| 383 | |||
| 323 | #define NFS_SCAN_MAXENTRIES 16 | 384 | #define NFS_SCAN_MAXENTRIES 16 |
| 324 | /** | 385 | /** |
| 325 | * nfs_scan_dirty - Scan the radix tree for dirty requests | 386 | * nfs_scan_dirty - Scan the radix tree for dirty requests |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 97f0f42e136d..0effa74992df 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
| @@ -27,7 +27,8 @@ | |||
| 27 | 27 | ||
| 28 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 28 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
| 29 | 29 | ||
| 30 | static int nfs_pagein_one(struct list_head *, struct inode *); | 30 | static int nfs_pagein_multi(struct inode *, struct list_head *, size_t, int); |
| 31 | static int nfs_pagein_one(struct inode *, struct list_head *, size_t, int); | ||
| 31 | static const struct rpc_call_ops nfs_read_partial_ops; | 32 | static const struct rpc_call_ops nfs_read_partial_ops; |
| 32 | static const struct rpc_call_ops nfs_read_full_ops; | 33 | static const struct rpc_call_ops nfs_read_full_ops; |
| 33 | 34 | ||
| @@ -133,7 +134,10 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | |||
| 133 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 134 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); |
| 134 | 135 | ||
| 135 | nfs_list_add_request(new, &one_request); | 136 | nfs_list_add_request(new, &one_request); |
| 136 | nfs_pagein_one(&one_request, inode); | 137 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) |
| 138 | nfs_pagein_multi(inode, &one_request, len, 0); | ||
| 139 | else | ||
| 140 | nfs_pagein_one(inode, &one_request, len, 0); | ||
| 137 | return 0; | 141 | return 0; |
| 138 | } | 142 | } |
| 139 | 143 | ||
| @@ -230,7 +234,7 @@ static void nfs_execute_read(struct nfs_read_data *data) | |||
| 230 | * won't see the new data until our attribute cache is updated. This is more | 234 | * won't see the new data until our attribute cache is updated. This is more |
| 231 | * or less conventional NFS client behavior. | 235 | * or less conventional NFS client behavior. |
| 232 | */ | 236 | */ |
| 233 | static int nfs_pagein_multi(struct list_head *head, struct inode *inode) | 237 | static int nfs_pagein_multi(struct inode *inode, struct list_head *head, size_t count, int flags) |
| 234 | { | 238 | { |
| 235 | struct nfs_page *req = nfs_list_entry(head->next); | 239 | struct nfs_page *req = nfs_list_entry(head->next); |
| 236 | struct page *page = req->wb_page; | 240 | struct page *page = req->wb_page; |
| @@ -242,7 +246,7 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode) | |||
| 242 | 246 | ||
| 243 | nfs_list_remove_request(req); | 247 | nfs_list_remove_request(req); |
| 244 | 248 | ||
| 245 | nbytes = req->wb_bytes; | 249 | nbytes = count; |
| 246 | do { | 250 | do { |
| 247 | size_t len = min(nbytes,rsize); | 251 | size_t len = min(nbytes,rsize); |
| 248 | 252 | ||
| @@ -258,23 +262,19 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode) | |||
| 258 | 262 | ||
| 259 | ClearPageError(page); | 263 | ClearPageError(page); |
| 260 | offset = 0; | 264 | offset = 0; |
| 261 | nbytes = req->wb_bytes; | 265 | nbytes = count; |
| 262 | do { | 266 | do { |
| 263 | data = list_entry(list.next, struct nfs_read_data, pages); | 267 | data = list_entry(list.next, struct nfs_read_data, pages); |
| 264 | list_del_init(&data->pages); | 268 | list_del_init(&data->pages); |
| 265 | 269 | ||
| 266 | data->pagevec[0] = page; | 270 | data->pagevec[0] = page; |
| 267 | 271 | ||
| 268 | if (nbytes > rsize) { | 272 | if (nbytes < rsize) |
| 269 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, | 273 | rsize = nbytes; |
| 270 | rsize, offset); | 274 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, |
| 271 | offset += rsize; | 275 | rsize, offset); |
| 272 | nbytes -= rsize; | 276 | offset += rsize; |
| 273 | } else { | 277 | nbytes -= rsize; |
| 274 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, | ||
| 275 | nbytes, offset); | ||
| 276 | nbytes = 0; | ||
| 277 | } | ||
| 278 | nfs_execute_read(data); | 278 | nfs_execute_read(data); |
| 279 | } while (nbytes != 0); | 279 | } while (nbytes != 0); |
| 280 | 280 | ||
| @@ -291,30 +291,24 @@ out_bad: | |||
| 291 | return -ENOMEM; | 291 | return -ENOMEM; |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | static int nfs_pagein_one(struct list_head *head, struct inode *inode) | 294 | static int nfs_pagein_one(struct inode *inode, struct list_head *head, size_t count, int flags) |
| 295 | { | 295 | { |
| 296 | struct nfs_page *req; | 296 | struct nfs_page *req; |
| 297 | struct page **pages; | 297 | struct page **pages; |
| 298 | struct nfs_read_data *data; | 298 | struct nfs_read_data *data; |
| 299 | unsigned int count; | ||
| 300 | |||
| 301 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) | ||
| 302 | return nfs_pagein_multi(head, inode); | ||
| 303 | 299 | ||
| 304 | data = nfs_readdata_alloc(NFS_SERVER(inode)->rsize); | 300 | data = nfs_readdata_alloc(count); |
| 305 | if (!data) | 301 | if (!data) |
| 306 | goto out_bad; | 302 | goto out_bad; |
| 307 | 303 | ||
| 308 | INIT_LIST_HEAD(&data->pages); | 304 | INIT_LIST_HEAD(&data->pages); |
| 309 | pages = data->pagevec; | 305 | pages = data->pagevec; |
| 310 | count = 0; | ||
| 311 | while (!list_empty(head)) { | 306 | while (!list_empty(head)) { |
| 312 | req = nfs_list_entry(head->next); | 307 | req = nfs_list_entry(head->next); |
| 313 | nfs_list_remove_request(req); | 308 | nfs_list_remove_request(req); |
| 314 | nfs_list_add_request(req, &data->pages); | 309 | nfs_list_add_request(req, &data->pages); |
| 315 | ClearPageError(req->wb_page); | 310 | ClearPageError(req->wb_page); |
| 316 | *pages++ = req->wb_page; | 311 | *pages++ = req->wb_page; |
| 317 | count += req->wb_bytes; | ||
| 318 | } | 312 | } |
| 319 | req = nfs_list_entry(data->pages.next); | 313 | req = nfs_list_entry(data->pages.next); |
| 320 | 314 | ||
| @@ -328,22 +322,20 @@ out_bad: | |||
| 328 | } | 322 | } |
| 329 | 323 | ||
| 330 | static int | 324 | static int |
| 331 | nfs_pagein_list(struct list_head *head, unsigned int rsize) | 325 | nfs_pagein_list(struct inode *inode, struct list_head *head, unsigned int rsize) |
| 332 | { | 326 | { |
| 333 | struct nfs_pageio_descriptor desc; | 327 | struct nfs_pageio_descriptor desc; |
| 334 | struct nfs_page *req; | ||
| 335 | unsigned int pages = 0; | 328 | unsigned int pages = 0; |
| 336 | int error = 0; | 329 | int error = 0; |
| 337 | 330 | ||
| 338 | while (!list_empty(head)) { | 331 | if (rsize < PAGE_CACHE_SIZE) |
| 339 | nfs_pageio_init(&desc, rsize); | 332 | nfs_pageio_init(&desc, inode, nfs_pagein_multi, rsize, 0); |
| 340 | nfs_pageio_add_list(&desc, head); | 333 | else |
| 341 | req = nfs_list_entry(desc.pg_list.next); | 334 | nfs_pageio_init(&desc, inode, nfs_pagein_one, rsize, 0); |
| 342 | error = nfs_pagein_one(&desc.pg_list, req->wb_context->dentry->d_inode); | 335 | |
| 343 | if (error < 0) | 336 | nfs_pageio_add_list(&desc, head); |
| 344 | break; | 337 | nfs_pageio_complete(&desc); |
| 345 | pages += (desc.pg_count + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 338 | pages += (desc.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
| 346 | } | ||
| 347 | 339 | ||
| 348 | nfs_async_read_error(head); | 340 | nfs_async_read_error(head); |
| 349 | if (error >= 0) | 341 | if (error >= 0) |
| @@ -597,7 +589,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
| 597 | filp->private_data); | 589 | filp->private_data); |
| 598 | ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); | 590 | ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); |
| 599 | if (!list_empty(&head)) { | 591 | if (!list_empty(&head)) { |
| 600 | int err = nfs_pagein_list(&head, server->rsize); | 592 | int err = nfs_pagein_list(inode, &head, server->rsize); |
| 601 | if (!ret) | 593 | if (!ret) |
| 602 | nfs_add_stats(inode, NFSIOS_READPAGES, err); | 594 | nfs_add_stats(inode, NFSIOS_READPAGES, err); |
| 603 | ret = err; | 595 | ret = err; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index b03ec1ba4d75..b6749967eead 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -835,7 +835,7 @@ static void nfs_execute_write(struct nfs_write_data *data) | |||
| 835 | * Generate multiple small requests to write out a single | 835 | * Generate multiple small requests to write out a single |
| 836 | * contiguous dirty area on one page. | 836 | * contiguous dirty area on one page. |
| 837 | */ | 837 | */ |
| 838 | static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how) | 838 | static int nfs_flush_multi(struct inode *inode, struct list_head *head, size_t count, int how) |
| 839 | { | 839 | { |
| 840 | struct nfs_page *req = nfs_list_entry(head->next); | 840 | struct nfs_page *req = nfs_list_entry(head->next); |
| 841 | struct page *page = req->wb_page; | 841 | struct page *page = req->wb_page; |
| @@ -847,7 +847,7 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how) | |||
| 847 | 847 | ||
| 848 | nfs_list_remove_request(req); | 848 | nfs_list_remove_request(req); |
| 849 | 849 | ||
| 850 | nbytes = req->wb_bytes; | 850 | nbytes = count; |
| 851 | do { | 851 | do { |
| 852 | size_t len = min(nbytes, wsize); | 852 | size_t len = min(nbytes, wsize); |
| 853 | 853 | ||
| @@ -862,23 +862,19 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how) | |||
| 862 | 862 | ||
| 863 | ClearPageError(page); | 863 | ClearPageError(page); |
| 864 | offset = 0; | 864 | offset = 0; |
| 865 | nbytes = req->wb_bytes; | 865 | nbytes = count; |
| 866 | do { | 866 | do { |
| 867 | data = list_entry(list.next, struct nfs_write_data, pages); | 867 | data = list_entry(list.next, struct nfs_write_data, pages); |
| 868 | list_del_init(&data->pages); | 868 | list_del_init(&data->pages); |
| 869 | 869 | ||
| 870 | data->pagevec[0] = page; | 870 | data->pagevec[0] = page; |
| 871 | 871 | ||
| 872 | if (nbytes > wsize) { | 872 | if (nbytes < wsize) |
| 873 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, | 873 | wsize = nbytes; |
| 874 | wsize, offset, how); | 874 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
| 875 | offset += wsize; | 875 | wsize, offset, how); |
| 876 | nbytes -= wsize; | 876 | offset += wsize; |
| 877 | } else { | 877 | nbytes -= wsize; |
| 878 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, | ||
| 879 | nbytes, offset, how); | ||
| 880 | nbytes = 0; | ||
| 881 | } | ||
| 882 | nfs_execute_write(data); | 878 | nfs_execute_write(data); |
| 883 | } while (nbytes != 0); | 879 | } while (nbytes != 0); |
| 884 | 880 | ||
| @@ -904,26 +900,23 @@ out_bad: | |||
| 904 | * This is the case if nfs_updatepage detects a conflicting request | 900 | * This is the case if nfs_updatepage detects a conflicting request |
| 905 | * that has been written but not committed. | 901 | * that has been written but not committed. |
| 906 | */ | 902 | */ |
| 907 | static int nfs_flush_one(struct inode *inode, struct list_head *head, int how) | 903 | static int nfs_flush_one(struct inode *inode, struct list_head *head, size_t count, int how) |
| 908 | { | 904 | { |
| 909 | struct nfs_page *req; | 905 | struct nfs_page *req; |
| 910 | struct page **pages; | 906 | struct page **pages; |
| 911 | struct nfs_write_data *data; | 907 | struct nfs_write_data *data; |
| 912 | unsigned int count; | ||
| 913 | 908 | ||
| 914 | data = nfs_writedata_alloc(NFS_SERVER(inode)->wsize); | 909 | data = nfs_writedata_alloc(count); |
| 915 | if (!data) | 910 | if (!data) |
| 916 | goto out_bad; | 911 | goto out_bad; |
| 917 | 912 | ||
| 918 | pages = data->pagevec; | 913 | pages = data->pagevec; |
| 919 | count = 0; | ||
| 920 | while (!list_empty(head)) { | 914 | while (!list_empty(head)) { |
| 921 | req = nfs_list_entry(head->next); | 915 | req = nfs_list_entry(head->next); |
| 922 | nfs_list_remove_request(req); | 916 | nfs_list_remove_request(req); |
| 923 | nfs_list_add_request(req, &data->pages); | 917 | nfs_list_add_request(req, &data->pages); |
| 924 | ClearPageError(req->wb_page); | 918 | ClearPageError(req->wb_page); |
| 925 | *pages++ = req->wb_page; | 919 | *pages++ = req->wb_page; |
| 926 | count += req->wb_bytes; | ||
| 927 | } | 920 | } |
| 928 | req = nfs_list_entry(data->pages.next); | 921 | req = nfs_list_entry(data->pages.next); |
| 929 | 922 | ||
| @@ -946,28 +939,22 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, int how) | |||
| 946 | static int nfs_flush_list(struct inode *inode, struct list_head *head, int npages, int how) | 939 | static int nfs_flush_list(struct inode *inode, struct list_head *head, int npages, int how) |
| 947 | { | 940 | { |
| 948 | struct nfs_pageio_descriptor desc; | 941 | struct nfs_pageio_descriptor desc; |
| 949 | int (*flush_one)(struct inode *, struct list_head *, int); | ||
| 950 | int wpages = NFS_SERVER(inode)->wpages; | 942 | int wpages = NFS_SERVER(inode)->wpages; |
| 951 | int wsize = NFS_SERVER(inode)->wsize; | 943 | int wsize = NFS_SERVER(inode)->wsize; |
| 952 | int error; | ||
| 953 | 944 | ||
| 954 | flush_one = nfs_flush_one; | ||
| 955 | if (wsize < PAGE_CACHE_SIZE) | ||
| 956 | flush_one = nfs_flush_multi; | ||
| 957 | /* For single writes, FLUSH_STABLE is more efficient */ | 945 | /* For single writes, FLUSH_STABLE is more efficient */ |
| 958 | if (npages <= wpages && npages == NFS_I(inode)->npages | 946 | if (npages <= wpages && npages == NFS_I(inode)->npages |
| 959 | && nfs_list_entry(head->next)->wb_bytes <= wsize) | 947 | && nfs_list_entry(head->next)->wb_bytes <= wsize) |
| 960 | how |= FLUSH_STABLE; | 948 | how |= FLUSH_STABLE; |
| 961 | 949 | ||
| 962 | do { | 950 | if (wsize < PAGE_CACHE_SIZE) |
| 963 | nfs_pageio_init(&desc, wsize); | 951 | nfs_pageio_init(&desc, inode, nfs_flush_multi, wsize, how); |
| 964 | nfs_pageio_add_list(&desc, head); | 952 | else |
| 965 | error = flush_one(inode, &desc.pg_list, how); | 953 | nfs_pageio_init(&desc, inode, nfs_flush_one, wsize, how); |
| 966 | if (error < 0) | 954 | nfs_pageio_add_list(&desc, head); |
| 967 | goto out_err; | 955 | nfs_pageio_complete(&desc); |
| 968 | } while (!list_empty(head)); | 956 | if (desc.pg_error == 0) |
| 969 | return 0; | 957 | return 0; |
| 970 | out_err: | ||
| 971 | while (!list_empty(head)) { | 958 | while (!list_empty(head)) { |
| 972 | struct nfs_page *req = nfs_list_entry(head->next); | 959 | struct nfs_page *req = nfs_list_entry(head->next); |
| 973 | nfs_list_remove_request(req); | 960 | nfs_list_remove_request(req); |
| @@ -975,7 +962,7 @@ out_err: | |||
| 975 | nfs_end_page_writeback(req->wb_page); | 962 | nfs_end_page_writeback(req->wb_page); |
| 976 | nfs_clear_page_writeback(req); | 963 | nfs_clear_page_writeback(req); |
| 977 | } | 964 | } |
| 978 | return error; | 965 | return desc.pg_error; |
| 979 | } | 966 | } |
| 980 | 967 | ||
| 981 | /* | 968 | /* |
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 3ef8e0441473..91c7b18c47d8 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h | |||
| @@ -50,9 +50,15 @@ struct nfs_page { | |||
| 50 | 50 | ||
| 51 | struct nfs_pageio_descriptor { | 51 | struct nfs_pageio_descriptor { |
| 52 | struct list_head pg_list; | 52 | struct list_head pg_list; |
| 53 | unsigned long pg_bytes_written; | ||
| 53 | size_t pg_count; | 54 | size_t pg_count; |
| 54 | size_t pg_bsize; | 55 | size_t pg_bsize; |
| 55 | unsigned int pg_base; | 56 | unsigned int pg_base; |
| 57 | |||
| 58 | struct inode *pg_inode; | ||
| 59 | int (*pg_doio)(struct inode *, struct list_head *, size_t, int); | ||
| 60 | int pg_ioflags; | ||
| 61 | int pg_error; | ||
| 56 | }; | 62 | }; |
| 57 | 63 | ||
| 58 | #define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags)) | 64 | #define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags)) |
| @@ -71,10 +77,14 @@ extern long nfs_scan_dirty(struct address_space *mapping, | |||
| 71 | struct list_head *dst); | 77 | struct list_head *dst); |
| 72 | extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst, | 78 | extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst, |
| 73 | unsigned long idx_start, unsigned int npages); | 79 | unsigned long idx_start, unsigned int npages); |
| 74 | extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc, | 80 | extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc, |
| 75 | size_t iosize); | 81 | struct inode *inode, |
| 82 | int (*doio)(struct inode *, struct list_head *, size_t, int), | ||
| 83 | size_t bsize, | ||
| 84 | int how); | ||
| 76 | extern void nfs_pageio_add_list(struct nfs_pageio_descriptor *, | 85 | extern void nfs_pageio_add_list(struct nfs_pageio_descriptor *, |
| 77 | struct list_head *); | 86 | struct list_head *); |
| 87 | extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc); | ||
| 78 | extern int nfs_wait_on_request(struct nfs_page *); | 88 | extern int nfs_wait_on_request(struct nfs_page *); |
| 79 | extern void nfs_unlock_request(struct nfs_page *req); | 89 | extern void nfs_unlock_request(struct nfs_page *req); |
| 80 | extern int nfs_set_page_writeback_locked(struct nfs_page *req); | 90 | extern int nfs_set_page_writeback_locked(struct nfs_page *req); |
