summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2010-02-26 17:15:35 -0800
committerH. Peter Anvin <hpa@zytor.com>2010-02-26 17:15:35 -0800
commit5143a9816e38bc518443392804d1d2ca80a225ab (patch)
tree310893fdd6f3bae410a1e0580e314d388f8054e3
parent3e89b30bfa7b90d785d8f97ea5638a7b63e12c94 (diff)
downloadsyslinux-5143a9816e38bc518443392804d1d2ca80a225ab.tar.gz
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@zytor.com>
-rw-r--r--core/Makefile2
-rw-r--r--core/fs/fat/fat.c152
-rw-r--r--core/fs/fat/fat_fs.h6
-rw-r--r--core/fs/fs.c4
-rw-r--r--core/fs/getfssec.c76
-rw-r--r--core/fs/iso9660/iso9660.c4
-rw-r--r--core/include/fs.h2
7 files changed, 141 insertions, 105 deletions
diff --git a/core/Makefile b/core/Makefile
index a5d0fdd5..b4964339 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 03c6f05c..3ea253d3 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 60b5aee1..7ea3db85 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 fc7948d0..94ee0c97 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 e8ae62f4..80923c1c 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 995cd21f..41c27ec7 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 1870de79..79499d80 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};