Index: sys/fs/ext2fs/ext2_bmap.c =================================================================== --- sys/fs/ext2fs/ext2_bmap.c (revision 295446) +++ sys/fs/ext2fs/ext2_bmap.c (working copy) @@ -114,6 +114,8 @@ if (runp != NULL) *runp = path.ep_sparse_ext.e_len - (lbn - path.ep_sparse_ext.e_blk) - 1; + if (runb != NULL) + *runb = lbn - path.ep_sparse_ext.e_blk; } else { ep = path.ep_ext; if (ep == NULL) @@ -127,6 +129,8 @@ if (runp != NULL) *runp = ep->e_len - (lbn - ep->e_blk) - 1; + if (runb != NULL) + *runb = lbn - ep->e_blk; } } Index: sys/fs/ext2fs/ext2_extents.c =================================================================== --- sys/fs/ext2fs/ext2_extents.c (revision 295446) +++ sys/fs/ext2fs/ext2_extents.c (working copy) @@ -43,14 +43,17 @@ #include #include -static void ext4_ext_binsearch_index(struct inode *ip, struct ext4_extent_path - *path, daddr_t lbn) +static int +ext4_ext_binsearch_index(struct inode *ip, struct ext4_extent_path *path, + daddr_t lbn, daddr_t *first_lbn, daddr_t *last_lbn) { struct ext4_extent_header *ehp = path->ep_header; - struct ext4_extent_index *l, *r, *m; + struct ext4_extent_index *first, *last, *l, *r, *m; - l = (struct ext4_extent_index *)(char *)(ehp + 1); - r = (struct ext4_extent_index *)(char *)(ehp + 1) + ehp->eh_ecount - 1; + first = (struct ext4_extent_index *)(char *)(ehp + 1); + last = first + ehp->eh_ecount - 1; + l = first; + r = last; while (l <= r) { m = l + (r - l) / 2; if (lbn < m->ei_blk) @@ -59,11 +62,24 @@ l = m + 1; } + if (l == first) { + path->ep_sparse_ext.e_blk = *first_lbn; + path->ep_sparse_ext.e_len = first->ei_blk - *first_lbn; + path->ep_sparse_ext.e_start_hi = 0; + path->ep_sparse_ext.e_start_lo = 0; + path->ep_is_sparse = 1; + return (1); + } path->ep_index = l - 1; + *first_lbn = path->ep_index->ei_blk; + if (path->ep_index < last) + *last_lbn = l->ei_blk - 1; + return (0); } static void -ext4_ext_binsearch(struct inode *ip, struct ext4_extent_path *path, daddr_t lbn) +ext4_ext_binsearch(struct inode *ip, struct ext4_extent_path *path, daddr_t lbn, + daddr_t first_lbn, daddr_t last_lbn) { struct ext4_extent_header *ehp = path->ep_header; struct ext4_extent *first, *l, *r, *m; @@ -83,8 +99,8 @@ } if (l == first) { - path->ep_sparse_ext.e_blk = lbn; - path->ep_sparse_ext.e_len = first->e_blk - lbn; + path->ep_sparse_ext.e_blk = first_lbn; + path->ep_sparse_ext.e_len = first->e_blk - first_lbn; path->ep_sparse_ext.e_start_hi = 0; path->ep_sparse_ext.e_start_lo = 0; path->ep_is_sparse = 1; @@ -92,11 +108,14 @@ } path->ep_ext = l - 1; if (path->ep_ext->e_blk + path->ep_ext->e_len <= lbn) { - path->ep_sparse_ext.e_blk = lbn; + path->ep_sparse_ext.e_blk = path->ep_ext->e_blk + + path->ep_ext->e_len; if (l <= (first + ehp->eh_ecount - 1)) - path->ep_sparse_ext.e_len = l->e_blk - lbn; - else // XXX: where does it end? - path->ep_sparse_ext.e_len = 1; + path->ep_sparse_ext.e_len = l->e_blk - + path->ep_sparse_ext.e_blk; + else + path->ep_sparse_ext.e_len = last_lbn - + path->ep_sparse_ext.e_blk + 1; path->ep_sparse_ext.e_start_hi = 0; path->ep_sparse_ext.e_start_lo = 0; path->ep_is_sparse = 1; @@ -162,10 +181,16 @@ path->ep_header = ehp; + daddr_t first_lbn = 0; + daddr_t last_lbn = lblkno(ip->i_e2fs, ip->i_size); + for (i = ehp->eh_depth; i != 0; --i) { - ext4_ext_binsearch_index(ip, path, lbn); - path->ep_depth = 0; + path->ep_depth = i; path->ep_ext = NULL; + if (ext4_ext_binsearch_index(ip, path, lbn, &first_lbn, + &last_lbn)) { + return (path); + } nblk = (daddr_t)path->ep_index->ei_leaf_hi << 32 | path->ep_index->ei_leaf_lo; @@ -190,6 +215,6 @@ path->ep_index = NULL; path->ep_is_sparse = 0; - ext4_ext_binsearch(ip, path, lbn); + ext4_ext_binsearch(ip, path, lbn, first_lbn, last_lbn); return (path); }