diff options
Diffstat (limited to 'fs/xfs/xfs_bmap_util.c')
-rw-r--r-- | fs/xfs/xfs_bmap_util.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index b9abce524c33..c1417919ab0a 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c | |||
@@ -528,7 +528,6 @@ xfs_getbmap( | |||
528 | xfs_bmbt_irec_t *map; /* buffer for user's data */ | 528 | xfs_bmbt_irec_t *map; /* buffer for user's data */ |
529 | xfs_mount_t *mp; /* file system mount point */ | 529 | xfs_mount_t *mp; /* file system mount point */ |
530 | int nex; /* # of user extents can do */ | 530 | int nex; /* # of user extents can do */ |
531 | int nexleft; /* # of user extents left */ | ||
532 | int subnex; /* # of bmapi's can do */ | 531 | int subnex; /* # of bmapi's can do */ |
533 | int nmap; /* number of map entries */ | 532 | int nmap; /* number of map entries */ |
534 | struct getbmapx *out; /* output structure */ | 533 | struct getbmapx *out; /* output structure */ |
@@ -686,10 +685,8 @@ xfs_getbmap( | |||
686 | goto out_free_map; | 685 | goto out_free_map; |
687 | } | 686 | } |
688 | 687 | ||
689 | nexleft = nex; | ||
690 | |||
691 | do { | 688 | do { |
692 | nmap = (nexleft > subnex) ? subnex : nexleft; | 689 | nmap = (nex> subnex) ? subnex : nex; |
693 | error = xfs_bmapi_read(ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset), | 690 | error = xfs_bmapi_read(ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset), |
694 | XFS_BB_TO_FSB(mp, bmv->bmv_length), | 691 | XFS_BB_TO_FSB(mp, bmv->bmv_length), |
695 | map, &nmap, bmapi_flags); | 692 | map, &nmap, bmapi_flags); |
@@ -697,8 +694,8 @@ xfs_getbmap( | |||
697 | goto out_free_map; | 694 | goto out_free_map; |
698 | ASSERT(nmap <= subnex); | 695 | ASSERT(nmap <= subnex); |
699 | 696 | ||
700 | for (i = 0; i < nmap && nexleft && bmv->bmv_length && | 697 | for (i = 0; i < nmap && bmv->bmv_length && |
701 | cur_ext < bmv->bmv_count; i++) { | 698 | cur_ext < bmv->bmv_count - 1; i++) { |
702 | out[cur_ext].bmv_oflags = 0; | 699 | out[cur_ext].bmv_oflags = 0; |
703 | if (map[i].br_state == XFS_EXT_UNWRITTEN) | 700 | if (map[i].br_state == XFS_EXT_UNWRITTEN) |
704 | out[cur_ext].bmv_oflags |= BMV_OF_PREALLOC; | 701 | out[cur_ext].bmv_oflags |= BMV_OF_PREALLOC; |
@@ -760,16 +757,27 @@ xfs_getbmap( | |||
760 | continue; | 757 | continue; |
761 | } | 758 | } |
762 | 759 | ||
760 | /* | ||
761 | * In order to report shared extents accurately, | ||
762 | * we report each distinct shared/unshared part | ||
763 | * of a single bmbt record using multiple bmap | ||
764 | * extents. To make that happen, we iterate the | ||
765 | * same map array item multiple times, each | ||
766 | * time trimming out the subextent that we just | ||
767 | * reported. | ||
768 | * | ||
769 | * Because of this, we must check the out array | ||
770 | * index (cur_ext) directly against bmv_count-1 | ||
771 | * to avoid overflows. | ||
772 | */ | ||
763 | if (inject_map.br_startblock != NULLFSBLOCK) { | 773 | if (inject_map.br_startblock != NULLFSBLOCK) { |
764 | map[i] = inject_map; | 774 | map[i] = inject_map; |
765 | i--; | 775 | i--; |
766 | } else | 776 | } |
767 | nexleft--; | ||
768 | bmv->bmv_entries++; | 777 | bmv->bmv_entries++; |
769 | cur_ext++; | 778 | cur_ext++; |
770 | } | 779 | } |
771 | } while (nmap && nexleft && bmv->bmv_length && | 780 | } while (nmap && bmv->bmv_length && cur_ext < bmv->bmv_count - 1); |
772 | cur_ext < bmv->bmv_count); | ||
773 | 781 | ||
774 | out_free_map: | 782 | out_free_map: |
775 | kmem_free(map); | 783 | kmem_free(map); |