aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/bmap.c
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 /fs/gfs2/bmap.c
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>
Diffstat (limited to 'fs/gfs2/bmap.c')
-rw-r--r--fs/gfs2/bmap.c131
1 files changed, 64 insertions, 67 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/**