aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2013-01-24 17:22:57 +0000
committerMatt Fleming <matt.fleming@intel.com>2013-01-24 17:22:57 +0000
commit12843abf1ffdf905455de0cc6ea8441dff9d89b7 (patch)
tree6a02040e7c2ed58179735a17c909b5b611d84470
parent75e2b7c282fc3b5c4f5314717f1b224f489b507e (diff)
parent129a5845aec4d6c750c4bddd936f315fb441d2fa (diff)
downloadsyslinux-12843abf1ffdf905455de0cc6ea8441dff9d89b7.tar.gz
Merge branch 'for-upstream' of git://git.zytor.com/users/pcacjr/syslinux into elflink
Pull XFS changes from Paulo Alcantara, "feel free to pull my for-upstream branch on zytor. it contains the cache for directory blocks on XFS, ldlinux.c32 installation support for XFS and one trivial fix for shortform-directory lookup." * 'for-upstream' of git://git.zytor.com/users/pcacjr/syslinux: extlinux: Also install ldlinux.c32 file on XFS xfs: Flush cache of directory blocks once done with readdir() xfs: Remove unnecessary free()'s xfs: Fix bug when listing shortform directory entries xfs: Add cache for directory blocks xfs: Make xfs_dir2_entry_name_cmp() inline xfs: Avoid useless malloc()'s and free()'s xfs: Make it more verbose on debug xfs: Improve error and debug printing xfs: Do some refactoring
-rw-r--r--core/fs/xfs/xfs.c56
-rw-r--r--core/fs/xfs/xfs.h15
-rw-r--r--core/fs/xfs/xfs_dinode.c4
-rw-r--r--core/fs/xfs/xfs_dir2.c212
-rw-r--r--core/fs/xfs/xfs_dir2.h21
-rw-r--r--core/fs/xfs/xfs_readdir.c112
-rw-r--r--extlinux/main.c30
7 files changed, 251 insertions, 199 deletions
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
index 89a9aef2..b6a396aa 100644
--- a/core/fs/xfs/xfs.c
+++ b/core/fs/xfs/xfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ * Copyright (c) 2012-2013 Paulo Alcantara <pcacjr@zytor.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -38,29 +38,26 @@
#include "xfs_readdir.h"
static inline int xfs_fmt_local_readdir(struct file *file,
- struct dirent *dirent, xfs_dinode_t *core)
+ struct dirent *dirent,
+ xfs_dinode_t *core)
{
- return xfs_readdir_dir2_block(file, dirent, core);
+ return xfs_readdir_dir2_local(file, dirent, core);
}
static inline int xfs_fmt_extents_readdir(struct file *file,
struct dirent *dirent,
xfs_dinode_t *core)
{
- int retval;
-
if (be32_to_cpu(core->di_nextents) <= 1) {
/* Single-block Directories */
- retval = xfs_readdir_dir2_block(file, dirent, core);
+ return xfs_readdir_dir2_block(file, dirent, core);
} else if (xfs_dir2_isleaf(file->fs, core)) {
/* Leaf Directory */
- retval = xfs_readdir_dir2_leaf(file, dirent, core);
+ return xfs_readdir_dir2_leaf(file, dirent, core);
} else {
/* Node Directory */
- retval = xfs_readdir_dir2_node(file, dirent, core);
+ return xfs_readdir_dir2_node(file, dirent, core);
}
-
- return retval;
}
static int xfs_readdir(struct file *file, struct dirent *dirent)
@@ -68,7 +65,8 @@ static int xfs_readdir(struct file *file, struct dirent *dirent)
struct fs_info *fs = file->fs;
xfs_dinode_t *core;
struct inode *inode = file->inode;
- int retval = -1;
+
+ xfs_debug("file %p dirent %p");
core = xfs_dinode_get_core(fs, inode->ino);
if (!core) {
@@ -77,11 +75,11 @@ static int xfs_readdir(struct file *file, struct dirent *dirent)
}
if (core->di_format == XFS_DINODE_FMT_LOCAL)
- retval = xfs_fmt_local_readdir(file, dirent, core);
+ return xfs_fmt_local_readdir(file, dirent, core);
else if (core->di_format == XFS_DINODE_FMT_EXTENTS)
- retval = xfs_fmt_extents_readdir(file, dirent, core);
+ return xfs_fmt_extents_readdir(file, dirent, core);
- return retval;
+ return -1;
}
static uint32_t xfs_getfssec(struct file *file, char *buf, int sectors,
@@ -106,6 +104,8 @@ static int xfs_next_extent(struct inode *inode, uint32_t lstart)
(void)lstart;
+ xfs_debug("inode %p lstart %lu", inode, lstart);
+
core = xfs_dinode_get_core(fs, inode->ino);
if (!core) {
xfs_error("Failed to get dinode from disk (ino %llx)", inode->ino);
@@ -190,20 +190,16 @@ static inline struct inode *xfs_fmt_extents_find_entry(const char *dname,
struct inode *parent,
xfs_dinode_t *core)
{
- struct inode *inode;
-
if (be32_to_cpu(core->di_nextents) <= 1) {
- /* Single-block Directories */
- inode = xfs_dir2_block_find_entry(dname, parent, core);
+ /* Single-block Directories */
+ return xfs_dir2_block_find_entry(dname, parent, core);
} else if (xfs_dir2_isleaf(parent->fs, core)) {
- /* Leaf Directory */
- inode = xfs_dir2_leaf_find_entry(dname, parent, core);
+ /* Leaf Directory */
+ return xfs_dir2_leaf_find_entry(dname, parent, core);
} else {
- /* Node Directory */
- inode = xfs_dir2_node_find_entry(dname, parent, core);
+ /* Node Directory */
+ return xfs_dir2_node_find_entry(dname, parent, core);
}
-
- return inode;
}
static inline struct inode *xfs_fmt_btree_find_entry(const char *dname,
@@ -233,11 +229,6 @@ static struct inode *xfs_iget(const char *dname, struct inode *parent)
inode = xfs_fmt_extents_find_entry(dname, parent, core);
} else if (core->di_format == XFS_DINODE_FMT_BTREE) {
inode = xfs_fmt_btree_find_entry(dname, parent, core);
- } else {
- xfs_debug("format %hhu", core->di_format);
- xfs_debug("TODO: format \"local\" and \"extents\" are the only "
- "supported ATM");
- goto out;
}
if (!inode) {
@@ -266,7 +257,9 @@ 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);
core = xfs_dinode_get_core(fs, inode->ino);
if (!core) {
@@ -289,7 +282,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
@@ -297,7 +290,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 da57221a..0d953d89 100644
--- a/core/fs/xfs/xfs.h
+++ b/core/fs/xfs/xfs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ * Copyright (c) 2012-2013 Paulo Alcantara <pcacjr@zytor.com>
*
* Some parts borrowed from Linux kernel tree (linux/fs/xfs):
*
@@ -30,11 +30,16 @@
#include "xfs_types.h"
#include "xfs_ag.h"
-#define xfs_error(fmt, args...) \
- printf("xfs: " fmt "\n", ## args);
+#define xfs_error(fmt, args...) \
+ ({ \
+ printf("%s:%u: xfs - [ERROR] " fmt "\n", __func__, __LINE__, ## args); \
+ })
-#define xfs_debug(fmt, args...) \
- dprintf("%s: " fmt "\n", __func__, ## 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_dinode.c b/core/fs/xfs/xfs_dinode.c
index 8e2d8d04..55be6e2d 100644
--- a/core/fs/xfs/xfs_dinode.c
+++ b/core/fs/xfs/xfs_dinode.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ * Copyright (c) 2012-2013 Paulo Alcantara <pcacjr@zytor.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -33,7 +33,7 @@ xfs_dinode_t *xfs_dinode_get_core(struct fs_info *fs, xfs_ino_t ino)
xfs_dinode_t *core;
uint64_t offset;
- xfs_debug("ino %lu", ino);
+ xfs_debug("fs %p ino %lu", fs, ino);
blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
offset = XFS_INO_TO_OFFSET(XFS_INFO(fs), ino) << XFS_INFO(fs)->inode_shift;
diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c
index c52196ae..de37ef7c 100644
--- a/core/fs/xfs/xfs_dir2.c
+++ b/core/fs/xfs/xfs_dir2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ * Copyright (c) 2012-2013 Paulo Alcantara <pcacjr@zytor.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -28,23 +28,16 @@
#include "xfs_dir2.h"
-char *xfs_dir2_get_entry_name(uint8_t *start, uint8_t *end)
-{
- char *s;
- char *p;
-
- s = malloc(end - start + 1);
- if (!s)
- malloc_error("string");
+#define XFS_DIR2_DIRBLKS_CACHE_SIZE 128
- p = s;
- while (start < end)
- *p++ = *start++;
+struct xfs_dir2_dirblks_cache {
+ block_t dc_startblock;
+ xfs_filblks_t dc_blkscount;
+ void *dc_area;
+};
- *p = '\0';
-
- return s;
-}
+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)
{
@@ -73,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;
@@ -96,6 +89,85 @@ 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;
+}
+
+void xfs_dir2_dirblks_flush_cache(void)
+{
+ unsigned char i;
+
+ for (i = 0; i < dirblks_cached_count; i++) {
+ free(dirblks_cache[i].dc_area);
+ memset(&dirblks_cache[i], 0, sizeof(dirblks_cache[i]));
+ }
+
+ dirblks_cached_count = 0;
+}
+
struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
xfs_dinode_t *core)
{
@@ -107,6 +179,7 @@ struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
xfs_intino_t ino;
xfs_dinode_t *ncore = NULL;
+ xfs_debug("dname %s parent %p core %p", dname, parent, core);
xfs_debug("count %hhu i8count %hhu", sf->hdr.count, sf->hdr.i8count);
sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
@@ -114,19 +187,12 @@ struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
while (count--) {
uint8_t *start_name = &sf_entry->name[0];
uint8_t *end_name = start_name + sf_entry->namelen;
- char *name;
- name = xfs_dir2_get_entry_name(start_name, end_name);
-
- xfs_debug("entry name: %s", name);
-
- if (!strncmp(name, dname, strlen(dname))) {
- free(name);
+ if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) {
+ xfs_debug("Found entry %s", dname);
goto found;
}
- free(name);
-
sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)sf_entry +
offsetof(struct xfs_dir2_sf_entry,
name[0]) +
@@ -184,7 +250,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;
@@ -194,10 +260,12 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
xfs_intino_t ino;
xfs_dinode_t *ncore;
+ xfs_debug("dname %s parent %p core %p", dname, parent, core);
+
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!");
@@ -213,7 +281,6 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
while (p < endp) {
uint8_t *start_name;
uint8_t *end_name;
- char *name;
dup = (xfs_dir2_data_unused_t *)p;
if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
@@ -225,20 +292,16 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
start_name = &dep->name[0];
end_name = start_name + dep->namelen;
- name = xfs_dir2_get_entry_name(start_name, end_name);
- if (!strncmp(name, dname, strlen(dname))) {
- free(name);
+ if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) {
+ xfs_debug("Found entry %s", dname);
goto found;
}
- free(name);
p += xfs_dir2_data_entsize(dep->namelen);
}
out:
- free(dirblk_buf);
-
return NULL;
found:
@@ -274,12 +337,10 @@ found:
xfs_debug("entry inode's number %lu", ino);
- free(dirblk_buf);
return inode;
failed:
free(inode);
- free(dirblk_buf);
return NULL;
}
@@ -302,25 +363,26 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
xfs_dir2_data_hdr_t *data_hdr;
uint8_t *start_name;
uint8_t *end_name;
- char *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);
bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) +
be32_to_cpu(core->di_nextents) - 1);
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;
}
if (!leaf->hdr.count)
- goto out;
+ goto out;
hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
@@ -355,18 +417,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;
@@ -377,21 +437,14 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
start_name = &dep->name[0];
end_name = start_name + dep->namelen;
- name = xfs_dir2_get_entry_name(start_name, end_name);
- if (!strncmp(name, dname, strlen(dname))) {
- free(name);
+ if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) {
+ xfs_debug("Found entry %s", dname);
goto found;
}
-
- free(name);
}
-out1:
- free(buf);
out:
- free(leaf);
-
return NULL;
found:
@@ -428,15 +481,10 @@ found:
xfs_debug("entry inode's number %lu", ino);
- free(buf);
- free(leaf);
-
return ip;
failed:
free(ip);
- free(buf);
- free(leaf);
return ip;
}
@@ -560,14 +608,15 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
struct inode *ip;
uint8_t *start_name;
uint8_t *end_name;
- char *name;
int low;
int high;
int mid = 0;
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);
hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
@@ -579,7 +628,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;
@@ -630,9 +680,8 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
goto out;
}
- 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;
@@ -675,20 +724,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;
@@ -699,21 +745,14 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
start_name = &dep->name[0];
end_name = start_name + dep->namelen;
- name = xfs_dir2_get_entry_name(start_name, end_name);
- if (!strncmp(name, dname, strlen(dname))) {
- free(name);
- goto found;
- }
- free(name);
+ if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) {
+ xfs_debug("Found entry %s", dname);
+ goto found;
+ }
}
-out1:
- free(buf);
-
out:
- free(node);
-
return NULL;
found:
@@ -745,15 +784,10 @@ 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 e1b96227..158cf44f 100644
--- a/core/fs/xfs/xfs_dir2.h
+++ b/core/fs/xfs/xfs_dir2.h
@@ -23,10 +23,12 @@
#include "xfs.h"
-char *xfs_dir2_get_entry_name(uint8_t *start, uint8_t *end);
-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);
+void xfs_dir2_dirblks_flush_cache(void);
+
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);
@@ -51,4 +53,17 @@ static inline bool xfs_dir2_isleaf(struct fs_info *fs, xfs_dinode_t *dip)
return (last == XFS_INFO(fs)->dirleafblk + (1 << XFS_INFO(fs)->dirblklog));
}
+static inline int xfs_dir2_entry_name_cmp(uint8_t *start, uint8_t *end,
+ const char *name)
+{
+ if (!name || (strlen(name) != end - start))
+ return -1;
+
+ while (start < end)
+ if (*start++ != *name++)
+ return -1;
+
+ return 0;
+}
+
#endif /* XFS_DIR2_H_ */
diff --git a/core/fs/xfs/xfs_readdir.c b/core/fs/xfs/xfs_readdir.c
index 0e013e55..86c8a77b 100644
--- a/core/fs/xfs/xfs_readdir.c
+++ b/core/fs/xfs/xfs_readdir.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ * Copyright (c) 2012-2013 Paulo Alcantara <pcacjr@zytor.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -35,6 +35,9 @@ static int fill_dirent(struct fs_info *fs, struct dirent *dirent,
{
xfs_dinode_t *core;
+ xfs_debug("fs %p, dirent %p offset %lu ino %llu name %s namelen %llu", fs,
+ dirent, offset, ino, name, namelen);
+
dirent->d_ino = ino;
dirent->d_off = offset;
dirent->d_reclen = offsetof(struct dirent, d_name) + namelen + 1;
@@ -52,7 +55,8 @@ static int fill_dirent(struct fs_info *fs, struct dirent *dirent,
else if (be16_to_cpu(core->di_mode) & S_IFLNK)
dirent->d_type = DT_LNK;
- memcpy(dirent->d_name, name, namelen + 1);
+ memcpy(dirent->d_name, name, namelen);
+ dirent->d_name[namelen] = '\0';
return 0;
}
@@ -66,15 +70,15 @@ int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
uint32_t offset = file->offset;
uint8_t *start_name;
uint8_t *end_name;
- char *name;
xfs_ino_t ino;
struct fs_info *fs = file->fs;
int retval = 0;
+ xfs_debug("file %p dirent %p core %p", file, dirent, core);
xfs_debug("count %hhu i8count %hhu", sf->hdr.count, sf->hdr.i8count);
if (file->offset + 1 > count)
- return -1;
+ goto out;
file->offset++;
@@ -96,22 +100,23 @@ int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
start_name = &sf_entry->name[0];
end_name = start_name + sf_entry->namelen;
- name = xfs_dir2_get_entry_name(start_name, end_name);
-
ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
(uint8_t *)sf_entry +
offsetof(struct xfs_dir2_sf_entry,
name[0]) +
sf_entry->namelen));
- retval = fill_dirent(fs, dirent, file->offset, ino, (char *)name,
+ retval = fill_dirent(fs, dirent, file->offset, ino, (char *)start_name,
end_name - start_name);
if (retval)
xfs_error("Failed to fill in dirent structure");
- free(name);
-
return retval;
+
+out:
+ xfs_dir2_dirblks_flush_cache();
+
+ return -1;
}
int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
@@ -120,7 +125,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;
@@ -129,28 +134,26 @@ int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
xfs_dir2_data_entry_t *dep;
uint8_t *start_name;
uint8_t *end_name;
- char *name;
xfs_ino_t ino;
int retval = 0;
+ xfs_debug("file %p dirent %p core %p", file, dirent, core);
+
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;
+ goto out;
}
btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
if (file->offset + 1 > be32_to_cpu(btp->count))
- return -1;
+ goto out;
file->offset++;
@@ -175,19 +178,20 @@ int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
start_name = &dep->name[0];
end_name = start_name + dep->namelen;
- name = xfs_dir2_get_entry_name(start_name, end_name);
ino = be64_to_cpu(dep->inumber);
- retval = fill_dirent(fs, dirent, file->offset, ino, name,
+ retval = fill_dirent(fs, dirent, file->offset, ino, (char *)start_name,
end_name - start_name);
if (retval)
xfs_error("Failed to fill in dirent structure");
- free(dirblk_buf);
- free(name);
-
return retval;
+
+out:
+ xfs_dir2_dirblks_flush_cache();
+
+ return -1;
}
int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
@@ -204,18 +208,19 @@ int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
xfs_dir2_data_hdr_t *data_hdr;
uint8_t *start_name;
uint8_t *end_name;
- char *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);
+
bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) +
be32_to_cpu(core->di_nextents) - 1);
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 +244,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));
@@ -252,26 +257,18 @@ int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
start_name = &dep->name[0];
end_name = start_name + dep->namelen;
- name = xfs_dir2_get_entry_name(start_name, end_name);
ino = be64_to_cpu(dep->inumber);
- retval = fill_dirent(fs, dirent, file->offset, ino, name,
+ retval = fill_dirent(fs, dirent, file->offset, ino, (char *)start_name,
end_name - start_name);
if (retval)
xfs_error("Failed to fill in dirent structure");
- free(name);
- free(buf);
- free(leaf);
-
return retval;
-out1:
- free(buf);
-
out:
- free(leaf);
+ xfs_dir2_dirblks_flush_cache();
return -1;
}
@@ -293,11 +290,12 @@ int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
xfs_dir2_data_entry_t *dep;
uint8_t *start_name;
uint8_t *end_name;
- char *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);
+
do {
bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
++node_off);
@@ -305,7 +303,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;
@@ -314,7 +312,7 @@ int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
try_next_btree:
if (!node->hdr.count ||
XFS_PVT(inode)->i_btree_offset >= be16_to_cpu(node->hdr.count))
- goto out;
+ goto out;
fsblkno = be32_to_cpu(node->btree[XFS_PVT(inode)->i_btree_offset].before);
fsblkno = xfs_dir2_get_right_blk(fs, core, fsblkno, &error);
@@ -323,17 +321,16 @@ 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;
+ goto out;
}
if (!leaf->hdr.count ||
XFS_PVT(inode)->i_leaf_ent_offset >= be16_to_cpu(leaf->hdr.count)) {
XFS_PVT(inode)->i_btree_offset++;
XFS_PVT(inode)->i_leaf_ent_offset = 0;
- free(leaf);
goto try_next_btree;
}
@@ -347,7 +344,6 @@ try_next_btree:
if (XFS_PVT(inode)->i_leaf_ent_offset == be16_to_cpu(leaf->hdr.count)) {
XFS_PVT(inode)->i_btree_offset++;
XFS_PVT(inode)->i_leaf_ent_offset = 0;
- free(leaf);
goto try_next_btree;
} else {
XFS_PVT(inode)->i_leaf_ent_offset++;
@@ -358,14 +354,14 @@ try_next_btree:
fsblkno = xfs_dir2_get_right_blk(fs, core, db, &error);
if (error) {
xfs_error("Cannot find data block!");
- goto out1;
+ goto out;
}
- 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 out;
}
offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
@@ -374,28 +370,16 @@ try_next_btree:
start_name = &dep->name[0];
end_name = start_name + dep->namelen;
- name = xfs_dir2_get_entry_name(start_name, end_name);
- retval = fill_dirent(fs, dirent, 0, be64_to_cpu(dep->inumber), name,
- end_name - start_name);
+ retval = fill_dirent(fs, dirent, 0, be64_to_cpu(dep->inumber),
+ (char *)start_name, end_name - start_name);
if (retval)
xfs_error("Failed to fill in dirent structure");
- free(name);
- free(buf);
- free(leaf);
- free(node);
-
return retval;
-out2:
- free(buf);
-
-out1:
- free(leaf);
-
out:
- free(node);
+ xfs_dir2_dirblks_flush_cache();
XFS_PVT(inode)->i_btree_offset = 0;
XFS_PVT(inode)->i_leaf_ent_offset = 0;
diff --git a/extlinux/main.c b/extlinux/main.c
index 01bfc9c4..aa20e1bd 100644
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -644,12 +644,16 @@ int btrfs_install_file(const char *path, int devfd, struct stat *rst)
*/
static int xfs_install_file(const char *path, int devfd, struct stat *rst)
{
- static char file[PATH_MAX];
+ static char file[PATH_MAX + 1];
+ static char c32file[PATH_MAX + 1];
int dirfd = -1;
int fd = -1;
+ int retval;
- snprintf(file, PATH_MAX, "%s%sldlinux.sys",
- path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
+ snprintf(file, PATH_MAX + 1, "%s%sldlinux.sys", path,
+ path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
+ snprintf(c32file, PATH_MAX + 1, "%s%sldlinux.c32", path,
+ path[0] && path[strlen(path) - 1] == '/' ? "" : "/");
dirfd = open(path, O_RDONLY | O_DIRECTORY);
if (dirfd < 0) {
@@ -683,10 +687,28 @@ static int xfs_install_file(const char *path, int devfd, struct stat *rst)
}
close(dirfd);
+ close(fd);
+
+ dirfd = -1;
+ fd = -1;
+
+ fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC,
+ S_IRUSR | S_IRGRP | S_IROTH);
+ if (fd < 0) {
+ perror(c32file);
+ goto bail;
+ }
+
+ retval = xpwrite(fd, syslinux_ldlinuxc32, syslinux_ldlinuxc32_len, 0);
+ if (retval != (int)syslinux_ldlinuxc32_len) {
+ fprintf(stderr, "%s: write failure on %s\n", program, file);
+ goto bail;
+ }
- sync();
close(fd);
+ sync();
+
return 0;
bail: