aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2006-09-18 17:18:23 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2006-09-18 17:18:23 -0400
commit7a6bbacbb8dec6fbd1242c959250388f907d429e (patch)
tree8e314f0b3fd6e54154562c0a9b20173d539470a2
parent65952fb4e91c159d253bd28ceaf028a86dbb0b02 (diff)
[GFS2] Map multiple blocks at once where possible
This is a tidy up of the GFS2 bmap code. The main change is that the bh is passed to gfs2_block_map allowing the flags to be set directly rather than having to repeat that code several times in ops_address.c. At the same time, the extent mapping code from gfs2_extent_map has been moved into gfs2_block_map. This allows all calls to gfs2_block_map to map extents in the case that no allocation is taking place. As a result reads and non-allocating writes should be faster. A quick test with postmark appears to support this. There is a limit on the number of blocks mapped in a single bmap call in that it will only ever map blocks which are pointed to from a single pointer block. So in other words, it will never try to do additional i/o in order to satisfy read-ahead. The maximum number of blocks is thus somewhat less than 512 (the GFS2 4k block size minus the header divided by sizeof(u64)). I've further limited the mapping of "normal" blocks to 32 blocks (to avoid extra work) since readpages() will currently read a maximum of 32 blocks ahead (128k). Some further work will probably be needed to set a suitable value for DIO as well, but for now thats left at the maximum 512 (see ops_address.c:gfs2_get_block_direct). There is probably a lot more that can be done to improve bmap for GFS2, but this is a good first step. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r--fs/gfs2/bmap.c131
-rw-r--r--fs/gfs2/bmap.h2
-rw-r--r--fs/gfs2/log.c14
-rw-r--r--fs/gfs2/ops_address.c68
-rw-r--r--fs/gfs2/quota.c8
-rw-r--r--fs/gfs2/recovery.c10
6 files changed, 92 insertions, 141 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 57caad7bc0d5..cc91e482eda0 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -423,8 +423,7 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
423 * gfs2_block_pointers - Map a block from an inode to a disk block 423 * gfs2_block_pointers - Map a block from an inode to a disk block
424 * @inode: The inode 424 * @inode: The inode
425 * @lblock: The logical block number 425 * @lblock: The logical block number
426 * @new: Value/Result argument (1 = may create/did create new blocks) 426 * @map_bh: The bh to be mapped
427 * @boundary: gets set if we've hit a block boundary
428 * @mp: metapath to use 427 * @mp: metapath to use
429 * 428 *
430 * Find the block number on the current device which corresponds to an 429 * Find the block number on the current device which corresponds to an
@@ -433,37 +432,35 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
433 * Returns: errno 432 * Returns: errno
434 */ 433 */
435 434
436static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock, 435static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create,
437 int *new, u64 *dblock, 436 struct buffer_head *bh_map, struct metapath *mp,
438 int *boundary, 437 unsigned int maxlen)
439 struct metapath *mp)
440{ 438{
441 struct gfs2_inode *ip = GFS2_I(inode); 439 struct gfs2_inode *ip = GFS2_I(inode);
442 struct gfs2_sbd *sdp = GFS2_SB(inode); 440 struct gfs2_sbd *sdp = GFS2_SB(inode);
443 struct buffer_head *bh; 441 struct buffer_head *bh;
444 int create = *new;
445 unsigned int bsize; 442 unsigned int bsize;
446 unsigned int height; 443 unsigned int height;
447 unsigned int end_of_metadata; 444 unsigned int end_of_metadata;
448 unsigned int x; 445 unsigned int x;
449 int error = 0; 446 int error = 0;
450 447 int new = 0;
451 *new = 0; 448 u64 dblock = 0;
452 *dblock = 0; 449 int boundary;
453 450
454 if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) 451 if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip)))
455 goto out; 452 return 0;
456 453
457 bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize; 454 bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize;
458 455
459 height = calc_tree_height(ip, (lblock + 1) * bsize); 456 height = calc_tree_height(ip, (lblock + 1) * bsize);
460 if (ip->i_di.di_height < height) { 457 if (ip->i_di.di_height < height) {
461 if (!create) 458 if (!create)
462 goto out; 459 return 0;
463 460
464 error = build_height(inode, height); 461 error = build_height(inode, height);
465 if (error) 462 if (error)
466 goto out; 463 return error;
467 } 464 }
468 465
469 find_metapath(ip, lblock, mp); 466 find_metapath(ip, lblock, mp);
@@ -471,32 +468,54 @@ static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock,
471 468
472 error = gfs2_meta_inode_buffer(ip, &bh); 469 error = gfs2_meta_inode_buffer(ip, &bh);
473 if (error) 470 if (error)
474 goto out; 471 return error;
475 472
476 for (x = 0; x < end_of_metadata; x++) { 473 for (x = 0; x < end_of_metadata; x++) {
477 lookup_block(ip, bh, x, mp, create, new, dblock); 474 lookup_block(ip, bh, x, mp, create, &new, &dblock);
478 brelse(bh); 475 brelse(bh);
479 if (!*dblock) 476 if (!dblock)
480 goto out; 477 return 0;
481 478
482 error = gfs2_meta_indirect_buffer(ip, x+1, *dblock, *new, &bh); 479 error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh);
483 if (error) 480 if (error)
484 goto out; 481 return error;
485 } 482 }
486 483
487 *boundary = lookup_block(ip, bh, end_of_metadata, mp, create, new, dblock); 484 boundary = lookup_block(ip, bh, end_of_metadata, mp, create, &new, &dblock);
488 if (*new) { 485 clear_buffer_mapped(bh_map);
489 struct buffer_head *dibh; 486 clear_buffer_new(bh_map);
490 error = gfs2_meta_inode_buffer(ip, &dibh); 487 clear_buffer_boundary(bh_map);
491 if (!error) { 488
492 gfs2_trans_add_bh(ip->i_gl, dibh, 1); 489 if (dblock) {
493 gfs2_dinode_out(&ip->i_di, dibh->b_data); 490 map_bh(bh_map, inode->i_sb, dblock);
494 brelse(dibh); 491 if (boundary)
492 set_buffer_boundary(bh);
493 if (new) {
494 struct buffer_head *dibh;
495 error = gfs2_meta_inode_buffer(ip, &dibh);
496 if (!error) {
497 gfs2_trans_add_bh(ip->i_gl, dibh, 1);
498 gfs2_dinode_out(&ip->i_di, dibh->b_data);
499 brelse(dibh);
500 }
501 set_buffer_new(bh_map);
502 goto out_brelse;
503 }
504 while(--maxlen && !buffer_boundary(bh_map)) {
505 u64 eblock;
506
507 mp->mp_list[end_of_metadata]++;
508 boundary = lookup_block(ip, bh, end_of_metadata, mp, 0, &new, &eblock);
509 if (eblock != ++dblock)
510 break;
511 bh_map->b_size += inode->i_blksize;
512 if (boundary)
513 set_buffer_boundary(bh_map);
495 } 514 }
496 } 515 }
497 return bh; 516out_brelse:
498out: 517 brelse(bh);
499 return ERR_PTR(error); 518 return 0;
500} 519}
501 520
502 521
@@ -518,30 +537,23 @@ static inline void bmap_unlock(struct inode *inode, int create)
518 up_read(&ip->i_rw_mutex); 537 up_read(&ip->i_rw_mutex);
519} 538}
520 539
521int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary) 540int gfs2_block_map(struct inode *inode, u64 lblock, int create,
541 struct buffer_head *bh, unsigned int maxlen)
522{ 542{
523 struct metapath mp; 543 struct metapath mp;
524 struct buffer_head *bh; 544 int ret;
525 int create = *new;
526 545
527 bmap_lock(inode, create); 546 bmap_lock(inode, create);
528 bh = gfs2_block_pointers(inode, lblock, new, dblock, boundary, &mp); 547 ret = gfs2_block_pointers(inode, lblock, create, bh, &mp, maxlen);
529 bmap_unlock(inode, create); 548 bmap_unlock(inode, create);
530 if (!bh) 549 return ret;
531 return 0;
532 if (IS_ERR(bh))
533 return PTR_ERR(bh);
534 brelse(bh);
535 return 0;
536} 550}
537 551
538int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen) 552int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen)
539{ 553{
540 struct gfs2_inode *ip = GFS2_I(inode);
541 struct gfs2_sbd *sdp = GFS2_SB(inode);
542 struct metapath mp; 554 struct metapath mp;
543 struct buffer_head *bh; 555 struct buffer_head bh = { .b_state = 0, .b_blocknr = 0, .b_size = 0 };
544 int boundary; 556 int ret;
545 int create = *new; 557 int create = *new;
546 558
547 BUG_ON(!extlen); 559 BUG_ON(!extlen);
@@ -549,30 +561,15 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
549 BUG_ON(!new); 561 BUG_ON(!new);
550 562
551 bmap_lock(inode, create); 563 bmap_lock(inode, create);
552 bh = gfs2_block_pointers(inode, lblock, new, dblock, &boundary, &mp); 564 ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp, *extlen);
553 *extlen = 1;
554
555 if (bh != NULL && !IS_ERR(bh) && *dblock != 0 && *new == 0) {
556 u64 tmp_dblock;
557 int tmp_new;
558 unsigned int nptrs;
559 unsigned end_of_metadata = ip->i_di.di_height - 1;
560
561 nptrs = (end_of_metadata) ? sdp->sd_inptrs : sdp->sd_diptrs;
562 while (++mp.mp_list[end_of_metadata] < nptrs) {
563 lookup_block(ip, bh, end_of_metadata, &mp, 0, &tmp_new, &tmp_dblock);
564 if (*dblock + *extlen != tmp_dblock)
565 break;
566 ++*extlen;
567 }
568 }
569 bmap_unlock(inode, create); 565 bmap_unlock(inode, create);
570 if (!bh) 566 *extlen = bh.b_size >> inode->i_blkbits;
571 return 0; 567 *dblock = bh.b_blocknr;
572 if (IS_ERR(bh)) 568 if (buffer_new(&bh))
573 return PTR_ERR(bh); 569 *new = 1;
574 brelse(bh); 570 else
575 return 0; 571 *new = 0;
572 return ret;
576} 573}
577 574
578/** 575/**
diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h
index 503f1cdda290..0fd379b4cd9e 100644
--- a/fs/gfs2/bmap.h
+++ b/fs/gfs2/bmap.h
@@ -15,7 +15,7 @@ struct gfs2_inode;
15struct page; 15struct page;
16 16
17int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page); 17int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
18int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary); 18int gfs2_block_map(struct inode *inode, u64 lblock, int create, struct buffer_head *bh, unsigned int maxlen);
19int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen); 19int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen);
20 20
21int gfs2_truncatei(struct gfs2_inode *ip, u64 size); 21int gfs2_truncatei(struct gfs2_inode *ip, u64 size);
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 50f88059c3d5..ab341cd0a76a 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -204,17 +204,15 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
204 204
205static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) 205static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
206{ 206{
207 int new = 0;
208 u64 dbn;
209 int error; 207 int error;
210 int bdy; 208 struct buffer_head bh_map;
211 209
212 error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, &new, &dbn, &bdy); 210 error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, 0, &bh_map, 1);
213 if (error || !dbn) 211 if (error || !bh_map.b_blocknr)
214 printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, (unsigned long long)dbn, lbn); 212 printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, bh_map.b_blocknr, lbn);
215 gfs2_assert_withdraw(sdp, !error && dbn); 213 gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr);
216 214
217 return dbn; 215 return bh_map.b_blocknr;
218} 216}
219 217
220/** 218/**
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index d44d42fb4163..6f9ac5e6e3f6 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -65,29 +65,11 @@ static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
65int gfs2_get_block(struct inode *inode, sector_t lblock, 65int gfs2_get_block(struct inode *inode, sector_t lblock,
66 struct buffer_head *bh_result, int create) 66 struct buffer_head *bh_result, int create)
67{ 67{
68 int new = create; 68 return gfs2_block_map(inode, lblock, create, bh_result, 32);
69 u64 dblock;
70 int error;
71 int boundary;
72
73 error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary);
74 if (error)
75 return error;
76
77 if (!dblock)
78 return 0;
79
80 map_bh(bh_result, inode->i_sb, dblock);
81 if (new)
82 set_buffer_new(bh_result);
83 if (boundary)
84 set_buffer_boundary(bh_result);
85
86 return 0;
87} 69}
88 70
89/** 71/**
90 * get_block_noalloc - Fills in a buffer head with details about a block 72 * gfs2_get_block_noalloc - Fills in a buffer head with details about a block
91 * @inode: The inode 73 * @inode: The inode
92 * @lblock: The block number to look up 74 * @lblock: The block number to look up
93 * @bh_result: The buffer head to return the result in 75 * @bh_result: The buffer head to return the result in
@@ -96,47 +78,25 @@ int gfs2_get_block(struct inode *inode, sector_t lblock,
96 * Returns: errno 78 * Returns: errno
97 */ 79 */
98 80
99static int get_block_noalloc(struct inode *inode, sector_t lblock, 81static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock,
100 struct buffer_head *bh_result, int create) 82 struct buffer_head *bh_result, int create)
101{ 83{
102 int new = 0;
103 u64 dblock;
104 int error; 84 int error;
105 int boundary;
106 85
107 error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary); 86 error = gfs2_block_map(inode, lblock, 0, bh_result, 1);
108 if (error) 87 if (error)
109 return error; 88 return error;
110 89 if (bh_result->b_blocknr == 0)
111 if (dblock) 90 return -EIO;
112 map_bh(bh_result, inode->i_sb, dblock); 91 return 0;
113 else if (gfs2_assert_withdraw(GFS2_SB(inode), !create))
114 error = -EIO;
115 if (boundary)
116 set_buffer_boundary(bh_result);
117
118 return error;
119} 92}
120 93
121static int get_block_direct(struct inode *inode, sector_t lblock, 94static int gfs2_get_block_direct(struct inode *inode, sector_t lblock,
122 struct buffer_head *bh_result, int create) 95 struct buffer_head *bh_result, int create)
123{ 96{
124 int new = 0; 97 return gfs2_block_map(inode, lblock, 0, bh_result, 512);
125 u64 dblock;
126 int error, boundary;
127
128 error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary);
129 if (error)
130 return error;
131
132 if (dblock) {
133 map_bh(bh_result, inode->i_sb, dblock);
134 if (boundary)
135 set_buffer_boundary(bh_result);
136 }
137
138 return 0;
139} 98}
99
140/** 100/**
141 * gfs2_writepage - Write complete page 101 * gfs2_writepage - Write complete page
142 * @page: Page to write 102 * @page: Page to write
@@ -184,7 +144,7 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
184 gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1); 144 gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1);
185 done_trans = 1; 145 done_trans = 1;
186 } 146 }
187 error = block_write_full_page(page, get_block_noalloc, wbc); 147 error = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
188 if (done_trans) 148 if (done_trans)
189 gfs2_trans_end(sdp); 149 gfs2_trans_end(sdp);
190 gfs2_meta_cache_flush(ip); 150 gfs2_meta_cache_flush(ip);
@@ -680,7 +640,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
680 rv = blockdev_direct_IO_own_locking(rw, iocb, inode, 640 rv = blockdev_direct_IO_own_locking(rw, iocb, inode,
681 inode->i_sb->s_bdev, 641 inode->i_sb->s_bdev,
682 iov, offset, nr_segs, 642 iov, offset, nr_segs,
683 get_block_direct, NULL); 643 gfs2_get_block_direct, NULL);
684out: 644out:
685 gfs2_glock_dq_m(1, &gh); 645 gfs2_glock_dq_m(1, &gh);
686 gfs2_holder_uninit(&gh); 646 gfs2_holder_uninit(&gh);
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index fe1828ffebfa..bc9ad058d20e 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -248,11 +248,9 @@ static int bh_get(struct gfs2_quota_data *qd)
248 struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; 248 struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
249 struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); 249 struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode);
250 unsigned int block, offset; 250 unsigned int block, offset;
251 u64 dblock;
252 int new = 0;
253 struct buffer_head *bh; 251 struct buffer_head *bh;
254 int error; 252 int error;
255 int boundary; 253 struct buffer_head bh_map;
256 254
257 mutex_lock(&sdp->sd_quota_mutex); 255 mutex_lock(&sdp->sd_quota_mutex);
258 256
@@ -264,10 +262,10 @@ static int bh_get(struct gfs2_quota_data *qd)
264 block = qd->qd_slot / sdp->sd_qc_per_block; 262 block = qd->qd_slot / sdp->sd_qc_per_block;
265 offset = qd->qd_slot % sdp->sd_qc_per_block;; 263 offset = qd->qd_slot % sdp->sd_qc_per_block;;
266 264
267 error = gfs2_block_map(&ip->i_inode, block, &new, &dblock, &boundary); 265 error = gfs2_block_map(&ip->i_inode, block, 0, &bh_map, 1);
268 if (error) 266 if (error)
269 goto fail; 267 goto fail;
270 error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh); 268 error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_START | DIO_WAIT, &bh);
271 if (error) 269 if (error)
272 goto fail; 270 goto fail;
273 error = -EIO; 271 error = -EIO;
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
index a27569c5d85e..130e9fbf9692 100644
--- a/fs/gfs2/recovery.c
+++ b/fs/gfs2/recovery.c
@@ -369,25 +369,23 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head)
369 struct gfs2_inode *ip = GFS2_I(jd->jd_inode); 369 struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
370 struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); 370 struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
371 unsigned int lblock; 371 unsigned int lblock;
372 int new = 0;
373 u64 dblock;
374 struct gfs2_log_header *lh; 372 struct gfs2_log_header *lh;
375 u32 hash; 373 u32 hash;
376 struct buffer_head *bh; 374 struct buffer_head *bh;
377 int error; 375 int error;
378 int boundary; 376 struct buffer_head bh_map;
379 377
380 lblock = head->lh_blkno; 378 lblock = head->lh_blkno;
381 gfs2_replay_incr_blk(sdp, &lblock); 379 gfs2_replay_incr_blk(sdp, &lblock);
382 error = gfs2_block_map(&ip->i_inode, lblock, &new, &dblock, &boundary); 380 error = gfs2_block_map(&ip->i_inode, lblock, 0, &bh_map, 1);
383 if (error) 381 if (error)
384 return error; 382 return error;
385 if (!dblock) { 383 if (!bh_map.b_blocknr) {
386 gfs2_consist_inode(ip); 384 gfs2_consist_inode(ip);
387 return -EIO; 385 return -EIO;
388 } 386 }
389 387
390 bh = sb_getblk(sdp->sd_vfs, dblock); 388 bh = sb_getblk(sdp->sd_vfs, bh_map.b_blocknr);
391 lock_buffer(bh); 389 lock_buffer(bh);
392 memset(bh->b_data, 0, bh->b_size); 390 memset(bh->b_data, 0, bh->b_size);
393 set_buffer_uptodate(bh); 391 set_buffer_uptodate(bh);