Date: Fri, 15 Mar 2002 21:12:15 +0200 From: Maxim Sobolev <sobomax@FreeBSD.org> To: Michael Smith <msmith@FreeBSD.org> Cc: hackers@FreeBSD.org, audit@FreeBSD.org, re@FreeBSD.org Subject: Re: Extending loader(8) for loading kerels/modules split across several disks Message-ID: <3C92478F.2B7C11DB@FreeBSD.org> References: <200203070940.g279eTa04750@mass.dis.org>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
Michael Smith wrote:
>
> > > > Please review attached patch, which adds long overdue feature to our
> > > > loader(8), allowing it to load sequence of files as a single object.
> > >
> > > I don't like this. I would much rather see support for 'split' files
> > > implemented as a stacking filesystem layer like the gzip support, with
> > > the simple recognition of 'foo.gz.aa' as the first part of a split
> > > version of 'foo.gz', which in turn is recognised as a compressed version
> > > of 'foo'.
> >
> > I am curious how in this case the layer is going to know how many
> > parts the file contains?
>
> The simple way to do it is to keep asking for more parts until there are
> no more.
>
> You can take the NetBSD approach of wrapping the file in a multipart tar
> archive.
>
> Or a more elegant method involves the use of a control file.
>
> eg. the splitfs code, when asked to open "foo" looks for "foo.split"
> which is a text file containing a list of filenames and media names, eg.
>
> foo.aa "Kernel floppy 1"
> foo.ab "Kernel floppy 2"
> foo.ac "Kernel and modules floppy"
>
> For each file segment, the process is:
>
> - try to open the file
> - prompt "please insert the disk labelled <whatever>'"
> - try to open the file
> - return error
>
> At any rate, my key point is that the splitting should be invisible, and
> *definitely* not pushed up into the loader.
Ok, attached is the path, which does exactly what described. Please
review and if there are no objections I would like to commit it
shortly, so that our re@ team would be able to consider it for the
forthcoming 5.0-DP1 release.
Thanks!
-Maxim
[-- Attachment #2 --]
Index: src/lib/libstand/Makefile
===================================================================
RCS file: /home/ncvs/src/lib/libstand/Makefile,v
retrieving revision 1.27
diff -d -u -r1.27 Makefile
--- src/lib/libstand/Makefile 27 Feb 2002 17:15:37 -0000 1.27
+++ src/lib/libstand/Makefile 15 Mar 2002 08:40:31 -0000
@@ -153,6 +153,7 @@
SRCS+= ufs.c nfs.c cd9660.c tftp.c zipfs.c bzipfs.c
SRCS+= netif.c nfs.c
SRCS+= dosfs.c ext2fs.c
+SRCS+= splitfs.c
beforeinstall:
${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/stand.h \
Index: src/lib/libstand/bzipfs.c
===================================================================
RCS file: /home/ncvs/src/lib/libstand/bzipfs.c,v
retrieving revision 1.3
diff -d -u -r1.3 bzipfs.c
--- src/lib/libstand/bzipfs.c 1 Feb 2002 16:33:40 -0000 1.3
+++ src/lib/libstand/bzipfs.c 15 Mar 2002 08:40:31 -0000
@@ -150,7 +150,7 @@
/* If the name already ends in .gz or .bz2, ignore it */
if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".gz")
- || !strcmp(cp, ".bz2")))
+ || !strcmp(cp, ".bz2") || !strcmp(cp, ".split")))
return(ENOENT);
/* Construct new name */
Index: src/lib/libstand/splitfs.c
===================================================================
RCS file: src/lib/libstand/splitfs.c
diff -N src/lib/libstand/splitfs.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/lib/libstand/splitfs.c 15 Mar 2002 08:40:31 -0000
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2002 Maxim Sobolev
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+#define NTRIES (3)
+#define CONF_BUF (512)
+#define SEEK_BUF (512)
+
+struct split_file
+{
+ char **filesv; /* Filenames */
+ char **descsv; /* Descriptions */
+ int filesc; /* Number of parts */
+ int curfile; /* Current file number */
+ int curfd; /* Current file descriptor */
+ off_t tot_pos; /* Offset from the beginning of the sequence */
+ off_t file_pos; /* Offset from the beginning of the slice */
+};
+
+static int splitfs_open(const char *path, struct open_file *f);
+static int splitfs_close(struct open_file *f);
+static int splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
+static off_t splitfs_seek(struct open_file *f, off_t offset, int where);
+static int splitfs_stat(struct open_file *f, struct stat *sb);
+
+struct fs_ops splitfs_fsops = {
+ "split",
+ splitfs_open,
+ splitfs_close,
+ splitfs_read,
+ null_write,
+ splitfs_seek,
+ splitfs_stat,
+ null_readdir
+};
+
+static void
+split_file_destroy(struct split_file *sf)
+{
+ int i;
+
+ if (sf->filesc > 0) {
+ for (i = 0; i < sf->filesc; i++) {
+ free(sf->filesv[i]);
+ free(sf->descsv[i]);
+ }
+ free(sf->filesv);
+ free(sf->descsv);
+ }
+ free(sf);
+}
+
+static int
+splitfs_open(const char *fname, struct open_file *f)
+{
+ char *buf, *confname, *cp;
+ int conffd;
+ struct split_file *sf;
+ struct stat sb;
+
+ printf("%s\n", fname);
+ /* Have to be in "just read it" mode */
+ if (f->f_flags != F_READ)
+ return(EPERM);
+
+ /* If the name already ends in `.split', ignore it */
+ if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".split")))
+ return(ENOENT);
+
+ /* Construct new name */
+ confname = malloc(strlen(fname) + 7);
+ sprintf(confname, "%s.split", fname);
+
+ /* Try to open the configuration file */
+ conffd = open(confname, O_RDONLY);
+ free(confname);
+ if (conffd == -1)
+ return(ENOENT);
+
+ if (fstat(conffd, &sb) < 0) {
+ printf("splitfs_open: stat failed\n");
+ close(conffd);
+ return(ENOENT);
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ printf("splitfs_open: not a file\n");
+ close(conffd);
+ return(EISDIR); /* best guess */
+ }
+
+ /* Allocate a split_file structure, populate it from the config file */
+ sf = malloc(sizeof(struct split_file));
+ bzero(sf, sizeof(struct split_file));
+ buf = malloc(CONF_BUF);
+ while (fgetstr(buf, CONF_BUF, conffd) > 0) {
+ cp = buf;
+ while ((*cp != '\0') && (isspace(*cp) == 0))
+ cp++;
+ if (*cp != '\0') {
+ *cp = '\0';
+ cp++;
+ }
+ while ((*cp != '\0') && (isspace(*cp) != 0))
+ cp++;
+ if (*cp == '\0')
+ cp = buf;
+ sf->filesc++;
+ sf->filesv = realloc(sf->filesv, sizeof(*(sf->filesv)) * sf->filesc);
+ sf->descsv = realloc(sf->descsv, sizeof(*(sf->descsv)) * sf->filesc);
+ sf->filesv[sf->filesc - 1] = strdup(buf);
+ sf->descsv[sf->filesc - 1] = strdup(cp);
+ }
+ free(buf);
+ close(conffd);
+
+ if ((sf->filesc == 0) || ((sf->curfd = open(sf->filesv[0], O_RDONLY)) == -1)) {
+ split_file_destroy(sf);
+ return(ENOENT);
+ }
+
+ /* Looks OK, we'll take it */
+ f->f_fsdata = sf;
+ return (0);
+}
+
+static int
+splitfs_close(struct open_file *f)
+{
+ int fd;
+ struct split_file *sf;
+
+ sf = (struct split_file *)f->f_fsdata;
+ fd = sf->curfd;
+ split_file_destroy(sf);
+ return(close(fd));
+}
+
+static int
+splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+ int i, nread, totread;
+ struct split_file *sf;
+
+ sf = (struct split_file *)f->f_fsdata;
+ totread = 0;
+ do {
+ nread = read(sf->curfd, buf, size - totread);
+
+ /* Error? */
+ if (nread == -1)
+ return (errno);
+
+ sf->tot_pos += nread;
+ sf->file_pos += nread;
+ totread += nread;
+ buf += nread;
+
+ if (totread < size) { /* EOF */
+ if (sf->curfile == (sf->filesc - 1)) /* Last slice */
+ break;
+
+ /* Close previous slice */
+ if (close(sf->curfd) != 0)
+ return (errno);
+
+ sf->curfile++;
+ for (i = 0;; i++) {
+ sf->curfd = open(sf->filesv[sf->curfile], O_RDONLY);
+ if (sf->curfd >= 0)
+ break;
+ if ((sf->curfd == -1) && (errno != ENOENT))
+ return (errno);
+ if (i == NTRIES)
+ return (EIO);
+ printf("\nInsert disk labelled %s and press any key...", sf->descsv[sf->curfile]);
+ getchar();putchar('\n');
+ }
+ sf->file_pos = 0;
+ }
+ } while (totread < size);
+
+ if (resid != NULL)
+ *resid = size - totread;
+
+ return (0);
+}
+
+static off_t
+splitfs_seek(struct open_file *f, off_t offset, int where)
+{
+ int nread;
+ size_t resid;
+ off_t new_pos, seek_by;
+ struct split_file *sf;
+
+ sf = (struct split_file *)f->f_fsdata;
+
+ seek_by = offset;
+ switch (where) {
+ case SEEK_SET:
+ seek_by -= sf->tot_pos;
+ break;
+ case SEEK_CUR:
+ break;
+ case SEEK_END:
+ panic("splitfs_seek: SEEK_END not supported");
+ break;
+ }
+
+ if (seek_by > 0) {
+ /*
+ * Seek forward - implemented using splitfs_read(), because otherwise we'll be
+ * unable to detect that we have crossed slice boundary and hence
+ * unable to do a long seek crossing that boundary.
+ */
+ void *tmp;
+
+ tmp = malloc(SEEK_BUF);
+ if (tmp == NULL)
+ return (-1);
+
+ nread = 0;
+ for (; seek_by > 0; seek_by -= nread) {
+ resid = 0;
+ errno = splitfs_read(f, tmp, min(seek_by, SEEK_BUF), &resid);
+ nread = min(seek_by, SEEK_BUF) - resid;
+ if ((errno != 0) || (nread == 0))
+ /* Error or EOF */
+ break;
+ }
+ free(tmp);
+ if (errno != 0)
+ return (-1);
+ }
+
+ if (seek_by != 0) {
+ /* Seek backward or seek past the boundary of the last slice */
+ if (sf->file_pos + seek_by < 0)
+ panic("splitfs_seek: can't seek past the beginning of the slice");
+ new_pos = lseek(sf->curfd, seek_by, SEEK_CUR);
+ if (new_pos < 0)
+ return (-1);
+ sf->tot_pos += new_pos - sf->file_pos;
+ sf->file_pos = new_pos;
+ }
+
+ return (sf->tot_pos);
+}
+
+static int
+splitfs_stat(struct open_file *f, struct stat *sb)
+{
+ int result;
+ struct split_file *sf = (struct split_file *)f->f_fsdata;
+
+ /* stat as normal, but indicate that size is unknown */
+ if ((result = fstat(sf->curfd, sb)) == 0)
+ sb->st_size = -1;
+ return (result);
+}
Index: src/lib/libstand/stand.h
===================================================================
RCS file: /home/ncvs/src/lib/libstand/stand.h,v
retrieving revision 1.29
diff -d -u -r1.29 stand.h
--- src/lib/libstand/stand.h 9 Mar 2002 21:02:11 -0000 1.29
+++ src/lib/libstand/stand.h 15 Mar 2002 08:40:31 -0000
@@ -125,6 +125,7 @@
extern struct fs_ops bzipfs_fsops;
extern struct fs_ops dosfs_fsops;
extern struct fs_ops ext2fs_fsops;
+extern struct fs_ops splitfs_fsops;
/* where values for lseek(2) */
#define SEEK_SET 0 /* set file offset to offset */
Index: src/lib/libstand/zipfs.c
===================================================================
RCS file: /home/ncvs/src/lib/libstand/zipfs.c,v
retrieving revision 1.8
diff -d -u -r1.8 zipfs.c
--- src/lib/libstand/zipfs.c 30 Sep 2001 22:28:01 -0000 1.8
+++ src/lib/libstand/zipfs.c 15 Mar 2002 08:40:31 -0000
@@ -175,7 +175,7 @@
/* If the name already ends in .gz or .bz2, ignore it */
if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".gz")
- || !strcmp(cp, ".bz2")))
+ || !strcmp(cp, ".bz2") || !strcmp(cp, ".split")))
return(ENOENT);
/* Construct new name */
Index: src/sys/boot/i386/loader/conf.c
===================================================================
RCS file: /home/ncvs/src/sys/boot/i386/loader/conf.c,v
retrieving revision 1.18
diff -d -u -r1.18 conf.c
--- src/sys/boot/i386/loader/conf.c 5 Nov 2001 18:59:13 -0000 1.18
+++ src/sys/boot/i386/loader/conf.c 15 Mar 2002 08:40:31 -0000
@@ -60,6 +60,7 @@
&ext2fs_fsops,
&dosfs_fsops,
&cd9660_fsops,
+ &splitfs_fsops,
#ifdef LOADER_GZIP_SUPPORT
&zipfs_fsops,
#endif
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3C92478F.2B7C11DB>
