--- /dev/null
+diff -Nuar -X /home/stevel/dontdiff main.orig/Documentation/filesystems/pramfs.txt main/Documentation/filesystems/pramfs.txt
+--- main.orig/Documentation/filesystems/pramfs.txt 1969-12-31 16:00:00.000000000 -0800
++++ main/Documentation/filesystems/pramfs.txt 2004-03-05 09:25:23.000000000 -0800
+@@ -0,0 +1,176 @@
++PRAMFS Overview
++===============
++
++Many embedded systems have a block of non-volatile RAM seperate from
++normal system memory, i.e. of which the kernel maintains no memory page
++descriptors. For such systems it would be beneficial to mount a
++fast read/write filesystem over this "I/O memory", for storing frequently
++accessed data that must survive system reboots and power cycles. An
++example usage might be system logs under /var/log, or a user address
++book in a cell phone or PDA.
++
++Linux traditionally had no support for a persistent, non-volatile RAM-based
++filesystem, persistent meaning the filesystem survives a system reboot
++or power cycle intact. The RAM-based filesystems such as tmpfs and ramfs
++have no actual backing store but exist entirely in the page and buffer
++caches, hence the filesystem disappears after a system reboot or
++power cycle.
++
++A relatively straight-forward solution is to write a simple block driver
++for the non-volatile RAM, and mount over it any disk-based filesystem such
++as ext2/ext3, reiserfs, etc.
++
++But the disk-based fs over non-volatile RAM block driver approach has
++some drawbacks:
++
++1. Disk-based filesystems such as ext2/ext3 were designed for optimum
++ performance on spinning disk media, so they implement features such
++ as block groups, which attempts to group inode data into a contiguous
++ set of data blocks to minimize disk seeking when accessing files. For
++ RAM there is no such concern; a file's data blocks can be scattered
++ throughout the media with no access speed penalty at all. So block
++ groups in a filesystem mounted over RAM just adds unnecessary
++ complexity. A better approach is to use a filesystem specifically
++ tailored to RAM media which does away with these disk-based features.
++ This increases the efficient use of space on the media, i.e. more
++ space is dedicated to actual file data storage and less to meta-data
++ needed to maintain that file data.
++
++2. If the backing-store RAM is comparable in access speed to system memory,
++ there's really no point in caching the file I/O data in the page
++ cache. Better to move file data directly between the user buffers
++ and the backing store RAM, i.e. use direct I/O. This prevents the
++ unnecessary populating of the page cache with dirty pages. However
++ direct I/O has to be enabled at every file open. To enable direct
++ I/O at all times for all regular files requires either that
++ applications be modified to include the O_DIRECT flag on all file
++ opens, or that a new filesystem be used that always performs direct
++ I/O by default.
++
++The Persistent/Protected RAM Special Filesystem (PRAMFS) is a
++full-featured read/write filesystem that has been designed to address
++these issues. PRAMFS is targeted to fast I/O memory, and if the memory
++is non-volatile, the filesystem will be persistent.
++
++In PRAMFS, direct I/O is enabled across all files in the filesystem, in
++other words the O_DIRECT flag is forced on every open of a PRAMFS file.
++Also, file I/O in the PRAMFS is always synchronous. There is no need
++to block the current process while the transfer to/from the PRAMFS
++is in progress, since one of the requirements of the PRAMFS is that the
++filesystem exist in fast RAM. So file I/O in PRAMFS is always direct,
++synchronous, and never blocks.
++
++The data organization in PRAMFS can be thought of as an extremely
++simplified version of ext2, such that the ratio of data to meta-data is
++very high.
++
++PRAMFS is also write protected. The page table entries that map the
++backing-store RAM are normally marked read-only. Write operations into
++the filesystem temporarily mark the affected pages as writeable, the
++write operation is carried out with locks held, and then the pte is
++marked read-only again. This feature provides some protection against
++filesystem corruption caused by errant writes into the RAM due to
++kernel bugs for instance. In case there are systems where the write
++protection is not possible (for instance the RAM cannot be mapped
++with page tables), this feature can be disabled with the CONFIG_PRAMFS_NOWP
++config option.
++
++In summary, PRAMFS is a light-weight, full-featured, and space-efficient
++special filesystem that is ideal for systems with a block of fast
++non-volatile RAM that need to access data on it using a standard
++filesytem interface.
++
++
++Supported mount options
++=======================
++
++The PRAMFS currently requires one mount option, and there are several
++optional mount options:
++
++physaddr= Required. It tells PRAMFS the physical address of the
++ start of the RAM that makes up the filesystem. The
++ physical address must be located on a page boundary.
++
++init= Optional. It is used to initialize the memory to an
++ empty filesystem. Any data in an existing filesystem
++ will be lost if this option is given. The parameter to
++ "init=" is the RAM size in bytes.
++
++bs= Optional. It is used to specify a block size. It is
++ ignored if the "init=" option is not specified, since
++ otherwise the block size is read from the PRAMFS
++ super-block. The default blocksize is 2048 bytes,
++ and the allowed block sizes are 512, 1024, 2048, and
++ 4096.
++
++bpi= Optional. It is used to specify the bytes per inode
++ ratio, i.e. For every N bytes in the filesystem, an
++ inode will be created. This behaves the same as the "-i"
++ option to mke2fs. It is ignored if the "init=" option is
++ not specified.
++
++N= Optional. It is used to specify the number of inodes to
++ allocate in the inode table. If the option is not
++ specified, the bytes-per-inode ratio is used the
++ calculate the number of inodes. If neither the "N=" or
++ "bpi=" options are specified, the default behavior is to
++ reserve 5% of the total space in the filesystem for the
++ inode table. This option behaves the same as the "-N"
++ option to mke2fs. It is ignored if the "init=" option is
++ not specified.
++
++Examples:
++
++mount -t pramfs -o physaddr=0x20000000,init=0x2F000,bs=1024 none /mnt/pram
++
++This example locates the filesystem at physical address 0x20000000, and
++also requests an empty filesystem be initialized, of total size 0x2f000
++bytes and blocksize 1024. The mount point is /mnt/pram.
++
++mount -t pramfs -o physaddr=0x20000000 none /mnt/pram
++
++This example locates the filesystem at physical address 0x20000000 as in
++the first example, but uses the intact filesystem that already exists.
++
++
++Current Limitations
++===================
++
++- The RAM used for PRAMFS must be directly addressable.
++
++- PRAMFS does not support hard links.
++
++- PRAMFS supports only private memory mappings. This allows most
++ executables to run, but programs that attempt shared memory
++ mappings, such as X apps that use X shared memory, will fail.
++
++Further Documentation
++=====================
++
++If you are interested in the internal design of PRAMFS, there is
++documentation available at the Sourceforge PRAMFS home page at
++http://pramfs.sourceforge.net.
++
++Please send bug reports/comments/feed back to the pramfs development
++list at sourceforge: pramfs-devel@lists.sourceforge.net.
++
++
++ChangeLog
++=========
++
++1.0.2:
++ - kernel 2.6.4.
++ - use pram_truncate() in pram_delete_inode().
++ - dangling pram_lock_inode() removed in pram_truncate_blocks().
++ - edits to this README
++
++1.0.1:
++ - port to kernel 2.6.3.
++ - implement direct_IO() method instead of custom file read/write
++ methods.
++ - do away with __ioremap_readonly() requirement.
++ - implement inode truncate() method.
++
++1.0.0:
++ - Started ChangeLog (kernel 2.4.22).
++
+diff -Nuar -X /home/stevel/dontdiff main.orig/fs/Kconfig main/fs/Kconfig
+--- main.orig/fs/Kconfig 2004-03-04 17:15:10.000000000 -0800
++++ main/fs/Kconfig 2004-03-04 15:58:57.000000000 -0800
+@@ -885,6 +885,27 @@
+ To compile this as a module, choose M here: the module will be called
+ ramfs.
+
++config PRAMFS
++ tristate "Persistent and Protected RAM file system support"
++ help
++ If your system has a block of fast (comparable in access speed to
++ system memory) and non-volatile RAM and you wish to mount a
++ light-weight, full-featured, and space-efficient filesystem over it,
++ say Y here, and read <file:Documentation/filesystems/pramfs.txt>.
++
++ To compile this as a module, choose M here: the module will be
++ called pramfs.
++
++config PRAMFS_NOWP
++ bool "Disable write protection (default is enabled)"
++ depends on PRAMFS
++ help
++ Say Y here to disable the write protect feature of PRAMFS.
++
++config ROOT_PRAMFS
++ bool "Root file system on pramfs"
++ depends on PRAMFS
++
+ endmenu
+
+ menu "Miscellaneous filesystems"
+diff -Nuar -X /home/stevel/dontdiff main.orig/fs/Makefile main/fs/Makefile
+--- main.orig/fs/Makefile 2004-03-04 17:15:10.000000000 -0800
++++ main/fs/Makefile 2004-03-04 15:58:57.000000000 -0800
+@@ -51,6 +51,7 @@
+ obj-$(CONFIG_EXT2_FS) += ext2/
+ obj-$(CONFIG_CRAMFS) += cramfs/
+ obj-$(CONFIG_RAMFS) += ramfs/
++obj-$(CONFIG_PRAMFS) += pramfs/
+ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/
+ obj-$(CONFIG_CODA_FS) += coda/
+ obj-$(CONFIG_INTERMEZZO_FS) += intermezzo/
+diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/balloc.c main/fs/pramfs/balloc.c
+--- main.orig/fs/pramfs/balloc.c 1969-12-31 16:00:00.000000000 -0800
++++ main/fs/pramfs/balloc.c 2004-03-04 15:59:03.000000000 -0800
+@@ -0,0 +1,163 @@
++/*
++ * balloc.c
++ *
++ * The blocks allocation and deallocation routines.
++ *
++ * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
++ *
++ * 2003 (c) MontaVista Software, Inc.
++ * Copyright 2003 Sony Corporation
++ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
++ *
++ * This software is being distributed under the terms of the GNU General Public
++ * License version 2. Some or all of the technology encompassed by this
++ * software may be subject to one or more patents pending as of the date of
++ * this notice. No additional patent license will be required for GPL
++ * implementations of the technology. If you want to create a non-GPL
++ * implementation of the technology encompassed by this software, please
++ * contact legal@mvista.com for details including licensing terms and fees.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++#include <linux/config.h>
++#include <linux/fs.h>
++#include <linux/pram_fs.h>
++#include <linux/quotaops.h>
++#include <asm/bitops.h>
++
++
++/*
++ * This just marks in-use the blocks that make up the bitmap.
++ * The bitmap must be writeable before calling.
++ */
++void pram_init_bitmap(struct super_block * sb)
++{
++ struct pram_super_block * ps = pram_get_super(sb);
++ u32* bitmap = pram_get_bitmap(sb);
++ int blocks = ps->s_bitmap_blocks;
++
++ memset(bitmap, 0, blocks<<sb->s_blocksize_bits);
++
++ while (blocks >= 32) {
++ *bitmap++ = 0xffffffff;
++ blocks -= 32;
++ }
++
++ if (blocks)
++ *bitmap = (1<<blocks) - 1;
++}
++
++
++/* Free absolute blocknr */
++void pram_free_block (struct super_block * sb, int blocknr)
++{
++ struct pram_super_block * ps;
++ pram_off_t bitmap_block;
++ unsigned long flags;
++ int bitmap_bnr;
++ void* bitmap;
++ void* bp;
++
++ lock_super (sb);
++
++ bitmap = pram_get_bitmap(sb);
++ /*
++ * find the block within the bitmap that contains the inuse bit
++ * for the block we need to free. We need to unlock this bitmap
++ * block to clear the inuse bit.
++ */
++ bitmap_bnr = blocknr >> (3 + sb->s_blocksize_bits);
++ bitmap_block = pram_get_block_off(sb, bitmap_bnr);
++ bp = pram_get_block(sb, bitmap_block);
++
++ pram_lock_block(sb, bp);
++ clear_bit(blocknr, bitmap); // mark the block free
++ pram_unlock_block(sb, bp);
++
++ ps = pram_get_super(sb);
++ pram_lock_super(ps);
++ if (blocknr < ps->s_free_blocknr_hint)
++ ps->s_free_blocknr_hint = blocknr;
++ ps->s_free_blocks_count++;
++ pram_unlock_super(ps);
++
++ unlock_super (sb);
++}
++
++
++/*
++ * allocate a block and return it's absolute blocknr. Zeroes out the
++ * block if zero set.
++ */
++int pram_new_block (struct super_block * sb, int* blocknr, int zero)
++{
++ struct pram_super_block * ps;
++ pram_off_t bitmap_block;
++ unsigned long flags;
++ int bnr, bitmap_bnr, errval;
++ void* bitmap;
++ void* bp;
++
++ lock_super (sb);
++ ps = pram_get_super(sb);
++ bitmap = pram_get_bitmap(sb);
++
++ if (ps->s_free_blocks_count) {
++ /* find the oldest unused block */
++ bnr = find_next_zero_bit(bitmap,
++ ps->s_blocks_count,
++ ps->s_free_blocknr_hint);
++
++ if (bnr < ps->s_bitmap_blocks || bnr >= ps->s_blocks_count) {
++ pram_err("no free blocks found!\n");
++ errval = -ENOSPC;
++ goto fail;
++ }
++
++ pram_dbg ("allocating blocknr %d\n", bnr);
++ pram_lock_super(ps);
++ ps->s_free_blocks_count--;
++ ps->s_free_blocknr_hint =
++ (bnr < ps->s_blocks_count-1) ? bnr+1 : 0;
++ pram_unlock_super(ps);
++ } else {
++ pram_err("all blocks allocated\n");
++ errval = -ENOSPC;
++ goto fail;
++ }
++
++ /*
++ * find the block within the bitmap that contains the inuse bit
++ * for the unused block we just found. We need to unlock it to
++ * set the inuse bit.
++ */
++ bitmap_bnr = bnr >> (3 + sb->s_blocksize_bits);
++ bitmap_block = pram_get_block_off(sb, bitmap_bnr);
++ bp = pram_get_block(sb, bitmap_block);
++
++ pram_lock_block(sb, bp);
++ set_bit(bnr, bitmap); // mark the new block in use
++ pram_unlock_block(sb, bp);
++
++ if (zero) {
++ bp = pram_get_block(sb, pram_get_block_off(sb, bnr));
++ pram_lock_block(sb, bp);
++ memset(bp, 0, sb->s_blocksize);
++ pram_unlock_block(sb, bp);
++ }
++
++ *blocknr = bnr;
++ errval = 0;
++ fail:
++ unlock_super (sb);
++ return errval;
++}
++
++
++unsigned long pram_count_free_blocks (struct super_block * sb)
++{
++ struct pram_super_block * ps = pram_get_super(sb);
++ return ps->s_free_blocks_count;
++}
+diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/dir.c main/fs/pramfs/dir.c
+--- main.orig/fs/pramfs/dir.c 1969-12-31 16:00:00.000000000 -0800
++++ main/fs/pramfs/dir.c 2004-03-04 15:59:03.000000000 -0800
+@@ -0,0 +1,225 @@
++/*
++ * dir.c
++ *
++ * File operations for directories.
++ *
++ * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
++ *
++ * 2003 (c) MontaVista Software, Inc.
++ * Copyright 2003 Sony Corporation
++ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
++ *
++ * This software is being distributed under the terms of the GNU General Public
++ * License version 2. Some or all of the technology encompassed by this
++ * software may be subject to one or more patents pending as of the date of
++ * this notice. No additional patent license will be required for GPL
++ * implementations of the technology. If you want to create a non-GPL
++ * implementation of the technology encompassed by this software, please
++ * contact legal@mvista.com for details including licensing terms and fees.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#include <linux/fs.h>
++#include <linux/pram_fs.h>
++#include <linux/pagemap.h>
++
++
++/*
++ * Parent is locked.
++ */
++int pram_add_link (struct dentry * dentry, struct inode * inode)
++{
++ struct inode * dir = dentry->d_parent->d_inode;
++ struct pram_inode * pidir, * pi, * pitail = NULL;
++ unsigned long flags;
++ pram_off_t tail_ino, prev_ino;
++ const char *name = dentry->d_name.name;
++ int namelen = dentry->d_name.len > PRAM_NAME_LEN ?
++ PRAM_NAME_LEN : dentry->d_name.len;
++
++ pidir = pram_get_inode(dir->i_sb, dir->i_ino);
++ pi = pram_get_inode(dir->i_sb, inode->i_ino);
++
++ dir->i_mtime = dir->i_ctime = CURRENT_TIME;
++
++ tail_ino = pidir->i_type.dir.tail;
++ if (tail_ino != 0) {
++ pitail = pram_get_inode(dir->i_sb, tail_ino);
++ pram_lock_inode(pitail);
++ pitail->i_d.d_next = inode->i_ino;
++ pram_unlock_inode(pitail);
++
++ prev_ino = tail_ino;
++
++ pram_lock_inode(pidir);
++ pidir->i_type.dir.tail = inode->i_ino;
++ pidir->i_mtime = dir->i_mtime.tv_sec;
++ pidir->i_ctime = dir->i_ctime.tv_sec;
++ pram_unlock_inode(pidir);
++ } else {
++ // the directory is empty
++ prev_ino = 0;
++
++ pram_lock_inode(pidir);
++ pidir->i_type.dir.head = pidir->i_type.dir.tail = inode->i_ino;
++ pidir->i_mtime = dir->i_mtime.tv_sec;
++ pidir->i_ctime = dir->i_ctime.tv_sec;
++ pram_unlock_inode(pidir);
++ }
++
++
++ pram_lock_inode(pi);
++ pi->i_d.d_prev = prev_ino;
++ pi->i_d.d_parent = dir->i_ino;
++ memcpy(pi->i_d.d_name, name, namelen);
++ pi->i_d.d_name[namelen] = '\0';
++ pram_unlock_inode(pi);
++ return 0;
++}
++
++int pram_remove_link(struct inode * inode)
++{
++ struct super_block * sb = inode->i_sb;
++ struct pram_inode * prev = NULL;
++ struct pram_inode * next = NULL;
++ struct pram_inode * pidir, * pi;
++ unsigned long flags;
++
++ pi = pram_get_inode(sb, inode->i_ino);
++ pidir = pram_get_inode(sb, pi->i_d.d_parent);
++ if (!pidir)
++ return -EACCES;
++
++ if (inode->i_ino == pidir->i_type.dir.head) {
++ // first inode in directory
++ next = pram_get_inode(sb, pi->i_d.d_next);
++
++ if (next) {
++ pram_lock_inode(next);
++ next->i_d.d_prev = 0;
++ pram_unlock_inode(next);
++
++ pram_lock_inode(pidir);
++ pidir->i_type.dir.head = pi->i_d.d_next;
++ } else {
++ pram_lock_inode(pidir);
++ pidir->i_type.dir.head = pidir->i_type.dir.tail = 0;
++ }
++ pram_unlock_inode(pidir);
++ } else if (inode->i_ino == pidir->i_type.dir.tail) {
++ // last inode in directory
++ prev = pram_get_inode(sb, pi->i_d.d_prev);
++
++ pram_lock_inode(prev);
++ prev->i_d.d_next = 0;
++ pram_unlock_inode(prev);
++
++ pram_lock_inode(pidir);
++ pidir->i_type.dir.tail = pi->i_d.d_prev;
++ pram_unlock_inode(pidir);
++ } else {
++ // somewhere in the middle
++ prev = pram_get_inode(sb, pi->i_d.d_prev);
++ next = pram_get_inode(sb, pi->i_d.d_next);
++
++ if (prev && next) {
++ pram_lock_inode(prev);
++ prev->i_d.d_next = pi->i_d.d_next;
++ pram_unlock_inode(prev);
++
++ pram_lock_inode(next);
++ next->i_d.d_prev = pi->i_d.d_prev;
++ pram_unlock_inode(next);
++ }
++ }
++
++ pram_lock_inode(pi);
++ pi->i_d.d_next = pi->i_d.d_prev = pi->i_d.d_parent = 0;
++ pram_unlock_inode(pi);
++
++ return 0;
++}
++
++#define S_SHIFT 12
++static unsigned int dtype_by_mode[S_IFMT >> S_SHIFT] = {
++ [S_IFREG >> S_SHIFT] DT_REG,
++ [S_IFDIR >> S_SHIFT] DT_DIR,
++ [S_IFCHR >> S_SHIFT] DT_CHR,
++ [S_IFBLK >> S_SHIFT] DT_BLK,
++ [S_IFIFO >> S_SHIFT] DT_FIFO,
++ [S_IFSOCK >> S_SHIFT] DT_SOCK,
++ [S_IFLNK >> S_SHIFT] DT_LNK,
++};
++
++static int
++pram_readdir (struct file * filp, void * dirent, filldir_t filldir)
++{
++ struct inode *inode = filp->f_dentry->d_inode;
++ struct super_block * sb = inode->i_sb;
++ struct pram_inode * pi;
++ int namelen, ret=0;
++ char *name;
++ ino_t ino;
++
++ if (filp->f_pos >> 32)
++ return 0;
++
++ pi = pram_get_inode(sb, inode->i_ino);
++
++ switch ((unsigned long)filp->f_pos) {
++ case 0:
++ ret = filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR);
++ filp->f_pos++;
++ return ret;
++ case 1:
++ ret = filldir(dirent, "..", 2, 1, pi->i_d.d_parent, DT_DIR);
++ ino = pi->i_type.dir.head;
++ filp->f_pos = ino ? ino : 2;
++ return ret;
++ case 2:
++ ino = pi->i_type.dir.head;
++ if (ino) {
++ filp->f_pos = ino;
++ pi = pram_get_inode(sb, ino);
++ break;
++ } else {
++ /* the directory is empty */
++ filp->f_pos = 2;
++ return 0;
++ }
++ case 3:
++ return 0;
++ default:
++ ino = filp->f_pos;
++ pi = pram_get_inode(sb, ino);
++ break;
++ }
++
++ while (pi && !pi->i_links_count) {
++ ino = filp->f_pos = pi->i_d.d_next;
++ pi = pram_get_inode(sb, ino);
++ }
++
++ if (pi) {
++ name = pi->i_d.d_name;
++ namelen = strlen(name);
++
++ ret = filldir(dirent, name, namelen,
++ filp->f_pos, ino,
++ dtype_by_mode[(pi->i_mode & S_IFMT)>>S_SHIFT]);
++ filp->f_pos = pi->i_d.d_next ? pi->i_d.d_next : 3;
++ } else
++ filp->f_pos = 3;
++
++ return ret;
++}
++
++struct file_operations pram_dir_operations = {
++ read: generic_read_dir,
++ readdir: pram_readdir,
++ ioctl: pram_ioctl,
++ fsync: pram_sync_file,
++};
+diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/file.c main/fs/pramfs/file.c
+--- main.orig/fs/pramfs/file.c 1969-12-31 16:00:00.000000000 -0800
++++ main/fs/pramfs/file.c 2004-03-04 15:59:03.000000000 -0800
+@@ -0,0 +1,143 @@
++/*
++ * file.c
++ *
++ * File operations for regular files.
++ *
++ * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
++ *
++ * 2003 (c) MontaVista Software, Inc.
++ * Copyright 2003 Sony Corporation
++ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
++ *
++ * This software is being distributed under the terms of the GNU General Public
++ * License version 2. Some or all of the technology encompassed by this
++ * software may be subject to one or more patents pending as of the date of
++ * this notice. No additional patent license will be required for GPL
++ * implementations of the technology. If you want to create a non-GPL
++ * implementation of the technology encompassed by this software, please
++ * contact legal@mvista.com for details including licensing terms and fees.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++#include <linux/fs.h>
++#include <linux/pram_fs.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/uio.h>
++#include <asm/uaccess.h>
++
++static int pram_open_file(struct inode * inode, struct file * filp)
++{
++ filp->f_flags |= O_DIRECT;
++ return generic_file_open(inode, filp);
++}
++
++/*
++ * Called when an inode is released. Note that this is different
++ * from pram_open_file: open gets called at every open, but release
++ * gets called only when /all/ the files are closed.
++ */
++static int pram_release_file (struct inode * inode, struct file * filp)
++{
++ return 0;
++}
++
++int pram_direct_IO(int rw, struct kiocb *iocb,
++ const struct iovec *iov,
++ loff_t offset, unsigned long nr_segs)
++{
++ struct file *file = iocb->ki_filp;
++ struct inode *inode = file->f_mapping->host;
++ struct super_block * sb = inode->i_sb;
++ int progress = 0, retval = 0;
++ struct pram_inode * pi;
++ void * tmp = NULL;
++ unsigned long blocknr, blockoff, flags;
++ int num_blocks, blocksize_mask, blocksize, blocksize_bits;
++ char __user *buf = iov->iov_base;
++ size_t length = iov->iov_len;
++
++ if (length < 0)
++ return -EINVAL;
++ if ((rw == READ) && (offset + length > inode->i_size))
++ length = inode->i_size - offset;
++ if (!length)
++ goto out;
++
++ blocksize_bits = inode->i_sb->s_blocksize_bits;
++ blocksize = 1 << blocksize_bits;
++ blocksize_mask = blocksize - 1;
++
++ /* find starting block number to access */
++ blocknr = offset >> blocksize_bits;
++ /* find starting offset within starting block */
++ blockoff = offset & blocksize_mask;
++ /* find number of blocks to access */
++ num_blocks = (blockoff + length + blocksize_mask) >> blocksize_bits;
++
++ if (rw == WRITE) {
++ // prepare a temporary buffer to hold a user data block
++ // for writing.
++ tmp = kmalloc(blocksize, GFP_KERNEL);
++ if (!tmp)
++ return -ENOMEM;
++ /* now allocate the data blocks we'll need */
++ retval = pram_alloc_blocks(inode, blocknr, num_blocks);
++ if (retval)
++ goto fail;
++ }
++
++ pi = pram_get_inode(inode->i_sb, inode->i_ino);
++
++ while (length) {
++ int count;
++ pram_off_t block = pram_find_data_block(inode, blocknr++);
++ u8* bp = (u8*)pram_get_block(sb, block);
++ if (!bp)
++ goto fail;
++
++ count = blockoff + length > blocksize ?
++ blocksize - blockoff : length;
++
++ if (rw == READ) {
++ copy_to_user(buf, &bp[blockoff], count);
++ } else {
++ copy_from_user(tmp, buf, count);
++
++ pram_lock_block(inode->i_sb, bp);
++ memcpy(&bp[blockoff], tmp, count);
++ pram_unlock_block(inode->i_sb, bp);
++ }
++
++ progress += count;
++ buf += count;
++ length -= count;
++ blockoff = 0;
++ }
++
++ retval = progress;
++ fail:
++ if (tmp)
++ kfree(tmp);
++ out:
++ return retval;
++}
++
++
++
++struct file_operations pram_file_operations = {
++ llseek: generic_file_llseek,
++ read: generic_file_read,
++ write: generic_file_write,
++ ioctl: pram_ioctl,
++ mmap: generic_file_mmap,
++ open: pram_open_file,
++ release: pram_release_file,
++ fsync: pram_sync_file,
++};
++
++struct inode_operations pram_file_inode_operations = {
++ truncate: pram_truncate,
++};
+diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/fsync.c main/fs/pramfs/fsync.c
+--- main.orig/fs/pramfs/fsync.c 1969-12-31 16:00:00.000000000 -0800
++++ main/fs/pramfs/fsync.c 2004-03-04 15:59:03.000000000 -0800
+@@ -0,0 +1,37 @@
++/*
++ * fsync.c
++ *
++ * fsync operation for directory and regular files.
++ *
++ * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
++ *
++ * 2003 (c) MontaVista Software, Inc.
++ * Copyright 2003 Sony Corporation
++ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
++ *
++ * This software is being distributed under the terms of the GNU General Public
++ * License version 2. Some or all of the technology encompassed by this
++ * software may be subject to one or more patents pending as of the date of
++ * this notice. No additional patent license will be required for GPL
++ * implementations of the technology. If you want to create a non-GPL
++ * implementation of the technology encompassed by this software, please
++ * contact legal@mvista.com for details including licensing terms and fees.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++#include <linux/fs.h>
++#include <linux/pram_fs.h>
++
++/*
++ * File may be NULL when we are called. Perhaps we shouldn't
++ * even pass file to fsync ?
++ */
++
++int pram_sync_file(struct file * file, struct dentry *dentry, int datasync)
++{
++ // FIXME: check
++ return 0;
++}
++
+diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/inode.c main/fs/pramfs/inode.c
+--- main.orig/fs/pramfs/inode.c 1969-12-31 16:00:00.000000000 -0800
++++ main/fs/pramfs/inode.c 2004-03-04 16:45:11.000000000 -0800
+@@ -0,0 +1,649 @@
++/*
++ * inode.c
++ *
++ * Inode methods (allocate/free/read/write).
++ *
++ * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
++ *
++ * 2003 (c) MontaVista Software, Inc.
++ * Copyright 2003 Sony Corporation
++ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
++ *
++ * This software is being distributed under the terms of the GNU General Public
++ * License version 2. Some or all of the technology encompassed by this
++ * software may be subject to one or more patents pending as of the date of
++ * this notice. No additional patent license will be required for GPL
++ * implementations of the technology. If you want to create a non-GPL
++ * implementation of the technology encompassed by this software, please
++ * contact legal@mvista.com for details including licensing terms and fees.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++#include <linux/fs.h>
++#include <linux/pram_fs.h>
++#include <linux/smp_lock.h>
++#include <linux/sched.h>
++#include <linux/highuid.h>
++#include <linux/quotaops.h>
++#include <linux/module.h>
++#include <linux/buffer_head.h>
++#include <linux/mpage.h>
++#include <linux/backing-dev.h>
++
++
++static struct backing_dev_info pram_backing_dev_info = {
++ .ra_pages = 0, /* No readahead */
++ .memory_backed = 1, /* Does not contribute to dirty memory */
++};
++
++/*
++ * allocate a data block for inode and return it's absolute blocknr.
++ * Zeroes out the block if zero set. Increments inode->i_blocks.
++ */
++static int
++pram_new_data_block (struct inode * inode, int* blocknr, int zero)
++{
++ unsigned long flags;
++ int errval = pram_new_block(inode->i_sb, blocknr, zero);
++
++ if (!errval) {
++ struct pram_inode * pi = pram_get_inode(inode->i_sb,
++ inode->i_ino);
++ inode->i_blocks++;
++ pram_lock_inode(pi);
++ pi->i_blocks = inode->i_blocks;
++ pram_unlock_inode(pi);
++ }
++
++ return errval;
++}
++
++/*
++ * find the offset to the block represented by the given inode's file
++ * relative block number.
++ */
++pram_off_t pram_find_data_block(struct inode * inode, int file_blocknr)
++{
++ struct super_block * sb = inode->i_sb;
++ struct pram_inode * pi;
++ pram_off_t * row; /* ptr to row block */
++ pram_off_t * col; /* ptr to column blocks */
++ pram_off_t bp = 0;
++ int i_row, i_col;
++ int N = sb->s_blocksize >> 2; // num block ptrs per block
++ int Nbits = sb->s_blocksize_bits - 2;
++
++ pi = pram_get_inode(sb, inode->i_ino);
++
++ i_row = file_blocknr >> Nbits;
++ i_col = file_blocknr & (N-1);
++
++ row = pram_get_block(sb, pi->i_type.reg.row_block);
++ if (row) {
++ col = pram_get_block(sb, row[i_row]);
++ if (col)
++ bp = col[i_col];
++ }
++
++ return bp;
++}
++
++
++/*
++ * Free data blocks from inode starting at first_trunc_block.
++ */
++static void
++pram_truncate_blocks(struct inode * inode, int first_trunc_block)
++{
++ struct super_block * sb = inode->i_sb;
++ struct pram_inode * pi = pram_get_inode(sb, inode->i_ino);
++ int N = sb->s_blocksize >> 2; // num block ptrs per block
++ int Nbits = sb->s_blocksize_bits - 2;
++ int first_row_index, last_row_index;
++ int i, j, first_blocknr, last_blocknr, blocknr;
++ unsigned long flags;
++ pram_off_t * row; /* ptr to row block */
++ pram_off_t * col; /* ptr to column blocks */
++
++ if (first_trunc_block >= inode->i_blocks ||
++ !inode->i_blocks || !pi->i_type.reg.row_block) {
++ return;
++ }
++
++ first_blocknr = first_trunc_block;
++ last_blocknr = inode->i_blocks - 1;
++ first_row_index = first_blocknr >> Nbits;
++ last_row_index = last_blocknr >> Nbits;
++
++ row = pram_get_block(sb, pi->i_type.reg.row_block);
++
++ for (i=first_row_index; i <= last_row_index; i++) {
++ int first_col_index = (i == first_row_index) ?
++ first_blocknr & (N-1) : 0;
++ int last_col_index = (i == last_row_index) ?
++ last_blocknr & (N-1) : N-1;
++
++ col = pram_get_block(sb, row[i]);
++ for (j=first_col_index; j <= last_col_index; j++) {
++ blocknr = pram_get_blocknr(sb, col[j]);
++ pram_free_block(sb, blocknr);
++ pram_lock_block(sb, col);
++ col[j] = 0;
++ pram_unlock_block(sb, col);
++ }
++
++ if (first_col_index == 0) {
++ blocknr = pram_get_blocknr(sb, row[i]);
++ pram_free_block(sb, blocknr);
++ pram_lock_block(sb, row);
++ row[i] = 0;
++ pram_unlock_block(sb, row);
++ }
++ }
++
++ inode->i_blocks -= (last_blocknr - first_blocknr + 1);
++
++ if (first_row_index == 0) {
++ blocknr = pram_get_blocknr(sb, pi->i_type.reg.row_block);
++ pram_free_block(sb, blocknr);
++ pram_lock_inode(pi);
++ pi->i_type.reg.row_block = 0;
++ pram_unlock_inode(pi);
++ }
++ pram_lock_inode(pi);
++ pi->i_blocks = inode->i_blocks;
++ pram_unlock_inode(pi);
++}
++
++/*
++ * Allocate num data blocks for inode, starting at given file-relative
++ * block number. Any unallocated file blocks before file_blocknr
++ * are allocated. All blocks except the last are zeroed out.
++ */
++int pram_alloc_blocks(struct inode * inode, int file_blocknr, int num)
++{
++ struct super_block * sb = inode->i_sb;
++ struct pram_inode * pi = pram_get_inode(sb, inode->i_ino);
++ int N = sb->s_blocksize >> 2; // num block ptrs per block
++ int Nbits = sb->s_blocksize_bits - 2;
++ int first_file_blocknr;
++ int last_file_blocknr;
++ int first_row_index, last_row_index;
++ int i, j, blocknr, errval;
++ unsigned long flags;
++ pram_off_t * row;
++ pram_off_t * col;
++
++ if (!pi->i_type.reg.row_block) {
++ /* alloc the 2nd order array block */
++ errval = pram_new_block(sb, &blocknr, 1);
++ if (errval) {
++ pram_err("failed to alloc 2nd order array block\n");
++ goto fail;
++ }
++ pram_lock_inode(pi);
++ pi->i_type.reg.row_block = pram_get_block_off(sb, blocknr);
++ pram_unlock_inode(pi);
++ }
++
++ row = pram_get_block(sb, pi->i_type.reg.row_block);
++
++ first_file_blocknr = (file_blocknr > inode->i_blocks) ?
++ inode->i_blocks : file_blocknr;
++ last_file_blocknr = file_blocknr + num - 1;
++
++ first_row_index = first_file_blocknr >> Nbits;
++ last_row_index = last_file_blocknr >> Nbits;
++
++ for (i=first_row_index; i<=last_row_index; i++) {
++ int first_col_index, last_col_index;
++ /*
++ * we are starting a new row, so make sure
++ * there is a block allocated for the row.
++ */
++ if (!row[i]) {
++ /* allocate the row block */
++ errval = pram_new_block(sb, &blocknr, 1);
++ if (errval) {
++ pram_err("failed to alloc row block\n");
++ goto fail;
++ }
++ pram_lock_block(sb, row);
++ row[i] = pram_get_block_off(sb, blocknr);
++ pram_unlock_block(sb, row);
++ }
++ col = pram_get_block(sb, row[i]);
++
++ first_col_index = (i == first_row_index) ?
++ first_file_blocknr & (N-1) : 0;
++
++ last_col_index = (i == last_row_index) ?
++ last_file_blocknr & (N-1) : N-1;
++
++ for (j=first_col_index; j<=last_col_index; j++) {
++ int last_block =
++ (i==last_row_index) && (j==last_col_index);
++ if (!col[j]) {
++ errval = pram_new_data_block(inode,
++ &blocknr,
++ !last_block);
++ if (errval) {
++ pram_err("failed to alloc "
++ "data block\n");
++ goto fail;
++ }
++ pram_lock_block(sb, col);
++ col[j] = pram_get_block_off(sb, blocknr);
++ pram_unlock_block(sb, col);
++ }
++ }
++ }
++
++ errval = 0;
++ fail:
++ return errval;
++}
++
++
++static int
++pram_fill_inode(struct inode * inode, struct pram_inode * pi)
++{
++ int ret = -EIO;
++
++ if (pram_calc_checksum((u32*)pi, PRAM_INODE_SIZE>>2)) {
++ pram_err("checksum error in inode %08x\n",
++ (u32)inode->i_ino);
++ goto bad_inode;
++ }
++
++ inode->i_mode = pi->i_mode;
++ inode->i_uid = pi->i_uid;
++ inode->i_gid = pi->i_gid;
++ inode->i_nlink = pi->i_links_count;
++ inode->i_size = pi->i_size;
++ inode->i_atime.tv_sec = pi->i_atime;
++ inode->i_ctime.tv_sec = pi->i_ctime;
++ inode->i_mtime.tv_sec = pi->i_mtime;
++ inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec =
++ inode->i_ctime.tv_nsec = 0;
++
++ /* check if the inode is active. */
++ if (inode->i_nlink == 0 && (inode->i_mode == 0 || pi->i_dtime)) {
++ /* this inode is deleted */
++ ret = -EINVAL;
++ goto bad_inode;
++ }
++
++ inode->i_blocks = pi->i_blocks;
++ inode->i_blksize = inode->i_sb->s_blocksize;
++ inode->i_ino = pram_get_inodenr(inode->i_sb, pi);
++ inode->i_mapping->a_ops = &pram_aops;
++ inode->i_mapping->backing_dev_info = &pram_backing_dev_info;
++
++ insert_inode_hash(inode);
++ switch (inode->i_mode & S_IFMT) {
++ case S_IFREG:
++ inode->i_op = &pram_file_inode_operations;
++ inode->i_fop = &pram_file_operations;
++ break;
++ case S_IFDIR:
++ inode->i_op = &pram_dir_inode_operations;
++ inode->i_fop = &pram_dir_operations;
++ break;
++ case S_IFLNK:
++ inode->i_op = &pram_symlink_inode_operations;
++ break;
++ default:
++ inode->i_size = 0;
++ init_special_inode(inode, inode->i_mode,
++ pi->i_type.dev.rdev);
++ break;
++ }
++
++ return 0;
++
++ bad_inode:
++ make_bad_inode(inode);
++ return ret;
++}
++
++static int pram_update_inode(struct inode * inode)
++{
++ struct pram_inode * pi;
++ unsigned long flags;
++ int retval = 0;
++
++ pi = pram_get_inode(inode->i_sb, inode->i_ino);
++
++ pram_lock_inode(pi);
++ pi->i_mode = inode->i_mode;
++ pi->i_uid = inode->i_uid;
++ pi->i_gid = inode->i_gid;
++ pi->i_links_count = inode->i_nlink;
++ pi->i_size = inode->i_size;
++ pi->i_blocks = inode->i_blocks;
++ pi->i_atime = inode->i_atime.tv_sec;
++ pi->i_ctime = inode->i_ctime.tv_sec;
++ pi->i_mtime = inode->i_mtime.tv_sec;
++
++ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
++ pi->i_type.dev.rdev = inode->i_rdev;
++
++ pram_unlock_inode(pi);
++ return retval;
++}
++
++/*
++ * NOTE! When we get the inode, we're the only people
++ * that have access to it, and as such there are no
++ * race conditions we have to worry about. The inode
++ * is not on the hash-lists, and it cannot be reached
++ * through the filesystem because the directory entry
++ * has been deleted earlier.
++ */
++static void pram_free_inode (struct inode * inode)
++{
++ struct super_block * sb = inode->i_sb;
++ struct pram_super_block * ps;
++ struct pram_inode * pi;
++ unsigned long flags, inode_nr;
++
++ /*
++ * Note: we must free any quota before locking the superblock,
++ * as writing the quota to disk may need the lock as well.
++ */
++ if (!is_bad_inode(inode)) {
++ /* Quota is already initialized in iput() */
++ DQUOT_FREE_INODE(inode);
++ DQUOT_DROP(inode);
++ }
++
++ lock_super (sb);
++ clear_inode (inode);
++
++ inode_nr = (inode->i_ino - PRAM_ROOT_INO) >> PRAM_INODE_BITS;
++
++ pi = pram_get_inode(sb, inode->i_ino);
++ pram_lock_inode(pi);
++ pi->i_dtime = get_seconds();
++ pi->i_type.reg.row_block = 0;
++ pram_unlock_inode(pi);
++
++ // increment s_free_inodes_count
++ ps = pram_get_super(sb);
++ pram_lock_super(ps);
++ if (inode_nr < ps->s_free_inode_hint)
++ ps->s_free_inode_hint = inode_nr;
++ ps->s_free_inodes_count++;
++ if (ps->s_free_inodes_count == ps->s_inodes_count - 1) {
++ // filesystem is empty
++ pram_dbg ("fs is empty!\n");
++ ps->s_free_inode_hint = 1;
++ }
++ pram_unlock_super(ps);
++
++ unlock_super (sb);
++}
++
++
++struct inode *
++pram_fill_new_inode(struct super_block *sb,
++ struct pram_inode * pi)
++{
++ struct inode * inode = new_inode(sb);
++
++ if (inode)
++ pram_fill_inode(inode, pi);
++
++ return inode;
++}
++
++
++/*
++ * Called at each iput()
++ */
++void pram_put_inode (struct inode * inode)
++{
++ // nothing to do
++}
++
++/*
++ * Called at the last iput() if i_nlink is zero.
++ */
++void pram_delete_inode (struct inode * inode)
++{
++ lock_kernel();
++
++ if (is_bad_inode(inode))
++ goto no_delete;
++
++ // unlink from chain in the inode's directory
++ pram_remove_link(inode);
++ inode->i_size = 0;
++ if (inode->i_blocks)
++ pram_truncate(inode);
++ pram_free_inode(inode);
++
++ unlock_kernel();
++ return;
++ no_delete:
++ unlock_kernel();
++ clear_inode(inode); /* We must guarantee clearing of inode... */
++}
++
++
++struct inode * pram_new_inode (const struct inode * dir, int mode)
++{
++ struct super_block * sb;
++ struct pram_super_block * ps;
++ struct inode * inode;
++ struct pram_inode * pi = NULL;
++ unsigned long flags;
++ int i, errval;
++ ino_t ino=0;
++
++ sb = dir->i_sb;
++ inode = new_inode(sb);
++ if (!inode)
++ return ERR_PTR(-ENOMEM);
++
++ lock_super (sb);
++ ps = pram_get_super(sb);
++
++ if (ps->s_free_inodes_count) {
++ /* find the oldest unused pram inode */
++ for (i=ps->s_free_inode_hint; i < ps->s_inodes_count; i++) {
++ ino = PRAM_ROOT_INO + (i << PRAM_INODE_BITS);
++ pi = pram_get_inode(sb, ino);
++ /* check if the inode is active. */
++ if (pi->i_links_count == 0 && (pi->i_mode == 0 ||
++ pi->i_dtime)) {
++ /* this inode is deleted */
++ break;
++ }
++ }
++
++ if (i >= ps->s_inodes_count) {
++ pram_err("s_free_inodes_count!=0 but none free!?\n");
++ errval = -ENOSPC;
++ goto fail;
++ }
++
++ pram_dbg ("allocating inode %lu\n", ino);
++ pram_lock_super(ps);
++ ps->s_free_inodes_count--;
++ ps->s_free_inode_hint = (i < ps->s_inodes_count-1) ? i+1 : 0;
++ pram_unlock_super(ps);
++ } else {
++ pram_err("no space left to create new inode!\n");
++ errval = -ENOSPC;
++ goto fail;
++ }
++
++ // chosen inode is in ino
++
++ inode->i_ino = ino;
++ inode->i_uid = current->fsuid;
++
++ if (dir->i_mode & S_ISGID) {
++ inode->i_gid = dir->i_gid;
++ if (S_ISDIR(mode))
++ mode |= S_ISGID;
++ } else
++ inode->i_gid = current->fsgid;
++ inode->i_mode = mode;
++
++ inode->i_blksize = sb->s_blocksize;
++ inode->i_blocks = inode->i_size = 0;
++ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
++
++ pram_lock_inode(pi);
++ pi->i_d.d_next = 0;
++ pi->i_d.d_prev = 0;
++ pram_unlock_inode(pi);
++
++ insert_inode_hash(inode);
++ pram_write_inode(inode, 0);
++
++ unlock_super (sb);
++
++ if(DQUOT_ALLOC_INODE(inode)) {
++ DQUOT_DROP(inode);
++ inode->i_flags |= S_NOQUOTA;
++ inode->i_nlink = 0;
++ iput(inode);
++ return ERR_PTR(-EDQUOT);
++ }
++ return inode;
++
++fail:
++ unlock_super(sb);
++ make_bad_inode(inode);
++ iput(inode);
++ return ERR_PTR(errval);
++}
++
++
++void pram_read_inode (struct inode * inode)
++{
++ struct pram_inode * pi;
++
++ pi = pram_get_inode(inode->i_sb, inode->i_ino);
++ pram_fill_inode(inode, pi);
++}
++
++void pram_truncate (struct inode * inode)
++{
++ int blocksize, blocksize_bits;
++ int blocknr;
++
++ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
++ S_ISLNK(inode->i_mode)))
++ return;
++ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
++ return;
++
++ blocksize_bits = inode->i_sb->s_blocksize_bits;
++ blocksize = 1 << blocksize_bits;
++ blocknr = (inode->i_size + blocksize-1) >> blocksize_bits;
++
++ lock_kernel();
++ pram_truncate_blocks(inode, blocknr);
++ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
++ pram_update_inode(inode);
++ unlock_kernel();
++}
++
++
++void pram_write_inode (struct inode * inode, int wait)
++{
++ lock_kernel();
++ pram_update_inode(inode);
++ unlock_kernel();
++}
++
++/*
++ * dirty_inode() is called from __mark_inode_dirty()
++ */
++void pram_dirty_inode(struct inode * inode)
++{
++ pram_write_inode(inode, 0);
++}
++
++
++static int pram_get_and_update_block(struct inode *inode, sector_t iblock,
++ struct buffer_head *bh, int create)
++{
++ struct super_block * sb = inode->i_sb;
++ unsigned int blocksize = 1 << inode->i_blkbits;
++ int err = -EIO;
++ unsigned long flags;
++ pram_off_t block;
++ void* bp;
++
++ lock_kernel();
++
++ block = pram_find_data_block(inode, iblock);
++
++ if (!block) {
++ if (!create)
++ goto out;
++
++ err = pram_alloc_blocks(inode, iblock, 1);
++ if (err)
++ goto out;
++ block = pram_find_data_block(inode, iblock);
++ if (!block) {
++ err = -EIO;
++ goto out;
++ }
++ set_buffer_new(bh);
++ }
++
++ bh->b_blocknr = block;
++ set_buffer_mapped(bh);
++
++ /* now update the buffer synchronously */
++ bp = pram_get_block(sb, block);
++ if (buffer_new(bh)) {
++ pram_lock_block(sb, bp);
++ memset(bp, 0, blocksize);
++ pram_unlock_block(sb, bp);
++ memset(bh->b_data, 0, blocksize);
++ } else {
++ memcpy(bh->b_data, bp, blocksize);
++ }
++
++ set_buffer_uptodate(bh);
++ err = 0;
++
++ out:
++ unlock_kernel();
++ return err;
++}
++
++#if 0
++static int pram_writepage(struct page *page)
++{
++ return 0;
++}
++
++static int pram_bmap(struct address_space *mapping, long block)
++{
++ return 0;
++}
++#endif
++
++static int pram_readpage(struct file *file, struct page *page)
++{
++ return block_read_full_page(page, pram_get_and_update_block);
++}
++
++struct address_space_operations pram_aops = {
++ readpage: pram_readpage,
++// writepage: pram_writepage,
++// bmap: pram_bmap,
++ direct_IO: pram_direct_IO,
++};
+diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/ioctl.c main/fs/pramfs/ioctl.c
+--- main.orig/fs/pramfs/ioctl.c 1969-12-31 16:00:00.000000000 -0800
++++ main/fs/pramfs/ioctl.c 2004-03-04 15:59:03.000000000 -0800
+@@ -0,0 +1,35 @@
++/*
++ * ioctl.c
++ *
++ * Ioctl method for directory and regular files.
++ *
++ * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
++ *
++ * 2003 (c) MontaVista Software, Inc.
++ * Copyright 2003 Sony Corporation
++ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
++ *
++ * This software is being distributed under the terms of the GNU General Public
++ * License version 2. Some or all of the technology encompassed by this
++ * software may be subject to one or more patents pending as of the date of
++ * this notice. No additional patent license will be required for GPL
++ * implementations of the technology. If you want to create a non-GPL
++ * implementation of the technology encompassed by this software, please
++ * contact legal@mvista.com for details including licensing terms and fees.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++#include <linux/fs.h>
++#include <linux/pram_fs.h>
++#include <linux/sched.h>
++#include <asm/uaccess.h>
++
++
++int pram_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
++ unsigned long arg)
++{
++ // FIXME: need any special ioctl's?
++ return 0;
++}
+diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/Makefile main/fs/pramfs/Makefile
+--- main.orig/fs/pramfs/Makefile 1969-12-31 16:00:00.000000000 -0800
++++ main/fs/pramfs/Makefile 2004-03-04 15:59:03.000000000 -0800
+@@ -0,0 +1,11 @@
++#
++# Makefile for the linux pram-filesystem routines.
++#
++
++obj-$(CONFIG_PRAMFS) += pramfs.o
++
++pramfs-objs := balloc.o dir.o file.o fsync.o inode.o ioctl.o namei.o \
++ super.o symlink.o
++ifndef CONFIG_PRAMFS_NOWP
++pramfs-objs += wprotect.o
++endif
+diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/namei.c main/fs/pramfs/namei.c
+--- main.orig/fs/pramfs/namei.c 1969-12-31 16:00:00.000000000 -0800
++++ main/fs/pramfs/namei.c 2004-03-04 15:59:03.000000000 -0800
+@@ -0,0 +1,331 @@
++/*
++ * namei.c
++ *
++ * Inode operations for directories.
++ *
++ * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
++ *
++ * 2003 (c) MontaVista Software, Inc.
++ * Copyright 2003 Sony Corporation
++ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
++ *
++ * This software is being distributed under the terms of the GNU General Public
++ * License version 2. Some or all of the technology encompassed by this
++ * software may be subject to one or more patents pending as of the date of
++ * this notice. No additional patent license will be required for GPL
++ * implementations of the technology. If you want to create a non-GPL
++ * implementation of the technology encompassed by this software, please
++ * contact legal@mvista.com for details including licensing terms and fees.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++#include <linux/fs.h>
++#include <linux/pram_fs.h>
++#include <linux/pagemap.h>
++
++
++/*
++ * Couple of helper functions - make the code slightly cleaner.
++ */
++
++static inline void pram_inc_count(struct inode *inode)
++{
++ inode->i_nlink++;
++ pram_write_inode(inode, 0);
++}
++
++static inline void pram_dec_count(struct inode *inode)
++{
++ if (inode->i_nlink) {
++ inode->i_nlink--;
++ pram_write_inode(inode, 0);
++ }
++}
++
++static inline int pram_add_nondir(struct inode * dir,
++ struct dentry * dentry,
++ struct inode * inode)
++{
++ int err = pram_add_link(dentry, inode);
++ if (!err) {
++ d_instantiate(dentry, inode);
++ return 0;
++ }
++ pram_dec_count(inode);
++ iput(inode);
++ return err;
++}
++
++/*
++ * Methods themselves.
++ */
++
++static ino_t
++pram_inode_by_name(struct inode * dir,
++ struct dentry * dentry)
++{
++ struct pram_inode * pi;
++ ino_t ino;
++ int namelen;
++
++ pi = pram_get_inode(dir->i_sb, dir->i_ino);
++ ino = pi->i_type.dir.head;
++
++ while (ino) {
++ pi = pram_get_inode(dir->i_sb, ino);
++
++ if (pi->i_links_count) {
++ namelen = strlen(pi->i_d.d_name);
++
++ if (namelen == dentry->d_name.len &&
++ !memcmp(dentry->d_name.name,
++ pi->i_d.d_name, namelen))
++ break;
++ }
++
++ ino = pi->i_d.d_next;
++ }
++
++ return ino;
++}
++
++static struct dentry *
++pram_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
++{
++ struct inode * inode = NULL;
++ ino_t ino;
++
++ if (dentry->d_name.len > PRAM_NAME_LEN)
++ return ERR_PTR(-ENAMETOOLONG);
++
++ ino = pram_inode_by_name(dir, dentry);
++ if (ino) {
++ struct pram_inode * pi = pram_get_inode(dir->i_sb, ino);
++ inode = pram_fill_new_inode(dir->i_sb, pi);
++ if (!inode)
++ return ERR_PTR(-EACCES);
++ }
++
++ d_add(dentry, inode);
++ return NULL;
++}
++
++
++/*
++ * By the time this is called, we already have created
++ * the directory cache entry for the new file, but it
++ * is so far negative - it has no inode.
++ *
++ * If the create succeeds, we fill in the inode information
++ * with d_instantiate().
++ */
++static int pram_create (struct inode * dir, struct dentry * dentry,
++ int mode, struct nameidata *nd)
++{
++ struct inode * inode = pram_new_inode (dir, mode);
++ int err = PTR_ERR(inode);
++ if (!IS_ERR(inode)) {
++ inode->i_op = &pram_file_inode_operations;
++ inode->i_fop = &pram_file_operations;
++ inode->i_mapping->a_ops = &pram_aops;
++ err = pram_add_nondir(dir, dentry, inode);
++ }
++ return err;
++}
++
++static int pram_mknod (struct inode * dir, struct dentry *dentry, int mode,
++ dev_t rdev)
++{
++ struct inode * inode = pram_new_inode (dir, mode);
++ int err = PTR_ERR(inode);
++ if (!IS_ERR(inode)) {
++ init_special_inode(inode, mode, rdev);
++ err = pram_add_nondir(dir, dentry, inode);
++ }
++ return err;
++}
++
++static int pram_symlink (struct inode * dir,
++ struct dentry * dentry,
++ const char * symname)
++{
++ struct super_block * sb = dir->i_sb;
++ int err = -ENAMETOOLONG;
++ unsigned len = strlen(symname);
++ struct inode * inode;
++
++ if (len+1 > sb->s_blocksize)
++ goto out;
++
++ inode = pram_new_inode (dir, S_IFLNK | S_IRWXUGO);
++ err = PTR_ERR(inode);
++ if (IS_ERR(inode))
++ goto out;
++
++ inode->i_op = &pram_symlink_inode_operations;
++ inode->i_mapping->a_ops = &pram_aops;
++ err = pram_block_symlink(inode, symname, len);
++ if (err)
++ goto out_fail;
++
++ inode->i_size = len;
++ pram_write_inode(inode, 0);
++
++ err = pram_add_nondir(dir, dentry, inode);
++out:
++ return err;
++
++out_fail:
++ pram_dec_count(inode);
++ iput (inode);
++ goto out;
++}
++
++static int pram_link (struct dentry * dest_dentry,
++ struct inode * dir,
++ struct dentry * dentry)
++{
++ pram_dbg ("hard links not supported\n");
++ return -ENOSYS;
++}
++
++static int pram_unlink(struct inode * dir, struct dentry *dentry)
++{
++ struct inode * inode = dentry->d_inode;
++ inode->i_ctime = dir->i_ctime;
++ pram_dec_count(inode);
++
++ return 0;
++}
++
++static int pram_mkdir(struct inode * dir, struct dentry * dentry, int mode)
++{
++ struct inode * inode;
++ struct pram_inode * pi;
++ unsigned long flags;
++ int err = -EMLINK;
++
++ if (dir->i_nlink >= PRAM_LINK_MAX)
++ goto out;
++
++ pram_inc_count(dir);
++
++ inode = pram_new_inode (dir, S_IFDIR | mode);
++ err = PTR_ERR(inode);
++ if (IS_ERR(inode))
++ goto out_dir;
++
++ inode->i_op = &pram_dir_inode_operations;
++ inode->i_fop = &pram_dir_operations;
++ inode->i_mapping->a_ops = &pram_aops;
++
++ pram_inc_count(inode);
++
++ // make the new directory empty
++ pi = pram_get_inode(dir->i_sb, inode->i_ino);
++ pram_lock_inode(pi);
++ pi->i_type.dir.head = pi->i_type.dir.tail = 0;
++ pram_unlock_inode(pi);
++
++ err = pram_add_link(dentry, inode);
++ if (err)
++ goto out_fail;
++
++ d_instantiate(dentry, inode);
++out:
++ return err;
++
++out_fail:
++ pram_dec_count(inode);
++ pram_dec_count(inode);
++ iput(inode);
++out_dir:
++ pram_dec_count(dir);
++ goto out;
++}
++
++static int pram_rmdir (struct inode * dir, struct dentry *dentry)
++{
++ struct inode * inode = dentry->d_inode;
++ struct pram_inode * pi;
++ int err = -ENOTEMPTY;
++
++ if (!inode)
++ return -ENOENT;
++
++ pi = pram_get_inode(dir->i_sb, inode->i_ino);
++
++ // directory to delete is empty?
++ if (pi->i_type.dir.tail == 0) {
++ inode->i_ctime = dir->i_ctime;
++ inode->i_size = 0;
++ inode->i_nlink = 0;
++ pram_write_inode(inode, 0);
++ pram_dec_count(dir);
++ err = 0;
++ } else {
++ pram_dbg("dir not empty\n");
++ }
++
++ return err;
++}
++
++static int pram_rename (struct inode * old_dir,
++ struct dentry * old_dentry,
++ struct inode * new_dir,
++ struct dentry * new_dentry)
++{
++ struct inode * old_inode = old_dentry->d_inode;
++ struct inode * new_inode = new_dentry->d_inode;
++ struct pram_inode * pi_new;
++ int err = -ENOENT;
++
++ if (new_inode) {
++ err = -ENOTEMPTY;
++ pi_new = pram_get_inode(new_dir->i_sb, new_inode->i_ino);
++ if (S_ISDIR(old_inode->i_mode)) {
++ if (pi_new->i_type.dir.tail != 0)
++ goto out;
++ if (new_inode->i_nlink)
++ new_inode->i_nlink--;
++ }
++
++ new_inode->i_ctime = CURRENT_TIME;
++ pram_dec_count(new_inode);
++ } else {
++ if (S_ISDIR(old_inode->i_mode)) {
++ err = -EMLINK;
++ if (new_dir->i_nlink >= PRAM_LINK_MAX)
++ goto out;
++ pram_dec_count(old_dir);
++ pram_inc_count(new_dir);
++ }
++ }
++
++ /* unlink the inode from the old directory ... */
++ if ((err = pram_remove_link(old_inode))) {
++ goto out;
++ }
++ /* and link it into the new directory. */
++ if ((err = pram_add_link(new_dentry, old_inode))) {
++ goto out;
++ }
++
++ err = 0;
++ out:
++ return err;
++}
++
++struct inode_operations pram_dir_inode_operations = {
++ create: pram_create,
++ lookup: pram_lookup,
++ link: pram_link,
++ unlink: pram_unlink,
++ symlink: pram_symlink,
++ mkdir: pram_mkdir,
++ rmdir: pram_rmdir,
++ mknod: pram_mknod,
++ rename: pram_rename,
++};
+diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/super.c main/fs/pramfs/super.c
+--- main.orig/fs/pramfs/super.c 1969-12-31 16:00:00.000000000 -0800
++++ main/fs/pramfs/super.c 2004-03-04 15:59:03.000000000 -0800
+@@ -0,0 +1,393 @@
++/*
++ * super.c
++ *
++ * Super block operations.
++ *
++ * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
++ *
++ * 2003 (c) MontaVista Software, Inc.
++ * Copyright 2003 Sony Corporation
++ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
++ *
++ * This software is being distributed under the terms of the GNU General Public
++ * License version 2. Some or all of the technology encompassed by this
++ * software may be subject to one or more patents pending as of the date of
++ * this notice. No additional patent license will be required for GPL
++ * implementations of the technology. If you want to create a non-GPL
++ * implementation of the technology encompassed by this software, please
++ * contact legal@mvista.com for details including licensing terms and fees.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/parser.h>
++#include <linux/vfs.h>
++#include <linux/pram_fs.h>
++#include <asm/uaccess.h>
++
++MODULE_AUTHOR("Steve Longerbeam, stevel@mvista.com");
++MODULE_DESCRIPTION("Protected/Persistent RAM Filesystem");
++MODULE_LICENSE("GPL");
++
++static struct super_operations pram_sops;
++
++#ifndef MODULE
++extern struct list_head super_blocks;
++
++struct super_block * find_pramfs_super(void)
++{
++ struct list_head *p;
++ list_for_each(p, &super_blocks) {
++ struct super_block * s = sb_entry(p);
++ if (s->s_magic == PRAM_SUPER_MAGIC)
++ return s;
++ }
++ return NULL;
++}
++EXPORT_SYMBOL(find_pramfs_super);
++#endif
++
++static void pram_set_blocksize(struct super_block * sb, unsigned long size)
++{
++ int bits;
++ for (bits = 9, size >>= 9; size >>= 1; bits++)
++ ;
++ if (bits > 12)
++ bits = 12;
++ sb->s_blocksize_bits = bits;
++ sb->s_blocksize = (1<<bits);
++}
++
++static inline void * pram_ioremap(unsigned long phys_addr, size_t size,
++ unsigned long flags)
++{
++ void * retval = __ioremap(phys_addr, size, flags, PAGE_SIZE);
++#ifndef CONFIG_PRAMFS_NOWP
++ if (retval) {
++ spin_lock(&init_mm.page_table_lock);
++ pram_writeable(retval, size, 0);
++ spin_unlock(&init_mm.page_table_lock);
++ }
++#endif
++ return retval;
++}
++
++
++static int pram_fill_super (struct super_block * sb, void * data, int silent)
++{
++ char *p;
++ struct pram_super_block * super;
++ struct pram_inode * root_i;
++ struct pram_sb_info * sbi=NULL;
++ pram_off_t root_offset;
++ unsigned long flags;
++ unsigned long maxsize, blocksize;
++ int retval = -EINVAL;
++
++ /*
++ * The physical location of the pram image is specified as
++ * a mount parameter. This parameter is mandatory for obvious
++ * reasons. Some validation is made on the phys address but this
++ * is not exhaustive and we count on the fact that someone using
++ * this feature is supposed to know what he/she's doing.
++ */
++ if (!data || !(p = strstr((char *)data, "physaddr="))) {
++ pram_err("unknown physical address for pramfs image\n");
++ goto out;
++ }
++
++ sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
++ if (!sbi)
++ return -ENOMEM;
++ sb->s_fs_info = sbi;
++ memset(sbi, 0, sizeof(*sbi));
++
++ sbi->phys_addr = simple_strtoul(p + 9, NULL, 0);
++ if (sbi->phys_addr & (PAGE_SIZE-1)) {
++ pram_err("physical address 0x%lx for pramfs isn't "
++ "aligned to a page boundary\n",
++ sbi->phys_addr);
++ goto out;
++ }
++
++ if (sbi->phys_addr == 0) {
++ pram_err("physical address for pramfs image can't be 0\n");
++ goto out;
++ }
++
++ if ((p = strstr((char *)data, "init="))) {
++ unsigned long bpi, num_inodes, bitmap_size;
++ unsigned long num_blocks;
++ pram_off_t bitmap_start;
++
++ maxsize = simple_strtoul(p + 5, NULL, 0);
++ pram_info("creating an empty pramfs of size %lu\n", maxsize);
++
++ sbi->virt_addr = pram_ioremap(sbi->phys_addr, maxsize, 0);
++ if (!sbi->virt_addr) {
++ pram_err("ioremap of the pramfs image failed\n");
++ goto out;
++ }
++
++ if ((p = strstr((char *)data, "bs=")))
++ blocksize = simple_strtoul(p + 3, NULL, 0);
++ else
++ blocksize = PRAM_DEF_BLOCK_SIZE;
++
++ pram_set_blocksize(sb, blocksize);
++ blocksize = sb->s_blocksize;
++
++ if ((p = strstr((char *)data, "bpi=")))
++ bpi = simple_strtoul(p + 4, NULL, 0);
++ else {
++ /* default is that 5% of the filesystem is
++ devoted to the inode table */
++ bpi = 20 * PRAM_INODE_SIZE;
++ }
++
++ if ((p = strstr((char *)data, "N=")))
++ num_inodes = simple_strtoul(p + 2, NULL, 0);
++ else
++ num_inodes = maxsize / bpi;
++
++ /* up num_inodes such that the end of the inode table
++ (and start of bitmap) is on a block boundary */
++ bitmap_start = PRAM_SB_SIZE + (num_inodes<<PRAM_INODE_BITS);
++ if (bitmap_start & (blocksize - 1))
++ bitmap_start = (bitmap_start + blocksize) &
++ ~(blocksize-1);
++ num_inodes = (bitmap_start - PRAM_SB_SIZE) >> PRAM_INODE_BITS;
++
++ num_blocks = (maxsize - bitmap_start) >> sb->s_blocksize_bits;
++
++ /* calc the data blocks in-use bitmap size in bytes */
++ if (num_blocks & 7)
++ bitmap_size = ((num_blocks + 8) & ~7) >> 3;
++ else
++ bitmap_size = num_blocks >> 3;
++ /* round it up to the nearest blocksize boundary */
++ if (bitmap_size & (blocksize - 1))
++ bitmap_size = (bitmap_size + blocksize) &
++ ~(blocksize-1);
++
++ pram_info("blocksize %lu, num inodes %lu, num blocks %lu\n",
++ blocksize, num_inodes, num_blocks);
++ pram_dbg("bitmap start 0x%08x, bitmap size %lu\n",
++ (unsigned long)bitmap_start, bitmap_size);
++ pram_dbg("max name length %d\n", PRAM_NAME_LEN);
++
++ super = pram_get_super(sb);
++ pram_lock_range(super, bitmap_start + bitmap_size);
++
++ /* clear out super-block and inode table */
++ memset(super, 0, bitmap_start);
++ super->s_size = maxsize;
++ super->s_blocksize = blocksize;
++ super->s_inodes_count = num_inodes;
++ super->s_blocks_count = num_blocks;
++ super->s_free_inodes_count = num_inodes - 1;
++ super->s_bitmap_blocks = bitmap_size >> sb->s_blocksize_bits;
++ super->s_free_blocks_count =
++ num_blocks - super->s_bitmap_blocks;
++ super->s_free_inode_hint = 1;
++ super->s_bitmap_start = bitmap_start;
++ super->s_magic = PRAM_SUPER_MAGIC;
++ pram_sync_super(super);
++
++ root_i = pram_get_inode(sb, PRAM_ROOT_INO);
++ root_i->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
++ root_i->i_links_count = 2;
++ root_i->i_d.d_parent = PRAM_ROOT_INO;
++ pram_sync_inode(root_i);
++
++ pram_init_bitmap(sb);
++
++ pram_unlock_range(super, bitmap_start + bitmap_size);
++
++ goto setup_sb;
++ }
++
++ pram_info("checking physical address 0x%lx for pramfs image\n",
++ sbi->phys_addr);
++
++ /* Map only one page for now. Will remap it when fs size is known. */
++ sbi->virt_addr = pram_ioremap(sbi->phys_addr, PAGE_SIZE, 0);
++ if (!sbi->virt_addr) {
++ pram_err("ioremap of the pramfs image failed\n");
++ goto out;
++ }
++
++ super = pram_get_super(sb);
++
++ /* Do sanity checks on the superblock */
++ if (super->s_magic != PRAM_SUPER_MAGIC) {
++ pram_err("wrong magic\n");
++ goto out;
++ }
++ /* Read the superblock */
++ if (pram_calc_checksum((u32*)super, PRAM_SB_SIZE>>2)) {
++ pram_err("checksum error in super block!\n");
++ goto out;
++ }
++
++ /* get feature flags first */
++ // FIXME: implement fs features?
++#if 0
++ if (super->s_features & ~PRAM_SUPPORTED_FLAGS) {
++ pram_err("unsupported filesystem features\n");
++ goto out;
++ }
++#endif
++
++ blocksize = super->s_blocksize;
++ pram_set_blocksize(sb, blocksize);
++
++ maxsize = super->s_size;
++ pram_info("pramfs image appears to be %lu KB in size\n", maxsize>>10);
++ pram_info("blocksize %lu\n", blocksize);
++
++ /* Read the root inode */
++ root_i = pram_get_inode(sb, PRAM_ROOT_INO);
++
++ if (pram_calc_checksum((u32*)root_i, PRAM_INODE_SIZE>>2)) {
++ pram_err("checksum error in root inode!\n");
++ goto out;
++ }
++
++ /* Check that the root inode is in a sane state */
++ if (root_i->i_d.d_next) {
++ pram_err("root->next not NULL??!!\n");
++ goto out;
++ }
++
++ if (!S_ISDIR(root_i->i_mode)) {
++ pram_err("root is not a directory!\n");
++ goto out;
++ }
++
++ root_offset = root_i->i_type.dir.head;
++ if (root_offset == 0)
++ pram_info("empty filesystem\n");
++
++ /* Remap the whole filesystem now */
++ iounmap(sbi->virt_addr);
++ sbi->virt_addr = pram_ioremap(sbi->phys_addr, maxsize, 0);
++ if (!sbi->virt_addr) {
++ pram_err("ioremap of the pramfs image failed\n");
++ goto out;
++ }
++ super = pram_get_super(sb);
++
++ /* Set it all up.. */
++ setup_sb:
++ sbi->maxsize = maxsize;
++ sb->s_magic = sbi->magic = super->s_magic;
++ sbi->features = super->s_features;
++
++ sb->s_op = &pram_sops;
++ sb->s_root = d_alloc_root(pram_fill_new_inode(sb, root_i));
++
++ retval = 0;
++ out:
++ if (retval && sbi->virt_addr)
++ iounmap(sbi->virt_addr);
++
++ return retval;
++}
++
++//static void pram_write_super (struct super_block * sb)
++//{
++//}
++
++int pram_statfs (struct super_block * sb, struct kstatfs * buf)
++{
++ struct pram_super_block * ps = pram_get_super(sb);
++
++ buf->f_type = PRAM_SUPER_MAGIC;
++ buf->f_bsize = sb->s_blocksize;
++ buf->f_blocks = ps->s_blocks_count;
++ buf->f_bfree = buf->f_bavail = ps->s_free_blocks_count;
++ buf->f_files = ps->s_inodes_count;
++ buf->f_ffree = ps->s_free_inodes_count;
++ buf->f_namelen = PRAM_NAME_LEN;
++ return 0;
++}
++
++int pram_remount (struct super_block * sb, int * mntflags, char * data)
++{
++ struct pram_super_block * ps;
++ unsigned long flags;
++
++ if ((*mntflags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
++ ps = pram_get_super(sb);
++ pram_lock_super(ps);
++ ps->s_mtime = get_seconds(); // update mount time
++ pram_unlock_super(ps);
++ }
++ return 0;
++}
++
++void pram_put_super (struct super_block * sb)
++{
++ struct pram_sb_info * sbi = (struct pram_sb_info *)sb->s_fs_info;
++
++ /* It's unmount time, so unmap the pramfs memory */
++ if (sbi->virt_addr) {
++ iounmap(sbi->virt_addr);
++ sbi->virt_addr = NULL;
++ }
++
++ sb->s_fs_info = NULL;
++ kfree(sbi);
++}
++
++/*
++ * the super block writes are all done "on the fly", so the
++ * super block is never in a "dirty" state, so there's no need
++ * for write_super.
++ */
++static struct super_operations pram_sops = {
++ read_inode: pram_read_inode,
++ write_inode: pram_write_inode,
++ dirty_inode: pram_dirty_inode,
++ put_inode: pram_put_inode,
++ delete_inode: pram_delete_inode,
++ put_super: pram_put_super,
++ //write_super: pram_write_super,
++ statfs: pram_statfs,
++ remount_fs: pram_remount,
++};
++
++static struct super_block *pram_get_sb(struct file_system_type *fs_type,
++ int flags, const char *dev_name,
++ void *data)
++{
++ return get_sb_single(fs_type, flags, data, pram_fill_super);
++}
++
++static struct file_system_type pram_fs_type = {
++ .owner = THIS_MODULE,
++ .name = "pramfs",
++ .get_sb = pram_get_sb,
++ .kill_sb = kill_anon_super,
++};
++
++static int __init init_pram_fs(void)
++{
++ return register_filesystem(&pram_fs_type);
++}
++
++static void __exit exit_pram_fs(void)
++{
++ unregister_filesystem(&pram_fs_type);
++}
++
++module_init(init_pram_fs)
++module_exit(exit_pram_fs)
+diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/symlink.c main/fs/pramfs/symlink.c
+--- main.orig/fs/pramfs/symlink.c 1969-12-31 16:00:00.000000000 -0800
++++ main/fs/pramfs/symlink.c 2004-03-04 15:59:03.000000000 -0800
+@@ -0,0 +1,76 @@
++/*
++ * symlink.c
++ *
++ * Symlink methods.
++ *
++ * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
++ *
++ * 2003 (c) MontaVista Software, Inc.
++ * Copyright 2003 Sony Corporation
++ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
++ *
++ * This software is being distributed under the terms of the GNU General Public
++ * License version 2. Some or all of the technology encompassed by this
++ * software may be subject to one or more patents pending as of the date of
++ * this notice. No additional patent license will be required for GPL
++ * implementations of the technology. If you want to create a non-GPL
++ * implementation of the technology encompassed by this software, please
++ * contact legal@mvista.com for details including licensing terms and fees.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++#include <linux/fs.h>
++#include <linux/pram_fs.h>
++
++int pram_block_symlink(struct inode *inode, const char *symname, int len)
++{
++ struct super_block * sb = inode->i_sb;
++ pram_off_t block;
++ char* blockp;
++ unsigned long flags;
++ int err;
++
++ err = pram_alloc_blocks (inode, 0, 1);
++ if (err)
++ return err;
++
++ block = pram_find_data_block(inode, 0);
++ blockp = pram_get_block(sb, block);
++
++ pram_lock_block(sb, blockp);
++ memcpy(blockp, symname, len);
++ blockp[len] = '\0';
++ pram_unlock_block(sb, blockp);
++ return 0;
++}
++
++static int pram_readlink(struct dentry *dentry, char *buffer, int buflen)
++{
++ struct inode * inode = dentry->d_inode;
++ struct super_block * sb = inode->i_sb;
++ pram_off_t block;
++ char* blockp;
++
++ block = pram_find_data_block(inode, 0);
++ blockp = pram_get_block(sb, block);
++ return vfs_readlink(dentry, buffer, buflen, blockp);
++}
++
++static int pram_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ struct inode * inode = dentry->d_inode;
++ struct super_block * sb = inode->i_sb;
++ pram_off_t block;
++ char* blockp;
++
++ block = pram_find_data_block(inode, 0);
++ blockp = pram_get_block(sb, block);
++ return vfs_follow_link(nd, blockp);
++}
++
++struct inode_operations pram_symlink_inode_operations = {
++ readlink: pram_readlink,
++ follow_link: pram_follow_link,
++};
+diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/wprotect.c main/fs/pramfs/wprotect.c
+--- main.orig/fs/pramfs/wprotect.c 1969-12-31 16:00:00.000000000 -0800
++++ main/fs/pramfs/wprotect.c 2004-03-04 15:59:03.000000000 -0800
+@@ -0,0 +1,80 @@
++/*
++ * wprotect.c
++ *
++ * Write protection for the filesystem pages.
++ *
++ * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
++ *
++ * 2003 (c) MontaVista Software, Inc.
++ * Copyright 2003 Sony Corporation
++ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
++ *
++ * This software is being distributed under the terms of the GNU General Public
++ * License version 2. Some or all of the technology encompassed by this
++ * software may be subject to one or more patents pending as of the date of
++ * this notice. No additional patent license will be required for GPL
++ * implementations of the technology. If you want to create a non-GPL
++ * implementation of the technology encompassed by this software, please
++ * contact legal@mvista.com for details including licensing terms and fees.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/pram_fs.h>
++#include <linux/mm.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++
++// init_mm.page_table_lock must be held before calling!
++static void pram_page_writeable(unsigned long addr, int rw)
++{
++ pgd_t *pgdp;
++ pmd_t *pmdp;
++ pte_t *ptep;
++
++ pgdp = pgd_offset_k(addr);
++ if (!pgd_none(*pgdp)) {
++ pmdp = pmd_offset(pgdp, addr);
++ if (!pmd_none(*pmdp)) {
++ pte_t pte;
++ ptep = pte_offset_kernel(pmdp, addr);
++ pte = *ptep;
++ if (pte_present(pte)) {
++ pte = rw ? pte_mkwrite(pte) :
++ pte_wrprotect(pte);
++ set_pte(ptep, pte);
++ }
++ }
++ }
++}
++
++
++// init_mm.page_table_lock must be held before calling!
++void pram_writeable(void * vaddr, unsigned long size, int rw)
++{
++ unsigned long addr = (unsigned long)vaddr & PAGE_MASK;
++ unsigned long end = (unsigned long)vaddr + size;
++ unsigned long start = addr;
++
++ do {
++ pram_page_writeable(addr, rw);
++ addr += PAGE_SIZE;
++ } while (addr && (addr < end));
++
++
++ /*
++ * NOTE: we will always flush just one page (one TLB
++ * entry) except possibly in one case: when a new
++ * filesystem is initialized at mount time, when pram_read_super
++ * calls pram_lock_range to make the super block, inode
++ * table, and bitmap writeable.
++ */
++ if (end <= start + PAGE_SIZE)
++ flush_tlb_kernel_page(start);
++ else
++ flush_tlb_kernel_range(start, end);
++}
+diff -Nuar -X /home/stevel/dontdiff main.orig/include/linux/pram_fs.h main/include/linux/pram_fs.h
+--- main.orig/include/linux/pram_fs.h 1969-12-31 16:00:00.000000000 -0800
++++ main/include/linux/pram_fs.h 2004-03-04 15:59:35.000000000 -0800
+@@ -0,0 +1,378 @@
++/*
++ * pram_fs.h
++ *
++ * Definitions for the PRAMFS filesystem.
++ *
++ * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
++ *
++ * 2003 (c) MontaVista Software, Inc.
++ * Copyright 2003 Sony Corporation
++ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
++ *
++ * This software is being distributed under the terms of the GNU General Public
++ * License version 2. Some or all of the technology encompassed by this
++ * software may be subject to one or more patents pending as of the date of
++ * this notice. No additional patent license will be required for GPL
++ * implementations of the technology. If you want to create a non-GPL
++ * implementation of the technology encompassed by this software, please
++ * contact legal@mvista.com for details including licensing terms and fees.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++#ifndef _LINUX_PRAM_FS_H
++#define _LINUX_PRAM_FS_H
++
++#include <linux/types.h>
++#include <linux/pram_fs_sb.h>
++
++#ifdef __KERNEL__
++#include <linux/sched.h>
++#endif
++
++/*
++ * The PRAM filesystem constants/structures
++ */
++
++/*
++ * Define PRAMFS_DEBUG to produce debug messages
++ */
++#undef PRAMFS_DEBUG
++
++/*
++ * The PRAM filesystem version
++ */
++#define PRAMFS_DATE "2003/06/15"
++#define PRAMFS_VERSION "0.1b"
++
++/*
++ * Debug code
++ */
++#ifdef __KERNEL__
++#define PFX "pramfs"
++#ifdef PRAMFS_DEBUG
++#define pram_dbg(format, arg...) \
++ printk(KERN_DEBUG PFX ": " format , ## arg)
++#else
++#define pram_dbg(format, arg...) do {} while (0)
++#endif
++#define pram_err(format, arg...) \
++ printk(KERN_ERR PFX ": " format , ## arg)
++#define pram_info(format, arg...) \
++ printk(KERN_INFO PFX ": " format , ## arg)
++#define pram_warn(format, arg...) \
++ printk(KERN_WARNING PFX ": " format , ## arg)
++#endif
++
++/*
++ * The PRAM file system magic number
++ */
++#define PRAM_SUPER_MAGIC 0xEFFA
++
++/*
++ * Maximal count of links to a file
++ */
++#define PRAM_LINK_MAX 32000
++
++typedef unsigned long pram_off_t;
++
++#define PRAM_MIN_BLOCK_SIZE 512
++#define PRAM_MAX_BLOCK_SIZE 4096
++#define PRAM_DEF_BLOCK_SIZE 2048
++
++#define PRAM_INODE_SIZE 128 // must be power of two
++#define PRAM_INODE_BITS 7
++
++/*
++ * Structure of a directory entry in PRAMFS.
++ * Offsets are to the inode that holds the referenced dentry.
++ */
++struct pram_dentry {
++ pram_off_t d_next; /* next dentry in this directory */
++ pram_off_t d_prev; /* previous dentry in this directory */
++ pram_off_t d_parent; /* parent directory */
++ char d_name[0];
++};
++
++
++/*
++ * Structure of an inode in PRAMFS
++ */
++struct pram_inode {
++ __u32 i_sum; /* checksum of this inode */
++ __u32 i_uid; /* Owner Uid */
++ __u32 i_gid; /* Group Id */
++ __u16 i_mode; /* File mode */
++ __u16 i_links_count; /* Links count */
++ __u32 i_blocks; /* Blocks count */
++ __u32 i_size; /* Size of data in bytes */
++ __u32 i_atime; /* Access time */
++ __u32 i_ctime; /* Creation time */
++ __u32 i_mtime; /* Modification time */
++ __u32 i_dtime; /* Deletion Time */
++
++ union {
++ struct {
++ /*
++ * ptr to row block of 2D block pointer array,
++ * file block #'s 0 to (blocksize/4)^2 - 1.
++ */
++ pram_off_t row_block;
++ } reg; // regular file or symlink inode
++ struct {
++ pram_off_t head; /* first entry in this directory */
++ pram_off_t tail; /* last entry in this directory */
++ } dir;
++ struct {
++ __u32 rdev; /* major/minor # */
++ } dev; // device inode
++ } i_type;
++
++ struct pram_dentry i_d;
++};
++
++#define PRAM_NAME_LEN \
++ (PRAM_INODE_SIZE - offsetof(struct pram_inode, i_d.d_name) - 1)
++
++
++/*
++ * Behaviour when detecting errors
++ */
++#define PRAM_ERRORS_CONTINUE 1 /* Continue execution */
++#define PRAM_ERRORS_RO 2 /* Remount fs read-only */
++#define PRAM_ERRORS_PANIC 3 /* Panic */
++#define PRAM_ERRORS_DEFAULT PRAM_ERRORS_CONTINUE
++
++#define PRAM_SB_SIZE 128 // must be power of two
++#define PRAM_SB_BITS 7
++
++/*
++ * Structure of the super block in PRAMFS
++ */
++struct pram_super_block {
++ __u32 s_size; /* total size of fs in bytes */
++ __u32 s_blocksize; /* blocksize in bytes */
++ __u32 s_features; /* feature flags */
++ __u32 s_inodes_count; /* total inodes count (used or free) */
++ __u32 s_free_inodes_count;/* free inodes count */
++ __u32 s_free_inode_hint; /* start hint for locating free inodes */
++ __u32 s_blocks_count; /* total data blocks count (used or free) */
++ __u32 s_free_blocks_count;/* free data blocks count */
++ __u32 s_free_blocknr_hint;/* free data blocks count */
++ pram_off_t s_bitmap_start; /* data block in-use bitmap location */
++ __u32 s_bitmap_blocks;/* size of bitmap in number of blocks */
++ __u32 s_mtime; /* Mount time */
++ __u32 s_wtime; /* Write time */
++ __u32 s_rev_level; /* Revision level */
++ __u16 s_magic; /* Magic signature */
++ __u16 s_state; /* File system state */
++ __u16 s_errors; /* Behaviour when detecting errors */
++ char s_volume_name[16]; /* volume name */
++ __u32 s_sum; /* checksum of this sb, including padding */
++};
++
++/* The root inode follows immediately after the super block */
++#define PRAM_ROOT_INO PRAM_SB_SIZE
++
++#ifdef __KERNEL__
++
++/* Function Prototypes */
++
++/* balloc.c */
++extern void pram_init_bitmap(struct super_block * sb);
++extern void pram_free_block (struct super_block * sb, int blocknr);
++extern int pram_new_block (struct super_block * sb, int* blocknr, int zero);
++extern unsigned long pram_count_free_blocks (struct super_block * sb);
++
++/* dir.c */
++extern int pram_add_link (struct dentry * dentry, struct inode *inode);
++extern int pram_remove_link(struct inode * inode);
++
++/* file.c */
++extern int pram_direct_IO(int rw, struct kiocb *iocb,
++ const struct iovec *iov,
++ loff_t offset, unsigned long nr_segs);
++
++/* fsync.c */
++extern int pram_sync_file (struct file *, struct dentry *, int);
++extern int pram_fsync_inode (struct inode *, int);
++
++/* inode.c */
++extern int pram_alloc_blocks(struct inode * inode, int file_blocknr, int num);
++extern pram_off_t pram_find_data_block(struct inode * inode,
++ int file_blocknr);
++extern struct inode * pram_fill_new_inode(struct super_block *sb,
++ struct pram_inode * raw_inode);
++extern void pram_put_inode (struct inode * inode);
++extern void pram_delete_inode (struct inode * inode);
++extern struct inode * pram_new_inode (const struct inode * dir, int mode);
++extern void pram_read_inode (struct inode * inode);
++extern void pram_truncate (struct inode * inode);
++extern void pram_write_inode (struct inode * inode, int wait);
++extern void pram_dirty_inode(struct inode * inode);
++
++/* ioctl.c */
++extern int pram_ioctl (struct inode *, struct file *, unsigned int,
++ unsigned long);
++
++/* super.c */
++extern struct super_block * find_pramfs_super(void);
++extern struct super_block * pram_read_super (struct super_block * sb,
++ void * data,
++ int silent);
++extern int pram_statfs (struct super_block * sb, struct kstatfs * buf);
++extern int pram_remount (struct super_block * sb, int * flags, char * data);
++
++/* symlink.c */
++extern int pram_block_symlink(struct inode *inode,
++ const char *symname, int len);
++
++/* wprotect.c */
++#ifndef CONFIG_PRAMFS_NOWP
++extern void pram_writeable (void * vaddr, unsigned long size, int rw);
++#endif
++
++/* Inline functions start here */
++
++static inline u32 pram_calc_checksum(u32* buf, int n)
++{
++ u32 sum = 0;
++ while (n--)
++ sum += *buf++;
++ return sum;
++}
++
++// If this is part of a read-modify-write of the super block,
++// pram_lock_super() before calling!
++static inline struct pram_super_block *
++pram_get_super(struct super_block * sb)
++{
++ struct pram_sb_info * sbi = (struct pram_sb_info *)sb->s_fs_info;
++ return (struct pram_super_block *)sbi->virt_addr;
++}
++
++// pram_lock_super() before calling!
++static inline void pram_sync_super(struct pram_super_block * ps)
++{
++ ps->s_wtime = get_seconds();
++ ps->s_sum = 0;
++ ps->s_sum = - pram_calc_checksum((u32*)ps, PRAM_SB_SIZE>>2);
++}
++
++// pram_lock_inode() before calling!
++static inline void pram_sync_inode(struct pram_inode * pi)
++{
++ //pi->i_mtime = CURRENT_TIME;
++ pi->i_sum = 0;
++ pi->i_sum = - pram_calc_checksum((u32*)pi, PRAM_INODE_SIZE>>2);
++}
++
++#ifndef CONFIG_PRAMFS_NOWP
++#define pram_lock_range(p, len) {\
++ spin_lock_irqsave(&init_mm.page_table_lock, flags);\
++ pram_writeable((p), (len), 1);\
++}
++
++#define pram_unlock_range(p, len) {\
++ pram_writeable((p), (len), 0);\
++ spin_unlock_irqrestore(&init_mm.page_table_lock, flags);\
++}
++#else
++#define pram_lock_range(p, len) do {} while (0)
++#define pram_unlock_range(p, len) do {} while (0)
++#endif
++
++// write protection for super block
++#define pram_lock_super(ps) \
++ pram_lock_range((ps), PRAM_SB_SIZE)
++#define pram_unlock_super(ps) {\
++ pram_sync_super(ps);\
++ pram_unlock_range((ps), PRAM_SB_SIZE);\
++}
++
++// write protection for inode metadata
++#define pram_lock_inode(pi) \
++ pram_lock_range((pi), PRAM_INODE_SIZE)
++#define pram_unlock_inode(pi) {\
++ pram_sync_inode(pi);\
++ pram_unlock_range((pi), PRAM_SB_SIZE);\
++}
++
++// write protection for a data block
++#define pram_lock_block(sb, bp) \
++ pram_lock_range((bp), (sb)->s_blocksize)
++#define pram_unlock_block(sb, bp) \
++ pram_unlock_range((bp), (sb)->s_blocksize)
++
++static inline void *
++pram_get_bitmap(struct super_block * sb)
++{
++ struct pram_super_block * ps = pram_get_super(sb);
++ return ((void*)ps + ps->s_bitmap_start);
++}
++
++// If this is part of a read-modify-write of the inode metadata,
++// pram_lock_inode() before calling!
++static inline struct pram_inode *
++pram_get_inode(struct super_block * sb, pram_off_t ino)
++{
++ struct pram_super_block * ps = pram_get_super(sb);
++ return ino ? (struct pram_inode *)((void*)ps + ino) : NULL;
++}
++
++static inline ino_t
++pram_get_inodenr(struct super_block * sb, struct pram_inode * pi)
++{
++ struct pram_super_block * ps = pram_get_super(sb);
++ return (ino_t)((unsigned long)pi - (unsigned long)ps);
++}
++
++static inline pram_off_t
++pram_get_block_off(struct super_block * sb, unsigned long blocknr)
++{
++ struct pram_super_block * ps = pram_get_super(sb);
++ return (pram_off_t)(ps->s_bitmap_start +
++ (blocknr << sb->s_blocksize_bits));
++}
++
++static inline unsigned long
++pram_get_blocknr(struct super_block * sb, pram_off_t block)
++{
++ struct pram_super_block * ps = pram_get_super(sb);
++ return (block - ps->s_bitmap_start) >> sb->s_blocksize_bits;
++}
++
++// If this is part of a read-modify-write of the block,
++// pram_lock_block() before calling!
++static inline void *
++pram_get_block(struct super_block * sb, pram_off_t block)
++{
++ struct pram_super_block * ps = pram_get_super(sb);
++ return block ? ((void*)ps + block) : NULL;
++}
++
++
++/*
++ * Inodes and files operations
++ */
++
++/* dir.c */
++extern struct file_operations pram_dir_operations;
++
++/* file.c */
++extern struct inode_operations pram_file_inode_operations;
++extern struct file_operations pram_file_operations;
++
++/* inode.c */
++extern struct address_space_operations pram_aops;
++
++/* namei.c */
++extern struct inode_operations pram_dir_inode_operations;
++
++/* symlink.c */
++extern struct inode_operations pram_symlink_inode_operations;
++
++#endif /* __KERNEL__ */
++
++#endif /* _LINUX_PRAM_FS_H */
+diff -Nuar -X /home/stevel/dontdiff main.orig/include/linux/pram_fs_sb.h main/include/linux/pram_fs_sb.h
+--- main.orig/include/linux/pram_fs_sb.h 1969-12-31 16:00:00.000000000 -0800
++++ main/include/linux/pram_fs_sb.h 2004-03-04 15:59:35.000000000 -0800
+@@ -0,0 +1,43 @@
++/*
++ * pram_fs_sb.h
++ *
++ * Definitions for the PRAM filesystem.
++ *
++ * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
++ *
++ * 2003 (c) MontaVista Software, Inc.
++ * Copyright 2003 Sony Corporation
++ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
++ *
++ * This software is being distributed under the terms of the GNU General Public
++ * License version 2. Some or all of the technology encompassed by this
++ * software may be subject to one or more patents pending as of the date of
++ * this notice. No additional patent license will be required for GPL
++ * implementations of the technology. If you want to create a non-GPL
++ * implementation of the technology encompassed by this software, please
++ * contact legal@mvista.com for details including licensing terms and fees.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++#ifndef _LINUX_PRAM_FS_SB
++#define _LINUX_PRAM_FS_SB
++
++/*
++ * PRAM filesystem super-block data in memory
++ */
++struct pram_sb_info {
++ /*
++ * base physical and virtual address of PRAMFS (which is also
++ * the pointer to the super block)
++ */
++ unsigned long phys_addr;
++ void * virt_addr;
++
++ u32 maxsize;
++ u32 features;
++ u16 magic;
++};
++
++#endif /* _LINUX_PRAM_FS_SB */
+diff -Nuar -X /home/stevel/dontdiff main.orig/init/do_mounts.c main/init/do_mounts.c
+--- main.orig/init/do_mounts.c 2004-03-04 17:17:14.000000000 -0800
++++ main/init/do_mounts.c 2004-03-04 15:59:38.000000000 -0800
+@@ -322,6 +322,17 @@
+ }
+ #endif
+
++#ifdef CONFIG_ROOT_PRAMFS
++static int __init mount_pramfs_root(void)
++{
++ create_dev("/dev/root", ROOT_DEV, NULL);
++ if (do_mount_root("/dev/root", "pramfs",
++ root_mountflags, root_mount_data) == 0)
++ return 1;
++ return 0;
++}
++#endif
++
+ #if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD)
+ void __init change_floppy(char *fmt, ...)
+ {
+@@ -363,6 +374,15 @@
+ ROOT_DEV = Root_FD0;
+ }
+ #endif
++#ifdef CONFIG_ROOT_PRAMFS
++ if (ROOT_DEV == MKDEV(0, 0)) {
++ if (mount_pramfs_root())
++ return;
++
++ printk (KERN_ERR "VFS: Unable to mount PRAMFS root\n");
++ ROOT_DEV = Root_FD0;
++ }
++#endif
+ #ifdef CONFIG_BLK_DEV_FD
+ if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
+ /* rd_doload is 2 for a dual initrd/ramload setup */