[syslinux:elflink] xfs: Add cache for directory blocks

syslinux-bot for Paulo Alcantara pcacjr at zytor.com
Thu Jan 24 09:45:07 PST 2013


Commit-ID:  90f5f81712b93a73b55a6baf7223e100753da73c
Gitweb:     http://www.syslinux.org/commit/90f5f81712b93a73b55a6baf7223e100753da73c
Author:     Paulo Alcantara <pcacjr at zytor.com>
AuthorDate: Mon, 21 Jan 2013 23:37:16 -0200
Committer:  Paulo Alcantara <pcacjr at zytor.com>
CommitDate: Mon, 21 Jan 2013 23:53:12 -0200

xfs: Add cache for directory blocks

This cache will avoid lots of malloc() and free() calls for getting an
allocated area for directory blocks whenever listing and finding
directory entries.

Signed-off-by: Paulo Alcantara <pcacjr at zytor.com>

---
 core/fs/xfs/xfs.c         |   5 +-
 core/fs/xfs/xfs.h         |  14 ++---
 core/fs/xfs/xfs_dir2.c    | 129 ++++++++++++++++++++++++++++++++++------------
 core/fs/xfs/xfs_dir2.h    |   4 +-
 core/fs/xfs/xfs_readdir.c |  37 +++++--------
 5 files changed, 118 insertions(+), 71 deletions(-)

diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
index 60a67f5..712888c 100644
--- a/core/fs/xfs/xfs.c
+++ b/core/fs/xfs/xfs.c
@@ -265,7 +265,7 @@ static int xfs_readlink(struct inode *inode, char *buf)
     int pathlen = -1;
     xfs_bmbt_irec_t rec;
     block_t db;
-    char *dir_buf;
+    const char *dir_buf;
 
     xfs_debug("inode %p buf %p", inode, buf);
 
@@ -290,7 +290,7 @@ static int xfs_readlink(struct inode *inode, char *buf)
     } else if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
 	bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
 	db = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
-	dir_buf = xfs_dir2_get_dirblks(fs, db, rec.br_blockcount);
+	dir_buf = xfs_dir2_dirblks_get_cached(fs, db, rec.br_blockcount);
 
         /*
          * Syslinux only supports filesystem block size larger than or equal to
@@ -298,7 +298,6 @@ static int xfs_readlink(struct inode *inode, char *buf)
 	 * symbolic link file content, which is only 1024 bytes long.
          */
 	memcpy(buf, dir_buf, pathlen);
-	free(dir_buf);
     }
 
 out:
diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h
index 11e8634..0d953d8 100644
--- a/core/fs/xfs/xfs.h
+++ b/core/fs/xfs/xfs.h
@@ -30,15 +30,15 @@
 #include "xfs_types.h"
 #include "xfs_ag.h"
 
-#define xfs_error(fmt, args...)                                               \
-    ({                                                                        \
-       printf("%s:%u: xfs - [ERROR] " fmt "\n", __func__, __LINE__, ## args); \
+#define xfs_error(fmt, args...)						\
+    ({									\
+	printf("%s:%u: xfs - [ERROR] " fmt "\n", __func__, __LINE__, ## args); \
     })
 
-#define xfs_debug(fmt, args...)                                       \
-    ({                                                                \
-	dprintf("%s:%u: xfs - [DEBUG] " fmt "\n", __func__, __LINE__, \
-		## args);					      \
+#define xfs_debug(fmt, args...)						\
+    ({									\
+	dprintf("%s:%u: xfs - [DEBUG] " fmt "\n", __func__, __LINE__,	\
+		## args);						\
     })
 
 struct xfs_fs_info;
diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c
index d833c25..81b8c24 100644
--- a/core/fs/xfs/xfs_dir2.c
+++ b/core/fs/xfs/xfs_dir2.c
@@ -28,6 +28,17 @@
 
 #include "xfs_dir2.h"
 
+#define XFS_DIR2_DIRBLKS_CACHE_SIZE 128
+
+struct xfs_dir2_dirblks_cache {
+    block_t        dc_startblock;
+    xfs_filblks_t  dc_blkscount;
+    void          *dc_area;
+};
+
+static struct xfs_dir2_dirblks_cache dirblks_cache[XFS_DIR2_DIRBLKS_CACHE_SIZE];
+static unsigned char                 dirblks_cached_count = 0;
+
 uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen)
 {
     uint32_t hash;
@@ -55,8 +66,8 @@ uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen)
     }
 }
 
-void *xfs_dir2_get_dirblks(struct fs_info *fs, block_t startblock,
-			   xfs_filblks_t c)
+static void *get_dirblks(struct fs_info *fs, block_t startblock,
+			 xfs_filblks_t c)
 {
     int count = c << XFS_INFO(fs)->dirblklog;
     uint8_t *p;
@@ -78,6 +89,73 @@ void *xfs_dir2_get_dirblks(struct fs_info *fs, block_t startblock,
     return buf;
 }
 
+const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock,
+					xfs_filblks_t c)
+{
+    unsigned char i;
+    void *buf;
+
+    xfs_debug("fs %p startblock %llu (0x%llx) blkscount %lu", fs, startblock,
+	      startblock, c);
+
+    if (!dirblks_cached_count) {
+	buf = get_dirblks(fs, startblock, c);
+
+	dirblks_cache[dirblks_cached_count].dc_startblock = startblock;
+	dirblks_cache[dirblks_cached_count].dc_blkscount = c;
+	dirblks_cache[dirblks_cached_count].dc_area = buf;
+
+	return dirblks_cache[dirblks_cached_count++].dc_area;
+    } else if (dirblks_cached_count == XFS_DIR2_DIRBLKS_CACHE_SIZE) {
+	for (i = 0; i < XFS_DIR2_DIRBLKS_CACHE_SIZE / 2; i++) {
+	    unsigned char k = XFS_DIR2_DIRBLKS_CACHE_SIZE - (i + 1);
+
+	    free(dirblks_cache[i].dc_area);
+	    dirblks_cache[i] = dirblks_cache[k];
+	    memset(&dirblks_cache[k], 0, sizeof(dirblks_cache[k]));
+	}
+
+	buf = get_dirblks(fs, startblock, c);
+
+	dirblks_cache[XFS_DIR2_DIRBLKS_CACHE_SIZE / 2].dc_startblock =
+	    startblock;
+	dirblks_cache[XFS_DIR2_DIRBLKS_CACHE_SIZE / 2].dc_blkscount = c;
+	dirblks_cache[XFS_DIR2_DIRBLKS_CACHE_SIZE / 2].dc_area = buf;
+
+	dirblks_cached_count = XFS_DIR2_DIRBLKS_CACHE_SIZE / 2;
+
+	return dirblks_cache[dirblks_cached_count++].dc_area;
+    } else {
+	block_t block;
+	xfs_filblks_t count;
+
+	block = dirblks_cache[dirblks_cached_count - 1].dc_startblock;
+	count = dirblks_cache[dirblks_cached_count - 1].dc_blkscount;
+
+	if (block == startblock && count == c) {
+	    return dirblks_cache[dirblks_cached_count - 1].dc_area;
+	} else {
+	    for (i = 0; i < dirblks_cached_count; i++) {
+		block = dirblks_cache[i].dc_startblock;
+		count = dirblks_cache[i].dc_blkscount;
+
+		if (block == startblock && count == c)
+		    return dirblks_cache[i].dc_area;
+	    }
+
+	    buf = get_dirblks(fs, startblock, c);
+
+	    dirblks_cache[dirblks_cached_count].dc_startblock = startblock;
+	    dirblks_cache[dirblks_cached_count].dc_blkscount = c;
+	    dirblks_cache[dirblks_cached_count].dc_area = buf;
+
+	    return dirblks_cache[dirblks_cached_count++].dc_area;
+	}
+    }
+
+    return NULL;
+}
+
 struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
 					xfs_dinode_t *core)
 {
@@ -160,7 +238,7 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
     xfs_bmbt_irec_t r;
     block_t dir_blk;
     struct fs_info *fs = parent->fs;
-    uint8_t *dirblk_buf;
+    const uint8_t *dirblk_buf;
     uint8_t *p, *endp;
     xfs_dir2_data_hdr_t *hdr;
     struct inode *inode = NULL;
@@ -175,7 +253,7 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
     bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
     dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
 
-    dirblk_buf = xfs_dir2_get_dirblks(fs, dir_blk, r.br_blockcount);
+    dirblk_buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, r.br_blockcount);
     hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
     if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
         xfs_error("Block directory header's magic number does not match!");
@@ -212,8 +290,6 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
     }
 
 out:
-    free(dirblk_buf);
-
     return NULL;
 
 found:
@@ -249,12 +325,10 @@ found:
 
     xfs_debug("entry inode's number %lu", ino);
 
-    free(dirblk_buf);
     return inode;
 
 failed:
     free(inode);
-    free(dirblk_buf);
 
     return NULL;
 }
@@ -279,7 +353,7 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
     uint8_t *end_name;
     xfs_intino_t ino;
     xfs_dinode_t *ncore;
-    uint8_t *buf = NULL;
+    const uint8_t *buf = NULL;
 
     xfs_debug("dname %s parent %p core %p", dname, parent, core);
 
@@ -288,8 +362,8 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
     leaf_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
 	    BLOCK_SHIFT(parent->fs);
 
-    leaf = (xfs_dir2_leaf_t *)xfs_dir2_get_dirblks(parent->fs, leaf_blk,
-						   irec.br_blockcount);
+    leaf = (xfs_dir2_leaf_t *)xfs_dir2_dirblks_get_cached(parent->fs, leaf_blk,
+							  irec.br_blockcount);
     if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
         xfs_error("Single leaf block header's magic number does not match!");
         goto out;
@@ -331,18 +405,16 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
 
         newdb = xfs_dir2_dataptr_to_db(parent->fs, be32_to_cpu(lep->address));
         if (newdb != curdb) {
-            if (buf)
-                free(buf);
-
             bmbt_irec_get(&irec,
 		  ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + newdb);
             dir_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
+
 		      BLOCK_SHIFT(parent->fs);
-            buf = xfs_dir2_get_dirblks(parent->fs, dir_blk, irec.br_blockcount);
+            buf = xfs_dir2_dirblks_get_cached(parent->fs, dir_blk, irec.br_blockcount);
             data_hdr = (xfs_dir2_data_hdr_t *)buf;
             if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
                 xfs_error("Leaf directory's data magic No. does not match!");
-                goto out1;
+                goto out;
             }
 
             curdb = newdb;
@@ -360,8 +432,6 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
         }
     }
 
-out1:
-    free(buf);
 out:
     free(leaf);
 
@@ -401,14 +471,12 @@ found:
 
     xfs_debug("entry inode's number %lu", ino);
 
-    free(buf);
     free(leaf);
 
     return ip;
 
 failed:
     free(ip);
-    free(buf);
     free(leaf);
 
     return ip;
@@ -539,7 +607,7 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
     uint32_t newdb, curdb = -1;
     xfs_intino_t ino;
     xfs_dinode_t *ncore;
-    uint8_t *buf = NULL;
+    const uint8_t *buf = NULL;
 
     xfs_debug("dname %s parent %p core %p", dname, parent, core);
 
@@ -553,7 +621,8 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
         return NULL;
     }
 
-    node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(parent->fs, fsblkno, 1);
+    node = (xfs_da_intnode_t *)xfs_dir2_dirblks_get_cached(parent->fs, fsblkno,
+							   1);
     if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
         xfs_error("Node's magic number does not match!");
         goto out;
@@ -605,8 +674,8 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
         }
 
         free(node);
-        node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(parent->fs,
-                                                        fsblkno, 1);
+        node = (xfs_da_intnode_t *)xfs_dir2_dirblks_get_cached(parent->fs,
+							       fsblkno, 1);
     } while(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
 
     leaf = (xfs_dir2_leaf_t*)node;
@@ -649,20 +718,17 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
 
         newdb = xfs_dir2_dataptr_to_db(parent->fs, be32_to_cpu(lep->address));
         if (newdb != curdb) {
-            if (buf)
-                free(buf);
-
             fsblkno = xfs_dir2_get_right_blk(parent->fs, core, newdb, &error);
             if (error) {
                 xfs_error("Cannot find data block!");
                 goto out;
             }
 
-            buf = xfs_dir2_get_dirblks(parent->fs, fsblkno, 1);
+            buf = xfs_dir2_dirblks_get_cached(parent->fs, fsblkno, 1);
             data_hdr = (xfs_dir2_data_hdr_t *)buf;
             if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
                 xfs_error("Leaf directory's data magic No. does not match!");
-                goto out1;
+                goto out;
             }
 
             curdb = newdb;
@@ -680,9 +746,6 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
         }
     }
 
-out1:
-    free(buf);
-
 out:
     free(node);
 
@@ -717,14 +780,12 @@ found:
 
     xfs_debug("entry inode's number %lu", ino);
 
-    free(buf);
     free(node);
 
     return ip;
 
 failed:
     free(ip);
-    free(buf);
     free(node);
 
     return NULL;
diff --git a/core/fs/xfs/xfs_dir2.h b/core/fs/xfs/xfs_dir2.h
index fa403f3..9c2785f 100644
--- a/core/fs/xfs/xfs_dir2.h
+++ b/core/fs/xfs/xfs_dir2.h
@@ -23,8 +23,8 @@
 
 #include "xfs.h"
 
-void *xfs_dir2_get_dirblks(struct fs_info *fs, block_t startblock,
-			   xfs_filblks_t c);
+const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock,
+					xfs_filblks_t c);
 uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen);
 block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
 			       block_t fsblkno, int *error);
diff --git a/core/fs/xfs/xfs_readdir.c b/core/fs/xfs/xfs_readdir.c
index bbfc026..e99ea71 100644
--- a/core/fs/xfs/xfs_readdir.c
+++ b/core/fs/xfs/xfs_readdir.c
@@ -120,7 +120,7 @@ int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
     xfs_bmbt_irec_t r;
     block_t dir_blk;
     struct fs_info *fs = file->fs;
-    uint8_t *dirblk_buf;
+    const uint8_t *dirblk_buf;
     uint8_t *p;
     uint32_t offset;
     xfs_dir2_data_hdr_t *hdr;
@@ -137,14 +137,11 @@ int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
     bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
     dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
 
-    dirblk_buf = xfs_dir2_get_dirblks(fs, dir_blk, r.br_blockcount);
+    dirblk_buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, r.br_blockcount);
     hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
     if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
         xfs_error("Block directory header's magic number does not match!");
         xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic));
-
-	free(dirblk_buf);
-
 	return -1;
     }
 
@@ -184,8 +181,6 @@ int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
     if (retval)
 	xfs_error("Failed to fill in dirent structure");
 
-    free(dirblk_buf);
-
     return retval;
 }
 
@@ -204,7 +199,7 @@ int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
     uint8_t *start_name;
     uint8_t *end_name;
     xfs_intino_t ino;
-    uint8_t *buf = NULL;
+    const uint8_t *buf = NULL;
     int retval = 0;
 
     xfs_debug("file %p dirent %p core %p", file, dirent, core);
@@ -214,8 +209,8 @@ int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
     leaf_blk = fsblock_to_bytes(fs, irec.br_startblock) >>
 					BLOCK_SHIFT(file->fs);
 
-    leaf = (xfs_dir2_leaf_t *)xfs_dir2_get_dirblks(fs, leaf_blk,
-						   irec.br_blockcount);
+    leaf = (xfs_dir2_leaf_t *)xfs_dir2_dirblks_get_cached(fs, leaf_blk,
+							  irec.br_blockcount);
     if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
         xfs_error("Single leaf block header's magic number does not match!");
         goto out;
@@ -239,11 +234,11 @@ int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
 
     dir_blk = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
 
-    buf = xfs_dir2_get_dirblks(fs, dir_blk, irec.br_blockcount);
+    buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, irec.br_blockcount);
     data_hdr = (xfs_dir2_data_hdr_t *)buf;
     if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
 	xfs_error("Leaf directory's data magic number does not match!");
-	goto out1;
+	goto out;
     }
 
     offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
@@ -260,14 +255,10 @@ int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
     if (retval)
 	xfs_error("Failed to fill in dirent structure");
 
-    free(buf);
     free(leaf);
 
     return retval;
 
-out1:
-    free(buf);
-
 out:
     free(leaf);
 
@@ -292,7 +283,7 @@ int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
     uint8_t *start_name;
     uint8_t *end_name;
     uint32_t db;
-    uint8_t *buf = NULL;
+    const uint8_t *buf = NULL;
     int retval = 0;
 
     xfs_debug("file %p dirent %p core %p", file, dirent, core);
@@ -304,7 +295,7 @@ int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
 
     fsblkno = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
 
-    node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(fs, fsblkno, 1);
+    node = (xfs_da_intnode_t *)xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
     if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
         xfs_error("Node's magic number does not match!");
         goto out;
@@ -322,7 +313,7 @@ try_next_btree:
         goto out;
     }
 
-    leaf = (xfs_dir2_leaf_t*)xfs_dir2_get_dirblks(fs, fsblkno, 1);
+    leaf = (xfs_dir2_leaf_t*)xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
     if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
         xfs_error("Leaf's magic number does not match!");
         goto out1;
@@ -360,11 +351,11 @@ try_next_btree:
 	goto out1;
     }
 
-    buf = xfs_dir2_get_dirblks(fs, fsblkno, 1);
+    buf = xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
     data_hdr = (xfs_dir2_data_hdr_t *)buf;
     if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
 	xfs_error("Leaf directory's data magic No. does not match!");
-	goto out2;
+	goto out1;
     }
 
     offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
@@ -379,15 +370,11 @@ try_next_btree:
     if (retval)
 	xfs_error("Failed to fill in dirent structure");
 
-    free(buf);
     free(leaf);
     free(node);
 
     return retval;
 
-out2:
-    free(buf);
-
 out1:
     free(leaf);
 


More information about the Syslinux-commits mailing list