[syslinux:pathbased] fs: add generic getfssec

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


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

fs: add generic getfssec

Add a generic getfssec method which operate on cached extents. This
should avoid the need to each filesystem to implement its own getfssec
loop.

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


---
 core/fs/getfssec.c |  156 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 core/include/fs.h  |   27 ++++++++-
 2 files changed, 181 insertions(+), 2 deletions(-)

diff --git a/core/fs/getfssec.c b/core/fs/getfssec.c
new file mode 100644
index 0000000..e8ae62f
--- /dev/null
+++ b/core/fs/getfssec.c
@@ -0,0 +1,156 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2010 Intel Corporation; author: H. Peter Anvin
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * getfssec.c
+ *
+ * Generic getfssec implementation for disk-based filesystems, which
+ * support the populate_next_extent method.
+ *
+ * The expected semantics of populate_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
+ * and inode->next_extent.len.  If inode->prev_extent.pstart != EXTENT_VOID
+ * then the routine is allowed to assume inode->prev_extent contains valid
+ * data.
+ *
+ * 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.
+ *
+ * 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 <minmax.h>
+#include "fs.h"
+
+static inline sector_t next_psector(sector_t psector, uint32_t skip)
+{
+    if (EXTENT_SPECIAL(psector))
+	return psector;
+    else
+	return psector + skip;
+}
+
+static inline sector_t next_pstart(const struct extent *e)
+{
+    return next_psector(e->pstart, e->len);
+}
+
+uint32_t generic_getfssec(struct file *file, char *buf,
+			  int sectors, bool *have_more)
+{
+    struct inode *inode = file->inode;
+    struct fs_info *fs = file->fs;
+    struct disk *disk = fs->fs_dev->disk;
+    uint32_t bytes_read = 0;
+    uint32_t bytes_left = inode->size - file->offset;
+    uint32_t sectors_left =
+	(bytes_left + SECTOR_SIZE(fs) - 1) >> SECTOR_SHIFT(fs);
+    uint32_t lsector;
+
+    if (sectors > sectors_left)
+	sectors = sectors_left;
+
+    lsector = file->offset >> SECTOR_SHIFT(fs);
+
+    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;
+    }
+
+    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;
+    } else {
+	/* We have some usable information */
+	uint32_t delta = lsector - inode->this_extent.lstart;
+	inode->this_extent.lstart = lsector;
+	inode->this_extent.len -= delta;
+	inode->this_extent.pstart
+	    = next_psector(inode->this_extent.pstart, delta);
+    }
+
+    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)
+	    inode->this_extent = inode->next_extent;
+
+	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);
+
+	    if (inode->next_extent.len &&
+		inode->next_extent.pstart == next_pstart(&inode->this_extent)) {
+		/* Coalesce extents and loop */
+		inode->this_extent.len += inode->next_extent.len;
+	    } else {
+		/* Discontiguous extents */
+		break;
+	    }
+	}
+
+	chunk = min(sectors, inode->this_extent.len);
+	len = chunk << SECTOR_SHIFT(fs);
+
+	if (inode->this_extent.pstart == EXTENT_ZERO) {
+	    memset(buf, 0, len);
+	} else {
+	    disk->rdwr_sectors(disk, buf, inode->this_extent.pstart, chunk, 0);
+	    inode->this_extent.pstart += chunk;
+	}
+
+	buf += len;
+	sectors -= chunk;
+	bytes_read += len;
+	inode->this_extent.lstart += chunk;
+	inode->this_extent.len -= chunk;
+    }
+
+    bytes_read = min(bytes_read, bytes_left);
+    file->offset += bytes_read;
+
+    if (have_more)
+	*have_more = bytes_read < bytes_left;
+
+    return bytes_read;
+}
diff --git a/core/include/fs.h b/core/include/fs.h
index 25219d9..1870de7 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -69,10 +69,28 @@ struct fs_ops {
 
     /* the _dir_ stuff */
     struct dirent * (*readdir)(struct file *);
+
+    void     (*populate_next_extent)(struct inode *);
 };
 
 enum inode_mode {I_FILE, I_DIR, I_SYMLINK};
 
+/*
+ * Extent structure: contains the mapping of some chunk of a file
+ * that is contiguous on disk.
+ */
+struct extent {
+    sector_t	pstart;		/* Physical start sector */
+    uint32_t	lstart;		/* Logical start sector */
+    uint32_t	len;		/* Number of contiguous sectors */
+};
+
+/* Special sector numbers used for struct extent.pstart */
+#define EXTENT_ZERO	((sector_t)-1) /* All-zero extent */
+#define EXTENT_VOID	((sector_t)-2) /* Invalid information */
+
+#define EXTENT_SPECIAL(x)	((x) >= EXTENT_VOID)
+
 /* 
  * The inode structure, including the detail file information 
  */
@@ -81,14 +99,15 @@ struct inode {
     int		 refcnt;
     int          mode;   /* FILE , DIR or SYMLINK */
     uint32_t     size;
+    uint32_t	 blocks; /* How many blocks the file take */
     uint32_t     ino;    /* Inode number */
     uint32_t     atime;  /* Access time */
     uint32_t     mtime;  /* Modify time */
     uint32_t     ctime;  /* Create time */
     uint32_t     dtime;  /* Delete time */
-    int          blocks; /* How many blocks the file take */
     uint32_t     flags;
     uint32_t     file_acl;
+    struct extent this_extent, prev_extent, next_extent;
     char         pvt[0]; /* Private filesystem data */
 };
 
@@ -104,7 +123,7 @@ struct file {
 	    uint32_t offset;            /* for next read */
 	};
 
-	/* For the old searhdir method */
+	/* For the old searchdir method */
 	struct {
 	    struct open_file_t *open_file;/* The fs-specific open file struct */
 	};
@@ -208,4 +227,8 @@ int generic_load_config(void);
 /* close.c */
 void generic_close_file(struct file *file);
 
+/* getfssec.c */
+uint32_t generic_getfssec(struct file *file, char *buf,
+			  int sectors, bool *have_more);
+
 #endif /* FS_H */



More information about the Syslinux-commits mailing list