Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'gfs2-v5.3-rc3.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2

Pull gfs2 fix from Andreas Gruenbacher:
"Fix incorrect lseek / fiemap results"

* tag 'gfs2-v5.3-rc3.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
gfs2: gfs2_walk_metadata fix

+101 -63
+101 -63
fs/gfs2/bmap.c
··· 390 390 return mp->mp_aheight - x - 1; 391 391 } 392 392 393 + static sector_t metapath_to_block(struct gfs2_sbd *sdp, struct metapath *mp) 394 + { 395 + sector_t factor = 1, block = 0; 396 + int hgt; 397 + 398 + for (hgt = mp->mp_fheight - 1; hgt >= 0; hgt--) { 399 + if (hgt < mp->mp_aheight) 400 + block += mp->mp_list[hgt] * factor; 401 + factor *= sdp->sd_inptrs; 402 + } 403 + return block; 404 + } 405 + 393 406 static void release_metapath(struct metapath *mp) 394 407 { 395 408 int i; ··· 443 430 return ptr - first; 444 431 } 445 432 446 - typedef const __be64 *(*gfs2_metadata_walker)( 447 - struct metapath *mp, 448 - const __be64 *start, const __be64 *end, 449 - u64 factor, void *data); 433 + enum walker_status { WALK_STOP, WALK_FOLLOW, WALK_CONTINUE }; 450 434 451 - #define WALK_STOP ((__be64 *)0) 452 - #define WALK_NEXT ((__be64 *)1) 435 + /* 436 + * gfs2_metadata_walker - walk an indirect block 437 + * @mp: Metapath to indirect block 438 + * @ptrs: Number of pointers to look at 439 + * 440 + * When returning WALK_FOLLOW, the walker must update @mp to point at the right 441 + * indirect block to follow. 442 + */ 443 + typedef enum walker_status (*gfs2_metadata_walker)(struct metapath *mp, 444 + unsigned int ptrs); 453 445 454 - static int gfs2_walk_metadata(struct inode *inode, sector_t lblock, 455 - u64 len, struct metapath *mp, gfs2_metadata_walker walker, 456 - void *data) 446 + /* 447 + * gfs2_walk_metadata - walk a tree of indirect blocks 448 + * @inode: The inode 449 + * @mp: Starting point of walk 450 + * @max_len: Maximum number of blocks to walk 451 + * @walker: Called during the walk 452 + * 453 + * Returns 1 if the walk was stopped by @walker, 0 if we went past @max_len or 454 + * past the end of metadata, and a negative error code otherwise. 455 + */ 456 + 457 + static int gfs2_walk_metadata(struct inode *inode, struct metapath *mp, 458 + u64 max_len, gfs2_metadata_walker walker) 457 459 { 458 - struct metapath clone; 459 460 struct gfs2_inode *ip = GFS2_I(inode); 460 461 struct gfs2_sbd *sdp = GFS2_SB(inode); 461 - const __be64 *start, *end, *ptr; 462 462 u64 factor = 1; 463 463 unsigned int hgt; 464 - int ret = 0; 464 + int ret; 465 465 466 - for (hgt = ip->i_height - 1; hgt >= mp->mp_aheight; hgt--) 466 + /* 467 + * The walk starts in the lowest allocated indirect block, which may be 468 + * before the position indicated by @mp. Adjust @max_len accordingly 469 + * to avoid a short walk. 470 + */ 471 + for (hgt = mp->mp_fheight - 1; hgt >= mp->mp_aheight; hgt--) { 472 + max_len += mp->mp_list[hgt] * factor; 473 + mp->mp_list[hgt] = 0; 467 474 factor *= sdp->sd_inptrs; 475 + } 468 476 469 477 for (;;) { 470 - u64 step; 478 + u16 start = mp->mp_list[hgt]; 479 + enum walker_status status; 480 + unsigned int ptrs; 481 + u64 len; 471 482 472 483 /* Walk indirect block. */ 473 - start = metapointer(hgt, mp); 474 - end = metaend(hgt, mp); 475 - 476 - step = (end - start) * factor; 477 - if (step > len) 478 - end = start + DIV_ROUND_UP_ULL(len, factor); 479 - 480 - ptr = walker(mp, start, end, factor, data); 481 - if (ptr == WALK_STOP) 484 + ptrs = (hgt >= 1 ? sdp->sd_inptrs : sdp->sd_diptrs) - start; 485 + len = ptrs * factor; 486 + if (len > max_len) 487 + ptrs = DIV_ROUND_UP_ULL(max_len, factor); 488 + status = walker(mp, ptrs); 489 + switch (status) { 490 + case WALK_STOP: 491 + return 1; 492 + case WALK_FOLLOW: 493 + BUG_ON(mp->mp_aheight == mp->mp_fheight); 494 + ptrs = mp->mp_list[hgt] - start; 495 + len = ptrs * factor; 482 496 break; 483 - if (step >= len) 497 + case WALK_CONTINUE: 484 498 break; 485 - len -= step; 486 - if (ptr != WALK_NEXT) { 487 - BUG_ON(!*ptr); 488 - mp->mp_list[hgt] += ptr - start; 489 - goto fill_up_metapath; 490 499 } 500 + if (len >= max_len) 501 + break; 502 + max_len -= len; 503 + if (status == WALK_FOLLOW) 504 + goto fill_up_metapath; 491 505 492 506 lower_metapath: 493 507 /* Decrease height of metapath. */ 494 - if (mp != &clone) { 495 - clone_metapath(&clone, mp); 496 - mp = &clone; 497 - } 498 508 brelse(mp->mp_bh[hgt]); 499 509 mp->mp_bh[hgt] = NULL; 510 + mp->mp_list[hgt] = 0; 500 511 if (!hgt) 501 512 break; 502 513 hgt--; ··· 528 491 529 492 /* Advance in metadata tree. */ 530 493 (mp->mp_list[hgt])++; 531 - start = metapointer(hgt, mp); 532 - end = metaend(hgt, mp); 533 - if (start >= end) { 534 - mp->mp_list[hgt] = 0; 494 + if (mp->mp_list[hgt] >= sdp->sd_inptrs) { 535 495 if (!hgt) 536 496 break; 537 497 goto lower_metapath; ··· 536 502 537 503 fill_up_metapath: 538 504 /* Increase height of metapath. */ 539 - if (mp != &clone) { 540 - clone_metapath(&clone, mp); 541 - mp = &clone; 542 - } 543 505 ret = fillup_metapath(ip, mp, ip->i_height - 1); 544 506 if (ret < 0) 545 - break; 507 + return ret; 546 508 hgt += ret; 547 509 for (; ret; ret--) 548 510 do_div(factor, sdp->sd_inptrs); 549 511 mp->mp_aheight = hgt + 1; 550 512 } 551 - if (mp == &clone) 552 - release_metapath(mp); 553 - return ret; 513 + return 0; 554 514 } 555 515 556 - struct gfs2_hole_walker_args { 557 - u64 blocks; 558 - }; 559 - 560 - static const __be64 *gfs2_hole_walker(struct metapath *mp, 561 - const __be64 *start, const __be64 *end, 562 - u64 factor, void *data) 516 + static enum walker_status gfs2_hole_walker(struct metapath *mp, 517 + unsigned int ptrs) 563 518 { 564 - struct gfs2_hole_walker_args *args = data; 565 - const __be64 *ptr; 519 + const __be64 *start, *ptr, *end; 520 + unsigned int hgt; 521 + 522 + hgt = mp->mp_aheight - 1; 523 + start = metapointer(hgt, mp); 524 + end = start + ptrs; 566 525 567 526 for (ptr = start; ptr < end; ptr++) { 568 527 if (*ptr) { 569 - args->blocks += (ptr - start) * factor; 528 + mp->mp_list[hgt] += ptr - start; 570 529 if (mp->mp_aheight == mp->mp_fheight) 571 530 return WALK_STOP; 572 - return ptr; /* increase height */ 531 + return WALK_FOLLOW; 573 532 } 574 533 } 575 - args->blocks += (end - start) * factor; 576 - return WALK_NEXT; 534 + return WALK_CONTINUE; 577 535 } 578 536 579 537 /** ··· 583 557 static int gfs2_hole_size(struct inode *inode, sector_t lblock, u64 len, 584 558 struct metapath *mp, struct iomap *iomap) 585 559 { 586 - struct gfs2_hole_walker_args args = { }; 587 - int ret = 0; 560 + struct metapath clone; 561 + u64 hole_size; 562 + int ret; 588 563 589 - ret = gfs2_walk_metadata(inode, lblock, len, mp, gfs2_hole_walker, &args); 590 - if (!ret) 591 - iomap->length = args.blocks << inode->i_blkbits; 564 + clone_metapath(&clone, mp); 565 + ret = gfs2_walk_metadata(inode, &clone, len, gfs2_hole_walker); 566 + if (ret < 0) 567 + goto out; 568 + 569 + if (ret == 1) 570 + hole_size = metapath_to_block(GFS2_SB(inode), &clone) - lblock; 571 + else 572 + hole_size = len; 573 + iomap->length = hole_size << inode->i_blkbits; 574 + ret = 0; 575 + 576 + out: 577 + release_metapath(&clone); 592 578 return ret; 593 579 } 594 580