[syslinux:pathbased] fat: use generic_getfssec(), fix generic_getfssec(), add dprintf

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


Commit-ID:  5143a9816e38bc518443392804d1d2ca80a225ab
Gitweb:     http://syslinux.zytor.com/commit/5143a9816e38bc518443392804d1d2ca80a225ab
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Fri, 26 Feb 2010 17:15:35 -0800
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Fri, 26 Feb 2010 17:15:35 -0800

fat: use generic_getfssec(), fix generic_getfssec(), add dprintf

Use generic_getfssec() for the FAT filesystem.  Do a bunch of
calculations based on clusters rather than on sectors, so we don't
have to do the same thing N times for N sectors per cluster.

Fix boundary conditions in generic_getfssec().  Adjust iso9660 to
match the resulting interface change.

Add dprintf's to generic_getfssec() and a few other routines.

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


---
 core/Makefile             |    2 +-
 core/fs/fat/fat.c         |  152 +++++++++++++++++++++------------------------
 core/fs/fat/fat_fs.h      |    6 +-
 core/fs/fs.c              |    4 +-
 core/fs/getfssec.c        |   76 ++++++++++++++++++-----
 core/fs/iso9660/iso9660.c |    4 +-
 core/include/fs.h         |    2 +-
 7 files changed, 141 insertions(+), 105 deletions(-)

diff --git a/core/Makefile b/core/Makefile
index a5d0fdd..b496433 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -58,7 +58,7 @@ NASMOPT  += $(NASMDEBUG)
 
 PREPCORE = ../lzo/prepcore
 
-# CFLAGS	+= -DDEBUG=1
+CFLAGS	+= -DDEBUG=1
 
 # The DATE is set on the make command line when building binaries for
 # official release.  Otherwise, substitute a hex string that is pretty much
diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c
index 03c6f05..3ea253d 100644
--- a/core/fs/fat/fat.c
+++ b/core/fs/fat/fat.c
@@ -29,7 +29,7 @@ static const void *get_fat_sector(struct fs_info *fs, sector_t sector)
 
 static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num)
 {
-    uint32_t next_cluster;
+    uint32_t next_cluster = 0;
     sector_t fat_sector;
     uint32_t offset;
     int lo, hi;
@@ -84,6 +84,70 @@ static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num)
     return next_cluster;
 }
 
+static void fat_next_extent(struct inode *inode)
+{
+    struct fs_info *fs = inode->fs;
+    struct fat_sb_info *sbi = FAT_SB(fs);
+    uint32_t mcluster = inode->next_extent.lstart >> sbi->clust_shift;
+    uint32_t lcluster;
+    uint32_t pcluster;
+    uint32_t tcluster;
+    uint32_t cluster_size = UINT32_C(1) << sbi->clust_shift;
+    sector_t data_area = sbi->data;
+
+    tcluster = (inode->size + cluster_size - 1) >> sbi->clust_shift;
+    if (mcluster >= tcluster)
+	goto err;		/* Requested cluster beyond end of file */
+
+    if (inode->prev_extent.len) {
+	if (inode->prev_extent.pstart < data_area)
+	    goto err;		/* Root directory has only one extent */
+	lcluster = (inode->prev_extent.lstart + inode->prev_extent.len)
+	    >> sbi->clust_shift;
+	pcluster = ((inode->prev_extent.pstart + inode->prev_extent.len
+		     - data_area) >> sbi->clust_shift) + 2;
+
+	if (lcluster > mcluster) {
+	    lcluster = 0;
+	    pcluster = PVT(inode)->start_cluster;
+	}
+    } else {
+	lcluster = 0;
+	pcluster = PVT(inode)->start_cluster;
+    }
+
+    for (;;) {
+	if (pcluster-2 >= sbi->clusters) {
+	    inode->size = lcluster << sbi->clust_shift;
+	    goto err;
+	}
+
+	if (lcluster >= mcluster)
+	    break;
+
+	lcluster++;
+	pcluster = get_next_cluster(fs, pcluster);
+    }
+
+    inode->next_extent.pstart =
+	((sector_t)(pcluster-2) << sbi->clust_shift) + data_area;
+    inode->next_extent.len = cluster_size;
+    lcluster++;
+
+    while (lcluster < tcluster) {
+	uint32_t xcluster;
+	xcluster = get_next_cluster(fs, pcluster);
+	if (xcluster != pcluster+1)
+	    break;		/* Not contiguous */
+	pcluster = xcluster;
+	inode->next_extent.len += cluster_size;
+	lcluster++;
+    }
+
+    /* In the case of error, the caller has already set next_extent.len = 0 */
+err:
+    return;
+}
 
 static sector_t get_next_sector(struct fs_info* fs, uint32_t sector)
 {
@@ -165,86 +229,6 @@ static sector_t next_sector(struct file *file)
     return sector;
 }
 
-/**
- * __getfssec:
- *
- * get multiple sectors from a file
- *
- * This routine makes sure the subransfers do not cross a 64K boundary
- * and will correct the situation if it does, UNLESS *sectos* cross
- * 64K boundaries.
- *
- */
-static void __getfssec(struct fs_info *fs, char *buf,
-                       struct file *file, uint32_t sectors)
-{
-    sector_t curr_sector = get_the_right_sector(file);
-    sector_t frag_start , next_sector;
-    uint32_t con_sec_cnt;
-    struct disk *disk = fs->fs_dev->disk;
-
-    while (sectors) {
-        /* get fragment */
-        con_sec_cnt = 0;
-        frag_start = curr_sector;
-
-        do {
-            /* get consective sector  count */
-            con_sec_cnt++;
-            sectors--;
-            next_sector = get_next_sector(fs, curr_sector);
-	    curr_sector++;
-        } while (sectors && next_sector == curr_sector);
-
-	PVT(file->inode)->offset += con_sec_cnt;
-	PVT(file->inode)->here    = next_sector;
-
-        /* do read */
-        disk->rdwr_sectors(disk, buf, frag_start, con_sec_cnt, 0);
-        buf += con_sec_cnt << SECTOR_SHIFT(fs);/* adjust buffer pointer */
-
-        curr_sector = next_sector;
-    }
-}
-
-
-
-/**
- * get multiple sectors from a file
- *
- * @param: buf, the buffer to store the read data
- * @param: file, the file structure pointer
- * @param: sectors, number of sectors wanna read
- * @param: have_more, set one if has more
- *
- * @return: number of bytes read
- *
- */
-static uint32_t vfat_getfssec(struct file *file, char *buf, int sectors,
-			      bool *have_more)
-{
-    struct fs_info *fs = file->fs;
-    uint32_t bytes_left = file->inode->size - file->offset;
-    uint32_t bytes_read = sectors << fs->sector_shift;
-    int sector_left;
-
-    sector_left = (bytes_left + SECTOR_SIZE(fs) - 1) >> fs->sector_shift;
-    if (sectors > sector_left)
-        sectors = sector_left;
-
-    __getfssec(fs, buf, file, sectors);
-
-    if (bytes_read >= bytes_left) {
-        bytes_read = bytes_left;
-        *have_more = 0;
-    } else {
-        *have_more = 1;
-    }
-    file->offset += bytes_read;
-
-    return bytes_read;
-}
-
 /*
  * Mangle a filename pointed to by src into a buffer pointed to by dst;
  * ends on encountering any whitespace.
@@ -555,6 +539,8 @@ static struct inode *vfat_find_entry(const char *dname, struct inode *dir)
 found:
     inode = new_fat_inode(fs);
     inode->size = de->file_size;
+    PVT(inode)->start_cluster = 
+	(de->first_cluster_high << 16) + de->first_cluster_low;
     PVT(inode)->start = PVT(inode)->here = first_sector(fs, de);
     inode->mode = get_inode_mode(de->attr);
 
@@ -570,6 +556,7 @@ static struct inode *vfat_iget_root(struct fs_info *fs)
      * For FAT32, the only way to get the root directory size is to
      * follow the entire FAT chain to the end... which seems pointless.
      */
+    PVT(inode)->start_cluster = FAT_SB(fs)->root_cluster;
     inode->size = root_size ? root_size << fs->sector_shift : ~0;
     PVT(inode)->start = PVT(inode)->here = FAT_SB(fs)->root;
     inode->mode = I_DIR;
@@ -835,7 +822,7 @@ const struct fs_ops vfat_fs_ops = {
     .fs_flags      = FS_USEMEM | FS_THISIND,
     .fs_init       = vfat_fs_init,
     .searchdir     = NULL,
-    .getfssec      = vfat_getfssec,
+    .getfssec      = generic_getfssec,
     .close_file    = generic_close_file,
     .mangle_name   = vfat_mangle_name,
     .unmangle_name = generic_unmangle_name,
@@ -843,4 +830,5 @@ const struct fs_ops vfat_fs_ops = {
     .readdir       = vfat_readdir,
     .iget_root     = vfat_iget_root,
     .iget          = vfat_iget,
+    .next_extent   = fat_next_extent,
 };
diff --git a/core/fs/fat/fat_fs.h b/core/fs/fat/fat_fs.h
index 60b5aee..7ea3db8 100644
--- a/core/fs/fat/fat_fs.h
+++ b/core/fs/fat/fat_fs.h
@@ -89,11 +89,12 @@ struct fat_sb_info {
 	sector_t data;            /* The data region */
 
 	uint32_t clusters;	  /* Total number of clusters */
-	int      root_size;       /* The root dir size in sectores */
+	uint32_t root_cluster;	  /* Cluster number for (FAT32) root dir */
+	int      root_size;       /* The root dir size in sectors */
 	
 	int      clust_shift;      /* based on sectors */
 	int      clust_byte_shift; /* based on bytes   */
-	int      clust_mask;
+	int      clust_mask;	   /* sectors per cluster mask */
 	int      clust_size;
 
 	int      fat_type;
@@ -146,6 +147,7 @@ static inline int root_dir_size(struct fs_info *fs, struct fat_bpb *fat)
  * FAT private inode information
  */
 struct fat_pvt_inode {
+    uint32_t start_cluster;	/* Starting cluster address */
     sector_t start;		/* Starting sector */
     sector_t offset;		/* Current sector offset */
     sector_t here;		/* Sector corresponding to offset */
diff --git a/core/fs/fs.c b/core/fs/fs.c
index fc7948d..94ee0c9 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -198,7 +198,6 @@ int searchdir(const char *name)
 	    goto err;
     }
 
-
     /* else, try the generic-path-lookup method */
 
     parent = get_inode(this_fs->cwd);
@@ -297,6 +296,9 @@ int searchdir(const char *name)
     file->offset = 0;
     file->file_len  = inode->size;
 
+    dprintf("File %s -> %p (inode %p) len %u\n", name, file,
+	    inode, inode->size);
+
     return file_to_handle(file);
 
 err:
diff --git a/core/fs/getfssec.c b/core/fs/getfssec.c
index e8ae62f..80923c1 100644
--- a/core/fs/getfssec.c
+++ b/core/fs/getfssec.c
@@ -29,9 +29,9 @@
  * getfssec.c
  *
  * Generic getfssec implementation for disk-based filesystems, which
- * support the populate_next_extent method.
+ * support the next_extent() method.
  *
- * The expected semantics of populate_next_extent are as follows:
+ * The expected semantics of next_extent are as follows:
  *
  * inode->next_extent.lstart will contain the initial sector number to
  * be mapped.  The routine is expected to populate inode->next_extent.pstart
@@ -41,14 +41,15 @@
  *
  * If the filesystem can map the entire file as a single extent
  * (e.g. iso9660), then the filesystem can simply insert the extent
- * information into inode->prev_extent at searchdir/iget time, and leave
- * populate_next_extent as NULL.
+ * information into inode->next_extent at searchdir/iget time, and leave
+ * next_extent() as NULL.
  *
  * Note: the filesystem driver is not required to do extent coalescing,
  * if that is difficult to do; this routine will perform extent lookahead
  * and coalescing.
  */
 
+#include <dprintf.h>
 #include <minmax.h>
 #include "fs.h"
 
@@ -65,6 +66,28 @@ static inline sector_t next_pstart(const struct extent *e)
     return next_psector(e->pstart, e->len);
 }
 
+
+static void get_next_extent(struct inode *inode)
+{
+    /* The logical start address that we care about... */
+
+    inode->next_extent.lstart =
+	inode->this_extent.lstart + inode->this_extent.len;
+    dprintf("next_extent.lstart = %u\n", inode->next_extent.lstart);
+
+    /* Whatever we had before... */
+    inode->prev_extent = inode->next_extent;
+
+    /* Dummy information to make failure returns easier */
+    inode->next_extent.len = 0;
+    
+    inode->fs->fs_ops->next_extent(inode);
+
+    dprintf("Extent: inode %p @ %u start %llu len %u\n",
+	    inode, inode->next_extent.lstart,
+	    inode->next_extent.pstart, inode->next_extent.len);
+}
+
 uint32_t generic_getfssec(struct file *file, char *buf,
 			  int sectors, bool *have_more)
 {
@@ -80,19 +103,23 @@ uint32_t generic_getfssec(struct file *file, char *buf,
     if (sectors > sectors_left)
 	sectors = sectors_left;
 
+    if (!sectors)
+	return 0;
+
     lsector = file->offset >> SECTOR_SHIFT(fs);
+    dprintf("Offset: %u  lsector: %u\n", file->offset, lsector);
 
     if (lsector < inode->this_extent.lstart ||
 	lsector >= inode->this_extent.lstart + inode->this_extent.len) {
-	/* inode->this_extent unusable, maybe prev_extent is... */
-	inode->this_extent = inode->prev_extent;
+	/* inode->this_extent unusable, maybe next_extent is... */
+	inode->this_extent = inode->next_extent;
     }
 
     if (lsector < inode->this_extent.lstart ||
 	lsector >= inode->this_extent.lstart + inode->this_extent.len) {
 	/* Still nothing useful... */
 	inode->this_extent.lstart = lsector;
-	inode->this_extent.len    = 0;
+	inode->this_extent.len = 0;
     } else {
 	/* We have some usable information */
 	uint32_t delta = lsector - inode->this_extent.lstart;
@@ -102,22 +129,30 @@ uint32_t generic_getfssec(struct file *file, char *buf,
 	    = next_psector(inode->this_extent.pstart, delta);
     }
 
+    dprintf("this_extent: lstart %u pstart %llu len %u\n",
+	    inode->this_extent.lstart,
+	    inode->this_extent.pstart,
+	    inode->this_extent.len);
+
+    if (inode->this_extent.len < sectors &&
+	(!inode->next_extent.len ||
+	 inode->next_extent.lstart !=
+	 inode->this_extent.lstart + inode->this_extent.len)) {
+	get_next_extent(inode);
+    }
+
     while (sectors) {
 	uint32_t chunk;
 	size_t len;
 
-	if (!inode->this_extent.len && inode->next_extent.len &&
-	    inode->this_extent.lstart == inode->next_extent.lstart)
+	if (!inode->this_extent.len) {
 	    inode->this_extent = inode->next_extent;
+	    if (!inode->next_extent.len)
+		break;		/* Can't read anything more */
+	}
 
 	while (sectors > inode->this_extent.len) {
-	    /* Whatever we had before... */
-	    inode->prev_extent = inode->next_extent;
-
-	    /* Dummy information to make failure returns easier */
-	    inode->next_extent.len = 0;
-
-	    fs->fs_ops->populate_next_extent(inode);
+	    get_next_extent(inode);
 
 	    if (inode->next_extent.len &&
 		inode->next_extent.pstart == next_pstart(&inode->this_extent)) {
@@ -129,9 +164,18 @@ uint32_t generic_getfssec(struct file *file, char *buf,
 	    }
 	}
 
+	dprintf("this_extent: lstart %u pstart %llu len %u\n",
+		inode->this_extent.lstart,
+		inode->this_extent.pstart,
+		inode->this_extent.len);
+
 	chunk = min(sectors, inode->this_extent.len);
 	len = chunk << SECTOR_SHIFT(fs);
 
+	dprintf("   I/O: inode %p @ %u start %llu len %u\n",
+		inode, inode->this_extent.lstart,
+		inode->this_extent.pstart, chunk);
+
 	if (inode->this_extent.pstart == EXTENT_ZERO) {
 	    memset(buf, 0, len);
 	} else {
diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c
index 995cd21..41c27ec 100644
--- a/core/fs/iso9660/iso9660.c
+++ b/core/fs/iso9660/iso9660.c
@@ -209,8 +209,8 @@ static struct inode *iso_get_inode(struct fs_info *fs,
     inode->blocks = (inode->size + BLOCK_SIZE(fs) - 1) >> BLOCK_SHIFT(fs);
 
     /* We have a single extent for all data */
-    inode->prev_extent.pstart = de->extent_le << blktosec;
-    inode->prev_extent.len = inode->blocks << blktosec;
+    inode->next_extent.pstart = de->extent_le << blktosec;
+    inode->next_extent.len = inode->blocks << blktosec;
 
     return inode;
 }
diff --git a/core/include/fs.h b/core/include/fs.h
index 1870de7..79499d8 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -70,7 +70,7 @@ struct fs_ops {
     /* the _dir_ stuff */
     struct dirent * (*readdir)(struct file *);
 
-    void     (*populate_next_extent)(struct inode *);
+    void     (*next_extent)(struct inode *);
 };
 
 enum inode_mode {I_FILE, I_DIR, I_SYMLINK};



More information about the Syslinux-commits mailing list