diff options
author | Paulo Alcantara <pcacjr@zytor.com> | 2013-01-21 23:37:16 -0200 |
---|---|---|
committer | Paulo Alcantara <pcacjr@zytor.com> | 2013-01-21 23:53:12 -0200 |
commit | 90f5f81712b93a73b55a6baf7223e100753da73c (patch) | |
tree | b938accce7dead4c28e8ada3931ba669cd81287f | |
parent | e92e971550777e3170c063e348a3aab5ccaf6ff9 (diff) | |
download | syslinux-90f5f81712b93a73b55a6baf7223e100753da73c.tar.gz syslinux-90f5f81712b93a73b55a6baf7223e100753da73c.tar.xz syslinux-90f5f81712b93a73b55a6baf7223e100753da73c.zip |
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@zytor.com>
-rw-r--r-- | core/fs/xfs/xfs.c | 5 | ||||
-rw-r--r-- | core/fs/xfs/xfs.h | 14 | ||||
-rw-r--r-- | core/fs/xfs/xfs_dir2.c | 129 | ||||
-rw-r--r-- | core/fs/xfs/xfs_dir2.h | 4 | ||||
-rw-r--r-- | 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 60a67f5d..712888c3 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 11e8634a..0d953d89 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 d833c259..81b8c241 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 fa403f38..9c2785f3 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 bbfc0264..e99ea710 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); |