diff options
author | H. Peter Anvin <hpa@zytor.com> | 2010-02-26 17:15:35 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-02-26 17:15:35 -0800 |
commit | 5143a9816e38bc518443392804d1d2ca80a225ab (patch) | |
tree | 310893fdd6f3bae410a1e0580e314d388f8054e3 | |
parent | 3e89b30bfa7b90d785d8f97ea5638a7b63e12c94 (diff) | |
download | syslinux-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/Makefile | 2 | ||||
-rw-r--r-- | core/fs/fat/fat.c | 152 | ||||
-rw-r--r-- | core/fs/fat/fat_fs.h | 6 | ||||
-rw-r--r-- | core/fs/fs.c | 4 | ||||
-rw-r--r-- | core/fs/getfssec.c | 76 | ||||
-rw-r--r-- | core/fs/iso9660/iso9660.c | 4 | ||||
-rw-r--r-- | core/include/fs.h | 2 |
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}; |