aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2006-11-15 15:21:06 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2006-11-30 10:35:49 -0500
commit4cf1ed8144e740de27c6146c25d5d7ea26679cc5 (patch)
tree481555ec6e88e4fedba90498f1ac212056ea7828 /fs
parentab923031ceb95ec50ef33ccadf28663c660aa94c (diff)
[GFS2] Tidy up bmap & fix boundary bug
This moves the locking for bmap into the bmap function itself rather than using a wrapper function. It also fixes a bug where the boundary flag was set on the wrong bh. Also the flags on the mapped bh are reset earlier in the function to ensure that they are 100% correct on the error path. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/gfs2/bmap.c117
1 files changed, 54 insertions, 63 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 06e3447ea132..8240c1ff94f4 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -423,12 +423,29 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
423 return 0; 423 return 0;
424} 424}
425 425
426static inline void bmap_lock(struct inode *inode, int create)
427{
428 struct gfs2_inode *ip = GFS2_I(inode);
429 if (create)
430 down_write(&ip->i_rw_mutex);
431 else
432 down_read(&ip->i_rw_mutex);
433}
434
435static inline void bmap_unlock(struct inode *inode, int create)
436{
437 struct gfs2_inode *ip = GFS2_I(inode);
438 if (create)
439 up_write(&ip->i_rw_mutex);
440 else
441 up_read(&ip->i_rw_mutex);
442}
443
426/** 444/**
427 * gfs2_block_pointers - Map a block from an inode to a disk block 445 * gfs2_block_map - Map a block from an inode to a disk block
428 * @inode: The inode 446 * @inode: The inode
429 * @lblock: The logical block number 447 * @lblock: The logical block number
430 * @map_bh: The bh to be mapped 448 * @bh_map: The bh to be mapped
431 * @mp: metapath to use
432 * 449 *
433 * Find the block number on the current device which corresponds to an 450 * Find the block number on the current device which corresponds to an
434 * inode's block. If the block had to be created, "new" will be set. 451 * inode's block. If the block had to be created, "new" will be set.
@@ -436,8 +453,8 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
436 * Returns: errno 453 * Returns: errno
437 */ 454 */
438 455
439static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, 456int gfs2_block_map(struct inode *inode, u64 lblock, int create,
440 struct buffer_head *bh_map, struct metapath *mp) 457 struct buffer_head *bh_map)
441{ 458{
442 struct gfs2_inode *ip = GFS2_I(inode); 459 struct gfs2_inode *ip = GFS2_I(inode);
443 struct gfs2_sbd *sdp = GFS2_SB(inode); 460 struct gfs2_sbd *sdp = GFS2_SB(inode);
@@ -451,51 +468,55 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create,
451 u64 dblock = 0; 468 u64 dblock = 0;
452 int boundary; 469 int boundary;
453 unsigned int maxlen = bh_map->b_size >> inode->i_blkbits; 470 unsigned int maxlen = bh_map->b_size >> inode->i_blkbits;
471 struct metapath mp;
472 u64 size;
454 473
455 BUG_ON(maxlen == 0); 474 BUG_ON(maxlen == 0);
456 475
457 if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) 476 if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip)))
458 return 0; 477 return 0;
459 478
479 bmap_lock(inode, create);
480 clear_buffer_mapped(bh_map);
481 clear_buffer_new(bh_map);
482 clear_buffer_boundary(bh_map);
460 bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize; 483 bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize;
461 484 size = (lblock + 1) * bsize;
462 height = calc_tree_height(ip, (lblock + 1) * bsize); 485
463 if (ip->i_di.di_height < height) { 486 if (size > ip->i_di.di_size) {
464 if (!create) 487 height = calc_tree_height(ip, size);
465 return 0; 488 if (ip->i_di.di_height < height) {
466 489 if (!create)
467 error = build_height(inode, height); 490 goto out_ok;
468 if (error) 491
469 return error; 492 error = build_height(inode, height);
493 if (error)
494 goto out_fail;
495 }
470 } 496 }
471 497
472 find_metapath(ip, lblock, mp); 498 find_metapath(ip, lblock, &mp);
473 end_of_metadata = ip->i_di.di_height - 1; 499 end_of_metadata = ip->i_di.di_height - 1;
474
475 error = gfs2_meta_inode_buffer(ip, &bh); 500 error = gfs2_meta_inode_buffer(ip, &bh);
476 if (error) 501 if (error)
477 return error; 502 goto out_fail;
478 503
479 for (x = 0; x < end_of_metadata; x++) { 504 for (x = 0; x < end_of_metadata; x++) {
480 lookup_block(ip, bh, x, mp, create, &new, &dblock); 505 lookup_block(ip, bh, x, &mp, create, &new, &dblock);
481 brelse(bh); 506 brelse(bh);
482 if (!dblock) 507 if (!dblock)
483 return 0; 508 goto out_ok;
484 509
485 error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh); 510 error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh);
486 if (error) 511 if (error)
487 return error; 512 goto out_fail;
488 } 513 }
489 514
490 boundary = lookup_block(ip, bh, end_of_metadata, mp, create, &new, &dblock); 515 boundary = lookup_block(ip, bh, end_of_metadata, &mp, create, &new, &dblock);
491 clear_buffer_mapped(bh_map);
492 clear_buffer_new(bh_map);
493 clear_buffer_boundary(bh_map);
494
495 if (dblock) { 516 if (dblock) {
496 map_bh(bh_map, inode->i_sb, dblock); 517 map_bh(bh_map, inode->i_sb, dblock);
497 if (boundary) 518 if (boundary)
498 set_buffer_boundary(bh); 519 set_buffer_boundary(bh_map);
499 if (new) { 520 if (new) {
500 struct buffer_head *dibh; 521 struct buffer_head *dibh;
501 error = gfs2_meta_inode_buffer(ip, &dibh); 522 error = gfs2_meta_inode_buffer(ip, &dibh);
@@ -510,8 +531,8 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create,
510 while(--maxlen && !buffer_boundary(bh_map)) { 531 while(--maxlen && !buffer_boundary(bh_map)) {
511 u64 eblock; 532 u64 eblock;
512 533
513 mp->mp_list[end_of_metadata]++; 534 mp.mp_list[end_of_metadata]++;
514 boundary = lookup_block(ip, bh, end_of_metadata, mp, 0, &new, &eblock); 535 boundary = lookup_block(ip, bh, end_of_metadata, &mp, 0, &new, &eblock);
515 if (eblock != ++dblock) 536 if (eblock != ++dblock)
516 break; 537 break;
517 bh_map->b_size += (1 << inode->i_blkbits); 538 bh_map->b_size += (1 << inode->i_blkbits);
@@ -521,43 +542,15 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create,
521 } 542 }
522out_brelse: 543out_brelse:
523 brelse(bh); 544 brelse(bh);
524 return 0; 545out_ok:
525} 546 error = 0;
526 547out_fail:
527
528static inline void bmap_lock(struct inode *inode, int create)
529{
530 struct gfs2_inode *ip = GFS2_I(inode);
531 if (create)
532 down_write(&ip->i_rw_mutex);
533 else
534 down_read(&ip->i_rw_mutex);
535}
536
537static inline void bmap_unlock(struct inode *inode, int create)
538{
539 struct gfs2_inode *ip = GFS2_I(inode);
540 if (create)
541 up_write(&ip->i_rw_mutex);
542 else
543 up_read(&ip->i_rw_mutex);
544}
545
546int gfs2_block_map(struct inode *inode, u64 lblock, int create,
547 struct buffer_head *bh)
548{
549 struct metapath mp;
550 int ret;
551
552 bmap_lock(inode, create);
553 ret = gfs2_block_pointers(inode, lblock, create, bh, &mp);
554 bmap_unlock(inode, create); 548 bmap_unlock(inode, create);
555 return ret; 549 return error;
556} 550}
557 551
558int 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)
559{ 553{
560 struct metapath mp;
561 struct buffer_head bh = { .b_state = 0, .b_blocknr = 0 }; 554 struct buffer_head bh = { .b_state = 0, .b_blocknr = 0 };
562 int ret; 555 int ret;
563 int create = *new; 556 int create = *new;
@@ -567,9 +560,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
567 BUG_ON(!new); 560 BUG_ON(!new);
568 561
569 bh.b_size = 1 << (inode->i_blkbits + 5); 562 bh.b_size = 1 << (inode->i_blkbits + 5);
570 bmap_lock(inode, create); 563 ret = gfs2_block_map(inode, lblock, create, &bh);
571 ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp);
572 bmap_unlock(inode, create);
573 *extlen = bh.b_size >> inode->i_blkbits; 564 *extlen = bh.b_size >> inode->i_blkbits;
574 *dblock = bh.b_blocknr; 565 *dblock = bh.b_blocknr;
575 if (buffer_new(&bh)) 566 if (buffer_new(&bh))