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@zytor.com>
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 */
+#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];
if (inode) {
inode->fs = fs;
inode->ino = ino;
+ inode->refcnt = 1;
}
return inode;
}
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;
/* 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 != '/')
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;
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);
+ }
}
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;
}
/* 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;
* 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;
* @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
#include <stdio.h>
#include <string.h>
#include <sys/dirent.h>
+#include <minmax.h>
#include <cache.h>
#include <core.h>
#include <disk.h>
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
*/
{
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));
}
/*
* 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);
}
* 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;
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)
{
struct ext2_dir_entry *de;
struct fs_info *fs = parent->fs;
-
+
de = ext2_find_entry(fs, parent, dname);
if (!de)
return NULL;
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)));
.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,
/*
* 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 */
}
-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
*/
.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,
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;
.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,
--- /dev/null
+#include "fs.h"
+
+void generic_close_file(struct file *file)
+{
+ if (file->inode) {
+ file->offset = 0;
+ free_inode(file->inode);
+ }
+}
com32sys_t regs;
chdir(CurrentDirName);
+ realpath(ConfigName, "extlinux.conf", FILENAME_MAX);
+
+ printf("config = %s\n", ConfigName);
memset(®s, 0, sizeof regs);
- snprintf(ConfigName, FILENAME_MAX, "%s/extlinux.conf", CurrentDirName);
regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
call16(core_open, ®s, ®s);
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 */
};
*/
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 */
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);
/* loadconfig.c */
int generic_load_config(void);
+/* close.c */
+void generic_close_file(struct file *file);
+
#endif /* FS_H */