summaryrefslogtreecommitdiffstats
path: root/sys/fs
diff options
context:
space:
mode:
authorpfg <pfg@FreeBSD.org>2016-02-11 00:34:11 +0000
committerpfg <pfg@FreeBSD.org>2016-02-11 00:34:11 +0000
commitcdb1cc5394259e8a8d82c29cd3dadf5e4945e3b7 (patch)
tree9fb1e8b8b08f15b79d3e4bbc45a79f796588b568 /sys/fs
parent9f5beacde17d38e5bc39c4755aea7f7674accd67 (diff)
downloadFreeBSD-src-cdb1cc5394259e8a8d82c29cd3dadf5e4945e3b7.zip
FreeBSD-src-cdb1cc5394259e8a8d82c29cd3dadf5e4945e3b7.tar.gz
Ext4: fix handling of files with sparse blocks before extent's index.
This is ongoing work from Damjan Jovanovic to improve ext4 read support with sparse files: Keep track of the first and last block in each extent as it descends down the extent tree, thus being able to work out that some blocks are sparse earlier. This solves an issue on r293680. In ext4_bmapext() start supporting the runb parameter, which appears to be the number of adjacent blocks prior to the block being converted in the same way that runp is the number of blocks after, speding up random access to mmaped files. PR: 206652
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/ext2fs/ext2_bmap.c4
-rw-r--r--sys/fs/ext2fs/ext2_extents.c55
2 files changed, 44 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..230356c 100644
--- a/sys/fs/ext2fs/ext2_extents.c
+++ b/sys/fs/ext2fs/ext2_extents.c
@@ -43,14 +43,17 @@
#include <fs/ext2fs/ext2_extents.h>
#include <fs/ext2fs/ext2_extern.h>
-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 @@ 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 +99,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 +108,14 @@ 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 +181,16 @@ 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 +215,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);
}
OpenPOWER on IntegriCloud