diff options
Diffstat (limited to 'fs/gfs2/bmap.c')
-rw-r--r-- | fs/gfs2/bmap.c | 131 |
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 | ||
436 | static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock, | 435 | static 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; | 516 | out_brelse: |
498 | out: | 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 | ||
521 | int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary) | 540 | int 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 | ||
538 | 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) |
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 | /** |