aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/bmap.c
diff options
context:
space:
mode:
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/**