diff options
author | Matt Fleming <matt.fleming@intel.com> | 2013-01-24 17:22:57 +0000 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2013-01-24 17:22:57 +0000 |
commit | 12843abf1ffdf905455de0cc6ea8441dff9d89b7 (patch) | |
tree | 6a02040e7c2ed58179735a17c909b5b611d84470 | |
parent | 75e2b7c282fc3b5c4f5314717f1b224f489b507e (diff) | |
parent | 129a5845aec4d6c750c4bddd936f315fb441d2fa (diff) | |
download | syslinux-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.c | 56 | ||||
-rw-r--r-- | core/fs/xfs/xfs.h | 15 | ||||
-rw-r--r-- | core/fs/xfs/xfs_dinode.c | 4 | ||||
-rw-r--r-- | core/fs/xfs/xfs_dir2.c | 212 | ||||
-rw-r--r-- | core/fs/xfs/xfs_dir2.h | 21 | ||||
-rw-r--r-- | core/fs/xfs/xfs_readdir.c | 112 | ||||
-rw-r--r-- | extlinux/main.c | 30 |
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: |