summaryrefslogtreecommitdiffstats
path: root/sys/fs/ext2fs/ext2_subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/ext2fs/ext2_subr.c')
-rw-r--r--sys/fs/ext2fs/ext2_subr.c51
1 files changed, 47 insertions, 4 deletions
diff --git a/sys/fs/ext2fs/ext2_subr.c b/sys/fs/ext2fs/ext2_subr.c
index df6e430..cd4a06b 100644
--- a/sys/fs/ext2fs/ext2_subr.c
+++ b/sys/fs/ext2fs/ext2_subr.c
@@ -50,10 +50,11 @@
#include <fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/fs.h>
-
-#ifdef KDB
+#include <fs/ext2fs/ext2_extents.h>
#include <fs/ext2fs/ext2_mount.h>
+#include <fs/ext2fs/ext2_dinode.h>
+#ifdef KDB
void ext2_checkoverlap(struct buf *, struct inode *);
#endif
@@ -70,21 +71,63 @@ ext2_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp)
struct buf *bp;
e2fs_lbn_t lbn;
int bsize, error;
+ daddr_t newblk;
+ struct ext4_extent *ep;
+ struct ext4_extent_path path;
ip = VTOI(vp);
fs = ip->i_e2fs;
lbn = lblkno(fs, offset);
bsize = blksize(fs, ip, lbn);
-
*bpp = NULL;
- if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) {
+
+ /*
+ * The EXT4_EXTENTS requires special treatment, otherwise we can
+ * fall back to the normal path.
+ */
+ if (!(ip->i_flags & EXT4_EXTENTS))
+ goto normal;
+
+ memset(&path, 0, sizeof(path));
+ if (ext4_ext_find_extent(fs, ip, lbn, &path) == NULL)
+ goto normal;
+ ep = path.ep_ext;
+ if (ep == NULL)
+ goto normal;
+
+ newblk = lbn - ep->e_blk +
+ (ep->e_start_lo | (daddr_t)ep->e_start_hi << 32);
+
+ if (path.ep_bp != NULL) {
+ brelse(path.ep_bp);
+ path.ep_bp = NULL;
+ }
+ error = bread(ip->i_devvp, fsbtodb(fs, newblk), bsize, NOCRED, &bp);
+ if (error != 0) {
brelse(bp);
return (error);
}
if (res)
*res = (char *)bp->b_data + blkoff(fs, offset);
+ /*
+ * If EXT4_EXTENTS is enabled we would get a wrong offset so
+ * reset b_offset here.
+ */
+ bp->b_offset = lbn * bsize;
*bpp = bp;
return (0);
+
+normal:
+ if (*bpp == NULL) {
+ if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) {
+ brelse(bp);
+ return (error);
+ }
+ if (res)
+ *res = (char *)bp->b_data + blkoff(fs, offset);
+ *bpp = bp;
+ }
+ return (0);
}
#ifdef KDB
OpenPOWER on IntegriCloud