diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/nfs/pagelist.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'fs/nfs/pagelist.c')
-rw-r--r-- | fs/nfs/pagelist.c | 100 |
1 files changed, 55 insertions, 45 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 919490232e17..009855716286 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -20,18 +20,16 @@ | |||
20 | #include <linux/nfs_mount.h> | 20 | #include <linux/nfs_mount.h> |
21 | 21 | ||
22 | #include "internal.h" | 22 | #include "internal.h" |
23 | #include "pnfs.h" | ||
23 | 24 | ||
24 | static struct kmem_cache *nfs_page_cachep; | 25 | static struct kmem_cache *nfs_page_cachep; |
25 | 26 | ||
26 | static inline struct nfs_page * | 27 | static inline struct nfs_page * |
27 | nfs_page_alloc(void) | 28 | nfs_page_alloc(void) |
28 | { | 29 | { |
29 | struct nfs_page *p; | 30 | struct nfs_page *p = kmem_cache_zalloc(nfs_page_cachep, GFP_KERNEL); |
30 | p = kmem_cache_alloc(nfs_page_cachep, GFP_KERNEL); | 31 | if (p) |
31 | if (p) { | ||
32 | memset(p, 0, sizeof(*p)); | ||
33 | INIT_LIST_HEAD(&p->wb_list); | 32 | INIT_LIST_HEAD(&p->wb_list); |
34 | } | ||
35 | return p; | 33 | return p; |
36 | } | 34 | } |
37 | 35 | ||
@@ -65,6 +63,13 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, | |||
65 | if (req == NULL) | 63 | if (req == NULL) |
66 | return ERR_PTR(-ENOMEM); | 64 | return ERR_PTR(-ENOMEM); |
67 | 65 | ||
66 | /* get lock context early so we can deal with alloc failures */ | ||
67 | req->wb_lock_context = nfs_get_lock_context(ctx); | ||
68 | if (req->wb_lock_context == NULL) { | ||
69 | nfs_page_free(req); | ||
70 | return ERR_PTR(-ENOMEM); | ||
71 | } | ||
72 | |||
68 | /* Initialize the request struct. Initially, we assume a | 73 | /* Initialize the request struct. Initially, we assume a |
69 | * long write-back delay. This will be adjusted in | 74 | * long write-back delay. This will be adjusted in |
70 | * update_nfs_request below if the region is not locked. */ | 75 | * update_nfs_request below if the region is not locked. */ |
@@ -79,7 +84,6 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, | |||
79 | req->wb_pgbase = offset; | 84 | req->wb_pgbase = offset; |
80 | req->wb_bytes = count; | 85 | req->wb_bytes = count; |
81 | req->wb_context = get_nfs_open_context(ctx); | 86 | req->wb_context = get_nfs_open_context(ctx); |
82 | req->wb_lock_context = nfs_get_lock_context(ctx); | ||
83 | kref_init(&req->wb_kref); | 87 | kref_init(&req->wb_kref); |
84 | return req; | 88 | return req; |
85 | } | 89 | } |
@@ -109,7 +113,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req) | |||
109 | { | 113 | { |
110 | if (!nfs_lock_request_dontget(req)) | 114 | if (!nfs_lock_request_dontget(req)) |
111 | return 0; | 115 | return 0; |
112 | if (req->wb_page != NULL) | 116 | if (test_bit(PG_MAPPED, &req->wb_flags)) |
113 | radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 117 | radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); |
114 | return 1; | 118 | return 1; |
115 | } | 119 | } |
@@ -119,7 +123,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req) | |||
119 | */ | 123 | */ |
120 | void nfs_clear_page_tag_locked(struct nfs_page *req) | 124 | void nfs_clear_page_tag_locked(struct nfs_page *req) |
121 | { | 125 | { |
122 | if (req->wb_page != NULL) { | 126 | if (test_bit(PG_MAPPED, &req->wb_flags)) { |
123 | struct inode *inode = req->wb_context->path.dentry->d_inode; | 127 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
124 | struct nfs_inode *nfsi = NFS_I(inode); | 128 | struct nfs_inode *nfsi = NFS_I(inode); |
125 | 129 | ||
@@ -131,14 +135,14 @@ void nfs_clear_page_tag_locked(struct nfs_page *req) | |||
131 | nfs_unlock_request(req); | 135 | nfs_unlock_request(req); |
132 | } | 136 | } |
133 | 137 | ||
134 | /** | 138 | /* |
135 | * nfs_clear_request - Free up all resources allocated to the request | 139 | * nfs_clear_request - Free up all resources allocated to the request |
136 | * @req: | 140 | * @req: |
137 | * | 141 | * |
138 | * Release page and open context resources associated with a read/write | 142 | * Release page and open context resources associated with a read/write |
139 | * request after it has completed. | 143 | * request after it has completed. |
140 | */ | 144 | */ |
141 | void nfs_clear_request(struct nfs_page *req) | 145 | static void nfs_clear_request(struct nfs_page *req) |
142 | { | 146 | { |
143 | struct page *page = req->wb_page; | 147 | struct page *page = req->wb_page; |
144 | struct nfs_open_context *ctx = req->wb_context; | 148 | struct nfs_open_context *ctx = req->wb_context; |
@@ -200,6 +204,22 @@ nfs_wait_on_request(struct nfs_page *req) | |||
200 | TASK_UNINTERRUPTIBLE); | 204 | TASK_UNINTERRUPTIBLE); |
201 | } | 205 | } |
202 | 206 | ||
207 | bool nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, struct nfs_page *prev, struct nfs_page *req) | ||
208 | { | ||
209 | /* | ||
210 | * FIXME: ideally we should be able to coalesce all requests | ||
211 | * that are not block boundary aligned, but currently this | ||
212 | * is problematic for the case of bsize < PAGE_CACHE_SIZE, | ||
213 | * since nfs_flush_multi and nfs_pagein_multi assume you | ||
214 | * can have only one struct nfs_page. | ||
215 | */ | ||
216 | if (desc->pg_bsize < PAGE_SIZE) | ||
217 | return 0; | ||
218 | |||
219 | return desc->pg_count + req->wb_bytes <= desc->pg_bsize; | ||
220 | } | ||
221 | EXPORT_SYMBOL_GPL(nfs_generic_pg_test); | ||
222 | |||
203 | /** | 223 | /** |
204 | * nfs_pageio_init - initialise a page io descriptor | 224 | * nfs_pageio_init - initialise a page io descriptor |
205 | * @desc: pointer to descriptor | 225 | * @desc: pointer to descriptor |
@@ -210,7 +230,7 @@ nfs_wait_on_request(struct nfs_page *req) | |||
210 | */ | 230 | */ |
211 | void nfs_pageio_init(struct nfs_pageio_descriptor *desc, | 231 | void nfs_pageio_init(struct nfs_pageio_descriptor *desc, |
212 | struct inode *inode, | 232 | struct inode *inode, |
213 | int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int), | 233 | int (*doio)(struct nfs_pageio_descriptor *), |
214 | size_t bsize, | 234 | size_t bsize, |
215 | int io_flags) | 235 | int io_flags) |
216 | { | 236 | { |
@@ -219,10 +239,14 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc, | |||
219 | desc->pg_count = 0; | 239 | desc->pg_count = 0; |
220 | desc->pg_bsize = bsize; | 240 | desc->pg_bsize = bsize; |
221 | desc->pg_base = 0; | 241 | desc->pg_base = 0; |
242 | desc->pg_moreio = 0; | ||
222 | desc->pg_inode = inode; | 243 | desc->pg_inode = inode; |
223 | desc->pg_doio = doio; | 244 | desc->pg_doio = doio; |
224 | desc->pg_ioflags = io_flags; | 245 | desc->pg_ioflags = io_flags; |
225 | desc->pg_error = 0; | 246 | desc->pg_error = 0; |
247 | desc->pg_lseg = NULL; | ||
248 | desc->pg_test = nfs_generic_pg_test; | ||
249 | pnfs_pageio_init(desc, inode); | ||
226 | } | 250 | } |
227 | 251 | ||
228 | /** | 252 | /** |
@@ -236,22 +260,23 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc, | |||
236 | * | 260 | * |
237 | * Return 'true' if this is the case, else return 'false'. | 261 | * Return 'true' if this is the case, else return 'false'. |
238 | */ | 262 | */ |
239 | static int nfs_can_coalesce_requests(struct nfs_page *prev, | 263 | static bool nfs_can_coalesce_requests(struct nfs_page *prev, |
240 | struct nfs_page *req) | 264 | struct nfs_page *req, |
265 | struct nfs_pageio_descriptor *pgio) | ||
241 | { | 266 | { |
242 | if (req->wb_context->cred != prev->wb_context->cred) | 267 | if (req->wb_context->cred != prev->wb_context->cred) |
243 | return 0; | 268 | return false; |
244 | if (req->wb_lock_context->lockowner != prev->wb_lock_context->lockowner) | 269 | if (req->wb_lock_context->lockowner != prev->wb_lock_context->lockowner) |
245 | return 0; | 270 | return false; |
246 | if (req->wb_context->state != prev->wb_context->state) | 271 | if (req->wb_context->state != prev->wb_context->state) |
247 | return 0; | 272 | return false; |
248 | if (req->wb_index != (prev->wb_index + 1)) | 273 | if (req->wb_index != (prev->wb_index + 1)) |
249 | return 0; | 274 | return false; |
250 | if (req->wb_pgbase != 0) | 275 | if (req->wb_pgbase != 0) |
251 | return 0; | 276 | return false; |
252 | if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE) | 277 | if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE) |
253 | return 0; | 278 | return false; |
254 | return 1; | 279 | return pgio->pg_test(pgio, prev, req); |
255 | } | 280 | } |
256 | 281 | ||
257 | /** | 282 | /** |
@@ -265,31 +290,18 @@ static int nfs_can_coalesce_requests(struct nfs_page *prev, | |||
265 | static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc, | 290 | static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc, |
266 | struct nfs_page *req) | 291 | struct nfs_page *req) |
267 | { | 292 | { |
268 | size_t newlen = req->wb_bytes; | ||
269 | |||
270 | if (desc->pg_count != 0) { | 293 | if (desc->pg_count != 0) { |
271 | struct nfs_page *prev; | 294 | struct nfs_page *prev; |
272 | 295 | ||
273 | /* | ||
274 | * FIXME: ideally we should be able to coalesce all requests | ||
275 | * that are not block boundary aligned, but currently this | ||
276 | * is problematic for the case of bsize < PAGE_CACHE_SIZE, | ||
277 | * since nfs_flush_multi and nfs_pagein_multi assume you | ||
278 | * can have only one struct nfs_page. | ||
279 | */ | ||
280 | if (desc->pg_bsize < PAGE_SIZE) | ||
281 | return 0; | ||
282 | newlen += desc->pg_count; | ||
283 | if (newlen > desc->pg_bsize) | ||
284 | return 0; | ||
285 | prev = nfs_list_entry(desc->pg_list.prev); | 296 | prev = nfs_list_entry(desc->pg_list.prev); |
286 | if (!nfs_can_coalesce_requests(prev, req)) | 297 | if (!nfs_can_coalesce_requests(prev, req, desc)) |
287 | return 0; | 298 | return 0; |
288 | } else | 299 | } else { |
289 | desc->pg_base = req->wb_pgbase; | 300 | desc->pg_base = req->wb_pgbase; |
301 | } | ||
290 | nfs_list_remove_request(req); | 302 | nfs_list_remove_request(req); |
291 | nfs_list_add_request(req, &desc->pg_list); | 303 | nfs_list_add_request(req, &desc->pg_list); |
292 | desc->pg_count = newlen; | 304 | desc->pg_count += req->wb_bytes; |
293 | return 1; | 305 | return 1; |
294 | } | 306 | } |
295 | 307 | ||
@@ -299,12 +311,7 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc, | |||
299 | static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc) | 311 | static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc) |
300 | { | 312 | { |
301 | if (!list_empty(&desc->pg_list)) { | 313 | if (!list_empty(&desc->pg_list)) { |
302 | int error = desc->pg_doio(desc->pg_inode, | 314 | int error = desc->pg_doio(desc); |
303 | &desc->pg_list, | ||
304 | nfs_page_array_len(desc->pg_base, | ||
305 | desc->pg_count), | ||
306 | desc->pg_count, | ||
307 | desc->pg_ioflags); | ||
308 | if (error < 0) | 315 | if (error < 0) |
309 | desc->pg_error = error; | 316 | desc->pg_error = error; |
310 | else | 317 | else |
@@ -328,9 +335,11 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
328 | struct nfs_page *req) | 335 | struct nfs_page *req) |
329 | { | 336 | { |
330 | while (!nfs_pageio_do_add_request(desc, req)) { | 337 | while (!nfs_pageio_do_add_request(desc, req)) { |
338 | desc->pg_moreio = 1; | ||
331 | nfs_pageio_doio(desc); | 339 | nfs_pageio_doio(desc); |
332 | if (desc->pg_error < 0) | 340 | if (desc->pg_error < 0) |
333 | return 0; | 341 | return 0; |
342 | desc->pg_moreio = 0; | ||
334 | } | 343 | } |
335 | return 1; | 344 | return 1; |
336 | } | 345 | } |
@@ -388,6 +397,7 @@ int nfs_scan_list(struct nfs_inode *nfsi, | |||
388 | pgoff_t idx_end; | 397 | pgoff_t idx_end; |
389 | int found, i; | 398 | int found, i; |
390 | int res; | 399 | int res; |
400 | struct list_head *list; | ||
391 | 401 | ||
392 | res = 0; | 402 | res = 0; |
393 | if (npages == 0) | 403 | if (npages == 0) |
@@ -408,10 +418,10 @@ int nfs_scan_list(struct nfs_inode *nfsi, | |||
408 | idx_start = req->wb_index + 1; | 418 | idx_start = req->wb_index + 1; |
409 | if (nfs_set_page_tag_locked(req)) { | 419 | if (nfs_set_page_tag_locked(req)) { |
410 | kref_get(&req->wb_kref); | 420 | kref_get(&req->wb_kref); |
411 | nfs_list_remove_request(req); | ||
412 | radix_tree_tag_clear(&nfsi->nfs_page_tree, | 421 | radix_tree_tag_clear(&nfsi->nfs_page_tree, |
413 | req->wb_index, tag); | 422 | req->wb_index, tag); |
414 | nfs_list_add_request(req, dst); | 423 | list = pnfs_choose_commit_list(req, dst); |
424 | nfs_list_add_request(req, list); | ||
415 | res++; | 425 | res++; |
416 | if (res == INT_MAX) | 426 | if (res == INT_MAX) |
417 | goto out; | 427 | goto out; |