From b5c91062d12f872362347e938ba8f021bcb92c0e Mon Sep 17 00:00:00 2001 From: Damjan Jovanovic Date: Tue, 26 Jan 2016 19:37:04 +0200 Subject: [PATCH] Fix handling of sparse files which begin with sparse blocks or contain sparse blocks prior to an extent's index. Also implement runb in EXT4's mmap(), which should speed up random access to mapped files. --- sys/fs/ext2fs/ext2_bmap.c | 4 ++++ sys/fs/ext2fs/ext2_extents.c | 50 +++++++++++++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/sys/fs/ext2fs/ext2_bmap.c b/sys/fs/ext2fs/ext2_bmap.c index 8656e59..8e5e986 100644 --- a/sys/fs/ext2fs/ext2_bmap.c +++ b/sys/fs/ext2fs/ext2_bmap.c @@ -114,6 +114,8 @@ ext4_bmapext(struct vnode *vp, int32_t bn, int64_t *bnp, int *runp, int *runb) 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 @@ ext4_bmapext(struct vnode *vp, int32_t bn, int64_t *bnp, int *runp, int *runb) if (runp != NULL) *runp = ep->e_len - (lbn - ep->e_blk) - 1; + if (runb != NULL) + *runb = lbn - ep->e_blk; } } diff --git a/sys/fs/ext2fs/ext2_extents.c b/sys/fs/ext2fs/ext2_extents.c index 1317fdc..04af7bf 100644 --- a/sys/fs/ext2fs/ext2_extents.c +++ b/sys/fs/ext2fs/ext2_extents.c @@ -43,14 +43,16 @@ #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 +61,24 @@ static void ext4_ext_binsearch_index(struct inode *ip, struct ext4_extent_path 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 +98,8 @@ ext4_ext_binsearch(struct inode *ip, struct ext4_extent_path *path, daddr_t lbn) } 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 +107,11 @@ ext4_ext_binsearch(struct inode *ip, struct ext4_extent_path *path, daddr_t lbn) } 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 +177,15 @@ ext4_ext_find_extent(struct m_ext2fs *fs, struct inode *ip, 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 +210,6 @@ ext4_ext_find_extent(struct m_ext2fs *fs, struct inode *ip, 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); } -- 2.6.4