[syslinux:pathbased] ext2: use generic_getfssec

syslinux-bot for H. Peter Anvin hpa at zytor.com
Fri Feb 26 18:18:08 PST 2010


Commit-ID:  0458be0391b4a7448e2a1911427c4c1800fe7145
Gitweb:     http://syslinux.zytor.com/commit/0458be0391b4a7448e2a1911427c4c1800fe7145
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Fri, 26 Feb 2010 18:15:55 -0800
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Fri, 26 Feb 2010 18:15:55 -0800

ext2: use generic_getfssec

Use generic_getfssec for ext2.

NOTE: Something seems wrong with the generic_getfssec() loop; running
this on an ext2 filesystem ends up with the code looking up the same
extent twice in a row, which should not happen.

Signed-off-by: H. Peter Anvin <hpa at zytor.com>


---
 core/fs/ext2/bmap.c    |  110 +++++++++++++++++++++++++++++-------
 core/fs/ext2/ext2.c    |  146 ++++++-----------------------------------------
 core/fs/ext2/ext2_fs.h |    3 +-
 3 files changed, 109 insertions(+), 150 deletions(-)

diff --git a/core/fs/ext2/bmap.c b/core/fs/ext2/bmap.c
index 73473e2..6940c1d 100644
--- a/core/fs/ext2/bmap.c
+++ b/core/fs/ext2/bmap.c
@@ -41,7 +41,9 @@ ext4_find_leaf(struct fs_info *fs, const struct ext4_extent_header *eh,
 }
 
 /* handle the ext4 extents to get the phsical block number */
-static block_t bmap_extent(struct inode *inode, block_t block)
+/* XXX: still need to handle sparse files with extents */
+static block_t
+bmap_extent(struct inode *inode, uint32_t block, size_t *nblocks)
 {
     struct fs_info *fs = inode->fs;
     const struct ext4_extent_header *leaf;
@@ -69,38 +71,77 @@ static block_t bmap_extent(struct inode *inode, block_t block)
     block -= ext[i].ee_block;
     if (block >= ext[i].ee_len)
 	return 0;
-    start = ext[i].ee_start_hi;
-    start = (start << 32) + ext[i].ee_start_lo;
+    start = ((block_t)ext[i].ee_start_hi << 32) + ext[i].ee_start_lo;
+
+    if (nblocks)
+	*nblocks = ext[i].ee_len - block;
 
     return start + block;
 }
 
 /*
+ * Scan forward in a range of blocks to see if they are contiguous,
+ * then return the initial value.
+ */
+static uint32_t
+scan_set_nblocks(const uint32_t *map, unsigned int count, size_t *nblocks)
+{
+    uint32_t blk = *map;
+
+    if (nblocks) {
+	uint32_t skip = blk ? 1 : 0;
+	uint32_t next = blk + skip;
+	size_t   cnt = 1;
+
+	while (--count) {
+	    map++;
+	    if (*map == next) {
+		cnt++;
+		next += skip;
+	    } else {
+		break;
+	    }
+	}
+
+	*nblocks = cnt;
+    }
+
+    return blk;
+}
+
+/*
  * The actual indirect block map handling - the block passed in should
  * be relative to the beginning of the particular block hierarchy.
  */
-static block_t bmap_indirect(struct fs_info *fs, uint32_t start,
-			     uint32_t block, int levels)
+static block_t
+bmap_indirect(struct fs_info *fs, uint32_t start, uint32_t block,
+	      int levels, size_t *nblocks)
 {
     int addr_shift = BLOCK_SHIFT(fs) - 2;
-    uint32_t addr_mask = (1 << addr_shift)-1;
-    uint32_t index;
-    const uint32_t *blk;
+    uint32_t addr_count = 1 << addr_shift;
+    const uint32_t *blk = NULL;
+    uint32_t index = 0;
 
     while (levels--) {
+	if (!start) {
+	    if (nblocks)
+		*nblocks = addr_count << (levels * addr_shift);
+	    return 0;
+	}
 	blk = get_cache(fs->fs_dev, start);
-	index = (block >> (levels * addr_shift)) & addr_mask;
+	index = (block >> (levels * addr_shift)) & (addr_count - 1);
 	start = blk[index];
     }
 
-    return start;
+    return scan_set_nblocks(blk + index, addr_count - index, nblocks);
 }
 
 /*
  * Handle the traditional block map, like indirect, double indirect
  * and triple indirect
  */
-static block_t bmap_traditional(struct inode *inode, block_t block)
+static block_t
+bmap_traditional(struct inode *inode, block_t block, size_t *nblocks)
 {
     struct fs_info *fs = inode->fs;
     const uint32_t addr_per_block = BLOCK_SIZE(fs) >> 2;
@@ -112,25 +153,26 @@ static block_t bmap_traditional(struct inode *inode, block_t block)
 
     /* direct blocks */
     if (block < direct_blocks)
-	return PVT(inode)->i_block[block];
+	return scan_set_nblocks(&PVT(inode)->i_block[block],
+				direct_blocks - block, nblocks);
 
     /* indirect blocks */
     block -= direct_blocks;
     if (block < indirect_blocks)
 	return bmap_indirect(fs, PVT(inode)->i_block[EXT2_IND_BLOCK],
-			     block, 1);
+			     block, 1, nblocks);
 
     /* double indirect blocks */
     block -= indirect_blocks;
     if (block < double_blocks)
 	return bmap_indirect(fs, PVT(inode)->i_block[EXT2_DIND_BLOCK],
-			     block, 2);
+			     block, 2, nblocks);
 
     /* triple indirect block */
     block -= double_blocks;
     if (block < triple_blocks)
 	return bmap_indirect(fs, PVT(inode)->i_block[EXT2_TIND_BLOCK],
-			     block, 3);
+			     block, 3, nblocks);
 
     /* This can't happen... */
     return 0;
@@ -142,20 +184,44 @@ static block_t bmap_traditional(struct inode *inode, block_t block)
  * In EXT4, there are two ways to handle the map process, extents and indirect.
  * EXT4 uses a inode flag to mark extent file and indirect block file.
  *
- * @fs:    the fs_info structure.
- * @inode: the inode structure.
- * @block: the logical block to be mapped.
- * @retrun: the physical block number.
+ * @fs:      the fs_info structure.
+ * @inode:   the inode structure.
+ * @block:   the logical block to be mapped.
+ * @nblocks: optional pointer to number of contiguous blocks (low estimate)
+ * @retrun:  the physical block number.
  *
  */
-block_t ext2_bmap(struct inode *inode, block_t block)
+block_t ext2_bmap(struct inode *inode, block_t block, size_t *nblocks)
 {
     block_t ret;
 
     if (inode->flags & EXT4_EXTENTS_FLAG)
-	ret = bmap_extent(inode, block);
+	ret = bmap_extent(inode, block, nblocks);
     else
-	ret = bmap_traditional(inode, block);
+	ret = bmap_traditional(inode, block, nblocks);
 
     return ret;
 }
+
+
+/*
+ * Next extent for getfssec
+ */
+void ext2_next_extent(struct inode *inode)
+{
+    struct fs_info *fs = inode->fs;
+    int blktosec =  BLOCK_SHIFT(fs) - SECTOR_SHIFT(fs);
+    int blkmask = (1 << blktosec) - 1;
+    block_t block;
+    size_t nblocks = 0;
+
+    block = ext2_bmap(inode, inode->next_extent.lstart >> blktosec, &nblocks);
+
+    if (!block)
+	inode->next_extent.pstart = EXTENT_ZERO;
+    else
+	inode->next_extent.pstart = ((sector_t)block << blktosec) |
+	    (inode->next_extent.lstart & blkmask);
+
+    inode->next_extent.len = nblocks << blktosec;
+}
diff --git a/core/fs/ext2/ext2.c b/core/fs/ext2/ext2.c
index 29d0371..f1853d3 100644
--- a/core/fs/ext2/ext2.c
+++ b/core/fs/ext2/ext2.c
@@ -12,8 +12,8 @@
 /*
  * get the group's descriptor of group_num
  */
-const struct ext2_group_desc *ext2_get_group_desc(struct fs_info *fs,
-						  uint32_t group_num)
+static const struct ext2_group_desc *
+ext2_get_group_desc(struct fs_info *fs, uint32_t group_num)
 {
     struct ext2_sb_info *sbi = EXT2_SB(fs);
     uint32_t desc_block, desc_index;
@@ -37,117 +37,6 @@ const struct ext2_group_desc *ext2_get_group_desc(struct fs_info *fs,
     return &desc_data_block[desc_index];
 }
 
-
-
-/**
- * linsector:
- *
- * Convert a linear sector index in a file to linear sector number
- *
- * well, alought this function converts a linear sector number to
- * physic sector number, it uses block cache in the implemention.
- *
- * @param: lin_sector, the lineral sector index
- *
- * @return: physic sector number
- */
-static sector_t linsector(struct inode *inode, uint32_t lin_sector)
-{
-    struct fs_info *fs = inode->fs;
-    int blk_bits = fs->block_shift - fs->sector_shift;
-    block_t block = ext2_bmap(inode, lin_sector >> blk_bits);
-
-    return (block << blk_bits) + (lin_sector & ((1 << blk_bits) - 1));
-}
-
-
-/**
- * getlinsec_ext:
- *
- * same as getlinsec, except load any sector from the zero
- * block as all zeros; use to load any data derived from
- * n ext2 block pointer, i.e. anything *except the superblock
- *
- */
-static void getlinsec_ext(struct fs_info *fs, char *buf,
-			  sector_t sector, int sector_cnt)
-{
-    int ext_cnt = 0;
-    int sec_per_block = 1 << (fs->block_shift - fs->sector_shift);
-    struct disk *disk = fs->fs_dev->disk;
-
-    if (sector < sec_per_block) {
-        ext_cnt = sec_per_block - sector;
-        memset(buf, 0, ext_cnt << fs->sector_shift);
-        buf += ext_cnt << fs->sector_shift;
-    }
-
-    sector += ext_cnt;
-    sector_cnt -= ext_cnt;
-    disk->rdwr_sectors(disk, buf, sector, sector_cnt, 0);
-}
-
-/*
- * Get multiple sectors from a file
- *
- * Alought we have made the buffer data based on block size,
- * we use sector for implemention; because reading multiple
- * sectors (then can be multiple blocks) is what the function
- * do. So, let it be based on sectors.
- *
- */
-static uint32_t ext2_getfssec(struct file *file, char *buf,
-			      int sectors, bool *have_more)
-{
-    struct inode *inode = file->inode;
-    struct fs_info *fs = file->fs;
-    int sector_left, next_sector, sector_idx;
-    int frag_start, con_sec_cnt;
-    int bytes_read = sectors << fs->sector_shift;
-    uint32_t bytesleft = inode->size - file->offset;
-
-    sector_left = (bytesleft + SECTOR_SIZE(fs) - 1) >> fs->sector_shift;
-    if (sectors > sector_left)
-        sectors = sector_left;
-
-    sector_idx = file->offset >> fs->sector_shift;
-    while (sectors) {
-        /*
-         * get the frament
-         */
-	next_sector = frag_start = linsector(inode, sector_idx);
-        con_sec_cnt = 0;
-
-        /* get the consective sectors count */
-        do {
-            con_sec_cnt++;
-            sectors--;
-            if (sectors <= 0)
-                break;
-
-            sector_idx++;
-            next_sector++;
-        } while (next_sector == linsector(inode, sector_idx));
-
-#if 0
-        printf("You are reading data stored at sector --0x%x--0x%x\n",
-               frag_start, frag_start + con_sec_cnt -1);
-#endif
-        getlinsec_ext(fs, buf, frag_start, con_sec_cnt);
-        buf += con_sec_cnt << fs->sector_shift;
-    } while(sectors);
-
-    if (bytes_read >= bytesleft) {
-        bytes_read = bytesleft;
-	*have_more = 0;
-    } else {
-        *have_more = 1;
-    }
-    file->offset += bytes_read;
-
-    return bytes_read;
-}
-
 /*
  * Unlike strncmp, ext2_match_entry returns 1 for success, 0 for failure.
  */
@@ -171,21 +60,29 @@ static inline struct ext2_dir_entry *ext2_next_entry(struct ext2_dir_entry *p)
 }
 
 /*
+ * Map a logical sector and load it into the cache
+ */
+static const void *
+ext2_get_cache(struct inode *inode, block_t lblock)
+{
+    block_t pblock = ext2_bmap(inode, lblock, NULL);
+    return get_cache(inode->fs->fs_dev, pblock);
+}
+
+/*
  * find a dir entry, return it if found, or return NULL.
  */
 static const struct ext2_dir_entry *
 ext2_find_entry(struct fs_info *fs, struct inode *inode, const char *dname)
 {
     block_t index = 0;
-    block_t block;
     uint32_t i = 0, offset, maxoffset;
     const struct ext2_dir_entry *de;
     const char *data;
     size_t dname_len = strlen(dname);
 
     while (i < inode->size) {
-	block = ext2_bmap(inode, index++);
-	data = get_cache(fs->fs_dev, block);
+	data = ext2_get_cache(inode, index++);
 	offset = 0;
 	maxoffset =  min(BLOCK_SIZE(fs), i-inode->size);
 
@@ -294,9 +191,7 @@ static struct inode *ext2_iget(const char *dname, struct inode *parent)
 static int cache_get_file(struct inode *inode, void *buf, size_t bytes)
 {
     struct fs_info *fs = inode->fs;
-    struct device *dev = fs->fs_dev;
     size_t block_size = BLOCK_SIZE(fs);
-    block_t block;
     uint32_t index = 0;		/* Logical block number */
     size_t chunk;
     const char *data;
@@ -307,8 +202,7 @@ static int cache_get_file(struct inode *inode, void *buf, size_t bytes)
 
     while (bytes) {
 	chunk = min(bytes, block_size);
-	block = ext2_bmap(inode, index++);
-	data = get_cache(dev, block);
+	data = ext2_get_cache(inode, index++);
 	memcpy(p, data, chunk);
 
 	bytes -= chunk;
@@ -318,7 +212,7 @@ static int cache_get_file(struct inode *inode, void *buf, size_t bytes)
     return 0;
 }
 	
-int ext2_readlink(struct inode *inode, char *buf)
+static int ext2_readlink(struct inode *inode, char *buf)
 {
     struct fs_info *fs = inode->fs;
     int sec_per_block = 1 << (fs->block_shift - fs->sector_shift);
@@ -347,14 +241,11 @@ static struct dirent *ext2_readdir(struct file *file)
     const struct ext2_dir_entry *de;
     const char *data;
     block_t index = file->offset >> fs->block_shift;
-    block_t block;
 
     if (file->offset >= inode->size)
 	return NULL;		/* End of file */
 
-    block = ext2_bmap(inode, index);
-
-    data = get_cache(fs->fs_dev, block);
+    data = ext2_get_cache(inode, index);
     de = (const struct ext2_dir_entry *)
 	(data + (file->offset & (BLOCK_SIZE(fs) - 1)));
 
@@ -434,7 +325,7 @@ const struct fs_ops ext2_fs_ops = {
     .fs_flags      = FS_THISIND | FS_USEMEM,
     .fs_init       = ext2_fs_init,
     .searchdir     = NULL,
-    .getfssec      = ext2_getfssec,
+    .getfssec      = generic_getfssec,
     .close_file    = generic_close_file,
     .mangle_name   = generic_mangle_name,
     .unmangle_name = generic_unmangle_name,
@@ -442,5 +333,6 @@ const struct fs_ops ext2_fs_ops = {
     .iget_root     = ext2_iget_root,
     .iget          = ext2_iget,
     .readlink      = ext2_readlink,
-    .readdir       = ext2_readdir
+    .readdir       = ext2_readdir,
+    .next_extent   = ext2_next_extent,
 };
diff --git a/core/fs/ext2/ext2_fs.h b/core/fs/ext2/ext2_fs.h
index 8d27609..f266091 100644
--- a/core/fs/ext2/ext2_fs.h
+++ b/core/fs/ext2/ext2_fs.h
@@ -304,6 +304,7 @@ struct ext2_pvt_inode {
 /*
  * functions
  */
-block_t ext2_bmap(struct inode *, block_t);
+block_t ext2_bmap(struct inode *, block_t, size_t *);
+void ext2_next_extent(struct inode *);
 
 #endif /* ext2_fs.h */



More information about the Syslinux-commits mailing list