diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-11-15 15:21:06 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-11-30 10:35:49 -0500 |
commit | 4cf1ed8144e740de27c6146c25d5d7ea26679cc5 (patch) | |
tree | 481555ec6e88e4fedba90498f1ac212056ea7828 | |
parent | ab923031ceb95ec50ef33ccadf28663c660aa94c (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>
-rw-r--r-- | fs/gfs2/bmap.c | 117 |
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 | ||
426 | static 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 | |||
435 | static 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 | ||
439 | static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, | 456 | int 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 | } |
522 | out_brelse: | 543 | out_brelse: |
523 | brelse(bh); | 544 | brelse(bh); |
524 | return 0; | 545 | out_ok: |
525 | } | 546 | error = 0; |
526 | 547 | out_fail: | |
527 | |||
528 | static 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 | |||
537 | static 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 | |||
546 | int 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 | ||
558 | int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen) | 552 | int 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)) |