Raphael S.Carvalho
2013-Oct-18 05:42 UTC
[syslinux] [RFC/PATCH 2/3] core: MultiFS infrastructure added.
From: Raphael S. Carvalho <raphael.scarv at gmail.com> MULTIFS SYNTAX: (hd[disk number]:[partition number])/path/to/file The meaning of this_fs was changed to improve the flexibility of the support. Now, this_fs means the file system being currently used. root_fs was created to save the context of the main file system (where ldlinux.sys lives in). get_fs_info is a function pointer that will be later hooked to a function from ldlinux.c32. get_fs_info is expected to return a fs_info structure given the MultiFS path. Signed-off-by: Raphael S. Carvalho <raphael.scarv at gmail.com> --- core/fs/cache.c | 2 +- core/fs/diskio.c | 26 ++++++++++++---- core/fs/diskio_bios.c | 40 ++++++++++++++----------- core/fs/fs.c | 22 +++++++++++--- core/fs/readdir.c | 9 +++++- core/include/multifs.h | 61 ++++++++++++++++++++++++++++++++++++++ core/multifs.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 205 insertions(+), 31 deletions(-) create mode 100644 core/include/multifs.h create mode 100644 core/multifs.c diff --git a/core/fs/cache.c b/core/fs/cache.c index 3b21fc2..b8ed8c2 100644 --- a/core/fs/cache.c +++ b/core/fs/cache.c @@ -16,7 +16,7 @@ * implementation since the block(cluster) size in FAT is a bit big. * */ -void cache_init(struct device *dev, int block_size_shift) +__export void cache_init(struct device *dev, int block_size_shift) { struct cache *prev, *cur; char *data = dev->cache_data; diff --git a/core/fs/diskio.c b/core/fs/diskio.c index 7d95d67..466b6a8 100644 --- a/core/fs/diskio.c +++ b/core/fs/diskio.c @@ -21,13 +21,27 @@ void getoneblk(struct disk *disk, char *buf, block_t block, int block_size) /* * Initialize the device structure. */ -struct device * device_init(void *args) +__export struct device *device_init(void *args) { - static struct device dev; + struct device *dev; - dev.disk = firmware->disk_init(args); - dev.cache_size = 128*1024; - dev.cache_data = malloc(dev.cache_size); + dev = malloc(sizeof(struct device)); + if (!dev) + return NULL; - return &dev; + dev->disk = firmware->disk_init(args); + if (!dev->disk) + goto out; + + dev->cache_size = 128*1024; + dev->cache_data = malloc(dev->cache_size); + if (!dev->cache_data) + goto out_disk; + + return dev; +out_disk: + free(dev->disk); +out: + free(dev); + return NULL; } diff --git a/core/fs/diskio_bios.c b/core/fs/diskio_bios.c index 9b935fe..27585f5 100644 --- a/core/fs/diskio_bios.c +++ b/core/fs/diskio_bios.c @@ -287,7 +287,7 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf, struct disk *bios_disk_init(void *private) { - static struct disk disk; + struct disk *disk; struct bios_disk_private *priv = (struct bios_disk_private *)private; com32sys_t *regs = priv->regs; static __lowmem struct edd_disk_params edd_params; @@ -302,6 +302,10 @@ struct disk *bios_disk_init(void *private) int sector_size; unsigned int hard_max_transfer; + disk = malloc(sizeof(struct disk)); + if (!disk) + return NULL; + memset(&ireg, 0, sizeof ireg); ireg.edx.b[0] = devno; @@ -319,18 +323,18 @@ struct disk *bios_disk_init(void *private) hard_max_transfer = 63; /* CBIOS parameters */ - disk.h = bsHeads; - disk.s = bsSecPerTrack; + disk->h = bsHeads; + disk->s = bsSecPerTrack; if ((int8_t)devno < 0) { /* Get hard disk geometry from BIOS */ - + ireg.eax.b[1] = 0x08; __intcall(0x13, &ireg, &oreg); - + if (!(oreg.eflags.l & EFLAGS_CF)) { - disk.h = oreg.edx.b[1] + 1; - disk.s = oreg.ecx.b[0] & 63; + disk->h = oreg.edx.b[1] + 1; + disk->s = oreg.ecx.b[0] & 63; } } @@ -370,24 +374,24 @@ struct disk *bios_disk_init(void *private) } - disk.disk_number = devno; - disk.sector_size = sector_size; - disk.sector_shift = ilog2(sector_size); - disk.part_start = part_start; - disk.secpercyl = disk.h * disk.s; - disk.rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors; + disk->disk_number = devno; + disk->sector_size = sector_size; + disk->sector_shift = ilog2(sector_size); + disk->part_start = part_start; + disk->secpercyl = disk->h * disk->s; + disk->rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors; if (!MaxTransfer || MaxTransfer > hard_max_transfer) MaxTransfer = hard_max_transfer; - disk.maxtransfer = MaxTransfer; + disk->maxtransfer = MaxTransfer; dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n", - devno, cdrom, ebios, sector_size, disk.sector_shift, - part_start, disk.maxtransfer); + devno, cdrom, ebios, sector_size, disk->sector_shift, + part_start, disk->maxtransfer); - disk.private = private; - return &disk; + disk->private = private; + return disk; } void pm_fs_init(com32sys_t *regs) diff --git a/core/fs/fs.c b/core/fs/fs.c index 8c1feea..c1838c2 100644 --- a/core/fs/fs.c +++ b/core/fs/fs.c @@ -9,9 +9,14 @@ #include "dev.h" #include "fs.h" #include "cache.h" +#include "multifs.h" -/* The currently mounted filesystem */ -__export struct fs_info *this_fs = NULL; /* Root filesystem */ +/* root_fs means the file system where ldlinux.sys lives in. */ +__export struct fs_info *root_fs = NULL; +/* this_fs means the file system being currently used. */ +__export struct fs_info *this_fs = NULL; +/* export p_ops to be used outside the core */ +__export const struct fs_ops **p_ops = NULL; /* Actual file structures (we don't have malloc yet...) */ __export struct file files[MAX_OPEN]; @@ -344,6 +349,9 @@ __export int open_file(const char *name, int flags, struct com32_filedata *filed dprintf("open_file %s\n", name); + if (switch_fs(&name)) + return -1; + mangle_name(mangled_name, name); rv = searchdir(mangled_name, flags); @@ -361,6 +369,9 @@ __export int open_file(const char *name, int flags, struct com32_filedata *filed filedata->blocklg2 = SECTOR_SHIFT(file->fs); filedata->handle = rv; + restore_fs(); + restore_chdir_start(); + return rv; } @@ -395,6 +406,7 @@ void fs_init(const struct fs_ops **ops, void *priv) /* Default name for the root directory */ fs.cwd_name[0] = '/'; + p_ops = ops; while ((blk_shift < 0) && *ops) { /* set up the fs stucture */ @@ -420,7 +432,7 @@ void fs_init(const struct fs_ops **ops, void *priv) while (1) ; } - this_fs = &fs; + root_fs = this_fs = &fs; /* initialize the cache */ if (fs.fs_dev && fs.fs_dev->cache_data) @@ -434,8 +446,8 @@ void fs_init(const struct fs_ops **ops, void *priv) } if (fs.fs_ops->chdir_start) { - if (fs.fs_ops->chdir_start() < 0) - printf("Failed to chdir to start directory\n"); + if (fs.fs_ops->chdir_start() < 0) + printf("Failed to chdir to start directory\n"); } SectorShift = fs.sector_shift; diff --git a/core/fs/readdir.c b/core/fs/readdir.c index 546a704..2a1efde 100644 --- a/core/fs/readdir.c +++ b/core/fs/readdir.c @@ -4,6 +4,7 @@ #include <sys/dirent.h> #include "fs.h" #include "core.h" +#include "multifs.h" /* * Open a directory @@ -13,6 +14,9 @@ __export DIR *opendir(const char *path) int rv; struct file *file; + if (switch_fs(&path)) + return NULL; + rv = searchdir(path, O_RDONLY|O_DIRECTORY); if (rv < 0) return NULL; @@ -24,6 +28,9 @@ __export DIR *opendir(const char *path) return NULL; } + restore_fs(); + restore_chdir_start(); + return (DIR *)file; } @@ -35,7 +42,7 @@ __export struct dirent *readdir(DIR *dir) static struct dirent buf; struct file *dd_dir = (struct file *)dir; int rv = -1; - + if (dd_dir) { if (dd_dir->fs->fs_ops->readdir) { rv = dd_dir->fs->fs_ops->readdir(dd_dir, &buf); diff --git a/core/include/multifs.h b/core/include/multifs.h new file mode 100644 index 0000000..a62a115 --- /dev/null +++ b/core/include/multifs.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef MULTIFS_H +#define MULTIFS_H + +/* + * MULTIFS SYNTAX: + * (hd[disk number]:[partition number])/path/to/file + * + * E.G.: (hd0:1)/dir/file means /dir/file at partition 1 of the disk 0. + * Disk and Partition numbering starts from 0 and 1 respectivelly. + */ +#include "fs.h" + +/* + * root_fs means the file system where ldlinux.sys lives in. + * this_fs means the file system being currently used. + */ +extern struct fs_info *this_fs, *root_fs; + +/* + * Set this_fs back to root_fs, + * otherwise unexpected behavior may occurs. + */ +static inline void restore_fs(void) +{ + this_fs = root_fs; +} + +/* + * Basically restores the cwd of the underlying fs. + */ +static inline void restore_chdir_start(void) +{ + if (this_fs->fs_ops->chdir_start) { + if (this_fs->fs_ops->chdir_start() < 0) + printf("Failed to chdir to start directory\n"); + } +} + +typedef struct fs_info *(*get_fs_info_t)(const char **); +extern int switch_fs(const char **); + +#endif /* MULTIFS_H */ \ No newline at end of file diff --git a/core/multifs.c b/core/multifs.c new file mode 100644 index 0000000..8951ef7 --- /dev/null +++ b/core/multifs.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <klibc/compiler.h> +#include <stdio.h> +#include <assert.h> +#include "multifs.h" + +static get_fs_info_t get_fs_info = NULL; + +/* + * Enable MultiFS support + * This function is called from ldlinux.c32 to enable MultiFS support. + * + * @addr: address of the get_fs_info function from ldlinux.c32. + */ +__export void enable_multifs(get_fs_info_t addr) +{ + if (addr) { + get_fs_info = addr; + dprintf("MultiFS: set get_fs_info to %p\n", get_fs_info); + } +} + +/* + * The request is considered MultiFS if the path starts + * with an open parentheses. + * + * @ret: Upon success, set this_fs to the fs where the underlying file + * resides and returns 0. Upon failure, returns -1; + */ +int switch_fs(const char **path) +{ + struct fs_info *fs; + + assert(path && *path); + if ((*path)[0] != '(') { + /* If so, don't need to restore chdir */ + if (this_fs == root_fs) + return 0; + + fs = root_fs; + goto ret; + } + + if (__unlikely(!get_fs_info)) { + printf("MultiFS support is not enabled!\n"); + return -1; + } + + fs = get_fs_info(path); + if (!fs) { + dprintf("MultiFS: It wasn't possible to get the proper fs!\n"); + return -1; + } +ret: + this_fs = fs; + restore_chdir_start(); + return 0; +} -- 1.7.2.5
Raphael S Carvalho
2013-Oct-18 16:15 UTC
[syslinux] [RFC/PATCH 2/3] core: MultiFS infrastructure added.
On Fri, Oct 18, 2013 at 2:42 AM, Raphael S.Carvalho <raphael.scarv at gmail.com> wrote:> From: Raphael S. Carvalho <raphael.scarv at gmail.com> > > MULTIFS SYNTAX: > (hd[disk number]:[partition number])/path/to/file >It's wrong (my fault), comma is currently the unique delimiter for MultiFS syntax. Correct syntax: (hd[disk number],[partition number])/path/to/file Nonetheless, it will be probably better to use a space instead as a comma would conflict with the delimiter of multiple initramfs files. As pointed out by Ady2, it would also be better from an user perspective and more consistent at the same time. -- Raphael S. Carvalho