--- linux/fs/ramfs/Makefile.orig Sat Oct 28 21:56:12 2000 +++ linux/fs/ramfs/Makefile Sat Oct 28 21:56:25 2000 @@ -5,6 +5,9 @@ O_TARGET := ramfs.o O_OBJS := inode.o +ifeq ($(CONFIG_RAMFS_ROOT),y) + O_OBJS += untar.o +endif M_OBJS := $(O_TARGET) --- linux/fs/ramfs/untar.c.empty Wed Dec 31 19:00:00 1969 +++ linux/fs/ramfs/untar.c Sat Oct 28 22:52:15 2000 @@ -0,0 +1,307 @@ +/* + * linux/fs/ramfs/untar.c + * Mount a RAM-based root filesystem from the contents of a tar archive + * + * Linux 2.4 version Copyright (c) 2000 Matt T. Yourst + * Original code for Linux 2.0 Copyright (c) 1998 Dimitri Maziuk and Dave Cinege + * + * 2000-07-29 Matt T. Yourst + * Upgraded all code to Linux 2.4. Now extracts to a full read-write ramfs + * based root running directly out of the page cache. + * + * 1998-03-31 + * Submission for linux kernel 2.0.34 + * This version is exectly like the 1998-01-17 version, plus the addition + * of a wrapper function to deal with the the simple_strtoul spaces issue. + * I did not feel it was wise (and would mean this patch is rejected : >) + * to require the vsprintf change in the stable kernel series. + * + * 1998-01-17 + * Is GNUtar the biggest fuck-up in released software since MS-DOS? + * It could be. + * + * Tar decides it sometimes likes to make a dir entry that is blank or "./". + * We now check for this, and modified our exit pattern to deal with it. + * + * Although both Dima and I thought it wasn't possible, tar can + * stor files without first storing the dir they require. + * If your nice freshly made archive doesn't work don't be surprised. + * Try specing a different way to make it. + * + * Dima has a forthcoming mini tar archive creator (ctar) that should + * better deal with these problems. You may want to look for it if normal + * tar does not suite your needs when using this kernel feature. + * + * 1998-01-10 + * This version of untar is very limited. It expects a fairly good archive, + * as well as expansion to a clean root. + * + * It does not: + * + * Look for a leading '/' + * Check before making links + * Look at the header checksum + * Check or create any leading directory structure + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef min +#define min(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +extern unsigned long initrd_start; +extern unsigned long initrd_end; +extern int mount_initrd; + +#define E_NAMETOOLONG 1 +#define E_CANNOTSTAT 2 +#define E_READLINK 3 +#define E_SHORTWRITE 4 +#define E_FOPEN 5 +#define E_MALLOC 6 +#define E_OPENDIR 7 +#define E_WRONG_FTYPE 8 + +#define TARBLOCKSIZE 512 + +#define NAME_FIELD_SIZE 100 +#define PREFIX_FIELD_SIZE 155 +#define UNAME_FIELD_SIZE 32 +#define GNAME_FIELD_SIZE 32 + +#define TMAGIC "ustar" /* ustar signature */ +#define TMAGLEN 5 +#define TVERSION " \0" /* 00 and no null */ +#define TVERSLEN 2 + +#define REGTYPE '0' /* regular file */ +#define AREGTYPE '\0' /* regular file */ +#define LNKTYPE '1' /* link */ +#define SYMTYPE '2' /* reserved */ +#define CHRTYPE '3' /* character special */ +#define BLKTYPE '4' /* block special */ +#define DIRTYPE '5' /* directory */ +#define FIFOTYPE '6' /* FIFO special */ +#define CONTTYPE '7' /* reserved */ + +/* POSIX tar header */ +struct fileHeader +{ /* byte offset */ + char name[NAME_FIELD_SIZE]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[NAME_FIELD_SIZE]; /* 157 */ + char magic[TMAGLEN]; /* 257 */ + char version[TVERSLEN]; /* 263 */ + char uname[UNAME_FIELD_SIZE]; /* 265 */ + char gname[GNAME_FIELD_SIZE]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[PREFIX_FIELD_SIZE]; /* 345 */ + /* 500 */ +}; + +union TarInfo +{ + char buf[TARBLOCKSIZE]; + struct fileHeader header; +}; + +typedef union TarInfo TarInfo; + +/* We use the normal system calls to build the filesystem: */ +extern int sys_write(unsigned int fd, char *buf,unsigned int count); +extern int sys_chmod(const char *filename, mode_t mode); +extern int sys_chown(const char *filename, uid_t user, gid_t group); +extern int sys_mknod(const char *filename, int mode, dev_t dev); +extern int sys_mkdir(const char *pathname, int mode); +extern int sys_chdir(const char *filename); +extern int sys_link(const char *oldname, const char *newname); +extern int sys_symlink(const char *oldname, const char *newname); +extern int sys_utime(char *filename, struct utimbuf *times); +extern int sys_time(int *t); + +/* + * Find out how much space is left in the in-memory tar archive, + * then return the amount actually "read" just like read() does. + * The caller should note the pointer to the actual data (at + * fileptr) before calling this routine. + */ +static inline int __init read_tar_memory(char** fileptr, char* fileend, size_t size) +{ + size_t bytes_to_read = min(size, fileend - *fileptr); + *fileptr += bytes_to_read; + return bytes_to_read; +} + +/* + * This is called by setup.c to let the ramfs image take control + * before the traditional initrd code fails to recognize it and + * hence frees the memory. + * + * If this is a ramfs tar file image, return 1. Otherwise, return 0. + */ +int __init ramfs_check_root(void) +{ + char* magic = (char*)(initrd_start + 0x101); + if (initrd_start && (!strncmp(magic, TMAGIC, TMAGLEN))) { + mount_initrd = 0; + return 1; + } + return 0; +} + +extern void free_initrd_mem(unsigned long start, unsigned long end); + +/* + * This routine reads in a standard tar archive stream in + * contiguous memory starting at start and ending at end. + */ +int __init ramfs_untar(char* start, char* end) +{ + char *buf = 0; + int err, fd; + unsigned long fsize; + mode_t fmode; + kdev_t fdev; + struct utimbuf ut; + union TarInfo *tarInfo; + + printk(KERN_NOTICE "ramfs: Building root..."); + + for (;;) { + /* Read header or return short read */ + tarInfo = (TarInfo*)start; + err = read_tar_memory(&start, end, TARBLOCKSIZE); + if (err < TARBLOCKSIZE) { + if (err == 0) { + goto exit; + } else { + printk(KERN_ERR "ramfs: Corrupt tar archive\n"); + err = -1; + goto exit; + } + } + + fmode = simple_strtoul(tarInfo->header.mode, NULL, 8); + fsize = simple_strtoul(tarInfo->header.size, NULL, 8); + +#ifdef DEBUG_UNTAR + printk("\n%c/%012o %013d %s", tarInfo->header.typeflag, fmode, fsize, tarInfo->header.name); +#endif + + /* + * This should fix the problem with '\0' named dirs killing the archive + * extraction. A better way would be to look to see if fsize[0] contains + * '\0' as a normal header would either have a number their or pad it with + * a ' '. Not sure if all tar's do this, so it may not be safe + */ + if ((tarInfo->header.name[0] == '\0') && (fmode == 0) && (fsize == 0)) { + err = 0; + goto exit; + } + + err = 0; + + /* Check the file type and extract as appropriate */ + switch (tarInfo->header.typeflag) { + case AREGTYPE: + case REGTYPE: + fd = sys_open(tarInfo->header.name, O_CREAT|O_WRONLY|O_TRUNC, fmode); + if (fd < 0) { + err = 1; + break; + } + + buf = (char*)start; + if (read_tar_memory(&start, end, fsize) < fsize) + err=1; + + if (sys_write(fd, buf, fsize) < fsize) + err=1; + + sys_close(fd); + + if (fsize % TARBLOCKSIZE != 0) + start += (TARBLOCKSIZE * (fsize / TARBLOCKSIZE + 1)) - fsize; + break; + + case DIRTYPE: + /* Skip if name is "" "./" "." ".." */ + if ((tarInfo->header.name[0] != '.' && tarInfo->header.name[0] != '\0') && + (tarInfo->header.name[1] != '/' && tarInfo->header.name[1] != '\0') && + (tarInfo->header.name[1] != '\0')) + err=sys_mkdir(tarInfo->header.name,fmode); + else continue; + break; + + case SYMTYPE: + err = sys_symlink(tarInfo->header.linkname, tarInfo->header.name); + break; + + case LNKTYPE: + err = sys_link(tarInfo->header.linkname, tarInfo->header.name); + break; + + case FIFOTYPE: + case CHRTYPE: + case BLKTYPE: + fdev = MKDEV(simple_strtoul(tarInfo->header.devmajor, NULL, 8), + simple_strtoul(tarInfo->header.devminor, NULL, 8)); + err = sys_mknod(tarInfo->header.name, fmode, fdev); + break; + + default: + printk(KERN_ERR "\nramfs: Corrupt tar archive\n"); + err = -1; + goto exit; + } + + if (err) printk(KERN_WARNING "\nramfs: Error creating %s\n", tarInfo->header.name); + + /* Set the owner/group and permissions */ + if (tarInfo->header.typeflag != LNKTYPE && tarInfo->header.typeflag != SYMTYPE) { + err = sys_chown(tarInfo->header.name, + simple_strtoul(tarInfo->header.uid, NULL, 8), + simple_strtoul(tarInfo->header.gid, NULL, 8)); + if (err) { + printk(KERN_WARNING "\nramfs: Error setting owner on %s\n", tarInfo->header.name); + sys_chown(tarInfo->header.name, 0, 0); /* Just to be safe */ + } + + err = sys_chmod(tarInfo->header.name, fmode); + if (err) { + if (err) printk(KERN_WARNING "\nramfs: Error setting permissions on %s\n", tarInfo->header.name); + sys_chmod(tarInfo->header.name, S_IRWXU | S_IRWXG | S_IROTH); /* Just to be safe */ + } + } + + /* Update the timestamps */ + ut.actime = sys_time(NULL); + ut.modtime = simple_strtoul(tarInfo->header.mtime, NULL, 8); + sys_utime(tarInfo->header.name, &ut); + } + +exit: + printk(KERN_NOTICE "done\n"); + + free_initrd_mem(initrd_start, initrd_end); +#ifdef DEBUG_UNTAR + printk(KERN_NOTICE "initrd memory for ramfs tar freed: 0x%08x to 0x%08x\n", initrd_start, initrd_end); +#endif + initrd_start = 0; + return err; +} --- linux/fs/Config.in.orig Sat Oct 28 21:56:12 2000 +++ linux/fs/Config.in Sat Oct 28 21:56:25 2000 @@ -40,6 +40,7 @@ fi tristate 'Compressed ROM file system support' CONFIG_CRAMFS tristate 'Simple RAM-based file system support' CONFIG_RAMFS +dep_bool ' RAM-based root filesystem from tar archive' CONFIG_RAMFS_ROOT $CONFIG_RAMFS tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS dep_mbool ' Microsoft Joliet CDROM extensions' CONFIG_JOLIET $CONFIG_ISO9660_FS --- linux/arch/i386/mm/init.c.orig Sat Oct 28 21:56:12 2000 +++ linux/arch/i386/mm/init.c Sat Oct 28 21:56:25 2000 @@ -669,7 +669,7 @@ printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); } -#ifdef CONFIG_BLK_DEV_INITRD +#if (defined(CONFIG_BLK_DEV_INITRD) || defined(CONFIG_RAMFS_ROOT)) void free_initrd_mem(unsigned long start, unsigned long end) { if (start < end) --- linux/arch/i386/kernel/setup.c.orig Sat Oct 28 21:56:12 2000 +++ linux/arch/i386/kernel/setup.c Sat Oct 28 22:06:45 2000 @@ -140,6 +140,16 @@ extern int rd_image_start; /* starting block # of image */ #endif +#if (defined(CONFIG_RAMFS_ROOT) || defined(CONFIG_BLK_DEV_INITRD)) +unsigned long initrd_start, initrd_end; +int mount_initrd = 1; /* zero if initrd should not be mounted */ +int initrd_below_start_ok; +#endif + +#ifdef CONFIG_RAMFS_ROOT +extern int ramfs_check_root(void); +#endif + extern int root_mountflags; extern char _text, _etext, _edata, _end; extern unsigned long cpu_khz; @@ -900,7 +910,7 @@ #ifdef CONFIG_X86_LOCAL_APIC init_apic_mappings(); #endif -#ifdef CONFIG_BLK_DEV_INITRD +#if (defined(CONFIG_BLK_DEV_INITRD) || defined(CONFIG_RAMFS_ROOT)) if (LOADER_TYPE && INITRD_START) { if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { reserve_bootmem(INITRD_START, INITRD_SIZE); @@ -916,6 +926,13 @@ initrd_start = 0; } } +#ifdef CONFIG_RAMFS_ROOT + /* + * Give ramfs a chance to take control before initrd + * doesn't recognize the tar format and frees the memory + */ + ramfs_check_root(); +#endif #endif /* --- linux/init/main.c.orig Sat Oct 28 21:56:12 2000 +++ linux/init/main.c Sat Oct 28 23:00:33 2000 @@ -123,10 +123,14 @@ int rows, cols; -#ifdef CONFIG_BLK_DEV_INITRD +#if (defined(CONFIG_BLK_DEV_INITRD) || defined(CONFIG_RAMFS_ROOT)) kdev_t real_root_dev; #endif +#ifdef CONFIG_RAMFS_ROOT +extern int ramfs_check_root(void); +#endif + int root_mountflags = MS_RDONLY; char *execute_command; char root_device_name[64]; @@ -144,12 +148,12 @@ __setup("profile=", profile_setup); - static struct dev_name_struct { const char *name; const int num; } root_dev_names[] __initdata = { { "nfs", 0x00ff }, + { "ramfs", 0x00fe }, { "hda", 0x0300 }, { "hdb", 0x0340 }, { "hdc", 0x1600 }, @@ -542,7 +546,7 @@ kmem_cache_init(); sti(); calibrate_delay(); -#ifdef CONFIG_BLK_DEV_INITRD +#if (defined(CONFIG_BLK_DEV_INITRD) || defined(CONFIG_RAMFS_ROOT)) if (initrd_start && !initrd_below_start_ok && initrd_start < min_low_pfn << PAGE_SHIFT) { printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " @@ -590,7 +594,7 @@ cpu_idle(); } -#ifdef CONFIG_BLK_DEV_INITRD +#if (defined(CONFIG_BLK_DEV_INITRD) || defined(CONFIG_RAMFS_ROOT)) static int do_linuxrc(void * shell) { static char *argv[] = { "linuxrc", NULL, }; @@ -627,8 +631,9 @@ */ static void __init do_basic_setup(void) { -#ifdef CONFIG_BLK_DEV_INITRD +#if (defined(CONFIG_BLK_DEV_INITRD) || defined(CONFIG_RAMFS_ROOT)) int real_root_mountflags; + int init_ramfs; #endif /* @@ -692,11 +697,16 @@ /* Networking initialization needs a process context */ sock_init(); -#ifdef CONFIG_BLK_DEV_INITRD +#if (defined(CONFIG_BLK_DEV_INITRD) || defined(CONFIG_RAMFS_ROOT)) real_root_dev = ROOT_DEV; real_root_mountflags = root_mountflags; +#ifdef CONFIG_RAMFS_ROOT + init_ramfs = ramfs_check_root(); +#else + init_ramfs = 0; +#endif if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY; - else mount_initrd =0; + else mount_initrd = 0; #endif do_initcalls(); @@ -715,13 +725,13 @@ mount_devfs_fs (); -#ifdef CONFIG_BLK_DEV_INITRD +#if (defined(CONFIG_BLK_DEV_INITRD) || defined(CONFIG_RAMFS_ROOT)) root_mountflags = real_root_mountflags; - if (mount_initrd && ROOT_DEV != real_root_dev - && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) { + if ((mount_initrd && ROOT_DEV != real_root_dev + && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) + || init_ramfs) { int error; int i, pid; - pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); if (pid>0) while (pid != wait(&i)); --- linux/drivers/block/rd.c.orig Sat Oct 28 21:56:12 2000 +++ linux/drivers/block/rd.c Sat Oct 28 21:56:25 2000 @@ -128,9 +128,10 @@ int rd_prompt = 1; /* 1 = prompt for RAM disk, 0 = don't prompt */ int rd_image_start; /* starting block # of image */ #ifdef CONFIG_BLK_DEV_INITRD -unsigned long initrd_start, initrd_end; -int mount_initrd = 1; /* zero if initrd should not be mounted */ -int initrd_below_start_ok; +/* These three are now in arch/.../setup.c: */ +extern unsigned long initrd_start, initrd_end; +extern int mount_initrd; /* zero if initrd should not be mounted */ +extern int initrd_below_start_ok; static int __init no_initrd(char *str) { --- linux/fs/super.c.orig Sat Oct 28 21:56:12 2000 +++ linux/fs/super.c Sat Oct 28 22:52:31 2000 @@ -36,6 +36,7 @@ #include #include #include +#include #include #define __NO_VERSION__ @@ -53,6 +54,11 @@ extern int root_mountflags; +#ifdef CONFIG_RAMFS_ROOT +extern int ramfs_untar(char* start, char* end); +extern int ramfs_check_root(void); +#endif + static int do_remount_sb(struct super_block *sb, int flags, char * data); /* this is initialized in init/main.c */ @@ -1470,10 +1476,31 @@ void *handle; char path[64]; int path_start = -1; + void *data; + int using_ramfs = 1; + +#ifdef CONFIG_RAMFS_ROOT + if ((!ramfs_check_root()) && (ROOT_DEV != MKDEV(UNNAMED_MAJOR, 0xfe))) + goto skip_ramfs; + fs_type = get_fs_type("ramfs"); + if (!fs_type) + goto no_ramfs; + ROOT_DEV = get_unnamed_dev(); + if (!ROOT_DEV) + goto no_anon_ramfs; + sb = read_super(ROOT_DEV, NULL, fs_type, 0, initrd_start, 1); + if (sb) + goto mount_it; +no_anon_ramfs: + put_filesystem(fs_type); +no_ramfs: + panic(KERN_ERR "VFS: Unable to mount root ramfs.\n"); +skip_ramfs: + using_ramfs = 0; +#endif #ifdef CONFIG_ROOT_NFS - void *data; - if (MAJOR(ROOT_DEV) != UNNAMED_MAJOR) + if (ROOT_DEV != MKDEV(UNNAMED_MAJOR, 0xff)) goto skip_nfs; fs_type = get_fs_type("nfs"); if (!fs_type) @@ -1613,6 +1640,10 @@ set_fs_pwd(current->fs, vfsmnt, sb->s_root); if (bdev) bdput(bdev); /* sb holds a reference */ +#ifdef CONFIG_RAMFS_ROOT + if (using_ramfs) + ramfs_untar((char*)initrd_start, (char*)initrd_end); +#endif return; } panic("VFS: add_vfsmnt failed for root fs"); @@ -1746,8 +1777,7 @@ goto out2; } - -#ifdef CONFIG_BLK_DEV_INITRD +#if (defined(CONFIG_BLK_DEV_INITRD) || defined(CONFIG_RAMFS_ROOT)) int __init change_root(kdev_t new_root_dev,const char *put_old) { --- linux/Documentation/Configure.help.old Sun Oct 29 14:56:42 2000 +++ linux/Documentation/Configure.help Sun Oct 29 15:02:38 2000 @@ -10826,6 +10826,37 @@ say M here and read Documentation/modules.txt. The module will be called ramfs.o. +RAM-based root filesystem from tar archive +CONFIG_RAMFS_ROOT + Allow the kernel to mount a ramfs namespace as the root filesystem + or as a pre-root filesystem for running a /linuxrc script (similar + to how initial RAM disk (initrd) support works.) + + Since ramfs has no physical or virtual block device to provide its + data as an initrd image would, you must provide a standard tar format + archive to be extracted into the empty ramfs root filesystem. Currently + this tar archive may *not* be compressed (i.e., tar.gz style); if + compression is desired, use a bootloader with automatic gunzip support + such as GRUB. + + To specify the tar archive used to build the root filesystem, use the + initrd= kernel command line option (except with a tar archive + instead of a real ext2/minix/romfs filesystem image.) + + To mount the tar archive as the actual root filesystem, specify the + same initrd= option above and also include "root=/dev/ramfs" + in the kernel command line. + + You may enable both this option and initrd support; however, if a + tar archive is detected instead of an initrd-supported filesystem + image, this option will override initrd support. + + Note: Some versions of GNU tar create invalid archives that cannot + be extracted by the kernel. In particular, tar may add a file to an + archive without previously adding its containing directory. If your + ramfs archive does not mount correctly because of this, try creating + it in another way or with another file order. + ISO 9660 CDROM file system support CONFIG_ISO9660_FS This is the standard file system used on CDROMs. It was previously --- linux/CREDITS.old Mon Oct 30 21:49:35 2000 +++ linux/CREDITS Mon Oct 30 21:51:20 2000 @@ -2928,6 +2928,13 @@ S: Alexandria, Virginia 22304 S: USA +N: Matt Yourst +E: yourst@mit.edu +D: ramfs root filesystem support +S: 476 Memorial Drive +S: Cambridge, MA 02139 +S: USA + N: Niibe Yutaka E: gniibe@mri.co.jp D: PLIP driver