aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2006-05-05 16:59:11 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2006-05-05 16:59:11 -0400
commitfd88de569b802c4a04aaa6ee74667775f4aed8c6 (patch)
tree1766c45303798bf289059afc8f117cf8bc784086
parent5bb76af1e089ac186c15c6aa792340d22b63d4b4 (diff)
[GFS2] Readpages support
This adds readpages support (and also corrects a small bug in the readpage error path at the same time). Hopefully this will improve performance by allowing GFS to submit larger lumps of I/O at a time. In order to simplify the setting of BH_Boundary, it currently gets set when we hit the end of a indirect pointer block. There is always a boundary at this point with the current allocation code. It doesn't get all the boundaries right though, so there is still room for improvement in this. See comments in fs/gfs2/ops_address.c for further information about readpages with GFS2. Signed-off-by: Steven Whitehouse
-rw-r--r--fs/gfs2/bmap.c170
-rw-r--r--fs/gfs2/bmap.h5
-rw-r--r--fs/gfs2/dir.c8
-rw-r--r--fs/gfs2/glock.c2
-rw-r--r--fs/gfs2/inode.c5
-rw-r--r--fs/gfs2/log.c4
-rw-r--r--fs/gfs2/ops_address.c145
-rw-r--r--fs/gfs2/ops_super.c3
-rw-r--r--fs/gfs2/ops_vm.c8
-rw-r--r--fs/gfs2/quota.c5
-rw-r--r--fs/gfs2/recovery.c8
-rw-r--r--fs/gfs2/rgrp.c15
-rw-r--r--fs/gfs2/unlinked.c5
13 files changed, 254 insertions, 129 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index cfe1a428c668..474b9a16f0f5 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -314,13 +314,17 @@ static void find_metapath(struct gfs2_inode *ip, uint64_t block,
314 * metadata tree. 314 * metadata tree.
315 */ 315 */
316 316
317static inline uint64_t *metapointer(struct buffer_head *bh, 317static inline u64 *metapointer(struct buffer_head *bh, int *boundary,
318 unsigned int height, struct metapath *mp) 318 unsigned int height, const struct metapath *mp)
319{ 319{
320 unsigned int head_size = (height > 0) ? 320 unsigned int head_size = (height > 0) ?
321 sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode); 321 sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode);
322 322 u64 *ptr;
323 return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height]; 323 *boundary = 0;
324 ptr = ((u64 *)(bh->b_data + head_size)) + mp->mp_list[height];
325 if (ptr + 1 == (u64*)(bh->b_data + bh->b_size))
326 *boundary = 1;
327 return ptr;
324} 328}
325 329
326/** 330/**
@@ -339,24 +343,24 @@ static inline uint64_t *metapointer(struct buffer_head *bh,
339 * 343 *
340 */ 344 */
341 345
342static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, 346static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
343 unsigned int height, struct metapath *mp, int create, 347 unsigned int height, struct metapath *mp, int create,
344 int *new, uint64_t *block) 348 int *new, uint64_t *block)
345{ 349{
346 uint64_t *ptr = metapointer(bh, height, mp); 350 int boundary;
351 uint64_t *ptr = metapointer(bh, &boundary, height, mp);
347 352
348 if (*ptr) { 353 if (*ptr) {
349 *block = be64_to_cpu(*ptr); 354 *block = be64_to_cpu(*ptr);
350 return; 355 return boundary;
351 } 356 }
352 357
353 *block = 0; 358 *block = 0;
354 359
355 if (!create) 360 if (!create)
356 return; 361 return 0;
357 362
358 if (height == ip->i_di.di_height - 1 && 363 if (height == ip->i_di.di_height - 1 && !gfs2_is_dir(ip))
359 !gfs2_is_dir(ip))
360 *block = gfs2_alloc_data(ip); 364 *block = gfs2_alloc_data(ip);
361 else 365 else
362 *block = gfs2_alloc_meta(ip); 366 *block = gfs2_alloc_meta(ip);
@@ -367,15 +371,16 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
367 ip->i_di.di_blocks++; 371 ip->i_di.di_blocks++;
368 372
369 *new = 1; 373 *new = 1;
374 return 0;
370} 375}
371 376
372/** 377/**
373 * gfs2_block_map - Map a block from an inode to a disk block 378 * gfs2_block_pointers - Map a block from an inode to a disk block
374 * @ip: The GFS2 inode 379 * @inode: The inode
375 * @lblock: The logical block number 380 * @lblock: The logical block number
376 * @new: Value/Result argument (1 = may create/did create new blocks) 381 * @new: Value/Result argument (1 = may create/did create new blocks)
377 * @dblock: the disk block number of the start of an extent 382 * @boundary: gets set if we've hit a block boundary
378 * @extlen: the size of the extent 383 * @mp: metapath to use
379 * 384 *
380 * Find the block number on the current device which corresponds to an 385 * Find the block number on the current device which corresponds to an
381 * inode's block. If the block had to be created, "new" will be set. 386 * inode's block. If the block had to be created, "new" will be set.
@@ -383,12 +388,14 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
383 * Returns: errno 388 * Returns: errno
384 */ 389 */
385 390
386int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, 391static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock,
387 uint64_t *dblock, uint32_t *extlen) 392 int *new, u64 *dblock,
393 int *boundary,
394 struct metapath *mp)
388{ 395{
396 struct gfs2_inode *ip = inode->u.generic_ip;
389 struct gfs2_sbd *sdp = ip->i_sbd; 397 struct gfs2_sbd *sdp = ip->i_sbd;
390 struct buffer_head *bh; 398 struct buffer_head *bh;
391 struct metapath mp;
392 int create = *new; 399 int create = *new;
393 unsigned int bsize; 400 unsigned int bsize;
394 unsigned int height; 401 unsigned int height;
@@ -398,13 +405,6 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
398 405
399 *new = 0; 406 *new = 0;
400 *dblock = 0; 407 *dblock = 0;
401 if (extlen)
402 *extlen = 0;
403
404 if (create)
405 down_write(&ip->i_rw_mutex);
406 else
407 down_read(&ip->i_rw_mutex);
408 408
409 if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) 409 if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip)))
410 goto out; 410 goto out;
@@ -421,7 +421,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
421 goto out; 421 goto out;
422 } 422 }
423 423
424 find_metapath(ip, lblock, &mp); 424 find_metapath(ip, lblock, mp);
425 end_of_metadata = ip->i_di.di_height - 1; 425 end_of_metadata = ip->i_di.di_height - 1;
426 426
427 error = gfs2_meta_inode_buffer(ip, &bh); 427 error = gfs2_meta_inode_buffer(ip, &bh);
@@ -429,7 +429,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
429 goto out; 429 goto out;
430 430
431 for (x = 0; x < end_of_metadata; x++) { 431 for (x = 0; x < end_of_metadata; x++) {
432 lookup_block(ip, bh, x, &mp, create, new, dblock); 432 lookup_block(ip, bh, x, mp, create, new, dblock);
433 brelse(bh); 433 brelse(bh);
434 if (!*dblock) 434 if (!*dblock)
435 goto out; 435 goto out;
@@ -439,49 +439,95 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
439 goto out; 439 goto out;
440 } 440 }
441 441
442 lookup_block(ip, bh, end_of_metadata, &mp, create, new, dblock); 442 *boundary = lookup_block(ip, bh, end_of_metadata, mp, create, new, dblock);
443
444 if (extlen && *dblock) {
445 *extlen = 1;
446
447 if (!*new) {
448 uint64_t tmp_dblock;
449 int tmp_new;
450 unsigned int nptrs;
451
452 nptrs = (end_of_metadata) ? sdp->sd_inptrs :
453 sdp->sd_diptrs;
454
455 while (++mp.mp_list[end_of_metadata] < nptrs) {
456 lookup_block(ip, bh, end_of_metadata, &mp,
457 0, &tmp_new, &tmp_dblock);
458
459 if (*dblock + *extlen != tmp_dblock)
460 break;
461
462 (*extlen)++;
463 }
464 }
465 }
466
467 brelse(bh);
468
469 if (*new) { 443 if (*new) {
470 error = gfs2_meta_inode_buffer(ip, &bh); 444 struct buffer_head *dibh;
445 error = gfs2_meta_inode_buffer(ip, &dibh);
471 if (!error) { 446 if (!error) {
472 gfs2_trans_add_bh(ip->i_gl, bh, 1); 447 gfs2_trans_add_bh(ip->i_gl, dibh, 1);
473 gfs2_dinode_out(&ip->i_di, bh->b_data); 448 gfs2_dinode_out(&ip->i_di, dibh->b_data);
474 brelse(bh); 449 brelse(dibh);
475 } 450 }
476 } 451 }
452 return bh;
453out:
454 return ERR_PTR(error);
455}
477 456
478 out: 457
458static inline void bmap_lock(struct inode *inode, int create)
459{
460 struct gfs2_inode *ip = inode->u.generic_ip;
461 if (create)
462 down_write(&ip->i_rw_mutex);
463 else
464 down_read(&ip->i_rw_mutex);
465}
466
467static inline void bmap_unlock(struct inode *inode, int create)
468{
469 struct gfs2_inode *ip = inode->u.generic_ip;
479 if (create) 470 if (create)
480 up_write(&ip->i_rw_mutex); 471 up_write(&ip->i_rw_mutex);
481 else 472 else
482 up_read(&ip->i_rw_mutex); 473 up_read(&ip->i_rw_mutex);
474}
483 475
484 return error; 476int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary)
477{
478 struct metapath mp;
479 struct buffer_head *bh;
480 int create = *new;
481
482 bmap_lock(inode, create);
483 bh = gfs2_block_pointers(inode, lblock, new, dblock, boundary, &mp);
484 bmap_unlock(inode, create);
485 if (!bh)
486 return 0;
487 if (IS_ERR(bh))
488 return PTR_ERR(bh);
489 brelse(bh);
490 return 0;
491}
492
493int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen)
494{
495 struct gfs2_inode *ip = inode->u.generic_ip;
496 struct gfs2_sbd *sdp = ip->i_sbd;
497 struct metapath mp;
498 struct buffer_head *bh;
499 int boundary;
500 int create = *new;
501
502 BUG_ON(!extlen);
503 BUG_ON(!dblock);
504 BUG_ON(!new);
505
506 bmap_lock(inode, create);
507 bh = gfs2_block_pointers(inode, lblock, new, dblock, &boundary, &mp);
508 *extlen = 1;
509
510 if (bh && !IS_ERR(bh) && *dblock && !*new) {
511 u64 tmp_dblock;
512 int tmp_new;
513 unsigned int nptrs;
514 unsigned end_of_metadata = ip->i_di.di_height - 1;
515
516 nptrs = (end_of_metadata) ? sdp->sd_inptrs : sdp->sd_diptrs;
517 while (++mp.mp_list[end_of_metadata] < nptrs) {
518 lookup_block(ip, bh, end_of_metadata, &mp, 0, &tmp_new, &tmp_dblock);
519 if (*dblock + *extlen != tmp_dblock)
520 break;
521 (*extlen)++;
522 }
523 }
524 bmap_unlock(inode, create);
525 if (!bh)
526 return 0;
527 if (IS_ERR(bh))
528 return PTR_ERR(bh);
529 brelse(bh);
530 return 0;
485} 531}
486 532
487/** 533/**
@@ -1053,7 +1099,7 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset,
1053 } 1099 }
1054 1100
1055 for (; lblock < lblock_stop; lblock += extlen) { 1101 for (; lblock < lblock_stop; lblock += extlen) {
1056 error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); 1102 error = gfs2_extent_map(ip->i_vnode, lblock, &new, &dblock, &extlen);
1057 if (error) 1103 if (error)
1058 return error; 1104 return error;
1059 1105
diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h
index 23fb6589d5e3..bc46c1149120 100644
--- a/fs/gfs2/bmap.h
+++ b/fs/gfs2/bmap.h
@@ -16,9 +16,8 @@ typedef int (*gfs2_unstuffer_t) (struct gfs2_inode * ip,
16int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, 16int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer,
17 void *private); 17 void *private);
18 18
19int gfs2_block_map(struct gfs2_inode *ip, 19int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary);
20 uint64_t lblock, int *new, 20int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen);
21 uint64_t *dblock, uint32_t *extlen);
22 21
23int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size); 22int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size);
24int gfs2_truncatei_resume(struct gfs2_inode *ip); 23int gfs2_truncatei_resume(struct gfs2_inode *ip);
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 0404783f39b3..7f8b27e40916 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -197,8 +197,8 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf,
197 197
198 if (!extlen) { 198 if (!extlen) {
199 new = 1; 199 new = 1;
200 error = gfs2_block_map(ip, lblock, &new, &dblock, 200 error = gfs2_extent_map(ip->i_vnode, lblock, &new,
201 &extlen); 201 &dblock, &extlen);
202 if (error) 202 if (error)
203 goto fail; 203 goto fail;
204 error = -EIO; 204 error = -EIO;
@@ -314,8 +314,8 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf,
314 314
315 if (!extlen) { 315 if (!extlen) {
316 new = 0; 316 new = 0;
317 error = gfs2_block_map(ip, lblock, &new, &dblock, 317 error = gfs2_extent_map(ip->i_vnode, lblock, &new,
318 &extlen); 318 &dblock, &extlen);
319 if (error) 319 if (error)
320 goto fail; 320 goto fail;
321 } 321 }
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 4fb8066dc745..9d4ae094fa2d 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -2125,7 +2125,7 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait)
2125 mutex_lock(&sdp->sd_invalidate_inodes_mutex); 2125 mutex_lock(&sdp->sd_invalidate_inodes_mutex);
2126 invalidate_inodes(sdp->sd_vfs); 2126 invalidate_inodes(sdp->sd_vfs);
2127 mutex_unlock(&sdp->sd_invalidate_inodes_mutex); 2127 mutex_unlock(&sdp->sd_invalidate_inodes_mutex);
2128 yield(); 2128 msleep(10);
2129 } 2129 }
2130} 2130}
2131 2131
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 9084d6037a0c..0817f6ede188 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -1606,9 +1606,8 @@ int gfs2_glock_nq_atime(struct gfs2_holder *gh)
1606 curtime = get_seconds(); 1606 curtime = get_seconds();
1607 if (curtime - ip->i_di.di_atime >= quantum) { 1607 if (curtime - ip->i_di.di_atime >= quantum) {
1608 gfs2_glock_dq(gh); 1608 gfs2_glock_dq(gh);
1609 gfs2_holder_reinit(LM_ST_EXCLUSIVE, 1609 gfs2_holder_reinit(LM_ST_EXCLUSIVE, gh->gh_flags & ~LM_FLAG_ANY,
1610 gh->gh_flags & ~LM_FLAG_ANY, 1610 gh);
1611 gh);
1612 error = gfs2_glock_nq(gh); 1611 error = gfs2_glock_nq(gh);
1613 if (error) 1612 if (error)
1614 return error; 1613 return error;
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 134fc57e21d3..02d31e35f0ca 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -211,9 +211,9 @@ static uint64_t log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
211 int new = 0; 211 int new = 0;
212 uint64_t dbn; 212 uint64_t dbn;
213 int error; 213 int error;
214 int bdy;
214 215
215 error = gfs2_block_map(sdp->sd_jdesc->jd_inode->u.generic_ip, 216 error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, &new, &dbn, &bdy);
216 lbn, &new, &dbn, NULL);
217 gfs2_assert_withdraw(sdp, !error && dbn); 217 gfs2_assert_withdraw(sdp, !error && dbn);
218 218
219 return dbn; 219 return dbn;
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index afcc12a00a3c..d89179b316fe 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -13,6 +13,7 @@
13#include <linux/completion.h> 13#include <linux/completion.h>
14#include <linux/buffer_head.h> 14#include <linux/buffer_head.h>
15#include <linux/pagemap.h> 15#include <linux/pagemap.h>
16#include <linux/pagevec.h>
16#include <linux/mpage.h> 17#include <linux/mpage.h>
17#include <linux/fs.h> 18#include <linux/fs.h>
18#include <linux/gfs2_ondisk.h> 19#include <linux/gfs2_ondisk.h>
@@ -47,12 +48,12 @@
47int gfs2_get_block(struct inode *inode, sector_t lblock, 48int gfs2_get_block(struct inode *inode, sector_t lblock,
48 struct buffer_head *bh_result, int create) 49 struct buffer_head *bh_result, int create)
49{ 50{
50 struct gfs2_inode *ip = inode->u.generic_ip;
51 int new = create; 51 int new = create;
52 uint64_t dblock; 52 uint64_t dblock;
53 int error; 53 int error;
54 int boundary;
54 55
55 error = gfs2_block_map(ip, lblock, &new, &dblock, NULL); 56 error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary);
56 if (error) 57 if (error)
57 return error; 58 return error;
58 59
@@ -62,6 +63,8 @@ int gfs2_get_block(struct inode *inode, sector_t lblock,
62 map_bh(bh_result, inode->i_sb, dblock); 63 map_bh(bh_result, inode->i_sb, dblock);
63 if (new) 64 if (new)
64 set_buffer_new(bh_result); 65 set_buffer_new(bh_result);
66 if (boundary)
67 set_buffer_boundary(bh_result);
65 68
66 return 0; 69 return 0;
67} 70}
@@ -83,8 +86,9 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock,
83 int new = 0; 86 int new = 0;
84 uint64_t dblock; 87 uint64_t dblock;
85 int error; 88 int error;
89 int boundary;
86 90
87 error = gfs2_block_map(ip, lblock, &new, &dblock, NULL); 91 error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary);
88 if (error) 92 if (error)
89 return error; 93 return error;
90 94
@@ -92,6 +96,8 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock,
92 map_bh(bh_result, inode->i_sb, dblock); 96 map_bh(bh_result, inode->i_sb, dblock);
93 else if (gfs2_assert_withdraw(ip->i_sbd, !create)) 97 else if (gfs2_assert_withdraw(ip->i_sbd, !create))
94 error = -EIO; 98 error = -EIO;
99 if (boundary)
100 set_buffer_boundary(bh_result);
95 101
96 return error; 102 return error;
97} 103}
@@ -151,6 +157,19 @@ out_ignore:
151 return 0; 157 return 0;
152} 158}
153 159
160static int zero_readpage(struct page *page)
161{
162 void *kaddr;
163
164 kaddr = kmap_atomic(page, KM_USER0);
165 memset(kaddr, 0, PAGE_CACHE_SIZE);
166 kunmap_atomic(page, KM_USER0);
167
168 SetPageUptodate(page);
169
170 return 0;
171}
172
154/** 173/**
155 * stuffed_readpage - Fill in a Linux page with stuffed file data 174 * stuffed_readpage - Fill in a Linux page with stuffed file data
156 * @ip: the inode 175 * @ip: the inode
@@ -165,17 +184,18 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
165 void *kaddr; 184 void *kaddr;
166 int error; 185 int error;
167 186
187 /* Only the first page of a stuffed file might contain data */
188 if (unlikely(page->index))
189 return zero_readpage(page);
190
168 error = gfs2_meta_inode_buffer(ip, &dibh); 191 error = gfs2_meta_inode_buffer(ip, &dibh);
169 if (error) 192 if (error)
170 return error; 193 return error;
171 194
172 kaddr = kmap_atomic(page, KM_USER0); 195 kaddr = kmap_atomic(page, KM_USER0);
173 memcpy((char *)kaddr, 196 memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode),
174 dibh->b_data + sizeof(struct gfs2_dinode),
175 ip->i_di.di_size); 197 ip->i_di.di_size);
176 memset((char *)kaddr + ip->i_di.di_size, 198 memset(kaddr + ip->i_di.di_size, 0, PAGE_CACHE_SIZE - ip->i_di.di_size);
177 0,
178 PAGE_CACHE_SIZE - ip->i_di.di_size);
179 kunmap_atomic(page, KM_USER0); 199 kunmap_atomic(page, KM_USER0);
180 200
181 brelse(dibh); 201 brelse(dibh);
@@ -185,19 +205,6 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
185 return 0; 205 return 0;
186} 206}
187 207
188static int zero_readpage(struct page *page)
189{
190 void *kaddr;
191
192 kaddr = kmap_atomic(page, KM_USER0);
193 memset(kaddr, 0, PAGE_CACHE_SIZE);
194 kunmap_atomic(page, KM_USER0);
195
196 SetPageUptodate(page);
197 unlock_page(page);
198
199 return 0;
200}
201 208
202/** 209/**
203 * gfs2_readpage - readpage with locking 210 * gfs2_readpage - readpage with locking
@@ -215,19 +222,16 @@ static int gfs2_readpage(struct file *file, struct page *page)
215 struct gfs2_holder gh; 222 struct gfs2_holder gh;
216 int error; 223 int error;
217 224
218 if (file != &gfs2_internal_file_sentinal) { 225 if (likely(file != &gfs2_internal_file_sentinal)) {
219 gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh); 226 gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh);
220 error = gfs2_glock_nq_m_atime(1, &gh); 227 error = gfs2_glock_nq_m_atime(1, &gh);
221 if (error) 228 if (unlikely(error))
222 goto out_unlock; 229 goto out_unlock;
223 } 230 }
224 231
225 if (gfs2_is_stuffed(ip)) { 232 if (gfs2_is_stuffed(ip)) {
226 if (!page->index) { 233 error = stuffed_readpage(ip, page);
227 error = stuffed_readpage(ip, page); 234 unlock_page(page);
228 unlock_page(page);
229 } else
230 error = zero_readpage(page);
231 } else 235 } else
232 error = mpage_readpage(page, gfs2_get_block); 236 error = mpage_readpage(page, gfs2_get_block);
233 237
@@ -242,6 +246,90 @@ out:
242 return error; 246 return error;
243out_unlock: 247out_unlock:
244 unlock_page(page); 248 unlock_page(page);
249 if (file != &gfs2_internal_file_sentinal)
250 gfs2_holder_uninit(&gh);
251 goto out;
252}
253
254#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
255
256/**
257 * gfs2_readpages - Read a bunch of pages at once
258 *
259 * Some notes:
260 * 1. This is only for readahead, so we can simply ignore any things
261 * which are slightly inconvenient (such as locking conflicts between
262 * the page lock and the glock) and return having done no I/O. Its
263 * obviously not something we'd want to do on too regular a basis.
264 * Any I/O we ignore at this time will be done via readpage later.
265 * 2. We have to handle stuffed files here too.
266 * 3. mpage_readpages() does most of the heavy lifting in the common case.
267 * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places.
268 * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as
269 * well as read-ahead.
270 */
271static int gfs2_readpages(struct file *file, struct address_space *mapping,
272 struct list_head *pages, unsigned nr_pages)
273{
274 struct inode *inode = mapping->host;
275 struct gfs2_inode *ip = inode->u.generic_ip;
276 struct gfs2_sbd *sdp = ip->i_sbd;
277 struct gfs2_holder gh;
278 unsigned page_idx;
279 int ret;
280
281 if (likely(file != &gfs2_internal_file_sentinal)) {
282 gfs2_holder_init(ip->i_gl, LM_ST_SHARED,
283 LM_FLAG_TRY_1CB|GL_ATIME|GL_AOP, &gh);
284 ret = gfs2_glock_nq_m_atime(1, &gh);
285 if (ret == GLR_TRYFAILED)
286 goto out_noerror;
287 if (unlikely(ret))
288 goto out_unlock;
289 }
290
291 if (gfs2_is_stuffed(ip)) {
292 struct pagevec lru_pvec;
293 pagevec_init(&lru_pvec, 0);
294 for (page_idx = 0; page_idx < nr_pages; page_idx++) {
295 struct page *page = list_to_page(pages);
296 list_del(&page->lru);
297 if (!add_to_page_cache(page, mapping,
298 page->index, GFP_KERNEL)) {
299 ret = stuffed_readpage(ip, page);
300 unlock_page(page);
301 if (!pagevec_add(&lru_pvec, page))
302 __pagevec_lru_add(&lru_pvec);
303 }
304 page_cache_release(page);
305 }
306 pagevec_lru_add(&lru_pvec);
307 ret = 0;
308 } else {
309 /* What we really want to do .... */
310 ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block);
311 }
312
313 if (likely(file != &gfs2_internal_file_sentinal)) {
314 gfs2_glock_dq_m(1, &gh);
315 gfs2_holder_uninit(&gh);
316 }
317out:
318 if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
319 ret = -EIO;
320 return ret;
321out_noerror:
322 ret = 0;
323out_unlock:
324 /* unlock all pages, we can't do any I/O right now */
325 for (page_idx = 0; page_idx < nr_pages; page_idx++) {
326 struct page *page = list_to_page(pages);
327 list_del(&page->lru);
328 unlock_page(page);
329 page_cache_release(page);
330 }
331 if (likely(file != &gfs2_internal_file_sentinal))
332 gfs2_holder_uninit(&gh);
245 goto out; 333 goto out;
246} 334}
247 335
@@ -572,6 +660,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
572struct address_space_operations gfs2_file_aops = { 660struct address_space_operations gfs2_file_aops = {
573 .writepage = gfs2_writepage, 661 .writepage = gfs2_writepage,
574 .readpage = gfs2_readpage, 662 .readpage = gfs2_readpage,
663 .readpages = gfs2_readpages,
575 .sync_page = block_sync_page, 664 .sync_page = block_sync_page,
576 .prepare_write = gfs2_prepare_write, 665 .prepare_write = gfs2_prepare_write,
577 .commit_write = gfs2_commit_write, 666 .commit_write = gfs2_commit_write,
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
index 60bf2563c7b4..5910c7b5c846 100644
--- a/fs/gfs2/ops_super.c
+++ b/fs/gfs2/ops_super.c
@@ -92,7 +92,6 @@ static void gfs2_put_super(struct super_block *sb)
92 if (error) 92 if (error)
93 gfs2_io_error(sdp); 93 gfs2_io_error(sdp);
94 } 94 }
95
96 /* At this point, we're through modifying the disk */ 95 /* At this point, we're through modifying the disk */
97 96
98 /* Release stuff */ 97 /* Release stuff */
@@ -125,12 +124,10 @@ static void gfs2_put_super(struct super_block *sb)
125 gfs2_jindex_free(sdp); 124 gfs2_jindex_free(sdp);
126 /* Take apart glock structures and buffer lists */ 125 /* Take apart glock structures and buffer lists */
127 gfs2_gl_hash_clear(sdp, WAIT); 126 gfs2_gl_hash_clear(sdp, WAIT);
128
129 /* Unmount the locking protocol */ 127 /* Unmount the locking protocol */
130 gfs2_lm_unmount(sdp); 128 gfs2_lm_unmount(sdp);
131 129
132 /* At this point, we're through participating in the lockspace */ 130 /* At this point, we're through participating in the lockspace */
133
134 gfs2_sys_fs_del(sdp); 131 gfs2_sys_fs_del(sdp);
135 vfree(sdp); 132 vfree(sdp);
136 sb->s_fs_info = NULL; 133 sb->s_fs_info = NULL;
diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c
index dbc57071e7bb..d67248cae9b9 100644
--- a/fs/gfs2/ops_vm.c
+++ b/fs/gfs2/ops_vm.c
@@ -90,8 +90,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
90 if (error) 90 if (error)
91 goto out_gunlock_q; 91 goto out_gunlock_q;
92 92
93 gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, 93 gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
94 &data_blocks, &ind_blocks);
95 94
96 al->al_requested = data_blocks + ind_blocks; 95 al->al_requested = data_blocks + ind_blocks;
97 96
@@ -99,8 +98,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
99 if (error) 98 if (error)
100 goto out_gunlock_q; 99 goto out_gunlock_q;
101 100
102 error = gfs2_trans_begin(sdp, 101 error = gfs2_trans_begin(sdp, al->al_rgd->rd_ri.ri_length +
103 al->al_rgd->rd_ri.ri_length +
104 ind_blocks + RES_DINODE + 102 ind_blocks + RES_DINODE +
105 RES_STATFS + RES_QUOTA, 0); 103 RES_STATFS + RES_QUOTA, 0);
106 if (error) 104 if (error)
@@ -117,7 +115,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
117 unsigned int extlen; 115 unsigned int extlen;
118 int new = 1; 116 int new = 1;
119 117
120 error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); 118 error = gfs2_extent_map(ip->i_vnode, lblock, &new, &dblock, &extlen);
121 if (error) 119 if (error)
122 goto out_trans; 120 goto out_trans;
123 121
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 942c4c8b9f56..d49ff43b3a86 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -255,6 +255,7 @@ static int bh_get(struct gfs2_quota_data *qd)
255 int new = 0; 255 int new = 0;
256 struct buffer_head *bh; 256 struct buffer_head *bh;
257 int error; 257 int error;
258 int boundary;
258 259
259 mutex_lock(&sdp->sd_quota_mutex); 260 mutex_lock(&sdp->sd_quota_mutex);
260 261
@@ -266,7 +267,7 @@ static int bh_get(struct gfs2_quota_data *qd)
266 block = qd->qd_slot / sdp->sd_qc_per_block; 267 block = qd->qd_slot / sdp->sd_qc_per_block;
267 offset = qd->qd_slot % sdp->sd_qc_per_block;; 268 offset = qd->qd_slot % sdp->sd_qc_per_block;;
268 269
269 error = gfs2_block_map(ip, block, &new, &dblock, NULL); 270 error = gfs2_block_map(ip->i_vnode, block, &new, &dblock, &boundary);
270 if (error) 271 if (error)
271 goto fail; 272 goto fail;
272 error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh); 273 error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh);
@@ -1162,7 +1163,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
1162 1163
1163 if (!extlen) { 1164 if (!extlen) {
1164 int new = 0; 1165 int new = 0;
1165 error = gfs2_block_map(ip, x, &new, &dblock, &extlen); 1166 error = gfs2_extent_map(ip->i_vnode, x, &new, &dblock, &extlen);
1166 if (error) 1167 if (error)
1167 goto fail; 1168 goto fail;
1168 } 1169 }
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
index d916817fb6e3..87adebea3bc3 100644
--- a/fs/gfs2/recovery.c
+++ b/fs/gfs2/recovery.c
@@ -40,8 +40,7 @@ int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
40 uint32_t extlen; 40 uint32_t extlen;
41 int error; 41 int error;
42 42
43 error = gfs2_block_map(ip, blk, &new, &dblock, 43 error = gfs2_extent_map(ip->i_vnode, blk, &new, &dblock, &extlen);
44 &extlen);
45 if (error) 44 if (error)
46 return error; 45 return error;
47 if (!dblock) { 46 if (!dblock) {
@@ -378,10 +377,11 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head)
378 uint32_t hash; 377 uint32_t hash;
379 struct buffer_head *bh; 378 struct buffer_head *bh;
380 int error; 379 int error;
381 380 int boundary;
381
382 lblock = head->lh_blkno; 382 lblock = head->lh_blkno;
383 gfs2_replay_incr_blk(sdp, &lblock); 383 gfs2_replay_incr_blk(sdp, &lblock);
384 error = gfs2_block_map(ip, lblock, &new, &dblock, NULL); 384 error = gfs2_block_map(ip->i_vnode, lblock, &new, &dblock, &boundary);
385 if (error) 385 if (error)
386 return error; 386 return error;
387 if (!dblock) { 387 if (!dblock) {
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 4ae559694396..15c326ce13d1 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -956,8 +956,7 @@ static uint32_t rgblk_search(struct gfs2_rgrpd *rgd, uint32_t goal,
956 search in the first part of our first-searched bit block. */ 956 search in the first part of our first-searched bit block. */
957 for (x = 0; x <= length; x++) { 957 for (x = 0; x <= length; x++) {
958 if (bi->bi_clone) 958 if (bi->bi_clone)
959 blk = gfs2_bitfit(rgd, 959 blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset,
960 bi->bi_clone + bi->bi_offset,
961 bi->bi_len, goal, old_state); 960 bi->bi_len, goal, old_state);
962 else 961 else
963 blk = gfs2_bitfit(rgd, 962 blk = gfs2_bitfit(rgd,
@@ -976,12 +975,10 @@ static uint32_t rgblk_search(struct gfs2_rgrpd *rgd, uint32_t goal,
976 blk = 0; 975 blk = 0;
977 976
978 gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); 977 gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
979 gfs2_setbit(rgd, 978 gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
980 bi->bi_bh->b_data + bi->bi_offset,
981 bi->bi_len, blk, new_state); 979 bi->bi_len, blk, new_state);
982 if (bi->bi_clone) 980 if (bi->bi_clone)
983 gfs2_setbit(rgd, 981 gfs2_setbit(rgd, bi->bi_clone + bi->bi_offset,
984 bi->bi_clone + bi->bi_offset,
985 bi->bi_len, blk, new_state); 982 bi->bi_len, blk, new_state);
986 983
987 return bi->bi_start * GFS2_NBBY + blk; 984 return bi->bi_start * GFS2_NBBY + blk;
@@ -1064,8 +1061,7 @@ uint64_t gfs2_alloc_data(struct gfs2_inode *ip)
1064 else 1061 else
1065 goal = rgd->rd_last_alloc_data; 1062 goal = rgd->rd_last_alloc_data;
1066 1063
1067 blk = rgblk_search(rgd, goal, 1064 blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED);
1068 GFS2_BLKST_FREE, GFS2_BLKST_USED);
1069 rgd->rd_last_alloc_data = blk; 1065 rgd->rd_last_alloc_data = blk;
1070 1066
1071 block = rgd->rd_ri.ri_data0 + blk; 1067 block = rgd->rd_ri.ri_data0 + blk;
@@ -1109,8 +1105,7 @@ uint64_t gfs2_alloc_meta(struct gfs2_inode *ip)
1109 else 1105 else
1110 goal = rgd->rd_last_alloc_meta; 1106 goal = rgd->rd_last_alloc_meta;
1111 1107
1112 blk = rgblk_search(rgd, goal, 1108 blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED);
1113 GFS2_BLKST_FREE, GFS2_BLKST_USED);
1114 rgd->rd_last_alloc_meta = blk; 1109 rgd->rd_last_alloc_meta = blk;
1115 1110
1116 block = rgd->rd_ri.ri_data0 + blk; 1111 block = rgd->rd_ri.ri_data0 + blk;
diff --git a/fs/gfs2/unlinked.c b/fs/gfs2/unlinked.c
index 24b91c23bc2d..0d2314a5252c 100644
--- a/fs/gfs2/unlinked.c
+++ b/fs/gfs2/unlinked.c
@@ -35,11 +35,12 @@ static int munge_ondisk(struct gfs2_sbd *sdp, unsigned int slot,
35 int new = 0; 35 int new = 0;
36 struct buffer_head *bh; 36 struct buffer_head *bh;
37 int error; 37 int error;
38 int boundary;
38 39
39 block = slot / sdp->sd_ut_per_block; 40 block = slot / sdp->sd_ut_per_block;
40 offset = slot % sdp->sd_ut_per_block; 41 offset = slot % sdp->sd_ut_per_block;
41 42
42 error = gfs2_block_map(ip, block, &new, &dblock, NULL); 43 error = gfs2_block_map(ip->i_vnode, block, &new, &dblock, &boundary);
43 if (error) 44 if (error)
44 return error; 45 return error;
45 error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh); 46 error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh);
@@ -354,7 +355,7 @@ int gfs2_unlinked_init(struct gfs2_sbd *sdp)
354 355
355 if (!extlen) { 356 if (!extlen) {
356 int new = 0; 357 int new = 0;
357 error = gfs2_block_map(ip, x, &new, &dblock, &extlen); 358 error = gfs2_extent_map(ip->i_vnode, x, &new, &dblock, &extlen);
358 if (error) 359 if (error)
359 goto fail; 360 goto fail;
360 } 361 }