[syslinux] [RFC/PATCH 2/3] core: MultiFS infrastructure added.

Raphael S.Carvalho raphael.scarv at gmail.com
Thu Oct 17 22:42:47 PDT 2013


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



More information about the Syslinux mailing list