[syslinux:pathbased] fs: reference-count inodes, fix generic loadconfig

syslinux-bot for H. Peter Anvin hpa at zytor.com
Mon Feb 15 20:36:08 PST 2010


Commit-ID:  b9885de16d126cbe9574cc939a181888b955499b
Gitweb:     http://syslinux.zytor.com/commit/b9885de16d126cbe9574cc939a181888b955499b
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Mon, 15 Feb 2010 20:32:21 -0800
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Mon, 15 Feb 2010 20:32:21 -0800

fs: reference-count inodes, fix generic loadconfig

Reference-count inodes, so we don't leak them all over the place.
This also lets us hold onto the root inode from the very beginning.
Make the generic loadconfig work again.  Significant cleanups to the
ext2 filesystem core.

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


---
 core/chdir.c              |    4 +-
 core/fs.c                 |   40 +++++++++---------
 core/fs/ext2/bmap.c       |   20 ++++------
 core/fs/ext2/ext2.c       |   97 +++++++++++++++++++++------------------------
 core/fs/ext2/ext2_fs.h    |    3 +-
 core/fs/fat/fat.c         |   11 +-----
 core/fs/iso9660/iso9660.c |   11 +-----
 core/fs/lib/close.c       |    9 ++++
 core/fs/lib/loadconfig.c  |    4 +-
 core/include/fs.h         |   17 +++++++-
 10 files changed, 106 insertions(+), 110 deletions(-)

diff --git a/core/chdir.c b/core/chdir.c
index c5c4d58..d5ef3f9 100644
--- a/core/chdir.c
+++ b/core/chdir.c
@@ -48,8 +48,8 @@ int chdir(const char *src)
 	return -1;
     }
 
-    this_fs->cwd = file->inode;
-    file->inode = NULL;		/* "Steal" the inode */
+    put_inode(this_fs->cwd);
+    this_fs->cwd = get_inode(file->inode);
     _close_file(file);
 
     /* Save the current working directory */
diff --git a/core/fs.c b/core/fs.c
index c53636f..77c51ac 100644
--- a/core/fs.c
+++ b/core/fs.c
@@ -1,12 +1,14 @@
+#define DEBUG
+
 #include <stdio.h>
 #include <stdbool.h>
 #include <string.h>
+#include <dprintf.h>
 #include "fs.h"
 #include "cache.h"
 
 /* The currently mounted filesystem */
 struct fs_info *this_fs = NULL;		/* Root filesystem */
-static struct inode *this_inode = NULL;	/* Current working directory */
 
 /* Actual file structures (we don't have malloc yet...) */
 struct file files[MAX_OPEN];
@@ -20,6 +22,7 @@ struct inode *alloc_inode(struct fs_info *fs, uint32_t ino, size_t data)
     if (inode) {
 	inode->fs = fs;
 	inode->ino = ino;
+	inode->refcnt = 1;
     }
     return inode;
 }
@@ -157,12 +160,9 @@ int searchdir(const char *name)
     char part[256];
     char *p;
     int symlink_count = 6;
-    bool got_parent;
-    
-#if 0
-    printf("filename: %s\n", name);
-#endif
 
+    dprintf("Filename: %s\n", name);
+    
     if (!(file = alloc_file()))
 	goto err_no_close;
     file->fs = this_fs;
@@ -179,15 +179,14 @@ int searchdir(const char *name)
 
     /* else, try the generic-path-lookup method */
     if (*name == '/') {
-	inode = this_fs->fs_ops->iget_root(this_fs);
+	parent = get_inode(this_fs->root);
 	while (*name == '/')
 	    name++;
     } else {
-	inode = this_fs->cwd;
+	parent = get_inode(this_fs->cwd);
     }
-    parent = inode;
-    got_parent = false;
-    
+    inode = NULL;
+
     while (*name) {
 	p = part;
 	while (*name && *name != '/')
@@ -203,22 +202,21 @@ int searchdir(const char *name)
 		    inode->size >= BLOCK_SIZE(this_fs))
 		    goto err;
 		name = this_fs->fs_ops->follow_symlink(inode, name);
-		free_inode(inode);
+		put_inode(inode);
 		continue;
 	    }
-	    if (got_parent)
-		free_inode(parent);
+	    put_inode(parent);
 	    parent = inode;
-	    got_parent = true;
 	}
 	if (!*name)
 	    break;
 	while (*name == '/')
 	    name++;
     }
-    
-    if (got_parent)
-	free_inode(parent);
+    put_inode(parent);
+
+    if (!inode)
+	goto err;
 
     file->inode  = inode;
     file->offset = 0;
@@ -304,6 +302,8 @@ void fs_init(com32sys_t *regs)
         cache_init(fs.fs_dev, blk_shift);
 
     /* start out in the root directory */
-    if (fs.fs_ops->iget_root)
-	fs.cwd = fs.fs_ops->iget_root(&fs);
+    if (fs.fs_ops->iget_root) {
+	fs.root = fs.fs_ops->iget_root(&fs);
+	fs.cwd = get_inode(fs.root);
+    }
 }
diff --git a/core/fs/ext2/bmap.c b/core/fs/ext2/bmap.c
index e4698d0..b6dce4b 100644
--- a/core/fs/ext2/bmap.c
+++ b/core/fs/ext2/bmap.c
@@ -13,7 +13,8 @@
 
 
 static struct ext4_extent_header * 
-ext4_find_leaf(struct fs_info *fs, struct ext4_extent_header *eh, block_t block)
+ext4_find_leaf(struct fs_info *fs, struct ext4_extent_header *eh,
+	       block_t block)
 {
     struct ext4_extent_idx *index;
     struct cache_struct *cs;
@@ -42,9 +43,8 @@ ext4_find_leaf(struct fs_info *fs, struct ext4_extent_header *eh, block_t block)
 }
 
 /* handle the ext4 extents to get the phsical block number */
-static uint64_t bmap_extent(struct fs_info *fs, 
-			    struct inode *inode, 
-			    uint32_t block)
+static block_t bmap_extent(struct fs_info *fs, struct inode *inode, 
+			   block_t block)
 {
     struct ext4_extent_header *leaf;
     struct ext4_extent *ext;
@@ -82,12 +82,11 @@ static uint64_t bmap_extent(struct fs_info *fs,
  * handle the traditional block map, like indirect, double indirect 
  * and triple indirect 
  */
-static unsigned int bmap_traditional(struct fs_info *fs, 
-				     struct inode *inode, 
-				     uint32_t block)
+static block_t bmap_traditional(struct fs_info *fs, struct inode *inode, 
+				block_t block)
 {
     int addr_per_block = BLOCK_SIZE(fs) >> 2;
-    uint32_t direct_blocks = EXT2_NDIR_BLOCKS,
+    block_t direct_blocks = EXT2_NDIR_BLOCKS,
 	indirect_blocks = addr_per_block,
 	double_blocks = addr_per_block * addr_per_block,
 	triple_blocks = double_blocks * addr_per_block;
@@ -169,13 +168,10 @@ static unsigned int bmap_traditional(struct fs_info *fs,
  * @retrun: the physic block number.
  *
  */
-block_t bmap(struct fs_info *fs, struct inode * inode, int block)
+block_t ext2_bmap(struct fs_info *fs, struct inode * inode, block_t block)
 {
     block_t ret;
     
-    if (block < 0)
-	return 0;
-    
     if (inode->flags & EXT4_EXTENTS_FLAG)
 	ret = bmap_extent(fs, inode, block);
     else
diff --git a/core/fs/ext2/ext2.c b/core/fs/ext2/ext2.c
index c794300..960b3e8 100644
--- a/core/fs/ext2/ext2.c
+++ b/core/fs/ext2/ext2.c
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/dirent.h>
+#include <minmax.h>
 #include <cache.h>
 #include <core.h>
 #include <disk.h>
@@ -23,14 +24,6 @@ static int strecpy(char *dst, const char *src, char *end)
         return 0;
 }
 
-static void ext2_close_file(struct file *file)
-{
-    if (file->inode) {
-	file->offset = 0;
-	free_inode(file->inode);
-    }
-}
-
 /*
  * get the group's descriptor of group_num
  */
@@ -80,7 +73,7 @@ static sector_t linsector(struct inode *inode, uint32_t lin_sector)
 {
     struct fs_info *fs = inode->fs;
     int blk_bits = fs->block_shift - fs->sector_shift;
-    block_t block = bmap(fs, inode, lin_sector >> blk_bits);
+    block_t block = ext2_bmap(fs, inode, lin_sector >> blk_bits);
     
     return (block << blk_bits) + (lin_sector & ((1 << blk_bits) - 1));
 }
@@ -180,14 +173,14 @@ static uint32_t ext2_getfssec(struct file *file, char *buf,
 /*
  * Unlike strncmp, ext2_match_entry returns 1 for success, 0 for failure.
  */
-static inline int ext2_match_entry (const char * const name,
+static inline bool ext2_match_entry (const char *name, size_t len,
                                     struct ext2_dir_entry * de)
 {
     if (!de->d_inode)
-        return 0;
-    if (strlen(name) != de->d_name_len)
-	return 0;
-    return !strncmp(name, de->d_name, de->d_name_len);
+        return false;
+    if (len != de->d_name_len)
+	return false;
+    return !memcmp(name, de->d_name, len);
 }
 
 
@@ -203,40 +196,40 @@ static inline struct ext2_dir_entry *ext2_next_entry(struct ext2_dir_entry *p)
  * find a dir entry, return it if found, or return NULL.
  */
 static struct ext2_dir_entry * 
-ext2_find_entry(struct fs_info *fs, struct inode *inode, char *dname)
+ext2_find_entry(struct fs_info *fs, struct inode *inode, const char *dname)
 {
-    int index = 0;
-    block_t  block;
-    uint32_t i = 0;
+    block_t index = 0;
+    block_t block;
+    uint32_t i = 0, offset, maxoffset;
     struct ext2_dir_entry *de;
     struct cache_struct *cs;
-    
-    if (!(block = bmap(fs, inode, index++)))
-	return NULL;
-    cs = get_cache_block(fs->fs_dev, block);
-    de = (struct ext2_dir_entry *)cs->data;
-    
-    while(i < (int)inode->size) {
-	if (ext2_match_entry(dname, de))
-	    return de;
-	i += de->d_rec_len;
-	if (i >= (int)inode->size)
-	    break;
-	if ((char *)de >= (char *)cs->data + BLOCK_SIZE(fs)) {
-	    if (!(block = bmap(fs, inode, index++)))
+    size_t dname_len = strlen(dname);
+
+    while (i < inode->size) {
+	if (!(block = ext2_bmap(fs, inode, index++)))
+	    return NULL;
+	cs = get_cache_block(fs->fs_dev, block);
+	offset = 0;
+	maxoffset =  min(BLOCK_SIZE(fs), i-inode->size);
+
+	/* The smallest possible size is 9 bytes */
+	while (offset < maxoffset-8) {
+	    de = (struct ext2_dir_entry *)((char *)cs->data + offset);
+	    if (de->d_rec_len > maxoffset - offset)
 		break;
-	    cs = get_cache_block(fs->fs_dev, block);
-	    de = (struct ext2_dir_entry *)cs->data;
-	    continue;
+
+	    if (ext2_match_entry(dname, dname_len, de))
+		return de;
+
+	    offset += de->d_rec_len;
 	}
-	
-	de = ext2_next_entry(de);
+	i += BLOCK_SIZE(fs);
     }
-    
+
     return NULL;
 }
 
-static struct ext2_inode * get_inode(struct fs_info *fs, int inr)
+static struct ext2_inode *ext2_get_inode(struct fs_info *fs, int inr)
 {
     struct ext2_group_desc *desc;
     struct cache_struct *cs;
@@ -287,15 +280,15 @@ static void fill_inode(struct inode *inode, struct ext2_inode *e_inode)
 
 static struct inode *ext2_iget_by_inr(struct fs_info *fs, uint32_t inr)
 {
-        struct ext2_inode *e_inode;
-        struct inode *inode;
-
-        e_inode = get_inode(fs, inr);
-        if (!(inode = alloc_inode(fs, inr, EXT2_N_BLOCKS*sizeof(uint32_t *))))
-	    return NULL;
-        fill_inode(inode, e_inode);
-	
-        return inode;
+    struct ext2_inode *e_inode;
+    struct inode *inode;
+    
+    e_inode = ext2_get_inode(fs, inr);
+    if (!(inode = alloc_inode(fs, inr, EXT2_N_BLOCKS*sizeof(uint32_t *))))
+	return NULL;
+    fill_inode(inode, e_inode);
+    
+    return inode;
 }
 
 static struct inode *ext2_iget_root(struct fs_info *fs)
@@ -307,7 +300,7 @@ static struct inode *ext2_iget(char *dname, struct inode *parent)
 {
         struct ext2_dir_entry *de;
 	struct fs_info *fs = parent->fs;
-        
+
         de = ext2_find_entry(fs, parent, dname);
         if (!de)
                 return NULL;
@@ -362,10 +355,10 @@ static struct dirent * ext2_readdir(struct file *file)
     struct dirent *dirent;
     struct ext2_dir_entry *de;
     struct cache_struct *cs;
-    int index = file->offset >> fs->block_shift;
+    block_t index = file->offset >> fs->block_shift;
     block_t block;
     
-    if (!(block = bmap(fs, inode, index)))
+    if (!(block = ext2_bmap(fs, inode, index)))
 	return NULL;        
     cs = get_cache_block(fs->fs_dev, block);
     de = (struct ext2_dir_entry *)(cs->data + (file->offset & (BLOCK_SIZE(fs) - 1)));
@@ -440,7 +433,7 @@ const struct fs_ops ext2_fs_ops = {
     .fs_init       = ext2_fs_init,
     .searchdir     = NULL,
     .getfssec      = ext2_getfssec,
-    .close_file    = ext2_close_file,
+    .close_file    = generic_close_file,
     .mangle_name   = generic_mangle_name,
     .unmangle_name = generic_unmangle_name,
     .load_config   = generic_load_config,
diff --git a/core/fs/ext2/ext2_fs.h b/core/fs/ext2/ext2_fs.h
index b74038e..2f5bc6e 100644
--- a/core/fs/ext2/ext2_fs.h
+++ b/core/fs/ext2/ext2_fs.h
@@ -293,7 +293,6 @@ static inline struct ext2_sb_info *EXT2_SB(struct fs_info *fs)
 /* 
  * functions 
  */
-block_t bmap(struct fs_info *, struct inode *, int);
-
+block_t ext2_bmap(struct fs_info *, struct inode *, block_t);
 
 #endif /* ext2_fs.h */
diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c
index 97dd715..5499351 100644
--- a/core/fs/fat/fat.c
+++ b/core/fs/fat/fat.c
@@ -19,15 +19,6 @@ static struct inode * new_fat_inode(struct fs_info *fs)
 }
 
 
-static void vfat_close_file(struct file *file)
-{
-    if (file->inode) {
-	file->offset = 0;
-	free_inode(file->inode);
-    }
-}
-
-
 /*
  * Check for a particular sector in the FAT cache
  */
@@ -846,7 +837,7 @@ const struct fs_ops vfat_fs_ops = {
     .fs_init       = vfat_fs_init,
     .searchdir     = NULL,
     .getfssec      = vfat_getfssec,
-    .close_file    = vfat_close_file,
+    .close_file    = generic_close_file,
     .mangle_name   = vfat_mangle_name,
     .unmangle_name = generic_unmangle_name,
     .load_config   = vfat_load_config,
diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c
index 06caedd..b8c790d 100644
--- a/core/fs/iso9660/iso9660.c
+++ b/core/fs/iso9660/iso9660.c
@@ -12,15 +12,6 @@ static struct inode *new_iso_inode(struct fs_info *fs)
     return alloc_inode(fs, 0, sizeof(uint32_t));
 }
 
-
-static void iso_close_file(struct file *file)
-{
-    if (file->inode) {
-	file->offset = 0;
-	free_inode(file->inode);
-    }
-}
-
 static inline struct iso_sb_info * ISO_SB(struct fs_info *fs)
 {
     return fs->fs_info;
@@ -438,7 +429,7 @@ const struct fs_ops iso_fs_ops = {
     .fs_init       = iso_fs_init,
     .searchdir     = NULL, 
     .getfssec      = iso_getfssec,
-    .close_file    = iso_close_file,
+    .close_file    = generic_close_file,
     .mangle_name   = iso_mangle_name,
     .unmangle_name = generic_unmangle_name,
     .load_config   = iso_load_config,
diff --git a/core/fs/lib/close.c b/core/fs/lib/close.c
new file mode 100644
index 0000000..4504327
--- /dev/null
+++ b/core/fs/lib/close.c
@@ -0,0 +1,9 @@
+#include "fs.h"
+
+void generic_close_file(struct file *file)
+{
+    if (file->inode) {
+	file->offset = 0;
+	free_inode(file->inode);
+    }
+}
diff --git a/core/fs/lib/loadconfig.c b/core/fs/lib/loadconfig.c
index da2ba50..b415347 100644
--- a/core/fs/lib/loadconfig.c
+++ b/core/fs/lib/loadconfig.c
@@ -11,9 +11,11 @@ int generic_load_config(void)
     com32sys_t regs;
 
     chdir(CurrentDirName);
+    realpath(ConfigName, "extlinux.conf", FILENAME_MAX);
+
+    printf("config = %s\n", ConfigName);
 
     memset(&regs, 0, sizeof regs);
-    snprintf(ConfigName, FILENAME_MAX, "%s/extlinux.conf", CurrentDirName);
     regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
     call16(core_open, &regs, &regs);
 
diff --git a/core/include/fs.h b/core/include/fs.h
index 4902614..d7feb7e 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -34,7 +34,7 @@ struct fs_info {
     void *fs_info;             /* The fs-specific information */
     int sector_shift, sector_size;
     int block_shift, block_size;
-    struct inode *cwd;	       		/* Current directory */
+    struct inode *root, *cwd;	   	/* Root and current directories */
     char cwd_name[CURRENTDIR_MAX];	/* Current directory by name */
 };
 
@@ -78,6 +78,7 @@ enum inode_mode {I_FILE, I_DIR, I_SYMLINK};
  */
 struct inode {
     struct fs_info *fs;	 /* The filesystem this inode is associated with */
+    int		 refcnt;
     int          mode;   /* FILE , DIR or SYMLINK */
     uint32_t     size;
     uint32_t     ino;    /* Inode number */
@@ -146,6 +147,17 @@ static inline void free_inode(struct inode * inode)
     free(inode);
 }
 
+static inline struct inode *get_inode(struct inode *inode)
+{
+    inode->refcnt++;
+    return inode;
+}
+static inline void put_inode(struct inode *inode)
+{
+    if (! --inode->refcnt)
+	free(inode);
+}
+
 static inline void malloc_error(char *obj)
 {
         printf("Out of memory: can't allocate memory for %s\n", obj);
@@ -190,4 +202,7 @@ void generic_mangle_name(char *, const char *);
 /* loadconfig.c */
 int generic_load_config(void);
 
+/* close.c */
+void generic_close_file(struct file *file);
+
 #endif /* FS_H */



More information about the Syslinux-commits mailing list