]> git.pld-linux.org Git - packages/kernel.git/commitdiff
pramfs support
authorcieciwa <cieciwa@pld-linux.org>
Thu, 6 May 2004 08:17:23 +0000 (08:17 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    pramfs-2.6.4.patch -> 1.1

pramfs-2.6.4.patch [new file with mode: 0644]

diff --git a/pramfs-2.6.4.patch b/pramfs-2.6.4.patch
new file mode 100644 (file)
index 0000000..985e251
--- /dev/null
@@ -0,0 +1,2875 @@
+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 */
This page took 2.748302 seconds and 4 git commands to generate.