Whamcloud - gitweb
fix the smfs inode patch
authorwangdi <wangdi>
Wed, 16 Apr 2003 13:38:26 +0000 (13:38 +0000)
committerwangdi <wangdi>
Wed, 16 Apr 2003 13:38:26 +0000 (13:38 +0000)
lustre/kernel_patches/patches/invalidate_show.patch

index 9f044a5..9273c5c 100644 (file)
 
 
 
- fs/block_dev.c     |  695 ++++++++++
- fs/devfs/base.c    | 3544 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- fs/exec.c          |    2 
- fs/inode.c         | 1247 ++++++++++++++++++
- fs/super.c         |  926 +++++++++++++
- include/linux/fs.h | 1709 +++++++++++++++++++++++++
- 6 files changed, 8122 insertions(+), 1 deletion(-)
+ fs/inode.c         |   21 ++++++++++++++-------
+ fs/smbfs/inode.c   |    2 +-
+ fs/super.c         |    4 ++--
+ include/linux/fs.h |    2 +-
+ 4 files changed, 18 insertions(+), 11 deletions(-)
 
---- /dev/null  2003-01-30 18:24:37.000000000 +0800
-+++ linux-2.4.19-hp3_pnnl1-root/fs/inode.c     2003-04-15 13:21:57.000000000 +0800
-@@ -0,0 +1,1247 @@
-+/*
-+ * linux/fs/inode.c
-+ *
-+ * (C) 1997 Linus Torvalds
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/fs.h>
-+#include <linux/string.h>
-+#include <linux/mm.h>
-+#include <linux/dcache.h>
-+#include <linux/init.h>
-+#include <linux/quotaops.h>
-+#include <linux/slab.h>
-+#include <linux/cache.h>
-+#include <linux/swap.h>
-+#include <linux/swapctl.h>
-+#include <linux/prefetch.h>
-+#include <linux/locks.h>
-+
-+/*
-+ * New inode.c implementation.
-+ *
-+ * This implementation has the basic premise of trying
-+ * to be extremely low-overhead and SMP-safe, yet be
-+ * simple enough to be "obviously correct".
-+ *
-+ * Famous last words.
-+ */
-+
-+/* inode dynamic allocation 1999, Andrea Arcangeli <andrea@suse.de> */
-+
-+/* #define INODE_PARANOIA 1 */
-+/* #define INODE_DEBUG 1 */
-+
-+/*
-+ * Inode lookup is no longer as critical as it used to be:
-+ * most of the lookups are going to be through the dcache.
-+ */
-+#define I_HASHBITS    i_hash_shift
-+#define I_HASHMASK    i_hash_mask
-+
-+static unsigned int i_hash_mask;
-+static unsigned int i_hash_shift;
-+
-+/*
-+ * Each inode can be on two separate lists. One is
-+ * the hash list of the inode, used for lookups. The
-+ * other linked list is the "type" list:
-+ *  "in_use" - valid inode, i_count > 0, i_nlink > 0
-+ *  "dirty"  - as "in_use" but also dirty
-+ *  "unused" - valid inode, i_count = 0
-+ *
-+ * A "dirty" list is maintained for each super block,
-+ * allowing for low-overhead inode sync() operations.
-+ */
-+
-+static LIST_HEAD(inode_in_use);
-+static LIST_HEAD(inode_unused);
-+static struct list_head *inode_hashtable;
-+static LIST_HEAD(anon_hash_chain); /* for inodes with NULL i_sb */
-+
-+/*
-+ * A simple spinlock to protect the list manipulations.
-+ *
-+ * NOTE! You also have to own the lock if you change
-+ * the i_state of an inode while it is in use..
-+ */
-+static spinlock_t inode_lock = SPIN_LOCK_UNLOCKED;
-+
-+/*
-+ * Statistics gathering..
-+ */
-+struct inodes_stat_t inodes_stat;
-+
-+static kmem_cache_t * inode_cachep;
-+
-+static struct inode *alloc_inode(struct super_block *sb)
-+{
-+      static struct address_space_operations empty_aops;
-+      static struct inode_operations empty_iops;
-+      static struct file_operations empty_fops;
-+      struct inode *inode;
-+
-+      if (sb->s_op->alloc_inode)
-+              inode = sb->s_op->alloc_inode(sb);
-+      else {
-+              inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL);
-+              /* will die */
-+              if (inode)
-+                      memset(&inode->u, 0, sizeof(inode->u));
-+      }
-+
-+      if (inode) {
-+              struct address_space * const mapping = &inode->i_data;
-+
-+              inode->i_sb = sb;
-+              inode->i_dev = sb->s_dev;
-+              inode->i_blkbits = sb->s_blocksize_bits;
-+              inode->i_flags = 0;
-+              atomic_set(&inode->i_count, 1);
-+              inode->i_sock = 0;
-+              inode->i_op = &empty_iops;
-+              inode->i_fop = &empty_fops;
-+              inode->i_nlink = 1;
-+              atomic_set(&inode->i_writecount, 0);
-+              inode->i_size = 0;
-+              inode->i_blocks = 0;
-+              inode->i_bytes = 0;
-+              inode->i_generation = 0;
-+              memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
-+              inode->i_pipe = NULL;
-+              inode->i_bdev = NULL;
-+              inode->i_cdev = NULL;
-+
-+              mapping->a_ops = &empty_aops;
-+              mapping->host = inode;
-+              mapping->gfp_mask = GFP_HIGHUSER;
-+              inode->i_mapping = mapping;
-+      }
-+      return inode;
-+}
-+
-+static void destroy_inode(struct inode *inode) 
-+{
-+      if (inode_has_buffers(inode))
-+              BUG();
-+      if (inode->i_sb->s_op->destroy_inode)
-+              inode->i_sb->s_op->destroy_inode(inode);
-+      else
-+              kmem_cache_free(inode_cachep, inode);
-+}
-+
-+
-+/*
-+ * These are initializations that only need to be done
-+ * once, because the fields are idempotent across use
-+ * of the inode, so let the slab aware of that.
-+ */
-+void inode_init_once(struct inode *inode)
-+{
-+      memset(inode, 0, sizeof(*inode));
-+      init_waitqueue_head(&inode->i_wait);
-+      INIT_LIST_HEAD(&inode->i_hash);
-+      INIT_LIST_HEAD(&inode->i_data.clean_pages);
-+      INIT_LIST_HEAD(&inode->i_data.dirty_pages);
-+      INIT_LIST_HEAD(&inode->i_data.locked_pages);
-+      INIT_LIST_HEAD(&inode->i_dentry);
-+      INIT_LIST_HEAD(&inode->i_dirty_buffers);
-+      INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
-+      INIT_LIST_HEAD(&inode->i_devices);
-+      sema_init(&inode->i_sem, 1);
-+      sema_init(&inode->i_zombie, 1);
-+      spin_lock_init(&inode->i_data.i_shared_lock);
-+}
-+
-+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
-+{
-+      struct inode * inode = (struct inode *) foo;
-+
-+      if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-+          SLAB_CTOR_CONSTRUCTOR)
-+              inode_init_once(inode);
-+}
-+
-+/*
-+ * Put the inode on the super block's dirty list.
-+ *
-+ * CAREFUL! We mark it dirty unconditionally, but
-+ * move it onto the dirty list only if it is hashed.
-+ * If it was not hashed, it will never be added to
-+ * the dirty list even if it is later hashed, as it
-+ * will have been marked dirty already.
-+ *
-+ * In short, make sure you hash any inodes _before_
-+ * you start marking them dirty..
-+ */
-+ 
-+/**
-+ *    __mark_inode_dirty -    internal function
-+ *    @inode: inode to mark
-+ *    @flags: what kind of dirty (i.e. I_DIRTY_SYNC)
-+ *    Mark an inode as dirty. Callers should use mark_inode_dirty or
-+ *    mark_inode_dirty_sync.
-+ */
-+ 
-+void __mark_inode_dirty(struct inode *inode, int flags)
-+{
-+      struct super_block * sb = inode->i_sb;
-+
-+      if (!sb)
-+              return;
-+
-+      /* Don't do this for I_DIRTY_PAGES - that doesn't actually dirty the inode itself */
-+      if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
-+              if (sb->s_op && sb->s_op->dirty_inode)
-+                      sb->s_op->dirty_inode(inode);
-+      }
-+
-+      /* avoid the locking if we can */
-+      if ((inode->i_state & flags) == flags)
-+              return;
-+
-+      spin_lock(&inode_lock);
-+      if ((inode->i_state & flags) != flags) {
-+              inode->i_state |= flags;
-+              /* Only add valid (ie hashed) inodes to the dirty list */
-+              if (!(inode->i_state & I_LOCK) && !list_empty(&inode->i_hash)) {
-+                      list_del(&inode->i_list);
-+                      list_add(&inode->i_list, &sb->s_dirty);
-+              }
-+      }
-+      spin_unlock(&inode_lock);
-+}
-+
-+static void __wait_on_inode(struct inode * inode)
-+{
-+      DECLARE_WAITQUEUE(wait, current);
-+
-+      add_wait_queue(&inode->i_wait, &wait);
-+repeat:
-+      set_current_state(TASK_UNINTERRUPTIBLE);
-+      if (inode->i_state & I_LOCK) {
-+              schedule();
-+              goto repeat;
-+      }
-+      remove_wait_queue(&inode->i_wait, &wait);
-+      current->state = TASK_RUNNING;
-+}
-+
-+static inline void wait_on_inode(struct inode *inode)
-+{
-+      if (inode->i_state & I_LOCK)
-+              __wait_on_inode(inode);
-+}
-+
-+
-+static inline void write_inode(struct inode *inode, int sync)
-+{
-+      if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->write_inode && !is_bad_inode(inode))
-+              inode->i_sb->s_op->write_inode(inode, sync);
-+}
-+
-+static inline void __iget(struct inode * inode)
-+{
-+      if (atomic_read(&inode->i_count)) {
-+              atomic_inc(&inode->i_count);
-+              return;
-+      }
-+      atomic_inc(&inode->i_count);
-+      if (!(inode->i_state & (I_DIRTY|I_LOCK))) {
-+              list_del(&inode->i_list);
-+              list_add(&inode->i_list, &inode_in_use);
-+      }
-+      inodes_stat.nr_unused--;
-+}
-+
-+static inline void __sync_one(struct inode *inode, int sync)
-+{
-+      unsigned dirty;
-+
-+      list_del(&inode->i_list);
-+      list_add(&inode->i_list, &inode->i_sb->s_locked_inodes);
-+
-+      if (inode->i_state & I_LOCK)
-+              BUG();
-+
-+      /* Set I_LOCK, reset I_DIRTY */
-+      dirty = inode->i_state & I_DIRTY;
-+      inode->i_state |= I_LOCK;
-+      inode->i_state &= ~I_DIRTY;
-+      spin_unlock(&inode_lock);
-+
-+      filemap_fdatasync(inode->i_mapping);
-+
-+      /* Don't write the inode if only I_DIRTY_PAGES was set */
-+      if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC))
-+              write_inode(inode, sync);
-+
-+      filemap_fdatawait(inode->i_mapping);
-+
-+      spin_lock(&inode_lock);
-+      inode->i_state &= ~I_LOCK;
-+      if (!(inode->i_state & I_FREEING)) {
-+              struct list_head *to;
-+              if (inode->i_state & I_DIRTY)
-+                      to = &inode->i_sb->s_dirty;
-+              else if (atomic_read(&inode->i_count))
-+                      to = &inode_in_use;
-+              else
-+                      to = &inode_unused;
-+              list_del(&inode->i_list);
-+              list_add(&inode->i_list, to);
-+      }
-+      wake_up(&inode->i_wait);
-+}
-+
-+static inline void sync_one(struct inode *inode, int sync)
-+{
-+      while (inode->i_state & I_LOCK) {
-+              __iget(inode);
-+              spin_unlock(&inode_lock);
-+              __wait_on_inode(inode);
-+              iput(inode);
-+              spin_lock(&inode_lock);
-+      }
-+
-+      __sync_one(inode, sync);
-+}
-+
-+static inline void sync_list(struct list_head *head)
-+{
-+      struct list_head * tmp;
-+
-+      while ((tmp = head->prev) != head) 
-+              __sync_one(list_entry(tmp, struct inode, i_list), 0);
-+}
-+
-+static inline void wait_on_locked(struct list_head *head)
-+{
-+      struct list_head * tmp;
-+      while ((tmp = head->prev) != head) {
-+              struct inode *inode = list_entry(tmp, struct inode, i_list);
-+              __iget(inode);
-+              spin_unlock(&inode_lock);
-+              __wait_on_inode(inode);
-+              iput(inode);
-+              spin_lock(&inode_lock);
-+      }
-+}
-+
-+static inline int try_to_sync_unused_list(struct list_head *head, int nr_inodes)
-+{
-+      struct list_head *tmp = head;
-+      struct inode *inode;
-+
-+      while (nr_inodes && (tmp = tmp->prev) != head) {
-+              inode = list_entry(tmp, struct inode, i_list);
-+
-+              if (!atomic_read(&inode->i_count)) {
-+                      __sync_one(inode, 0);
-+                      nr_inodes--;
-+
-+                      /* 
-+                       * __sync_one moved the inode to another list,
-+                       * so we have to start looking from the list head.
-+                       */
-+                      tmp = head;
-+              }
-+      }
-+
-+      return nr_inodes;
-+}
-+
-+void sync_inodes_sb(struct super_block *sb)
-+{
-+      spin_lock(&inode_lock);
-+      while (!list_empty(&sb->s_dirty)||!list_empty(&sb->s_locked_inodes)) {
-+              sync_list(&sb->s_dirty);
-+              wait_on_locked(&sb->s_locked_inodes);
-+      }
-+      spin_unlock(&inode_lock);
-+}
-+
-+/*
-+ * Note:
-+ * We don't need to grab a reference to superblock here. If it has non-empty
-+ * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed
-+ * past sync_inodes_sb() until both ->s_dirty and ->s_locked_inodes are
-+ * empty. Since __sync_one() regains inode_lock before it finally moves
-+ * inode from superblock lists we are OK.
-+ */
-+
-+void sync_unlocked_inodes(void)
-+{
-+      struct super_block * sb;
-+      spin_lock(&inode_lock);
-+      spin_lock(&sb_lock);
-+      sb = sb_entry(super_blocks.next);
-+      for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
-+              if (!list_empty(&sb->s_dirty)) {
-+                      spin_unlock(&sb_lock);
-+                      sync_list(&sb->s_dirty);
-+                      spin_lock(&sb_lock);
-+              }
-+      }
-+      spin_unlock(&sb_lock);
-+      spin_unlock(&inode_lock);
-+}
-+
-+/*
-+ * Find a superblock with inodes that need to be synced
-+ */
-+
-+static struct super_block *get_super_to_sync(void)
-+{
-+      struct list_head *p;
-+restart:
-+      spin_lock(&inode_lock);
-+      spin_lock(&sb_lock);
-+      list_for_each(p, &super_blocks) {
-+              struct super_block *s = list_entry(p,struct super_block,s_list);
-+              if (list_empty(&s->s_dirty) && list_empty(&s->s_locked_inodes))
-+                      continue;
-+              s->s_count++;
-+              spin_unlock(&sb_lock);
-+              spin_unlock(&inode_lock);
-+              down_read(&s->s_umount);
-+              if (!s->s_root) {
-+                      drop_super(s);
-+                      goto restart;
-+              }
-+              return s;
-+      }
-+      spin_unlock(&sb_lock);
-+      spin_unlock(&inode_lock);
-+      return NULL;
-+}
-+
-+/**
-+ *    sync_inodes
-+ *    @dev: device to sync the inodes from.
-+ *
-+ *    sync_inodes goes through the super block's dirty list, 
-+ *    writes them out, and puts them back on the normal list.
-+ */
-+
-+void sync_inodes(kdev_t dev)
-+{
-+      struct super_block * s;
-+
-+      /*
-+       * Search the super_blocks array for the device(s) to sync.
-+       */
-+      if (dev) {
-+              if ((s = get_super(dev)) != NULL) {
-+                      sync_inodes_sb(s);
-+                      drop_super(s);
-+              }
-+      } else {
-+              while ((s = get_super_to_sync()) != NULL) {
-+                      sync_inodes_sb(s);
-+                      drop_super(s);
-+              }
-+      }
-+}
-+
-+static void try_to_sync_unused_inodes(void * arg)
-+{
-+      struct super_block * sb;
-+      int nr_inodes = inodes_stat.nr_unused;
-+
-+      spin_lock(&inode_lock);
-+      spin_lock(&sb_lock);
-+      sb = sb_entry(super_blocks.next);
-+      for (; nr_inodes && sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
-+              if (list_empty(&sb->s_dirty))
-+                      continue;
-+              spin_unlock(&sb_lock);
-+              nr_inodes = try_to_sync_unused_list(&sb->s_dirty, nr_inodes);
-+              spin_lock(&sb_lock);
-+      }
-+      spin_unlock(&sb_lock);
-+      spin_unlock(&inode_lock);
-+}
-+
-+static struct tq_struct unused_inodes_flush_task;
-+
-+/**
-+ *    write_inode_now -       write an inode to disk
-+ *    @inode: inode to write to disk
-+ *    @sync: whether the write should be synchronous or not
-+ *
-+ *    This function commits an inode to disk immediately if it is
-+ *    dirty. This is primarily needed by knfsd.
-+ */
-+ 
-+void write_inode_now(struct inode *inode, int sync)
-+{
-+      struct super_block * sb = inode->i_sb;
-+
-+      if (sb) {
-+              spin_lock(&inode_lock);
-+              while (inode->i_state & I_DIRTY)
-+                      sync_one(inode, sync);
-+              spin_unlock(&inode_lock);
-+              if (sync)
-+                      wait_on_inode(inode);
-+      }
-+      else
-+              printk(KERN_ERR "write_inode_now: no super block\n");
-+}
-+
-+/**
-+ * generic_osync_inode - flush all dirty data for a given inode to disk
-+ * @inode: inode to write
-+ * @datasync: if set, don't bother flushing timestamps
-+ *
-+ * This can be called by file_write functions for files which have the
-+ * O_SYNC flag set, to flush dirty writes to disk.  
-+ */
-+
-+int generic_osync_inode(struct inode *inode, int what)
-+{
-+      int err = 0, err2 = 0, need_write_inode_now = 0;
-+      
-+      /* 
-+       * WARNING
-+       *
-+       * Currently, the filesystem write path does not pass the
-+       * filp down to the low-level write functions.  Therefore it
-+       * is impossible for (say) __block_commit_write to know if
-+       * the operation is O_SYNC or not.
-+       *
-+       * Ideally, O_SYNC writes would have the filesystem call
-+       * ll_rw_block as it went to kick-start the writes, and we
-+       * could call osync_inode_buffers() here to wait only for
-+       * those IOs which have already been submitted to the device
-+       * driver layer.  As it stands, if we did this we'd not write
-+       * anything to disk since our writes have not been queued by
-+       * this point: they are still on the dirty LRU.
-+       * 
-+       * So, currently we will call fsync_inode_buffers() instead,
-+       * to flush _all_ dirty buffers for this inode to disk on 
-+       * every O_SYNC write, not just the synchronous I/Os.  --sct
-+       */
-+
-+      if (what & OSYNC_METADATA)
-+              err = fsync_inode_buffers(inode);
-+      if (what & OSYNC_DATA)
-+              err2 = fsync_inode_data_buffers(inode);
-+      if (!err)
-+              err = err2;
-+
-+      spin_lock(&inode_lock);
-+      if ((inode->i_state & I_DIRTY) &&
-+          ((what & OSYNC_INODE) || (inode->i_state & I_DIRTY_DATASYNC)))
-+              need_write_inode_now = 1;
-+      spin_unlock(&inode_lock);
-+
-+      if (need_write_inode_now)
-+              write_inode_now(inode, 1);
-+      else
-+              wait_on_inode(inode);
-+
-+      return err;
-+}
-+
-+/**
-+ * clear_inode - clear an inode
-+ * @inode: inode to clear
-+ *
-+ * This is called by the filesystem to tell us
-+ * that the inode is no longer useful. We just
-+ * terminate it with extreme prejudice.
-+ */
-+ 
-+void clear_inode(struct inode *inode)
-+{
-+      invalidate_inode_buffers(inode);
-+       
-+      if (inode->i_data.nrpages)
-+              BUG();
-+      if (!(inode->i_state & I_FREEING))
-+              BUG();
-+      if (inode->i_state & I_CLEAR)
-+              BUG();
-+      wait_on_inode(inode);
-+      DQUOT_DROP(inode);
-+      if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->clear_inode)
-+              inode->i_sb->s_op->clear_inode(inode);
-+      if (inode->i_bdev)
-+              bd_forget(inode);
-+      else if (inode->i_cdev) {
-+              cdput(inode->i_cdev);
-+              inode->i_cdev = NULL;
-+      }
-+      inode->i_state = I_CLEAR;
-+}
-+
-+/*
-+ * Dispose-list gets a local list with local inodes in it, so it doesn't
-+ * need to worry about list corruption and SMP locks.
-+ */
-+static void dispose_list(struct list_head * head)
-+{
-+      struct list_head * inode_entry;
-+      struct inode * inode;
-+
-+      while ((inode_entry = head->next) != head)
-+      {
-+              list_del(inode_entry);
-+
-+              inode = list_entry(inode_entry, struct inode, i_list);
-+              if (inode->i_data.nrpages)
-+                      truncate_inode_pages(&inode->i_data, 0);
-+              clear_inode(inode);
-+              destroy_inode(inode);
-+              inodes_stat.nr_inodes--;
-+      }
-+}
-+
-+/*
-+ * Invalidate all inodes for a device.
-+ */
+--- linux-rh-2.4.20-8/fs/inode.c~invalidate_show       2003-04-11 14:04:56.000000000 +0800
++++ linux-rh-2.4.20-8-root/fs/inode.c  2003-04-16 20:59:35.000000000 +0800
+@@ -604,7 +604,8 @@ static void dispose_list(struct list_hea
+ /*
+  * Invalidate all inodes for a device.
+  */
+-static int invalidate_list(struct list_head *head, struct super_block * sb, struct list_head * dispose)
 +static int invalidate_list(struct list_head *head, struct super_block * sb,
 +                         struct list_head * dispose, int show)
-+{
-+      struct list_head *next;
-+      int busy = 0, count = 0;
-+
-+      next = head->next;
-+      for (;;) {
-+              struct list_head * tmp = next;
-+              struct inode * inode;
-+
-+              next = next->next;
-+              if (tmp == head)
-+                      break;
-+              inode = list_entry(tmp, struct inode, i_list);
-+              if (inode->i_sb != sb)
-+                      continue;
-+              invalidate_inode_buffers(inode);
-+              if (!atomic_read(&inode->i_count)) {
-+                      list_del_init(&inode->i_hash);
-+                      list_del(&inode->i_list);
-+                      list_add(&inode->i_list, dispose);
-+                      inode->i_state |= I_FREEING;
-+                      count++;
-+                      continue;
-+              }
+ {
+       struct list_head *next;
+       int busy = 0, count = 0;
+@@ -629,6 +630,11 @@ static int invalidate_list(struct list_h
+                       count++;
+                       continue;
+               }
 +              if (show)
 +                      printk(KERN_ERR
 +                             "inode busy: dev %s:%lu (%p) mode %o count %u\n",
 +                             kdevname(sb->s_dev), inode->i_ino, inode,
 +                             inode->i_mode, atomic_read(&inode->i_count));
-+              busy = 1;
-+      }
-+      /* only unused inodes may be cached with i_count zero */
-+      inodes_stat.nr_unused -= count;
-+      return busy;
-+}
-+
-+/*
-+ * This is a two-stage process. First we collect all
-+ * offending inodes onto the throw-away list, and in
-+ * the second stage we actually dispose of them. This
-+ * is because we don't want to sleep while messing
-+ * with the global lists..
-+ */
-+ 
-+/**
-+ *    invalidate_inodes       - discard the inodes on a device
-+ *    @sb: superblock
+               busy = 1;
+       }
+       /* only unused inodes may be cached with i_count zero */
+@@ -647,22 +653,23 @@ static int invalidate_list(struct list_h
+ /**
+  *    invalidate_inodes       - discard the inodes on a device
+  *    @sb: superblock
 + *    @show: whether we should display any busy inodes found
-+ *
-+ *    Discard all of the inodes for a given superblock. If the discard
-+ *    fails because there are busy inodes then a non zero value is returned.
-+ *    If the discard is successful all the inodes have been discarded.
-+ */
-+ 
+  *
+  *    Discard all of the inodes for a given superblock. If the discard
+  *    fails because there are busy inodes then a non zero value is returned.
+  *    If the discard is successful all the inodes have been discarded.
+  */
+  
+-int invalidate_inodes(struct super_block * sb)
 +int invalidate_inodes(struct super_block * sb, int show)
-+{
-+      int busy;
-+      LIST_HEAD(throw_away);
-+
-+      spin_lock(&inode_lock);
+ {
+       int busy;
+       LIST_HEAD(throw_away);
+       spin_lock(&inode_lock);
+-      busy = invalidate_list(&inode_in_use, sb, &throw_away);
+-      busy |= invalidate_list(&inode_unused, sb, &throw_away);
+-      busy |= invalidate_list(&sb->s_dirty, sb, &throw_away);
+-      busy |= invalidate_list(&sb->s_locked_inodes, sb, &throw_away);
 +      busy = invalidate_list(&inode_in_use, sb, &throw_away, show);
 +      busy |= invalidate_list(&inode_unused, sb, &throw_away, show);
 +      busy |= invalidate_list(&sb->s_dirty, sb, &throw_away, show);
 +      busy |= invalidate_list(&sb->s_locked_inodes, sb, &throw_away, show);
-+      spin_unlock(&inode_lock);
-+
-+      dispose_list(&throw_away);
-+
-+      return busy;
-+}
-+ 
-+int invalidate_device(kdev_t dev, int do_sync)
-+{
-+      struct super_block *sb;
-+      int res;
-+
-+      if (do_sync)
-+              fsync_dev(dev);
-+
-+      res = 0;
-+      sb = get_super(dev);
-+      if (sb) {
-+              /*
-+               * no need to lock the super, get_super holds the
-+               * read semaphore so the filesystem cannot go away
-+               * under us (->put_super runs with the write lock
-+               * hold).
-+               */
-+              shrink_dcache_sb(sb);
+       spin_unlock(&inode_lock);
+       dispose_list(&throw_away);
+@@ -688,7 +695,7 @@ int invalidate_device(kdev_t dev, int do
+                * hold).
+                */
+               shrink_dcache_sb(sb);
+-              res = invalidate_inodes(sb);
 +              res = invalidate_inodes(sb, 0);
-+              drop_super(sb);
-+      }
-+      invalidate_buffers(dev);
-+      return res;
-+}
-+
-+
-+/*
-+ * This is called with the inode lock held. It searches
-+ * the in-use for freeable inodes, which are moved to a
-+ * temporary list and then placed on the unused list by
-+ * dispose_list. 
-+ *
-+ * We don't expect to have to call this very often.
-+ *
-+ * N.B. The spinlock is released during the call to
-+ *      dispose_list.
-+ */
-+#define CAN_UNUSE(inode) \
-+      ((((inode)->i_state | (inode)->i_data.nrpages) == 0)  && \
-+       !inode_has_buffers(inode))
-+#define INODE(entry)  (list_entry(entry, struct inode, i_list))
-+
-+void prune_icache(int goal)
-+{
-+      LIST_HEAD(list);
-+      struct list_head *entry, *freeable = &list;
-+      int count;
-+      struct inode * inode;
-+
-+      spin_lock(&inode_lock);
-+
-+      count = 0;
-+      entry = inode_unused.prev;
-+      while (entry != &inode_unused)
-+      {
-+              struct list_head *tmp = entry;
-+
-+              entry = entry->prev;
-+              inode = INODE(tmp);
-+              if (inode->i_state & (I_FREEING|I_CLEAR|I_LOCK))
-+                      continue;
-+              if (!CAN_UNUSE(inode))
-+                      continue;
-+              if (atomic_read(&inode->i_count))
-+                      continue;
-+              list_del(tmp);
-+              list_del(&inode->i_hash);
-+              INIT_LIST_HEAD(&inode->i_hash);
-+              list_add(tmp, freeable);
-+              inode->i_state |= I_FREEING;
-+              count++;
-+              if (!--goal)
-+                      break;
-+      }
-+      inodes_stat.nr_unused -= count;
-+      spin_unlock(&inode_lock);
-+
-+      dispose_list(freeable);
-+
-+      /* 
-+       * If we didn't freed enough clean inodes schedule
-+       * a sync of the dirty inodes, we cannot do it
-+       * from here or we're either synchronously dogslow
-+       * or we deadlock with oom.
-+       */
-+      if (goal)
-+              schedule_task(&unused_inodes_flush_task);
-+}
-+
-+int shrink_icache_memory(int priority, int gfp_mask)
-+{
-+      int count = 0;
-+
-+      /*
-+       * Nasty deadlock avoidance..
-+       *
-+       * We may hold various FS locks, and we don't
-+       * want to recurse into the FS that called us
-+       * in clear_inode() and friends..
-+       */
-+      if (!(gfp_mask & __GFP_FS))
-+              return 0;
-+
-+      count = inodes_stat.nr_unused / priority;
-+
-+      prune_icache(count);
-+      return kmem_cache_shrink(inode_cachep);
-+}
-+
-+/*
-+ * Called with the inode lock held.
-+ * NOTE: we are not increasing the inode-refcount, you must call __iget()
-+ * by hand after calling find_inode now! This simplifies iunique and won't
-+ * add any additional branch in the common code.
-+ */
-+static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
-+{
-+      struct list_head *tmp;
-+      struct inode * inode;
-+
-+      tmp = head;
-+      for (;;) {
-+              tmp = tmp->next;
-+              inode = NULL;
-+              if (tmp == head)
-+                      break;
-+              inode = list_entry(tmp, struct inode, i_hash);
-+              if (inode->i_ino != ino)
-+                      continue;
-+              if (inode->i_sb != sb)
-+                      continue;
-+              if (find_actor && !find_actor(inode, ino, opaque))
-+                      continue;
-+              break;
-+      }
-+      return inode;
-+}
-+
-+/**
-+ *    new_inode       - obtain an inode
-+ *    @sb: superblock
-+ *
-+ *    Allocates a new inode for given superblock.
-+ */
-+ 
-+struct inode * new_inode(struct super_block *sb)
-+{
-+      static unsigned long last_ino;
-+      struct inode * inode;
-+
-+      spin_lock_prefetch(&inode_lock);
-+      
-+      inode = alloc_inode(sb);
-+      if (inode) {
-+              spin_lock(&inode_lock);
-+              inodes_stat.nr_inodes++;
-+              list_add(&inode->i_list, &inode_in_use);
-+              inode->i_ino = ++last_ino;
-+              inode->i_state = 0;
-+              spin_unlock(&inode_lock);
-+      }
-+      return inode;
-+}
-+
-+void unlock_new_inode(struct inode *inode)
-+{
-+      /*
-+       * This is special!  We do not need the spinlock
-+       * when clearing I_LOCK, because we're guaranteed
-+       * that nobody else tries to do anything about the
-+       * state of the inode when it is locked, as we
-+       * just created it (so there can be no old holders
-+       * that haven't tested I_LOCK).
-+       */
-+      inode->i_state &= ~(I_LOCK|I_NEW);
-+      wake_up(&inode->i_wait);
-+}
-+
-+/*
-+ * This is called without the inode lock held.. Be careful.
-+ *
-+ * We no longer cache the sb_flags in i_flags - see fs.h
-+ *    -- rmk@arm.uk.linux.org
-+ */
-+static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
-+{
-+      struct inode * inode;
-+
-+      inode = alloc_inode(sb);
-+      if (inode) {
-+              struct inode * old;
-+
-+              spin_lock(&inode_lock);
-+              /* We released the lock, so.. */
-+              old = find_inode(sb, ino, head, find_actor, opaque);
-+              if (!old) {
-+                      inodes_stat.nr_inodes++;
-+                      list_add(&inode->i_list, &inode_in_use);
-+                      list_add(&inode->i_hash, head);
-+                      inode->i_ino = ino;
-+                      inode->i_state = I_LOCK|I_NEW;
-+                      spin_unlock(&inode_lock);
-+
-+                      /*
-+                       * Return the locked inode with I_NEW set, the
-+                       * caller is responsible for filling in the contents
-+                       */
-+                      return inode;
-+              }
-+
-+              /*
-+               * Uhhuh, somebody else created the same inode under
-+               * us. Use the old inode instead of the one we just
-+               * allocated.
-+               */
-+              __iget(old);
-+              spin_unlock(&inode_lock);
-+              destroy_inode(inode);
-+              inode = old;
-+              wait_on_inode(inode);
-+      }
-+      return inode;
-+}
-+
-+static inline unsigned long hash(struct super_block *sb, unsigned long i_ino)
-+{
-+      unsigned long tmp = i_ino + ((unsigned long) sb / L1_CACHE_BYTES);
-+      tmp = tmp + (tmp >> I_HASHBITS);
-+      return tmp & I_HASHMASK;
-+}
-+
-+/* Yeah, I know about quadratic hash. Maybe, later. */
-+
-+/**
-+ *    iunique - get a unique inode number
-+ *    @sb: superblock
-+ *    @max_reserved: highest reserved inode number
-+ *
-+ *    Obtain an inode number that is unique on the system for a given
-+ *    superblock. This is used by file systems that have no natural
-+ *    permanent inode numbering system. An inode number is returned that
-+ *    is higher than the reserved limit but unique.
-+ *
-+ *    BUGS:
-+ *    With a large number of inodes live on the file system this function
-+ *    currently becomes quite slow.
-+ */
-+ 
-+ino_t iunique(struct super_block *sb, ino_t max_reserved)
-+{
-+      static ino_t counter = 0;
-+      struct inode *inode;
-+      struct list_head * head;
-+      ino_t res;
-+      spin_lock(&inode_lock);
-+retry:
-+      if (counter > max_reserved) {
-+              head = inode_hashtable + hash(sb,counter);
-+              inode = find_inode(sb, res = counter++, head, NULL, NULL);
-+              if (!inode) {
-+                      spin_unlock(&inode_lock);
-+                      return res;
-+              }
-+      } else {
-+              counter = max_reserved + 1;
-+      }
-+      goto retry;
-+      
-+}
-+
-+struct inode *igrab(struct inode *inode)
-+{
-+      spin_lock(&inode_lock);
-+      if (!(inode->i_state & I_FREEING))
-+              __iget(inode);
-+      else
-+              /*
-+               * Handle the case where s_op->clear_inode is not been
-+               * called yet, and somebody is calling igrab
-+               * while the inode is getting freed.
-+               */
-+              inode = NULL;
-+      spin_unlock(&inode_lock);
-+      return inode;
-+}
-+
-+struct inode *iget4_locked(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
-+{
-+      struct list_head * head = inode_hashtable + hash(sb,ino);
-+      struct inode * inode;
-+
-+      spin_lock(&inode_lock);
-+      inode = find_inode(sb, ino, head, find_actor, opaque);
-+      if (inode) {
-+              __iget(inode);
-+              spin_unlock(&inode_lock);
-+              wait_on_inode(inode);
-+              return inode;
-+      }
-+      spin_unlock(&inode_lock);
-+
-+      /*
-+       * get_new_inode() will do the right thing, re-trying the search
-+       * in case it had to block at any point.
-+       */
-+      return get_new_inode(sb, ino, head, find_actor, opaque);
-+}
-+
-+/**
-+ *    insert_inode_hash - hash an inode
-+ *    @inode: unhashed inode
-+ *
-+ *    Add an inode to the inode hash for this superblock. If the inode
-+ *    has no superblock it is added to a separate anonymous chain.
-+ */
-+ 
-+void insert_inode_hash(struct inode *inode)
-+{
-+      struct list_head *head = &anon_hash_chain;
-+      if (inode->i_sb)
-+              head = inode_hashtable + hash(inode->i_sb, inode->i_ino);
-+      spin_lock(&inode_lock);
-+      list_add(&inode->i_hash, head);
-+      spin_unlock(&inode_lock);
-+}
-+
-+/**
-+ *    remove_inode_hash - remove an inode from the hash
-+ *    @inode: inode to unhash
-+ *
-+ *    Remove an inode from the superblock or anonymous hash.
-+ */
-+ 
-+void remove_inode_hash(struct inode *inode)
-+{
-+      spin_lock(&inode_lock);
-+      list_del(&inode->i_hash);
-+      INIT_LIST_HEAD(&inode->i_hash);
-+      spin_unlock(&inode_lock);
-+}
-+
-+/**
-+ *    iput    - put an inode 
-+ *    @inode: inode to put
-+ *
-+ *    Puts an inode, dropping its usage count. If the inode use count hits
-+ *    zero the inode is also then freed and may be destroyed.
-+ */
-+ 
-+void iput(struct inode *inode)
-+{
-+      if (inode) {
-+              struct super_block *sb = inode->i_sb;
-+              struct super_operations *op = NULL;
-+
-+              if (inode->i_state == I_CLEAR)
-+                      BUG();
-+
-+              if (sb && sb->s_op)
-+                      op = sb->s_op;
-+              if (op && op->put_inode)
-+                      op->put_inode(inode);
-+
-+              if (!atomic_dec_and_lock(&inode->i_count, &inode_lock))
-+                      return;
-+
-+              if (!inode->i_nlink) {
-+                      list_del(&inode->i_hash);
-+                      INIT_LIST_HEAD(&inode->i_hash);
-+                      list_del(&inode->i_list);
-+                      INIT_LIST_HEAD(&inode->i_list);
-+                      inode->i_state|=I_FREEING;
-+                      inodes_stat.nr_inodes--;
-+                      spin_unlock(&inode_lock);
-+
-+                      if (inode->i_data.nrpages)
-+                              truncate_inode_pages(&inode->i_data, 0);
-+
-+                      if (op && op->delete_inode) {
-+                              void (*delete)(struct inode *) = op->delete_inode;
-+                              if (!is_bad_inode(inode))
-+                                      DQUOT_INIT(inode);
-+                              /* s_op->delete_inode internally recalls clear_inode() */
-+                              delete(inode);
-+                      } else
-+                              clear_inode(inode);
-+                      if (inode->i_state != I_CLEAR)
-+                              BUG();
-+              } else {
-+                      if (!list_empty(&inode->i_hash)) {
-+                              if (!(inode->i_state & (I_DIRTY|I_LOCK))) {
-+                                      list_del(&inode->i_list);
-+                                      list_add(&inode->i_list, &inode_unused);
-+                              }
-+                              inodes_stat.nr_unused++;
-+                              spin_unlock(&inode_lock);
-+                              if (!sb || (sb->s_flags & MS_ACTIVE))
-+                                      return;
-+                              write_inode_now(inode, 1);
-+                              spin_lock(&inode_lock);
-+                              inodes_stat.nr_unused--;
-+                              list_del_init(&inode->i_hash);
-+                      }
-+                      list_del_init(&inode->i_list);
-+                      inode->i_state|=I_FREEING;
-+                      inodes_stat.nr_inodes--;
-+                      spin_unlock(&inode_lock);
-+                      if (inode->i_data.nrpages)
-+                              truncate_inode_pages(&inode->i_data, 0);
-+                      clear_inode(inode);
-+              }
-+              destroy_inode(inode);
-+      }
-+}
-+
-+void force_delete(struct inode *inode)
-+{
-+      /*
-+       * Kill off unused inodes ... iput() will unhash and
-+       * delete the inode if we set i_nlink to zero.
-+       */
-+      if (atomic_read(&inode->i_count) == 1)
-+              inode->i_nlink = 0;
-+}
-+
-+/**
-+ *    bmap    - find a block number in a file
-+ *    @inode: inode of file
-+ *    @block: block to find
-+ *
-+ *    Returns the block number on the device holding the inode that
-+ *    is the disk block number for the block of the file requested.
-+ *    That is, asked for block 4 of inode 1 the function will return the
-+ *    disk block relative to the disk start that holds that block of the 
-+ *    file.
-+ */
-+ 
-+int bmap(struct inode * inode, int block)
-+{
-+      int res = 0;
-+      if (inode->i_mapping->a_ops->bmap)
-+              res = inode->i_mapping->a_ops->bmap(inode->i_mapping, block);
-+      return res;
-+}
-+
-+/*
-+ * Initialize the hash tables.
-+ */
-+void __init inode_init(unsigned long mempages)
-+{
-+      struct list_head *head;
-+      unsigned long order;
-+      unsigned int nr_hash;
-+      int i;
-+
-+      mempages >>= (14 - PAGE_SHIFT);
-+      mempages *= sizeof(struct list_head);
-+      for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)
-+              ;
-+
-+      do {
-+              unsigned long tmp;
-+
-+              nr_hash = (1UL << order) * PAGE_SIZE /
-+                      sizeof(struct list_head);
-+              i_hash_mask = (nr_hash - 1);
-+
-+              tmp = nr_hash;
-+              i_hash_shift = 0;
-+              while ((tmp >>= 1UL) != 0UL)
-+                      i_hash_shift++;
-+
-+              inode_hashtable = (struct list_head *)
-+                      __get_free_pages(GFP_ATOMIC, order);
-+      } while (inode_hashtable == NULL && --order >= 0);
-+
-+      printk(KERN_INFO "Inode cache hash table entries: %d (order: %ld, %ld bytes)\n",
-+                      nr_hash, order, (PAGE_SIZE << order));
-+
-+      if (!inode_hashtable)
-+              panic("Failed to allocate inode hash table\n");
-+
-+      head = inode_hashtable;
-+      i = nr_hash;
-+      do {
-+              INIT_LIST_HEAD(head);
-+              head++;
-+              i--;
-+      } while (i);
-+
-+      /* inode slab cache */
-+      inode_cachep = kmem_cache_create("inode_cache", sizeof(struct inode),
-+                                       0, SLAB_HWCACHE_ALIGN, init_once,
-+                                       NULL);
-+      if (!inode_cachep)
-+              panic("cannot create inode slab cache");
-+
-+      unused_inodes_flush_task.routine = try_to_sync_unused_inodes;
-+}
-+
-+/**
-+ *    update_atime    -       update the access time
-+ *    @inode: inode accessed
-+ *
-+ *    Update the accessed time on an inode and mark it for writeback.
-+ *    This function automatically handles read only file systems and media,
-+ *    as well as the "noatime" flag and inode specific "noatime" markers.
-+ */
-+ 
-+void update_atime (struct inode *inode)
-+{
-+      if (inode->i_atime == CURRENT_TIME)
-+              return;
-+      if ( IS_NOATIME (inode) ) return;
-+      if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
-+      if ( IS_RDONLY (inode) ) return;
-+      inode->i_atime = CURRENT_TIME;
-+      mark_inode_dirty_sync (inode);
-+}   /*  End Function update_atime  */
-+
-+
-+/*
-+ *    Quota functions that want to walk the inode lists..
-+ */
-+#ifdef CONFIG_QUOTA
-+
-+/* Functions back in dquot.c */
-+void put_dquot_list(struct list_head *);
-+int remove_inode_dquot_ref(struct inode *, int, struct list_head *);
-+
-+void remove_dquot_ref(struct super_block *sb, int type)
-+{
-+      struct inode *inode;
-+      struct list_head *act_head;
-+      LIST_HEAD(tofree_head);
-+
-+      if (!sb->dq_op)
-+              return; /* nothing to do */
-+      /* We have to be protected against other CPUs */
-+      lock_kernel();          /* This lock is for quota code */
-+      spin_lock(&inode_lock); /* This lock is for inodes code */
-+ 
-+      list_for_each(act_head, &inode_in_use) {
-+              inode = list_entry(act_head, struct inode, i_list);
-+              if (inode->i_sb == sb && IS_QUOTAINIT(inode))
-+                      remove_inode_dquot_ref(inode, type, &tofree_head);
-+      }
-+      list_for_each(act_head, &inode_unused) {
-+              inode = list_entry(act_head, struct inode, i_list);
-+              if (inode->i_sb == sb && IS_QUOTAINIT(inode))
-+                      remove_inode_dquot_ref(inode, type, &tofree_head);
-+      }
-+      list_for_each(act_head, &sb->s_dirty) {
-+              inode = list_entry(act_head, struct inode, i_list);
-+              if (IS_QUOTAINIT(inode))
-+                      remove_inode_dquot_ref(inode, type, &tofree_head);
-+      }
-+      list_for_each(act_head, &sb->s_locked_inodes) {
-+              inode = list_entry(act_head, struct inode, i_list);
-+              if (IS_QUOTAINIT(inode))
-+                      remove_inode_dquot_ref(inode, type, &tofree_head);
-+      }
-+      spin_unlock(&inode_lock);
-+      unlock_kernel();
-+
-+      put_dquot_list(&tofree_head);
-+}
-+
-+#endif
---- /dev/null  2003-01-30 18:24:37.000000000 +0800
-+++ linux-2.4.19-hp3_pnnl1-root/fs/block_dev.c 2002-08-03 08:39:45.000000000 +0800
-@@ -0,0 +1,695 @@
-+/*
-+ *  linux/fs/block_dev.c
-+ *
-+ *  Copyright (C) 1991, 1992  Linus Torvalds
-+ *  Copyright (C) 2001  Andrea Arcangeli <andrea@suse.de> SuSE
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/init.h>
-+#include <linux/mm.h>
-+#include <linux/locks.h>
-+#include <linux/fcntl.h>
-+#include <linux/slab.h>
-+#include <linux/kmod.h>
-+#include <linux/major.h>
-+#include <linux/devfs_fs_kernel.h>
-+#include <linux/smp_lock.h>
-+#include <linux/iobuf.h>
-+#include <linux/highmem.h>
-+#include <linux/blkdev.h>
-+#include <linux/module.h>
-+
-+#include <asm/uaccess.h>
-+
-+static unsigned long max_block(kdev_t dev)
-+{
-+      unsigned int retval = ~0U;
-+      int major = MAJOR(dev);
-+
-+      if (blk_size[major]) {
-+              int minor = MINOR(dev);
-+              unsigned int blocks = blk_size[major][minor];
-+              if (blocks) {
-+                      unsigned int size = block_size(dev);
-+                      unsigned int sizebits = blksize_bits(size);
-+                      blocks += (size-1) >> BLOCK_SIZE_BITS;
-+                      retval = blocks << (BLOCK_SIZE_BITS - sizebits);
-+                      if (sizebits > BLOCK_SIZE_BITS)
-+                              retval = blocks >> (sizebits - BLOCK_SIZE_BITS);
-+              }
-+      }
-+      return retval;
-+}
-+
-+static loff_t blkdev_size(kdev_t dev)
-+{
-+      unsigned int blocks = ~0U;
-+      int major = MAJOR(dev);
-+
-+      if (blk_size[major]) {
-+              int minor = MINOR(dev);
-+              blocks = blk_size[major][minor];
-+      }
-+      return (loff_t) blocks << BLOCK_SIZE_BITS;
-+}
-+
-+/* Kill _all_ buffers, dirty or not.. */
-+static void kill_bdev(struct block_device *bdev)
-+{
-+      invalidate_bdev(bdev, 1);
-+      truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
-+}     
-+
-+int set_blocksize(kdev_t dev, int size)
-+{
-+      int oldsize;
-+      struct block_device *bdev;
-+
-+      /* Size must be a power of two, and between 512 and PAGE_SIZE */
-+      if (size > PAGE_SIZE || size < 512 || (size & (size-1)))
-+              return -EINVAL;
-+
-+      /* Size cannot be smaller than the size supported by the device */
-+      if (size < get_hardsect_size(dev))
-+              return -EINVAL;
-+
-+      /* No blocksize array? Implies hardcoded BLOCK_SIZE */
-+      if (!blksize_size[MAJOR(dev)]) {
-+              if (size == BLOCK_SIZE)
-+                      return 0;
-+              return -EINVAL;
-+      }
-+
-+      oldsize = blksize_size[MAJOR(dev)][MINOR(dev)];
-+      if (oldsize == size)
-+              return 0;
-+
-+      if (!oldsize && size == BLOCK_SIZE) {
-+              blksize_size[MAJOR(dev)][MINOR(dev)] = size;
-+              return 0;
-+      }
-+
-+      /* Ok, we're actually changing the blocksize.. */
-+      bdev = bdget(dev);
-+      sync_buffers(dev, 2);
-+      blksize_size[MAJOR(dev)][MINOR(dev)] = size;
-+      bdev->bd_inode->i_blkbits = blksize_bits(size);
-+      kill_bdev(bdev);
-+      bdput(bdev);
-+      return 0;
-+}
-+
-+int sb_set_blocksize(struct super_block *sb, int size)
-+{
-+      int bits;
-+      if (set_blocksize(sb->s_dev, size) < 0)
-+              return 0;
-+      sb->s_blocksize = size;
-+      for (bits = 9, size >>= 9; size >>= 1; bits++)
-+              ;
-+      sb->s_blocksize_bits = bits;
-+      return sb->s_blocksize;
-+}
-+
-+int sb_min_blocksize(struct super_block *sb, int size)
-+{
-+      int minsize = get_hardsect_size(sb->s_dev);
-+      if (size < minsize)
-+              size = minsize;
-+      return sb_set_blocksize(sb, size);
-+}
-+
-+static int blkdev_get_block(struct inode * inode, long iblock, struct buffer_head * bh, int create)
-+{
-+      if (iblock >= max_block(inode->i_rdev))
-+              return -EIO;
-+
-+      bh->b_dev = inode->i_rdev;
-+      bh->b_blocknr = iblock;
-+      bh->b_state |= 1UL << BH_Mapped;
-+      return 0;
-+}
-+
-+static int blkdev_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsigned long blocknr, int blocksize)
-+{
-+      return generic_direct_IO(rw, inode, iobuf, blocknr, blocksize, blkdev_get_block);
-+}
-+
-+static int blkdev_writepage(struct page * page)
-+{
-+      return block_write_full_page(page, blkdev_get_block);
-+}
-+
-+static int blkdev_readpage(struct file * file, struct page * page)
-+{
-+      return block_read_full_page(page, blkdev_get_block);
-+}
-+
-+static int blkdev_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
-+{
-+      return block_prepare_write(page, from, to, blkdev_get_block);
-+}
-+
-+static int blkdev_commit_write(struct file *file, struct page *page, unsigned from, unsigned to)
-+{
-+      return block_commit_write(page, from, to);
-+}
-+
-+/*
-+ * private llseek:
-+ * for a block special file file->f_dentry->d_inode->i_size is zero
-+ * so we compute the size by hand (just as in block_read/write above)
-+ */
-+static loff_t block_llseek(struct file *file, loff_t offset, int origin)
-+{
-+      /* ewww */
-+      loff_t size = file->f_dentry->d_inode->i_bdev->bd_inode->i_size;
-+      loff_t retval;
-+
-+      switch (origin) {
-+              case 2:
-+                      offset += size;
-+                      break;
-+              case 1:
-+                      offset += file->f_pos;
-+      }
-+      retval = -EINVAL;
-+      if (offset >= 0 && offset <= size) {
-+              if (offset != file->f_pos) {
-+                      file->f_pos = offset;
-+                      file->f_reada = 0;
-+                      file->f_version = ++event;
-+              }
-+              retval = offset;
-+      }
-+      return retval;
-+}
-+      
-+
-+static int __block_fsync(struct inode * inode)
-+{
-+      int ret, err;
-+
-+      ret = filemap_fdatasync(inode->i_mapping);
-+      err = sync_buffers(inode->i_rdev, 1);
-+      if (err && !ret)
-+              ret = err;
-+      err = filemap_fdatawait(inode->i_mapping);
-+      if (err && !ret)
-+              ret = err;
-+
-+      return ret;
-+}
-+
-+/*
-+ *    Filp may be NULL when we are called by an msync of a vma
-+ *    since the vma has no handle.
-+ */
-+ 
-+static int block_fsync(struct file *filp, struct dentry *dentry, int datasync)
-+{
-+      struct inode * inode = dentry->d_inode;
-+
-+      return __block_fsync(inode);
-+}
-+
-+/*
-+ * pseudo-fs
-+ */
-+
-+static struct super_block *bd_read_super(struct super_block *sb, void *data, int silent)
-+{
-+      static struct super_operations sops = {};
-+      struct inode *root = new_inode(sb);
-+      if (!root)
-+              return NULL;
-+      root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
-+      root->i_uid = root->i_gid = 0;
-+      root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
-+      sb->s_maxbytes = ~0ULL;
-+      sb->s_blocksize = 1024;
-+      sb->s_blocksize_bits = 10;
-+      sb->s_magic = 0x62646576;
-+      sb->s_op = &sops;
-+      sb->s_root = d_alloc(NULL, &(const struct qstr) { "bdev:", 5, 0 });
-+      if (!sb->s_root) {
-+              iput(root);
-+              return NULL;
-+      }
-+      sb->s_root->d_sb = sb;
-+      sb->s_root->d_parent = sb->s_root;
-+      d_instantiate(sb->s_root, root);
-+      return sb;
-+}
-+
-+static DECLARE_FSTYPE(bd_type, "bdev", bd_read_super, FS_NOMOUNT);
-+
-+static struct vfsmount *bd_mnt;
-+
-+/*
-+ * bdev cache handling - shamelessly stolen from inode.c
-+ * We use smaller hashtable, though.
-+ */
-+
-+#define HASH_BITS     6
-+#define HASH_SIZE     (1UL << HASH_BITS)
-+#define HASH_MASK     (HASH_SIZE-1)
-+static struct list_head bdev_hashtable[HASH_SIZE];
-+static spinlock_t bdev_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-+static kmem_cache_t * bdev_cachep;
-+
-+#define alloc_bdev() \
-+       ((struct block_device *) kmem_cache_alloc(bdev_cachep, SLAB_KERNEL))
-+#define destroy_bdev(bdev) kmem_cache_free(bdev_cachep, (bdev))
-+
-+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
-+{
-+      struct block_device * bdev = (struct block_device *) foo;
-+
-+      if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-+          SLAB_CTOR_CONSTRUCTOR)
-+      {
-+              memset(bdev, 0, sizeof(*bdev));
-+              sema_init(&bdev->bd_sem, 1);
-+              INIT_LIST_HEAD(&bdev->bd_inodes);
-+      }
-+}
-+
-+void __init bdev_cache_init(void)
-+{
-+      int i, err;
-+      struct list_head *head = bdev_hashtable;
-+
-+      i = HASH_SIZE;
-+      do {
-+              INIT_LIST_HEAD(head);
-+              head++;
-+              i--;
-+      } while (i);
-+
-+      bdev_cachep = kmem_cache_create("bdev_cache",
-+                                       sizeof(struct block_device),
-+                                       0, SLAB_HWCACHE_ALIGN, init_once,
-+                                       NULL);
-+      if (!bdev_cachep)
-+              panic("Cannot create bdev_cache SLAB cache");
-+      err = register_filesystem(&bd_type);
-+      if (err)
-+              panic("Cannot register bdev pseudo-fs");
-+      bd_mnt = kern_mount(&bd_type);
-+      err = PTR_ERR(bd_mnt);
-+      if (IS_ERR(bd_mnt))
-+              panic("Cannot create bdev pseudo-fs");
-+}
-+
-+/*
-+ * Most likely _very_ bad one - but then it's hardly critical for small
-+ * /dev and can be fixed when somebody will need really large one.
-+ */
-+static inline unsigned long hash(dev_t dev)
-+{
-+      unsigned long tmp = dev;
-+      tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);
-+      return tmp & HASH_MASK;
-+}
-+
-+static struct block_device *bdfind(dev_t dev, struct list_head *head)
-+{
-+      struct list_head *p;
-+      struct block_device *bdev;
-+      for (p=head->next; p!=head; p=p->next) {
-+              bdev = list_entry(p, struct block_device, bd_hash);
-+              if (bdev->bd_dev != dev)
-+                      continue;
-+              atomic_inc(&bdev->bd_count);
-+              return bdev;
-+      }
-+      return NULL;
-+}
-+
-+struct block_device *bdget(dev_t dev)
-+{
-+      struct list_head * head = bdev_hashtable + hash(dev);
-+      struct block_device *bdev, *new_bdev;
-+      spin_lock(&bdev_lock);
-+      bdev = bdfind(dev, head);
-+      spin_unlock(&bdev_lock);
-+      if (bdev)
-+              return bdev;
-+      new_bdev = alloc_bdev();
-+      if (new_bdev) {
-+              struct inode *inode = new_inode(bd_mnt->mnt_sb);
-+              if (inode) {
-+                      kdev_t kdev = to_kdev_t(dev);
-+                      atomic_set(&new_bdev->bd_count,1);
-+                      new_bdev->bd_dev = dev;
-+                      new_bdev->bd_op = NULL;
-+                      new_bdev->bd_inode = inode;
-+                      inode->i_rdev = kdev;
-+                      inode->i_dev = kdev;
-+                      inode->i_bdev = new_bdev;
-+                      inode->i_data.a_ops = &def_blk_aops;
-+                      inode->i_data.gfp_mask = GFP_USER;
-+                      inode->i_mode = S_IFBLK;
-+                      spin_lock(&bdev_lock);
-+                      bdev = bdfind(dev, head);
-+                      if (!bdev) {
-+                              list_add(&new_bdev->bd_hash, head);
-+                              spin_unlock(&bdev_lock);
-+                              return new_bdev;
-+                      }
-+                      spin_unlock(&bdev_lock);
-+                      iput(new_bdev->bd_inode);
-+              }
-+              destroy_bdev(new_bdev);
-+      }
-+      return bdev;
-+}
-+
-+static inline void __bd_forget(struct inode *inode)
-+{
-+      list_del_init(&inode->i_devices);
-+      inode->i_bdev = NULL;
-+      inode->i_mapping = &inode->i_data;
-+}
-+
-+void bdput(struct block_device *bdev)
-+{
-+      if (atomic_dec_and_lock(&bdev->bd_count, &bdev_lock)) {
-+              struct list_head *p;
-+              if (bdev->bd_openers)
-+                      BUG();
-+              list_del(&bdev->bd_hash);
-+              while ( (p = bdev->bd_inodes.next) != &bdev->bd_inodes ) {
-+                      __bd_forget(list_entry(p, struct inode, i_devices));
-+              }
-+              spin_unlock(&bdev_lock);
-+              iput(bdev->bd_inode);
-+              destroy_bdev(bdev);
-+      }
-+}
-+ 
-+int bd_acquire(struct inode *inode)
-+{
-+      struct block_device *bdev;
-+      spin_lock(&bdev_lock);
-+      if (inode->i_bdev) {
-+              atomic_inc(&inode->i_bdev->bd_count);
-+              spin_unlock(&bdev_lock);
-+              return 0;
-+      }
-+      spin_unlock(&bdev_lock);
-+      bdev = bdget(kdev_t_to_nr(inode->i_rdev));
-+      if (!bdev)
-+              return -ENOMEM;
-+      spin_lock(&bdev_lock);
-+      if (!inode->i_bdev) {
-+              inode->i_bdev = bdev;
-+              inode->i_mapping = bdev->bd_inode->i_mapping;
-+              list_add(&inode->i_devices, &bdev->bd_inodes);
-+      } else if (inode->i_bdev != bdev)
-+              BUG();
-+      spin_unlock(&bdev_lock);
-+      return 0;
-+}
-+
-+/* Call when you free inode */
-+
-+void bd_forget(struct inode *inode)
-+{
-+      spin_lock(&bdev_lock);
-+      if (inode->i_bdev)
-+              __bd_forget(inode);
-+      spin_unlock(&bdev_lock);
-+}
-+
-+static struct {
-+      const char *name;
-+      struct block_device_operations *bdops;
-+} blkdevs[MAX_BLKDEV];
-+
-+int get_blkdev_list(char * p)
-+{
-+      int i;
-+      int len;
-+
-+      len = sprintf(p, "\nBlock devices:\n");
-+      for (i = 0; i < MAX_BLKDEV ; i++) {
-+              if (blkdevs[i].bdops) {
-+                      len += sprintf(p+len, "%3d %s\n", i, blkdevs[i].name);
-+              }
-+      }
-+      return len;
-+}
-+
-+/*
-+      Return the function table of a device.
-+      Load the driver if needed.
-+*/
-+const struct block_device_operations * get_blkfops(unsigned int major)
-+{
-+      const struct block_device_operations *ret = NULL;
-+
-+      /* major 0 is used for non-device mounts */
-+      if (major && major < MAX_BLKDEV) {
-+#ifdef CONFIG_KMOD
-+              if (!blkdevs[major].bdops) {
-+                      char name[20];
-+                      sprintf(name, "block-major-%d", major);
-+                      request_module(name);
-+              }
-+#endif
-+              ret = blkdevs[major].bdops;
-+      }
-+      return ret;
-+}
-+
-+int register_blkdev(unsigned int major, const char * name, struct block_device_operations *bdops)
-+{
-+      if (major == 0) {
-+              for (major = MAX_BLKDEV-1; major > 0; major--) {
-+                      if (blkdevs[major].bdops == NULL) {
-+                              blkdevs[major].name = name;
-+                              blkdevs[major].bdops = bdops;
-+                              return major;
-+                      }
-+              }
-+              return -EBUSY;
-+      }
-+      if (major >= MAX_BLKDEV)
-+              return -EINVAL;
-+      if (blkdevs[major].bdops && blkdevs[major].bdops != bdops)
-+              return -EBUSY;
-+      blkdevs[major].name = name;
-+      blkdevs[major].bdops = bdops;
-+      return 0;
-+}
-+
-+int unregister_blkdev(unsigned int major, const char * name)
-+{
-+      if (major >= MAX_BLKDEV)
-+              return -EINVAL;
-+      if (!blkdevs[major].bdops)
-+              return -EINVAL;
-+      if (strcmp(blkdevs[major].name, name))
-+              return -EINVAL;
-+      blkdevs[major].name = NULL;
-+      blkdevs[major].bdops = NULL;
-+      return 0;
-+}
-+
-+/*
-+ * This routine checks whether a removable media has been changed,
-+ * and invalidates all buffer-cache-entries in that case. This
-+ * is a relatively slow routine, so we have to try to minimize using
-+ * it. Thus it is called only upon a 'mount' or 'open'. This
-+ * is the best way of combining speed and utility, I think.
-+ * People changing diskettes in the middle of an operation deserve
-+ * to lose :-)
-+ */
-+int check_disk_change(kdev_t dev)
-+{
-+      int i;
-+      const struct block_device_operations * bdops = NULL;
-+
-+      i = MAJOR(dev);
-+      if (i < MAX_BLKDEV)
-+              bdops = blkdevs[i].bdops;
-+      if (bdops == NULL) {
-+              devfs_handle_t de;
-+
-+              de = devfs_find_handle (NULL, NULL, i, MINOR (dev),
-+                                      DEVFS_SPECIAL_BLK, 0);
-+              if (de) {
-+                      bdops = devfs_get_ops (de);
-+                      devfs_put_ops (de); /* We're running in owner module */
-+              }
-+      }
-+      if (bdops == NULL)
-+              return 0;
-+      if (bdops->check_media_change == NULL)
-+              return 0;
-+      if (!bdops->check_media_change(dev))
-+              return 0;
-+
-+      if (invalidate_device(dev, 0))
-+              printk("VFS: busy inodes on changed media.\n");
-+
-+      if (bdops->revalidate)
-+              bdops->revalidate(dev);
-+      return 1;
-+}
-+
-+int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)
-+{
-+      int res;
-+      mm_segment_t old_fs = get_fs();
-+
-+      if (!bdev->bd_op->ioctl)
-+              return -EINVAL;
-+      set_fs(KERNEL_DS);
-+      res = bdev->bd_op->ioctl(bdev->bd_inode, NULL, cmd, arg);
-+      set_fs(old_fs);
-+      return res;
-+}
-+
-+static int do_open(struct block_device *bdev, struct inode *inode, struct file *file)
-+{
-+      int ret = -ENXIO;
-+      kdev_t dev = to_kdev_t(bdev->bd_dev);
-+
-+      down(&bdev->bd_sem);
-+      lock_kernel();
-+      if (!bdev->bd_op)
-+              bdev->bd_op = get_blkfops(MAJOR(dev));
-+      if (bdev->bd_op) {
-+              ret = 0;
-+              if (bdev->bd_op->owner)
-+                      __MOD_INC_USE_COUNT(bdev->bd_op->owner);
-+              if (bdev->bd_op->open)
-+                      ret = bdev->bd_op->open(inode, file);
-+              if (!ret) {
-+                      bdev->bd_openers++;
-+                      bdev->bd_inode->i_size = blkdev_size(dev);
-+                      bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev));
-+              } else {
-+                      if (bdev->bd_op->owner)
-+                              __MOD_DEC_USE_COUNT(bdev->bd_op->owner);
-+                      if (!bdev->bd_openers)
-+                              bdev->bd_op = NULL;
-+              }
-+      }
-+      unlock_kernel();
-+      up(&bdev->bd_sem);
-+      if (ret)
-+              bdput(bdev);
-+      return ret;
-+}
-+
-+int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind)
-+{
-+      /*
-+       * This crockload is due to bad choice of ->open() type.
-+       * It will go away.
-+       * For now, block device ->open() routine must _not_
-+       * examine anything in 'inode' argument except ->i_rdev.
-+       */
-+      struct file fake_file = {};
-+      struct dentry fake_dentry = {};
-+      fake_file.f_mode = mode;
-+      fake_file.f_flags = flags;
-+      fake_file.f_dentry = &fake_dentry;
-+      fake_dentry.d_inode = bdev->bd_inode;
-+
-+      return do_open(bdev, bdev->bd_inode, &fake_file);
-+}
-+
-+int blkdev_open(struct inode * inode, struct file * filp)
-+{
-+      struct block_device *bdev;
-+
-+      /*
-+       * Preserve backwards compatibility and allow large file access
-+       * even if userspace doesn't ask for it explicitly. Some mkfs
-+       * binary needs it. We might want to drop this workaround
-+       * during an unstable branch.
-+       */
-+      filp->f_flags |= O_LARGEFILE;
-+
-+      bd_acquire(inode);
-+      bdev = inode->i_bdev;
-+
-+      return do_open(bdev, inode, filp);
-+}     
-+
-+int blkdev_put(struct block_device *bdev, int kind)
-+{
-+      int ret = 0;
-+      kdev_t rdev = to_kdev_t(bdev->bd_dev); /* this should become bdev */
-+      struct inode *bd_inode = bdev->bd_inode;
-+
-+      down(&bdev->bd_sem);
-+      lock_kernel();
-+      if (kind == BDEV_FILE && bdev->bd_openers == 1)
-+              __block_fsync(bd_inode);
-+      else if (kind == BDEV_FS)
-+              fsync_no_super(rdev);
-+      if (!--bdev->bd_openers)
-+              kill_bdev(bdev);
-+      if (bdev->bd_op->release)
-+              ret = bdev->bd_op->release(bd_inode, NULL);
-+      if (bdev->bd_op->owner)
-+              __MOD_DEC_USE_COUNT(bdev->bd_op->owner);
-+      if (!bdev->bd_openers)
-+              bdev->bd_op = NULL;
-+      unlock_kernel();
-+      up(&bdev->bd_sem);
-+      bdput(bdev);
-+      return ret;
-+}
-+
-+int blkdev_close(struct inode * inode, struct file * filp)
-+{
-+      return blkdev_put(inode->i_bdev, BDEV_FILE);
-+}
-+
-+static int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
-+                      unsigned long arg)
-+{
-+      if (inode->i_bdev->bd_op->ioctl)
-+              return inode->i_bdev->bd_op->ioctl(inode, file, cmd, arg);
-+      return -EINVAL;
-+}
-+
-+struct address_space_operations def_blk_aops = {
-+      readpage: blkdev_readpage,
-+      writepage: blkdev_writepage,
-+      sync_page: block_sync_page,
-+      prepare_write: blkdev_prepare_write,
-+      commit_write: blkdev_commit_write,
-+      direct_IO: blkdev_direct_IO,
-+};
-+
-+struct file_operations def_blk_fops = {
-+      open:           blkdev_open,
-+      release:        blkdev_close,
-+      llseek:         block_llseek,
-+      read:           generic_file_read,
-+      write:          generic_file_write,
-+      mmap:           generic_file_mmap,
-+      fsync:          block_fsync,
-+      ioctl:          blkdev_ioctl,
-+};
-+
-+const char * bdevname(kdev_t dev)
-+{
-+      static char buffer[32];
-+      const char * name = blkdevs[MAJOR(dev)].name;
-+
-+      if (!name)
-+              name = "unknown-block";
-+
-+      sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
-+      return buffer;
-+}
---- /dev/null  2003-01-30 18:24:37.000000000 +0800
-+++ linux-2.4.19-hp3_pnnl1-root/fs/devfs/base.c        2002-08-03 08:39:45.000000000 +0800
-@@ -0,0 +1,3544 @@
-+/*  devfs (Device FileSystem) driver.
-+
-+    Copyright (C) 1998-2002  Richard Gooch
-+
-+    This library is free software; you can redistribute it and/or
-+    modify it under the terms of the GNU Library General Public
-+    License as published by the Free Software Foundation; either
-+    version 2 of the License, or (at your option) any later version.
-+
-+    This library is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+    Library General Public License for more details.
-+
-+    You should have received a copy of the GNU Library General Public
-+    License along with this library; if not, write to the Free
-+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+
-+    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
-+    The postal address is:
-+      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
-+
-+    ChangeLog
-+
-+    19980110   Richard Gooch <rgooch@atnf.csiro.au>
-+               Original version.
-+  v0.1
-+    19980111   Richard Gooch <rgooch@atnf.csiro.au>
-+               Created per-fs inode table rather than using inode->u.generic_ip
-+  v0.2
-+    19980111   Richard Gooch <rgooch@atnf.csiro.au>
-+               Created .epoch inode which has a ctime of 0.
-+             Fixed loss of named pipes when dentries lost.
-+             Fixed loss of inode data when devfs_register() follows mknod().
-+  v0.3
-+    19980111   Richard Gooch <rgooch@atnf.csiro.au>
-+               Fix for when compiling with CONFIG_KERNELD.
-+    19980112   Richard Gooch <rgooch@atnf.csiro.au>
-+               Fix for readdir() which sometimes didn't show entries.
-+             Added <<tolerant>> option to <devfs_register>.
-+  v0.4
-+    19980113   Richard Gooch <rgooch@atnf.csiro.au>
-+               Created <devfs_fill_file> function.
-+  v0.5
-+    19980115   Richard Gooch <rgooch@atnf.csiro.au>
-+               Added subdirectory support. Major restructuring.
-+    19980116   Richard Gooch <rgooch@atnf.csiro.au>
-+               Fixed <find_by_dev> to not search major=0,minor=0.
-+             Added symlink support.
-+  v0.6
-+    19980120   Richard Gooch <rgooch@atnf.csiro.au>
-+               Created <devfs_mk_dir> function and support directory unregister
-+    19980120   Richard Gooch <rgooch@atnf.csiro.au>
-+               Auto-ownership uses real uid/gid rather than effective uid/gid.
-+  v0.7
-+    19980121   Richard Gooch <rgooch@atnf.csiro.au>
-+               Supported creation of sockets.
-+  v0.8
-+    19980122   Richard Gooch <rgooch@atnf.csiro.au>
-+               Added DEVFS_FL_HIDE_UNREG flag.
-+             Interface change to <devfs_mk_symlink>.
-+               Created <devfs_symlink> to support symlink(2).
-+  v0.9
-+    19980123   Richard Gooch <rgooch@atnf.csiro.au>
-+               Added check to <devfs_fill_file> to check inode is in devfs.
-+             Added optional traversal of symlinks.
-+  v0.10
-+    19980124   Richard Gooch <rgooch@atnf.csiro.au>
-+               Created <devfs_get_flags> and <devfs_set_flags>.
-+  v0.11
-+    19980125   C. Scott Ananian <cananian@alumni.princeton.edu>
-+               Created <devfs_find_handle>.
-+    19980125   Richard Gooch <rgooch@atnf.csiro.au>
-+               Allow removal of symlinks.
-+  v0.12
-+    19980125   Richard Gooch <rgooch@atnf.csiro.au>
-+               Created <devfs_set_symlink_destination>.
-+    19980126   Richard Gooch <rgooch@atnf.csiro.au>
-+               Moved DEVFS_SUPER_MAGIC into header file.
-+             Added DEVFS_FL_HIDE flag.
-+             Created <devfs_get_maj_min>.
-+             Created <devfs_get_handle_from_inode>.
-+             Fixed minor bug in <find_by_dev>.
-+    19980127   Richard Gooch <rgooch@atnf.csiro.au>
-+             Changed interface to <find_by_dev>, <find_entry>,
-+             <devfs_unregister>, <devfs_fill_file> and <devfs_find_handle>.
-+             Fixed inode times when symlink created with symlink(2).
-+  v0.13
-+    19980129   C. Scott Ananian <cananian@alumni.princeton.edu>
-+               Exported <devfs_set_symlink_destination>, <devfs_get_maj_min>
-+             and <devfs_get_handle_from_inode>.
-+    19980129   Richard Gooch <rgooch@atnf.csiro.au>
-+             Created <devfs_unlink> to support unlink(2).
-+  v0.14
-+    19980129   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed kerneld support for entries in devfs subdirectories.
-+    19980130   Richard Gooch <rgooch@atnf.csiro.au>
-+             Bugfixes in <call_kerneld>.
-+  v0.15
-+    19980207   Richard Gooch <rgooch@atnf.csiro.au>
-+             Call kerneld when looking up unregistered entries.
-+  v0.16
-+    19980326   Richard Gooch <rgooch@atnf.csiro.au>
-+             Modified interface to <devfs_find_handle> for symlink traversal.
-+  v0.17
-+    19980331   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed persistence bug with device numbers for manually created
-+             device files.
-+             Fixed problem with recreating symlinks with different content.
-+  v0.18
-+    19980401   Richard Gooch <rgooch@atnf.csiro.au>
-+             Changed to CONFIG_KMOD.
-+             Hide entries which are manually unlinked.
-+             Always invalidate devfs dentry cache when registering entries.
-+             Created <devfs_rmdir> to support rmdir(2).
-+             Ensure directories created by <devfs_mk_dir> are visible.
-+  v0.19
-+    19980402   Richard Gooch <rgooch@atnf.csiro.au>
-+             Invalidate devfs dentry cache when making directories.
-+             Invalidate devfs dentry cache when removing entries.
-+             Fixed persistence bug with fifos.
-+  v0.20
-+    19980421   Richard Gooch <rgooch@atnf.csiro.au>
-+             Print process command when debugging kerneld/kmod.
-+             Added debugging for register/unregister/change operations.
-+    19980422   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added "devfs=" boot options.
-+  v0.21
-+    19980426   Richard Gooch <rgooch@atnf.csiro.au>
-+             No longer lock/unlock superblock in <devfs_put_super>.
-+             Drop negative dentries when they are released.
-+             Manage dcache more efficiently.
-+  v0.22
-+    19980427   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added DEVFS_FL_AUTO_DEVNUM flag.
-+  v0.23
-+    19980430   Richard Gooch <rgooch@atnf.csiro.au>
-+             No longer set unnecessary methods.
-+  v0.24
-+    19980504   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added PID display to <call_kerneld> debugging message.
-+             Added "after" debugging message to <call_kerneld>.
-+    19980519   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added "diread" and "diwrite" boot options.
-+    19980520   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed persistence problem with permissions.
-+  v0.25
-+    19980602   Richard Gooch <rgooch@atnf.csiro.au>
-+             Support legacy device nodes.
-+             Fixed bug where recreated inodes were hidden.
-+  v0.26
-+    19980602   Richard Gooch <rgooch@atnf.csiro.au>
-+             Improved debugging in <get_vfs_inode>.
-+    19980607   Richard Gooch <rgooch@atnf.csiro.au>
-+             No longer free old dentries in <devfs_mk_dir>.
-+             Free all dentries for a given entry when deleting inodes.
-+  v0.27
-+    19980627   Richard Gooch <rgooch@atnf.csiro.au>
-+             Limit auto-device numbering to majors 128 to 239.
-+  v0.28
-+    19980629   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed inode times persistence problem.
-+  v0.29
-+    19980704   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed spelling in <devfs_readlink> debug.
-+             Fixed bug in <devfs_setup> parsing "dilookup".
-+  v0.30
-+    19980705   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed devfs inode leak when manually recreating inodes.
-+             Fixed permission persistence problem when recreating inodes.
-+  v0.31
-+    19980727   Richard Gooch <rgooch@atnf.csiro.au>
-+             Removed harmless "unused variable" compiler warning.
-+             Fixed modes for manually recreated device nodes.
-+  v0.32
-+    19980728   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added NULL devfs inode warning in <devfs_read_inode>.
-+             Force all inode nlink values to 1.
-+  v0.33
-+    19980730   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added "dimknod" boot option.
-+             Set inode nlink to 0 when freeing dentries.
-+             Fixed modes for manually recreated symlinks.
-+  v0.34
-+    19980802   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed bugs in recreated directories and symlinks.
-+  v0.35
-+    19980806   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed bugs in recreated device nodes.
-+    19980807   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed bug in currently unused <devfs_get_handle_from_inode>.
-+             Defined new <devfs_handle_t> type.
-+             Improved debugging when getting entries.
-+             Fixed bug where directories could be emptied.
-+  v0.36
-+    19980809   Richard Gooch <rgooch@atnf.csiro.au>
-+             Replaced dummy .epoch inode with .devfsd character device.
-+    19980810   Richard Gooch <rgooch@atnf.csiro.au>
-+             Implemented devfsd protocol revision 0.
-+  v0.37
-+    19980819   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added soothing message to warning in <devfs_d_iput>.
-+  v0.38
-+    19980829   Richard Gooch <rgooch@atnf.csiro.au>
-+             Use GCC extensions for structure initialisations.
-+             Implemented async open notification.
-+             Incremented devfsd protocol revision to 1.
-+  v0.39
-+    19980908   Richard Gooch <rgooch@atnf.csiro.au>
-+             Moved async open notification to end of <devfs_open>.
-+  v0.40
-+    19980910   Richard Gooch <rgooch@atnf.csiro.au>
-+             Prepended "/dev/" to module load request.
-+             Renamed <call_kerneld> to <call_kmod>.
-+  v0.41
-+    19980910   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed typo "AYSNC" -> "ASYNC".
-+  v0.42
-+    19980910   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added open flag for files.
-+  v0.43
-+    19980927   Richard Gooch <rgooch@atnf.csiro.au>
-+             Set i_blocks=0 and i_blksize=1024 in <devfs_read_inode>.
-+  v0.44
-+    19981005   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added test for empty <<name>> in <devfs_find_handle>.
-+             Renamed <generate_path> to <devfs_generate_path> and published.
-+  v0.45
-+    19981006   Richard Gooch <rgooch@atnf.csiro.au>
-+             Created <devfs_get_fops>.
-+  v0.46
-+    19981007   Richard Gooch <rgooch@atnf.csiro.au>
-+             Limit auto-device numbering to majors 144 to 239.
-+  v0.47
-+    19981010   Richard Gooch <rgooch@atnf.csiro.au>
-+             Updated <devfs_follow_link> for VFS change in 2.1.125.
-+  v0.48
-+    19981022   Richard Gooch <rgooch@atnf.csiro.au>
-+             Created DEVFS_ FL_COMPAT flag.
-+  v0.49
-+    19981023   Richard Gooch <rgooch@atnf.csiro.au>
-+             Created "nocompat" boot option.
-+  v0.50
-+    19981025   Richard Gooch <rgooch@atnf.csiro.au>
-+             Replaced "mount" boot option with "nomount".
-+  v0.51
-+    19981110   Richard Gooch <rgooch@atnf.csiro.au>
-+             Created "only" boot option.
-+  v0.52
-+    19981112   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added DEVFS_FL_REMOVABLE flag.
-+  v0.53
-+    19981114   Richard Gooch <rgooch@atnf.csiro.au>
-+             Only call <scan_dir_for_removable> on first call to
-+             <devfs_readdir>.
-+  v0.54
-+    19981205   Richard Gooch <rgooch@atnf.csiro.au>
-+             Updated <devfs_rmdir> for VFS change in 2.1.131.
-+  v0.55
-+    19981218   Richard Gooch <rgooch@atnf.csiro.au>
-+             Created <devfs_mk_compat>.
-+    19981220   Richard Gooch <rgooch@atnf.csiro.au>
-+             Check for partitions on removable media in <devfs_lookup>.
-+  v0.56
-+    19990118   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added support for registering regular files.
-+             Created <devfs_set_file_size>.
-+             Update devfs inodes from entries if not changed through FS.
-+  v0.57
-+    19990124   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed <devfs_fill_file> to only initialise temporary inodes.
-+             Trap for NULL fops in <devfs_register>.
-+             Return -ENODEV in <devfs_fill_file> for non-driver inodes.
-+  v0.58
-+    19990126   Richard Gooch <rgooch@atnf.csiro.au>
-+             Switched from PATH_MAX to DEVFS_PATHLEN.
-+  v0.59
-+    19990127   Richard Gooch <rgooch@atnf.csiro.au>
-+             Created "nottycompat" boot option.
-+  v0.60
-+    19990318   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed <devfsd_read> to not overrun event buffer.
-+  v0.61
-+    19990329   Richard Gooch <rgooch@atnf.csiro.au>
-+             Created <devfs_auto_unregister>.
-+  v0.62
-+    19990330   Richard Gooch <rgooch@atnf.csiro.au>
-+             Don't return unregistred entries in <devfs_find_handle>.
-+             Panic in <devfs_unregister> if entry unregistered.
-+    19990401   Richard Gooch <rgooch@atnf.csiro.au>
-+             Don't panic in <devfs_auto_unregister> for duplicates.
-+  v0.63
-+    19990402   Richard Gooch <rgooch@atnf.csiro.au>
-+             Don't unregister already unregistered entries in <unregister>.
-+  v0.64
-+    19990510   Richard Gooch <rgooch@atnf.csiro.au>
-+             Disable warning messages when unable to read partition table for
-+             removable media.
-+  v0.65
-+    19990512   Richard Gooch <rgooch@atnf.csiro.au>
-+             Updated <devfs_lookup> for VFS change in 2.3.1-pre1.
-+             Created "oops-on-panic" boot option.
-+             Improved debugging in <devfs_register> and <devfs_unregister>.
-+  v0.66
-+    19990519   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added documentation for some functions.
-+    19990525   Richard Gooch <rgooch@atnf.csiro.au>
-+             Removed "oops-on-panic" boot option: now always Oops.
-+  v0.67
-+    19990531   Richard Gooch <rgooch@atnf.csiro.au>
-+             Improved debugging in <devfs_register>.
-+  v0.68
-+    19990604   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added "diunlink" and "nokmod" boot options.
-+             Removed superfluous warning message in <devfs_d_iput>.
-+  v0.69
-+    19990611   Richard Gooch <rgooch@atnf.csiro.au>
-+             Took account of change to <d_alloc_root>.
-+  v0.70
-+    19990614   Richard Gooch <rgooch@atnf.csiro.au>
-+             Created separate event queue for each mounted devfs.
-+             Removed <devfs_invalidate_dcache>.
-+             Created new ioctl()s.
-+             Incremented devfsd protocol revision to 3.
-+             Fixed bug when re-creating directories: contents were lost.
-+             Block access to inodes until devfsd updates permissions.
-+    19990615   Richard Gooch <rgooch@atnf.csiro.au>
-+             Support 2.2.x kernels.
-+  v0.71
-+    19990623   Richard Gooch <rgooch@atnf.csiro.au>
-+             Switched to sending process uid/gid to devfsd.
-+             Renamed <call_kmod> to <try_modload>.
-+             Added DEVFSD_NOTIFY_LOOKUP event.
-+    19990624   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added DEVFSD_NOTIFY_CHANGE event.
-+             Incremented devfsd protocol revision to 4.
-+  v0.72
-+    19990713   Richard Gooch <rgooch@atnf.csiro.au>
-+             Return EISDIR rather than EINVAL for read(2) on directories.
-+  v0.73
-+    19990809   Richard Gooch <rgooch@atnf.csiro.au>
-+             Changed <devfs_setup> to new __init scheme.
-+  v0.74
-+    19990901   Richard Gooch <rgooch@atnf.csiro.au>
-+             Changed remaining function declarations to new __init scheme.
-+  v0.75
-+    19991013   Richard Gooch <rgooch@atnf.csiro.au>
-+             Created <devfs_get_info>, <devfs_set_info>,
-+             <devfs_get_first_child> and <devfs_get_next_sibling>.
-+             Added <<dir>> parameter to <devfs_register>, <devfs_mk_compat>,
-+             <devfs_mk_dir> and <devfs_find_handle>.
-+             Work sponsored by SGI.
-+  v0.76
-+    19991017   Richard Gooch <rgooch@atnf.csiro.au>
-+             Allow multiple unregistrations.
-+             Work sponsored by SGI.
-+  v0.77
-+    19991026   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added major and minor number to devfsd protocol.
-+             Incremented devfsd protocol revision to 5.
-+             Work sponsored by SGI.
-+  v0.78
-+    19991030   Richard Gooch <rgooch@atnf.csiro.au>
-+             Support info pointer for all devfs entry types.
-+             Added <<info>> parameter to <devfs_mk_dir> and
-+             <devfs_mk_symlink>.
-+             Work sponsored by SGI.
-+  v0.79
-+    19991031   Richard Gooch <rgooch@atnf.csiro.au>
-+             Support "../" when searching devfs namespace.
-+             Work sponsored by SGI.
-+  v0.80
-+    19991101   Richard Gooch <rgooch@atnf.csiro.au>
-+             Created <devfs_get_unregister_slave>.
-+             Work sponsored by SGI.
-+  v0.81
-+    19991103   Richard Gooch <rgooch@atnf.csiro.au>
-+             Exported <devfs_get_parent>.
-+             Work sponsored by SGI.
-+  v0.82
-+    19991104   Richard Gooch <rgooch@atnf.csiro.au>
-+               Removed unused <devfs_set_symlink_destination>.
-+    19991105   Richard Gooch <rgooch@atnf.csiro.au>
-+               Do not hide entries from devfsd or children.
-+             Removed DEVFS_ FL_TTY_COMPAT flag.
-+             Removed "nottycompat" boot option.
-+             Removed <devfs_mk_compat>.
-+             Work sponsored by SGI.
-+  v0.83
-+    19991107   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added DEVFS_FL_WAIT flag.
-+             Work sponsored by SGI.
-+  v0.84
-+    19991107   Richard Gooch <rgooch@atnf.csiro.au>
-+             Support new "disc" naming scheme in <get_removable_partition>.
-+             Allow NULL fops in <devfs_register>.
-+             Work sponsored by SGI.
-+  v0.85
-+    19991110   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fall back to major table if NULL fops given to <devfs_register>.
-+             Work sponsored by SGI.
-+  v0.86
-+    19991204   Richard Gooch <rgooch@atnf.csiro.au>
-+             Support fifos when unregistering.
-+             Work sponsored by SGI.
-+  v0.87
-+    19991209   Richard Gooch <rgooch@atnf.csiro.au>
-+             Removed obsolete DEVFS_ FL_COMPAT and DEVFS_ FL_TOLERANT flags.
-+             Work sponsored by SGI.
-+  v0.88
-+    19991214   Richard Gooch <rgooch@atnf.csiro.au>
-+             Removed kmod support.
-+             Work sponsored by SGI.
-+  v0.89
-+    19991216   Richard Gooch <rgooch@atnf.csiro.au>
-+             Improved debugging in <get_vfs_inode>.
-+             Ensure dentries created by devfsd will be cleaned up.
-+             Work sponsored by SGI.
-+  v0.90
-+    19991223   Richard Gooch <rgooch@atnf.csiro.au>
-+             Created <devfs_get_name>.
-+             Work sponsored by SGI.
-+  v0.91
-+    20000203   Richard Gooch <rgooch@atnf.csiro.au>
-+             Ported to kernel 2.3.42.
-+             Removed <devfs_fill_file>.
-+             Work sponsored by SGI.
-+  v0.92
-+    20000306   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added DEVFS_ FL_NO_PERSISTENCE flag.
-+             Removed unnecessary call to <update_devfs_inode_from_entry> in
-+             <devfs_readdir>.
-+             Work sponsored by SGI.
-+  v0.93
-+    20000413   Richard Gooch <rgooch@atnf.csiro.au>
-+             Set inode->i_size to correct size for symlinks.
-+    20000414   Richard Gooch <rgooch@atnf.csiro.au>
-+             Only give lookup() method to directories to comply with new VFS
-+             assumptions.
-+             Work sponsored by SGI.
-+    20000415   Richard Gooch <rgooch@atnf.csiro.au>
-+             Remove unnecessary tests in symlink methods.
-+             Don't kill existing block ops in <devfs_read_inode>.
-+             Work sponsored by SGI.
-+  v0.94
-+    20000424   Richard Gooch <rgooch@atnf.csiro.au>
-+             Don't create missing directories in <devfs_find_handle>.
-+             Work sponsored by SGI.
-+  v0.95
-+    20000430   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added CONFIG_DEVFS_MOUNT.
-+             Work sponsored by SGI.
-+  v0.96
-+    20000608   Richard Gooch <rgooch@atnf.csiro.au>
-+             Disabled multi-mount capability (use VFS bindings instead).
-+             Work sponsored by SGI.
-+  v0.97
-+    20000610   Richard Gooch <rgooch@atnf.csiro.au>
-+             Switched to FS_SINGLE to disable multi-mounts.
-+    20000612   Richard Gooch <rgooch@atnf.csiro.au>
-+             Removed module support.
-+             Removed multi-mount code.
-+             Removed compatibility macros: VFS has changed too much.
-+             Work sponsored by SGI.
-+  v0.98
-+    20000614   Richard Gooch <rgooch@atnf.csiro.au>
-+             Merged devfs inode into devfs entry.
-+             Work sponsored by SGI.
-+  v0.99
-+    20000619   Richard Gooch <rgooch@atnf.csiro.au>
-+             Removed dead code in <devfs_register> which used to call
-+             <free_dentries>.
-+             Work sponsored by SGI.
-+  v0.100
-+    20000621   Richard Gooch <rgooch@atnf.csiro.au>
-+             Changed interface to <devfs_register>.
-+             Work sponsored by SGI.
-+  v0.101
-+    20000622   Richard Gooch <rgooch@atnf.csiro.au>
-+             Simplified interface to <devfs_mk_symlink> and <devfs_mk_dir>.
-+             Simplified interface to <devfs_find_handle>.
-+             Work sponsored by SGI.
-+  v0.102
-+    20010519   Richard Gooch <rgooch@atnf.csiro.au>
-+             Ensure <devfs_generate_path> terminates string for root entry.
-+             Exported <devfs_get_name> to modules.
-+    20010520   Richard Gooch <rgooch@atnf.csiro.au>
-+             Make <devfs_mk_symlink> send events to devfsd.
-+             Cleaned up option processing in <devfs_setup>.
-+    20010521   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed bugs in handling symlinks: could leak or cause Oops.
-+    20010522   Richard Gooch <rgooch@atnf.csiro.au>
-+             Cleaned up directory handling by separating fops.
-+  v0.103
-+    20010601   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed handling of inverted options in <devfs_setup>.
-+  v0.104
-+    20010604   Richard Gooch <rgooch@atnf.csiro.au>
-+             Adjusted <try_modload> to account for <devfs_generate_path> fix.
-+  v0.105
-+    20010617   Richard Gooch <rgooch@atnf.csiro.au>
-+             Answered question posed by Al Viro and removed his comments.
-+             Moved setting of registered flag after other fields are changed.
-+             Fixed race between <devfsd_close> and <devfsd_notify_one>.
-+             Global VFS changes added bogus BKL to <devfsd_close>: removed.
-+             Widened locking in <devfs_readlink> and <devfs_follow_link>.
-+             Replaced <devfsd_read> stack usage with <devfsd_ioctl> kmalloc.
-+             Simplified locking in <devfsd_ioctl> and fixed memory leak.
-+  v0.106
-+    20010709   Richard Gooch <rgooch@atnf.csiro.au>
-+             Removed broken devnum allocation and use <devfs_alloc_devnum>.
-+             Fixed old devnum leak by calling new <devfs_dealloc_devnum>.
-+  v0.107
-+    20010712   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed bug in <devfs_setup> which could hang boot process.
-+  v0.108
-+    20010730   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added DEVFSD_NOTIFY_DELETE event.
-+    20010801   Richard Gooch <rgooch@atnf.csiro.au>
-+             Removed #include <asm/segment.h>.
-+  v0.109
-+    20010807   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed inode table races by removing it and using
-+             inode->u.generic_ip instead.
-+             Moved <devfs_read_inode> into <get_vfs_inode>.
-+             Moved <devfs_write_inode> into <devfs_notify_change>.
-+  v0.110
-+    20010808   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed race in <devfs_do_symlink> for uni-processor.
-+  v0.111
-+    20010818   Richard Gooch <rgooch@atnf.csiro.au>
-+             Removed remnant of multi-mount support in <devfs_mknod>.
-+               Removed unused DEVFS_FL_SHOW_UNREG flag.
-+  v0.112
-+    20010820   Richard Gooch <rgooch@atnf.csiro.au>
-+             Removed nlink field from struct devfs_inode.
-+  v0.113
-+    20010823   Richard Gooch <rgooch@atnf.csiro.au>
-+             Replaced BKL with global rwsem to protect symlink data (quick
-+             and dirty hack).
-+  v0.114
-+    20010827   Richard Gooch <rgooch@atnf.csiro.au>
-+             Replaced global rwsem for symlink with per-link refcount.
-+  v0.115
-+    20010919   Richard Gooch <rgooch@atnf.csiro.au>
-+             Set inode->i_mapping->a_ops for block nodes in <get_vfs_inode>.
-+  v0.116
-+    20011008   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed overrun in <devfs_link> by removing function (not needed).
-+    20011009   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed buffer underrun in <try_modload>.
-+    20011029   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed race in <devfsd_ioctl> when setting event mask.
-+    20011114   Richard Gooch <rgooch@atnf.csiro.au>
-+             First release of new locking code.
-+  v1.0
-+    20011117   Richard Gooch <rgooch@atnf.csiro.au>
-+             Discard temporary buffer, now use "%s" for dentry names.
-+    20011118   Richard Gooch <rgooch@atnf.csiro.au>
-+             Don't generate path in <try_modload>: use fake entry instead.
-+             Use "existing" directory in <_devfs_make_parent_for_leaf>.
-+    20011122   Richard Gooch <rgooch@atnf.csiro.au>
-+             Use slab cache rather than fixed buffer for devfsd events.
-+  v1.1
-+    20011125   Richard Gooch <rgooch@atnf.csiro.au>
-+             Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir>.
-+    20011127   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed locking bug in <devfs_d_revalidate_wait> due to typo.
-+             Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from
-+             devfsd or children.
-+  v1.2
-+    20011202   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed bug in <devfsd_read>: was dereferencing freed pointer.
-+  v1.3
-+    20011203   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed bug in <devfsd_close>: was dereferencing freed pointer.
-+             Added process group check for devfsd privileges.
-+  v1.4
-+    20011204   Richard Gooch <rgooch@atnf.csiro.au>
-+             Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete>.
-+  v1.5
-+    20011211   Richard Gooch <rgooch@atnf.csiro.au>
-+             Return old entry in <devfs_mk_dir> for 2.4.x kernels.
-+    20011212   Richard Gooch <rgooch@atnf.csiro.au>
-+             Increment refcount on module in <check_disc_changed>.
-+    20011215   Richard Gooch <rgooch@atnf.csiro.au>
-+             Created <devfs_get_handle> and exported <devfs_put>.
-+             Increment refcount on module in <devfs_get_ops>.
-+             Created <devfs_put_ops>.
-+  v1.6
-+    20011216   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added poisoning to <devfs_put>.
-+             Improved debugging messages.
-+  v1.7
-+    20011221   Richard Gooch <rgooch@atnf.csiro.au>
-+             Corrected (made useful) debugging message in <unregister>.
-+             Moved <kmem_cache_create> in <mount_devfs_fs> to <init_devfs_fs>
-+    20011224   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added magic number to guard against scribbling drivers.
-+    20011226   Richard Gooch <rgooch@atnf.csiro.au>
-+             Only return old entry in <devfs_mk_dir> if a directory.
-+             Defined macros for error and debug messages.
-+  v1.8
-+    20020113   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed (rare, old) race in <devfs_lookup>.
-+  v1.9
-+    20020120   Richard Gooch <rgooch@atnf.csiro.au>
-+             Fixed deadlock bug in <devfs_d_revalidate_wait>.
-+             Tag VFS deletable in <devfs_mk_symlink> if handle ignored.
-+  v1.10
-+    20020129   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added KERN_* to remaining messages.
-+             Cleaned up declaration of <stat_read>.
-+  v1.11
-+    20020219   Richard Gooch <rgooch@atnf.csiro.au>
-+             Changed <devfs_rmdir> to allow later additions if not yet empty.
-+  v1.12
-+    20020514   Richard Gooch <rgooch@atnf.csiro.au>
-+             Added BKL to <devfs_open> because drivers still need it.
-+             Protected <scan_dir_for_removable> and <get_removable_partition>
-+             from changing directory contents.
-+  v1.12a
-+*/
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/sched.h>
-+#include <linux/tty.h>
-+#include <linux/timer.h>
-+#include <linux/config.h>
-+#include <linux/kernel.h>
-+#include <linux/wait.h>
-+#include <linux/string.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/delay.h>
-+#include <linux/ctype.h>
-+#include <linux/mm.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/devfs_fs.h>
-+#include <linux/devfs_fs_kernel.h>
-+#include <linux/smp_lock.h>
-+#include <linux/smp.h>
-+#include <linux/version.h>
-+#include <linux/rwsem.h>
-+
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+#include <asm/processor.h>
-+#include <asm/system.h>
-+#include <asm/pgtable.h>
-+#include <asm/bitops.h>
-+#include <asm/atomic.h>
-+
-+#define DEVFS_VERSION            "1.12a (20020514)"
-+
-+#define DEVFS_NAME "devfs"
-+
-+#define FIRST_INODE 1
-+
-+#define STRING_LENGTH 256
-+#define FAKE_BLOCK_SIZE 1024
-+#define POISON_PTR ( *(void **) poison_array )
-+#define MAGIC_VALUE 0x327db823
-+
-+#ifndef TRUE
-+#  define TRUE 1
-+#  define FALSE 0
-+#endif
-+
-+#define MODE_DIR (S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO)
-+
-+#define IS_HIDDEN(de) ( (de)->hide && !is_devfsd_or_child(fs_info) )
-+
-+#define DEBUG_NONE         0x0000000
-+#define DEBUG_MODULE_LOAD  0x0000001
-+#define DEBUG_REGISTER     0x0000002
-+#define DEBUG_UNREGISTER   0x0000004
-+#define DEBUG_FREE         0x0000008
-+#define DEBUG_SET_FLAGS    0x0000010
-+#define DEBUG_S_READ       0x0000100        /*  Break  */
-+#define DEBUG_I_LOOKUP     0x0001000        /*  Break  */
-+#define DEBUG_I_CREATE     0x0002000
-+#define DEBUG_I_GET        0x0004000
-+#define DEBUG_I_CHANGE     0x0008000
-+#define DEBUG_I_UNLINK     0x0010000
-+#define DEBUG_I_RLINK      0x0020000
-+#define DEBUG_I_FLINK      0x0040000
-+#define DEBUG_I_MKNOD      0x0080000
-+#define DEBUG_F_READDIR    0x0100000        /*  Break  */
-+#define DEBUG_D_DELETE     0x1000000        /*  Break  */
-+#define DEBUG_D_RELEASE    0x2000000
-+#define DEBUG_D_IPUT       0x4000000
-+#define DEBUG_ALL          0xfffffff
-+#define DEBUG_DISABLED     DEBUG_NONE
-+
-+#define OPTION_NONE             0x00
-+#define OPTION_MOUNT            0x01
-+#define OPTION_ONLY             0x02
-+
-+#define PRINTK(format, args...) \
-+   {printk (KERN_ERR "%s" format, __FUNCTION__ , ## args);}
-+
-+#define OOPS(format, args...) \
-+   {printk (KERN_CRIT "%s" format, __FUNCTION__ , ## args); \
-+    printk ("Forcing Oops\n"); \
-+    BUG();}
-+
-+#ifdef CONFIG_DEVFS_DEBUG
-+#  define VERIFY_ENTRY(de) \
-+   {if ((de) && (de)->magic_number != MAGIC_VALUE) \
-+        OOPS ("(%p): bad magic value: %x\n", (de), (de)->magic_number);}
-+#  define WRITE_ENTRY_MAGIC(de,magic) (de)->magic_number = (magic)
-+#  define DPRINTK(flag, format, args...) \
-+   {if (devfs_debug & flag) \
-+      printk (KERN_INFO "%s" format, __FUNCTION__ , ## args);}
-+#else
-+#  define VERIFY_ENTRY(de)
-+#  define WRITE_ENTRY_MAGIC(de,magic)
-+#  define DPRINTK(flag, format, args...)
-+#endif
-+
-+
-+struct directory_type
-+{
-+    rwlock_t lock;                   /*  Lock for searching(R)/updating(W)   */
-+    struct devfs_entry *first;
-+    struct devfs_entry *last;
-+    unsigned short num_removable;    /*  Lock for writing but not reading    */
-+    unsigned char no_more_additions:1;
-+};
-+
-+struct file_type
-+{
-+    unsigned long size;
-+};
-+
-+struct device_type
-+{
-+    unsigned short major;
-+    unsigned short minor;
-+};
-+
-+struct fcb_type  /*  File, char, block type  */
-+{
-+    void *ops;
-+    union 
-+    {
-+      struct file_type file;
-+      struct device_type device;
-+    }
-+    u;
-+    unsigned char auto_owner:1;
-+    unsigned char aopen_notify:1;
-+    unsigned char removable:1;  /*  Belongs in device_type, but save space   */
-+    unsigned char open:1;       /*  Not entirely correct                     */
-+    unsigned char autogen:1;    /*  Belongs in device_type, but save space   */
-+};
-+
-+struct symlink_type
-+{
-+    unsigned int length;         /*  Not including the NULL-termimator       */
-+    char *linkname;              /*  This is NULL-terminated                 */
-+};
-+
-+struct devfs_inode     /*  This structure is for "persistent" inode storage  */
-+{
-+    struct dentry *dentry;
-+    time_t atime;
-+    time_t mtime;
-+    time_t ctime;
-+    unsigned int ino;            /*  Inode number as seen in the VFS         */
-+    uid_t uid;
-+    gid_t gid;
-+};
-+
-+struct devfs_entry
-+{
-+#ifdef CONFIG_DEVFS_DEBUG
-+    unsigned int magic_number;
-+#endif
-+    void *info;
-+    atomic_t refcount;           /*  When this drops to zero, it's unused    */
-+    union 
-+    {
-+      struct directory_type dir;
-+      struct fcb_type fcb;
-+      struct symlink_type symlink;
-+      const char *name;        /*  Only used for (mode == 0)               */
-+    }
-+    u;
-+    struct devfs_entry *prev;    /*  Previous entry in the parent directory  */
-+    struct devfs_entry *next;    /*  Next entry in the parent directory      */
-+    struct devfs_entry *parent;  /*  The parent directory                    */
-+    struct devfs_entry *slave;   /*  Another entry to unregister             */
-+    struct devfs_inode inode;
-+    umode_t mode;
-+    unsigned short namelen;      /*  I think 64k+ filenames are a way off... */
-+    unsigned char hide:1;
-+    unsigned char vfs_deletable:1;/*  Whether the VFS may delete the entry   */
-+    char name[1];                /*  This is just a dummy: the allocated array
-+                                   is bigger. This is NULL-terminated      */
-+};
-+
-+/*  The root of the device tree  */
-+static struct devfs_entry *root_entry;
-+
-+struct devfsd_buf_entry
-+{
-+    struct devfs_entry *de;      /*  The name is generated with this         */
-+    unsigned short type;         /*  The type of event                       */
-+    umode_t mode;
-+    uid_t uid;
-+    gid_t gid;
-+    struct devfsd_buf_entry *next;
-+};
-+
-+struct fs_info                  /*  This structure is for the mounted devfs  */
-+{
-+    struct super_block *sb;
-+    spinlock_t devfsd_buffer_lock;  /*  Lock when inserting/deleting events  */
-+    struct devfsd_buf_entry *devfsd_first_event;
-+    struct devfsd_buf_entry *devfsd_last_event;
-+    volatile int devfsd_sleeping;
-+    volatile struct task_struct *devfsd_task;
-+    volatile pid_t devfsd_pgrp;
-+    volatile struct file *devfsd_file;
-+    struct devfsd_notify_struct *devfsd_info;
-+    volatile unsigned long devfsd_event_mask;
-+    atomic_t devfsd_overrun_count;
-+    wait_queue_head_t devfsd_wait_queue;      /*  Wake devfsd on input       */
-+    wait_queue_head_t revalidate_wait_queue;  /*  Wake when devfsd sleeps    */
-+};
-+
-+static struct fs_info fs_info = {devfsd_buffer_lock: SPIN_LOCK_UNLOCKED};
-+static kmem_cache_t *devfsd_buf_cache;
-+#ifdef CONFIG_DEVFS_DEBUG
-+static unsigned int devfs_debug_init __initdata = DEBUG_NONE;
-+static unsigned int devfs_debug = DEBUG_NONE;
-+static spinlock_t stat_lock = SPIN_LOCK_UNLOCKED;
-+static unsigned int stat_num_entries;
-+static unsigned int stat_num_bytes;
-+#endif
-+static unsigned char poison_array[8] =
-+    {0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a};
-+
-+#ifdef CONFIG_DEVFS_MOUNT
-+static unsigned int boot_options = OPTION_MOUNT;
-+#else
-+static unsigned int boot_options = OPTION_NONE;
-+#endif
-+
-+/*  Forward function declarations  */
-+static devfs_handle_t _devfs_walk_path (struct devfs_entry *dir,
-+                                      const char *name, int namelen,
-+                                      int traverse_symlink);
-+static ssize_t devfsd_read (struct file *file, char *buf, size_t len,
-+                          loff_t *ppos);
-+static int devfsd_ioctl (struct inode *inode, struct file *file,
-+                       unsigned int cmd, unsigned long arg);
-+static int devfsd_close (struct inode *inode, struct file *file);
-+#ifdef CONFIG_DEVFS_DEBUG
-+static ssize_t stat_read (struct file *file, char *buf, size_t len,
-+                        loff_t *ppos);
-+static struct file_operations stat_fops =
-+{
-+    read:    stat_read,
-+};
-+#endif
-+
-+
-+/*  Devfs daemon file operations  */
-+static struct file_operations devfsd_fops =
-+{
-+    read:    devfsd_read,
-+    ioctl:   devfsd_ioctl,
-+    release: devfsd_close,
-+};
-+
-+
-+/*  Support functions follow  */
-+
-+
-+/**
-+ *    devfs_get - Get a reference to a devfs entry.
-+ *    @de:  The devfs entry.
-+ */
-+
-+static struct devfs_entry *devfs_get (struct devfs_entry *de)
-+{
-+    VERIFY_ENTRY (de);
-+    if (de) atomic_inc (&de->refcount);
-+    return de;
-+}   /*  End Function devfs_get  */
-+
-+/**
-+ *    devfs_put - Put (release) a reference to a devfs entry.
-+ *    @de:  The handle to the devfs entry.
-+ */
-+
-+void devfs_put (devfs_handle_t de)
-+{
-+    if (!de) return;
-+    VERIFY_ENTRY (de);
-+    if (de->info == POISON_PTR) OOPS ("(%p): poisoned pointer\n", de);
-+    if ( !atomic_dec_and_test (&de->refcount) ) return;
-+    if (de == root_entry) OOPS ("(%p): root entry being freed\n", de);
-+    DPRINTK (DEBUG_FREE, "(%s): de: %p, parent: %p \"%s\"\n",
-+           de->name, de, de->parent,
-+           de->parent ? de->parent->name : "no parent");
-+    if ( S_ISLNK (de->mode) ) kfree (de->u.symlink.linkname);
-+    if ( ( S_ISCHR (de->mode) || S_ISBLK (de->mode) ) && de->u.fcb.autogen )
-+    {
-+      devfs_dealloc_devnum ( S_ISCHR (de->mode) ? DEVFS_SPECIAL_CHR :
-+                             DEVFS_SPECIAL_BLK,
-+                             mk_kdev (de->u.fcb.u.device.major,
-+                                      de->u.fcb.u.device.minor) );
-+    }
-+    WRITE_ENTRY_MAGIC (de, 0);
-+#ifdef CONFIG_DEVFS_DEBUG
-+    spin_lock (&stat_lock);
-+    --stat_num_entries;
-+    stat_num_bytes -= sizeof *de + de->namelen;
-+    if ( S_ISLNK (de->mode) ) stat_num_bytes -= de->u.symlink.length + 1;
-+    spin_unlock (&stat_lock);
-+#endif
-+    de->info = POISON_PTR;
-+    kfree (de);
-+}   /*  End Function devfs_put  */
-+
-+/**
-+ *    _devfs_search_dir - Search for a devfs entry in a directory.
-+ *    @dir:  The directory to search.
-+ *    @name:  The name of the entry to search for.
-+ *    @namelen:  The number of characters in @name.
-+ *
-+ *  Search for a devfs entry in a directory and returns a pointer to the entry
-+ *   on success, else %NULL. The directory must be locked already.
-+ *   An implicit devfs_get() is performed on the returned entry.
-+ */
-+
-+static struct devfs_entry *_devfs_search_dir (struct devfs_entry *dir,
-+                                            const char *name,
-+                                            unsigned int namelen)
-+{
-+    struct devfs_entry *curr;
-+
-+    if ( !S_ISDIR (dir->mode) )
-+    {
-+      PRINTK ("(%s): not a directory\n", dir->name);
-+      return NULL;
-+    }
-+    for (curr = dir->u.dir.first; curr != NULL; curr = curr->next)
-+    {
-+      if (curr->namelen != namelen) continue;
-+      if (memcmp (curr->name, name, namelen) == 0) break;
-+      /*  Not found: try the next one  */
-+    }
-+    return devfs_get (curr);
-+}   /*  End Function _devfs_search_dir  */
-+
-+
-+/**
-+ *    _devfs_alloc_entry - Allocate a devfs entry.
-+ *    @name:  The name of the entry.
-+ *    @namelen:  The number of characters in @name.
-+ *
-+ *  Allocate a devfs entry and returns a pointer to the entry on success, else
-+ *   %NULL.
-+ */
-+
-+static struct devfs_entry *_devfs_alloc_entry (const char *name,
-+                                             unsigned int namelen,
-+                                             umode_t mode)
-+{
-+    struct devfs_entry *new;
-+    static unsigned long inode_counter = FIRST_INODE;
-+    static spinlock_t counter_lock = SPIN_LOCK_UNLOCKED;
-+
-+    if ( name && (namelen < 1) ) namelen = strlen (name);
-+    if ( ( new = kmalloc (sizeof *new + namelen, GFP_KERNEL) ) == NULL )
-+      return NULL;
-+    memset (new, 0, sizeof *new + namelen);  /*  Will set '\0' on name  */
-+    new->mode = mode;
-+    if ( S_ISDIR (mode) ) rwlock_init (&new->u.dir.lock);
-+    atomic_set (&new->refcount, 1);
-+    spin_lock (&counter_lock);
-+    new->inode.ino = inode_counter++;
-+    spin_unlock (&counter_lock);
-+    if (name) memcpy (new->name, name, namelen);
-+    new->namelen = namelen;
-+    WRITE_ENTRY_MAGIC (new, MAGIC_VALUE);
-+#ifdef CONFIG_DEVFS_DEBUG
-+    spin_lock (&stat_lock);
-+    ++stat_num_entries;
-+    stat_num_bytes += sizeof *new + namelen;
-+    spin_unlock (&stat_lock);
-+#endif
-+    return new;
-+}   /*  End Function _devfs_alloc_entry  */
-+
-+
-+/**
-+ *    _devfs_append_entry - Append a devfs entry to a directory's child list.
-+ *    @dir:  The directory to add to.
-+ *    @de:  The devfs entry to append.
-+ *    @removable: If TRUE, increment the count of removable devices for %dir.
-+ *    @old_de: If an existing entry exists, it will be written here. This may
-+ *             be %NULL. An implicit devfs_get() is performed on this entry.
-+ *
-+ *  Append a devfs entry to a directory's list of children, checking first to
-+ *   see if an entry of the same name exists. The directory will be locked.
-+ *   The value 0 is returned on success, else a negative error code.
-+ *   On failure, an implicit devfs_put() is performed on %de.
-+ */
-+
-+static int _devfs_append_entry (devfs_handle_t dir, devfs_handle_t de,
-+                              int removable, devfs_handle_t *old_de)
-+{
-+    int retval;
-+
-+    if (old_de) *old_de = NULL;
-+    if ( !S_ISDIR (dir->mode) )
-+    {
-+      PRINTK ("(%s): dir: \"%s\" is not a directory\n", de->name, dir->name);
-+      devfs_put (de);
-+      return -ENOTDIR;
-+    }
-+    write_lock (&dir->u.dir.lock);
-+    if (dir->u.dir.no_more_additions) retval = -ENOENT;
-+    else
-+    {
-+      struct devfs_entry *old;
-+
-+      old = _devfs_search_dir (dir, de->name, de->namelen);
-+      if (old_de) *old_de = old;
-+      else devfs_put (old);
-+      if (old == NULL)
-+      {
-+          de->parent = dir;
-+          de->prev = dir->u.dir.last;
-+          /*  Append to the directory's list of children  */
-+          if (dir->u.dir.first == NULL) dir->u.dir.first = de;
-+          else dir->u.dir.last->next = de;
-+          dir->u.dir.last = de;
-+          if (removable) ++dir->u.dir.num_removable;
-+          retval = 0;
-+      }
-+      else retval = -EEXIST;
-+    }
-+    write_unlock (&dir->u.dir.lock);
-+    if (retval) devfs_put (de);
-+    return retval;
-+}   /*  End Function _devfs_append_entry  */
-+
-+
-+/**
-+ *    _devfs_get_root_entry - Get the root devfs entry.
-+ *
-+ *    Returns the root devfs entry on success, else %NULL.
-+ */
-+
-+static struct devfs_entry *_devfs_get_root_entry (void)
-+{
-+    kdev_t devnum;
-+    struct devfs_entry *new;
-+    static spinlock_t root_lock = SPIN_LOCK_UNLOCKED;
-+
-+    /*  Always ensure the root is created  */
-+    if (root_entry) return root_entry;
-+    if ( ( new = _devfs_alloc_entry (NULL, 0,MODE_DIR) ) == NULL ) return NULL;
-+    spin_lock (&root_lock);
-+    if (root_entry)
-+    {
-+      spin_unlock (&root_lock);
-+      devfs_put (new);
-+      return (root_entry);
-+    }
-+    root_entry = new;
-+    spin_unlock (&root_lock);
-+    /*  And create the entry for ".devfsd"  */
-+    if ( ( new = _devfs_alloc_entry (".devfsd", 0, S_IFCHR |S_IRUSR |S_IWUSR) )
-+       == NULL ) return NULL;
-+    devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR);
-+    new->u.fcb.u.device.major = major (devnum);
-+    new->u.fcb.u.device.minor = minor (devnum);
-+    new->u.fcb.ops = &devfsd_fops;
-+    _devfs_append_entry (root_entry, new, FALSE, NULL);
-+#ifdef CONFIG_DEVFS_DEBUG
-+    if ( ( new = _devfs_alloc_entry (".stat", 0, S_IFCHR | S_IRUGO | S_IWUGO) )
-+       == NULL ) return NULL;
-+    devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR);
-+    new->u.fcb.u.device.major = major (devnum);
-+    new->u.fcb.u.device.minor = minor (devnum);
-+    new->u.fcb.ops = &stat_fops;
-+    _devfs_append_entry (root_entry, new, FALSE, NULL);
-+#endif
-+    return root_entry;
-+}   /*  End Function _devfs_get_root_entry  */
-+
-+
-+/**
-+ *    _devfs_descend - Descend down a tree using the next component name.
-+ *    @dir:  The directory to search.
-+ *    @name:  The component name to search for.
-+ *    @namelen:  The length of %name.
-+ *    @next_pos:  The position of the next '/' or '\0' is written here.
-+ *
-+ *  Descend into a directory, searching for a component. This function forms
-+ *   the core of a tree-walking algorithm. The directory will be locked.
-+ *   The devfs entry corresponding to the component is returned. If there is
-+ *   no matching entry, %NULL is returned.
-+ *   An implicit devfs_get() is performed on the returned entry.
-+ */
-+
-+static struct devfs_entry *_devfs_descend (struct devfs_entry *dir,
-+                                         const char *name, int namelen,
-+                                         int *next_pos)
-+{
-+    const char *stop, *ptr;
-+    struct devfs_entry *entry;
-+
-+    if ( (namelen >= 3) && (strncmp (name, "../", 3) == 0) )
-+    {   /*  Special-case going to parent directory  */
-+      *next_pos = 3;
-+      return devfs_get (dir->parent);
-+    }
-+    stop = name + namelen;
-+    /*  Search for a possible '/'  */
-+    for (ptr = name; (ptr < stop) && (*ptr != '/'); ++ptr);
-+    *next_pos = ptr - name;
-+    read_lock (&dir->u.dir.lock);
-+    entry = _devfs_search_dir (dir, name, *next_pos);
-+    read_unlock (&dir->u.dir.lock);
-+    return entry;
-+}   /*  End Function _devfs_descend  */
-+
-+
-+static devfs_handle_t _devfs_make_parent_for_leaf (struct devfs_entry *dir,
-+                                                 const char *name,
-+                                                 int namelen, int *leaf_pos)
-+{
-+    int next_pos = 0;
-+
-+    if (dir == NULL) dir = _devfs_get_root_entry ();
-+    if (dir == NULL) return NULL;
-+    devfs_get (dir);
-+    /*  Search for possible trailing component and ignore it  */
-+    for (--namelen; (namelen > 0) && (name[namelen] != '/'); --namelen);
-+    *leaf_pos = (name[namelen] == '/') ? (namelen + 1) : 0;
-+    for (; namelen > 0; name += next_pos, namelen -= next_pos)
-+    {
-+      struct devfs_entry *de, *old;
-+
-+      if ( ( de = _devfs_descend (dir, name, namelen, &next_pos) ) == NULL )
-+      {
-+          de = _devfs_alloc_entry (name, next_pos, MODE_DIR);
-+          devfs_get (de);
-+          if ( !de || _devfs_append_entry (dir, de, FALSE, &old) )
-+          {
-+              devfs_put (de);
-+              if ( !old || !S_ISDIR (old->mode) )
-+              {
-+                  devfs_put (old);
-+                  devfs_put (dir);
-+                  return NULL;
-+              }
-+              de = old;  /*  Use the existing directory  */
-+          }
-+      }
-+      if (de == dir->parent)
-+      {
-+          devfs_put (dir);
-+          devfs_put (de);
-+          return NULL;
-+      }
-+      devfs_put (dir);
-+      dir = de;
-+      if (name[next_pos] == '/') ++next_pos;
-+    }
-+    return dir;
-+}   /*  End Function _devfs_make_parent_for_leaf  */
-+
-+
-+static devfs_handle_t _devfs_prepare_leaf (devfs_handle_t *dir,
-+                                         const char *name, umode_t mode)
-+{
-+    int namelen, leaf_pos;
-+    struct devfs_entry *de;
-+
-+    namelen = strlen (name);
-+    if ( ( *dir = _devfs_make_parent_for_leaf (*dir, name, namelen,
-+                                             &leaf_pos) ) == NULL )
-+    {
-+      PRINTK ("(%s): could not create parent path\n", name);
-+      return NULL;
-+    }
-+    if ( ( de = _devfs_alloc_entry (name + leaf_pos, namelen - leaf_pos,mode) )
-+       == NULL )
-+    {
-+      PRINTK ("(%s): could not allocate entry\n", name);
-+      devfs_put (*dir);
-+      return NULL;
-+    }
-+    return de;
-+}   /*  End Function _devfs_prepare_leaf  */
-+
-+
-+static devfs_handle_t _devfs_walk_path (struct devfs_entry *dir,
-+                                      const char *name, int namelen,
-+                                      int traverse_symlink)
-+{
-+    int next_pos = 0;
-+
-+    if (dir == NULL) dir = _devfs_get_root_entry ();
-+    if (dir == NULL) return NULL;
-+    devfs_get (dir);
-+    for (; namelen > 0; name += next_pos, namelen -= next_pos)
-+    {
-+      struct devfs_entry *de, *link;
-+
-+      if ( ( de = _devfs_descend (dir, name, namelen, &next_pos) ) == NULL )
-+      {
-+          devfs_put (dir);
-+          return NULL;
-+      }
-+      if (S_ISLNK (de->mode) && traverse_symlink)
-+      {   /*  Need to follow the link: this is a stack chomper  */
-+          link = _devfs_walk_path (dir, de->u.symlink.linkname,
-+                                   de->u.symlink.length, TRUE);
-+          devfs_put (de);
-+          if (!link)
-+          {
-+              devfs_put (dir);
-+              return NULL;
-+          }
-+          de = link;
-+      }
-+      devfs_put (dir);
-+      dir = de;
-+      if (name[next_pos] == '/') ++next_pos;
-+    }
-+    return dir;
-+}   /*  End Function _devfs_walk_path  */
-+
-+
-+/**
-+ *    _devfs_find_by_dev - Find a devfs entry in a directory.
-+ *    @dir: The directory where to search
-+ *    @major: The major number to search for.
-+ *    @minor: The minor number to search for.
-+ *    @type: The type of special file to search for. This may be either
-+ *            %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK.
-+ *
-+ *    Returns the devfs_entry pointer on success, else %NULL. An implicit
-+ *    devfs_get() is performed.
-+ */
-+
-+static struct devfs_entry *_devfs_find_by_dev (struct devfs_entry *dir,
-+                                             unsigned int major,
-+                                             unsigned int minor, char type)
-+{
-+    struct devfs_entry *entry, *de;
-+
-+    devfs_get (dir);
-+    if (dir == NULL) return NULL;
-+    if ( !S_ISDIR (dir->mode) )
-+    {
-+      PRINTK ("(%p): not a directory\n", dir);
-+      devfs_put (dir);
-+      return NULL;
-+    }
-+    /*  First search files in this directory  */
-+    read_lock (&dir->u.dir.lock);
-+    for (entry = dir->u.dir.first; entry != NULL; entry = entry->next)
-+    {
-+      if ( !S_ISCHR (entry->mode) && !S_ISBLK (entry->mode) ) continue;
-+      if ( S_ISCHR (entry->mode) && (type != DEVFS_SPECIAL_CHR) ) continue;
-+      if ( S_ISBLK (entry->mode) && (type != DEVFS_SPECIAL_BLK) ) continue;
-+      if ( (entry->u.fcb.u.device.major == major) &&
-+           (entry->u.fcb.u.device.minor == minor) )
-+      {
-+          devfs_get (entry);
-+          read_unlock (&dir->u.dir.lock);
-+          devfs_put (dir);
-+          return entry;
-+      }
-+      /*  Not found: try the next one  */
-+    }
-+    /*  Now recursively search the subdirectories: this is a stack chomper  */
-+    for (entry = dir->u.dir.first; entry != NULL; entry = entry->next)
-+    {
-+      if ( !S_ISDIR (entry->mode) ) continue;
-+      de = _devfs_find_by_dev (entry, major, minor, type);
-+      if (de)
-+      {
-+          read_unlock (&dir->u.dir.lock);
-+          devfs_put (dir);
-+          return de;
-+      }
-+    }
-+    read_unlock (&dir->u.dir.lock);
-+    devfs_put (dir);
-+    return NULL;
-+}   /*  End Function _devfs_find_by_dev  */
-+
-+
-+/**
-+ *    _devfs_find_entry - Find a devfs entry.
-+ *    @dir: The handle to the parent devfs directory entry. If this is %NULL the
-+ *            name is relative to the root of the devfs.
-+ *    @name: The name of the entry. This may be %NULL.
-+ *    @major: The major number. This is used if lookup by @name fails.
-+ *    @minor: The minor number. This is used if lookup by @name fails.
-+ *            NOTE: If @major and @minor are both 0, searching by major and minor
-+ *            numbers is disabled.
-+ *    @type: The type of special file to search for. This may be either
-+ *            %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK.
-+ *    @traverse_symlink: If %TRUE then symbolic links are traversed.
-+ *
-+ *    Returns the devfs_entry pointer on success, else %NULL. An implicit
-+ *    devfs_get() is performed.
-+ */
-+
-+static struct devfs_entry *_devfs_find_entry (devfs_handle_t dir,
-+                                            const char *name,
-+                                            unsigned int major,
-+                                            unsigned int minor,
-+                                            char type, int traverse_symlink)
-+{
-+    struct devfs_entry *entry;
-+
-+    if (name != NULL)
-+    {
-+      unsigned int namelen = strlen (name);
-+
-+      if (name[0] == '/')
-+      {
-+          /*  Skip leading pathname component  */
-+          if (namelen < 2)
-+          {
-+              PRINTK ("(%s): too short\n", name);
-+              return NULL;
-+          }
-+          for (++name, --namelen; (*name != '/') && (namelen > 0);
-+               ++name, --namelen);
-+          if (namelen < 2)
-+          {
-+              PRINTK ("(%s): too short\n", name);
-+              return NULL;
-+          }
-+          ++name;
-+          --namelen;
-+      }
-+      entry = _devfs_walk_path (dir, name, namelen, traverse_symlink);
-+      if (entry != NULL) return entry;
-+    }
-+    /*  Have to search by major and minor: slow  */
-+    if ( (major == 0) && (minor == 0) ) return NULL;
-+    return _devfs_find_by_dev (root_entry, major, minor, type);
-+}   /*  End Function _devfs_find_entry  */
-+
-+static struct devfs_entry *get_devfs_entry_from_vfs_inode (struct inode *inode)
-+{
-+    if (inode == NULL) return NULL;
-+    VERIFY_ENTRY ( (struct devfs_entry *) inode->u.generic_ip );
-+    return inode->u.generic_ip;
-+}   /*  End Function get_devfs_entry_from_vfs_inode  */
-+
-+
-+/**
-+ *    free_dentry - Free the dentry for a device entry and invalidate inode.
-+ *    @de: The entry.
-+ *
-+ *    This must only be called after the entry has been unhooked from it's
-+ *     parent directory.
-+ */
-+
-+static void free_dentry (struct devfs_entry *de)
-+{
-+    struct dentry *dentry = de->inode.dentry;
-+
-+    if (!dentry) return;
-+    spin_lock (&dcache_lock);
-+    dget_locked (dentry);
-+    spin_unlock (&dcache_lock);
-+    /*  Forcefully remove the inode  */
-+    if (dentry->d_inode != NULL) dentry->d_inode->i_nlink = 0;
-+    d_drop (dentry);
-+    dput (dentry);
-+}   /*  End Function free_dentry  */
-+
-+
-+/**
-+ *    is_devfsd_or_child - Test if the current process is devfsd or one of its children.
-+ *    @fs_info: The filesystem information.
-+ *
-+ *    Returns %TRUE if devfsd or child, else %FALSE.
-+ */
-+
-+static int is_devfsd_or_child (struct fs_info *fs_info)
-+{
-+    struct task_struct *p;
-+
-+    if (current == fs_info->devfsd_task) return (TRUE);
-+    if (current->pgrp == fs_info->devfsd_pgrp) return (TRUE);
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,1)
-+    for (p = current->p_opptr; p != &init_task; p = p->p_opptr)
-+    {
-+      if (p == fs_info->devfsd_task) return (TRUE);
-+    }
-+#endif
-+    return (FALSE);
-+}   /*  End Function is_devfsd_or_child  */
-+
-+
-+/**
-+ *    devfsd_queue_empty - Test if devfsd has work pending in its event queue.
-+ *    @fs_info: The filesystem information.
-+ *
-+ *    Returns %TRUE if the queue is empty, else %FALSE.
-+ */
-+
-+static inline int devfsd_queue_empty (struct fs_info *fs_info)
-+{
-+    return (fs_info->devfsd_last_event) ? FALSE : TRUE;
-+}   /*  End Function devfsd_queue_empty  */
-+
-+
-+/**
-+ *    wait_for_devfsd_finished - Wait for devfsd to finish processing its event queue.
-+ *    @fs_info: The filesystem information.
-+ *
-+ *    Returns %TRUE if no more waiting will be required, else %FALSE.
-+ */
-+
-+static int wait_for_devfsd_finished (struct fs_info *fs_info)
-+{
-+    DECLARE_WAITQUEUE (wait, current);
-+
-+    if (fs_info->devfsd_task == NULL) return (TRUE);
-+    if (devfsd_queue_empty (fs_info) && fs_info->devfsd_sleeping) return TRUE;
-+    if ( is_devfsd_or_child (fs_info) ) return (FALSE);
-+    add_wait_queue (&fs_info->revalidate_wait_queue, &wait);
-+    current->state = TASK_UNINTERRUPTIBLE;
-+    if (!devfsd_queue_empty (fs_info) || !fs_info->devfsd_sleeping)
-+      if (fs_info->devfsd_task) schedule ();
-+    remove_wait_queue (&fs_info->revalidate_wait_queue, &wait);
-+    current->state = TASK_RUNNING;
-+    return (TRUE);
-+}   /*  End Function wait_for_devfsd_finished  */
-+
-+
-+/**
-+ *    devfsd_notify_de - Notify the devfsd daemon of a change.
-+ *    @de: The devfs entry that has changed. This and all parent entries will
-+ *            have their reference counts incremented if the event was queued.
-+ *    @type: The type of change.
-+ *    @mode: The mode of the entry.
-+ *    @uid: The user ID.
-+ *    @gid: The group ID.
-+ *    @fs_info: The filesystem info.
-+ *
-+ *    Returns %TRUE if an event was queued and devfsd woken up, else %FALSE.
-+ */
-+
-+static int devfsd_notify_de (struct devfs_entry *de,
-+                           unsigned short type, umode_t mode,
-+                           uid_t uid, gid_t gid, struct fs_info *fs_info,
-+                           int atomic)
-+{
-+    struct devfsd_buf_entry *entry;
-+    struct devfs_entry *curr;
-+
-+    if ( !( fs_info->devfsd_event_mask & (1 << type) ) ) return (FALSE);
-+    if ( ( entry = kmem_cache_alloc (devfsd_buf_cache,
-+                                   atomic ? SLAB_ATOMIC : SLAB_KERNEL) )
-+       == NULL )
-+    {
-+      atomic_inc (&fs_info->devfsd_overrun_count);
-+      return (FALSE);
-+    }
-+    for (curr = de; curr != NULL; curr = curr->parent) devfs_get (curr);
-+    entry->de = de;
-+    entry->type = type;
-+    entry->mode = mode;
-+    entry->uid = uid;
-+    entry->gid = gid;
-+    entry->next = NULL;
-+    spin_lock (&fs_info->devfsd_buffer_lock);
-+    if (!fs_info->devfsd_first_event) fs_info->devfsd_first_event = entry;
-+    if (fs_info->devfsd_last_event) fs_info->devfsd_last_event->next = entry;
-+    fs_info->devfsd_last_event = entry;
-+    spin_unlock (&fs_info->devfsd_buffer_lock);
-+    wake_up_interruptible (&fs_info->devfsd_wait_queue);
-+    return (TRUE);
-+}   /*  End Function devfsd_notify_de  */
-+
-+
-+/**
-+ *    devfsd_notify - Notify the devfsd daemon of a change.
-+ *    @de: The devfs entry that has changed.
-+ *    @type: The type of change event.
-+ *    @wait: If TRUE, the function waits for the daemon to finish processing
-+ *            the event.
-+ */
-+
-+static void devfsd_notify (struct devfs_entry *de,unsigned short type,int wait)
-+{
-+    if (devfsd_notify_de (de, type, de->mode, current->euid,
-+                        current->egid, &fs_info, 0) && wait)
-+      wait_for_devfsd_finished (&fs_info);
-+}   /*  End Function devfsd_notify  */
-+
-+
-+/**
-+ *    devfs_register - Register a device entry.
-+ *    @dir: The handle to the parent devfs directory entry. If this is %NULL the
-+ *            new name is relative to the root of the devfs.
-+ *    @name: The name of the entry.
-+ *    @flags: A set of bitwise-ORed flags (DEVFS_FL_*).
-+ *    @major: The major number. Not needed for regular files.
-+ *    @minor: The minor number. Not needed for regular files.
-+ *    @mode: The default file mode.
-+ *    @ops: The &file_operations or &block_device_operations structure.
-+ *            This must not be externally deallocated.
-+ *    @info: An arbitrary pointer which will be written to the @private_data
-+ *            field of the &file structure passed to the device driver. You can set
-+ *            this to whatever you like, and change it once the file is opened (the next
-+ *            file opened will not see this change).
-+ *
-+ *    Returns a handle which may later be used in a call to devfs_unregister().
-+ *    On failure %NULL is returned.
-+ */
-+
-+devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,
-+                             unsigned int flags,
-+                             unsigned int major, unsigned int minor,
-+                             umode_t mode, void *ops, void *info)
-+{
-+    char devtype = S_ISCHR (mode) ? DEVFS_SPECIAL_CHR : DEVFS_SPECIAL_BLK;
-+    int err;
-+    kdev_t devnum = NODEV;
-+    struct devfs_entry *de;
-+
-+    if (name == NULL)
-+    {
-+      PRINTK ("(): NULL name pointer\n");
-+      return NULL;
-+    }
-+    if (ops == NULL)
-+    {
-+      if ( S_ISBLK (mode) ) ops = (void *) get_blkfops (major);
-+      if (ops == NULL)
-+      {
-+          PRINTK ("(%s): NULL ops pointer\n", name);
-+          return NULL;
-+      }
-+      PRINTK ("(%s): NULL ops, got %p from major table\n", name, ops);
-+    }
-+    if ( S_ISDIR (mode) )
-+    {
-+      PRINTK ("(%s): creating directories is not allowed\n", name);
-+      return NULL;
-+    }
-+    if ( S_ISLNK (mode) )
-+    {
-+      PRINTK ("(%s): creating symlinks is not allowed\n", name);
-+      return NULL;
-+    }
-+    if ( ( S_ISCHR (mode) || S_ISBLK (mode) ) &&
-+       (flags & DEVFS_FL_AUTO_DEVNUM) )
-+    {
-+      if ( kdev_none ( devnum = devfs_alloc_devnum (devtype) ) )
-+      {
-+          PRINTK ("(%s): exhausted %s device numbers\n",
-+                  name, S_ISCHR (mode) ? "char" : "block");
-+          return NULL;
-+      }
-+      major = major (devnum);
-+      minor = minor (devnum);
-+    }
-+    if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL )
-+    {
-+      PRINTK ("(%s): could not prepare leaf\n", name);
-+      if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);
-+      return NULL;
-+    }
-+    if ( S_ISCHR (mode) || S_ISBLK (mode) )
-+    {
-+      de->u.fcb.u.device.major = major;
-+      de->u.fcb.u.device.minor = minor;
-+      de->u.fcb.autogen = kdev_none (devnum) ? FALSE : TRUE;
-+    }
-+    else if ( !S_ISREG (mode) )
-+    {
-+      PRINTK ("(%s): illegal mode: %x\n", name, mode);
-+      devfs_put (de);
-+      devfs_put (dir);
-+      return (NULL);
-+    }
-+    de->info = info;
-+    if (flags & DEVFS_FL_CURRENT_OWNER)
-+    {
-+      de->inode.uid = current->uid;
-+      de->inode.gid = current->gid;
-+    }
-+    else
-+    {
-+      de->inode.uid = 0;
-+      de->inode.gid = 0;
-+    }
-+    de->u.fcb.ops = ops;
-+    de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE;
-+    de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE : FALSE;
-+    de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
-+    if (flags & DEVFS_FL_REMOVABLE) de->u.fcb.removable = TRUE;
-+    if ( ( err = _devfs_append_entry (dir, de, de->u.fcb.removable, NULL) )
-+       != 0 )
-+    {
-+      PRINTK ("(%s): could not append to parent, err: %d\n", name, err);
-+      devfs_put (dir);
-+      if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);
-+      return NULL;
-+    }
-+    DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\"  pp: %p\n",
-+           name, de, dir, dir->name, dir->parent);
-+    devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);
-+    devfs_put (dir);
-+    return de;
-+}   /*  End Function devfs_register  */
-+
-+
-+/**
-+ *    _devfs_unhook - Unhook a device entry from its parents list
-+ *    @de: The entry to unhook.
-+ *
-+ *    Returns %TRUE if the entry was unhooked, else %FALSE if it was
-+ *            previously unhooked.
-+ *    The caller must have a write lock on the parent directory.
-+ */
-+
-+static int _devfs_unhook (struct devfs_entry *de)
-+{
-+    struct devfs_entry *parent;
-+
-+    if ( !de || (de->prev == de) ) return FALSE;
-+    parent = de->parent;
-+    if (de->prev == NULL) parent->u.dir.first = de->next;
-+    else de->prev->next = de->next;
-+    if (de->next == NULL) parent->u.dir.last = de->prev;
-+    else de->next->prev = de->prev;
-+    de->prev = de;          /*  Indicate we're unhooked                      */
-+    de->next = NULL;        /*  Force early termination for <devfs_readdir>  */
-+    if ( ( S_ISREG (de->mode) || S_ISCHR (de->mode) || S_ISBLK (de->mode) ) &&
-+       de->u.fcb.removable )
-+      --parent->u.dir.num_removable;
-+    return TRUE;
-+}   /*  End Function _devfs_unhook  */
-+
-+
-+/**
-+ *    _devfs_unregister - Unregister a device entry from it's parent.
-+ *    @dir: The parent directory.
-+ *    @de: The entry to unregister.
-+ *
-+ *    The caller must have a write lock on the parent directory, which is
-+ *    unlocked by this function.
-+ */
-+
-+static void _devfs_unregister (struct devfs_entry *dir, struct devfs_entry *de)
-+{
-+    int unhooked = _devfs_unhook (de);
-+
-+    write_unlock (&dir->u.dir.lock);
-+    if (!unhooked) return;
-+    devfs_get (dir);
-+    devfs_unregister (de->slave);  /*  Let it handle the locking  */
-+    devfsd_notify (de, DEVFSD_NOTIFY_UNREGISTERED, 0);
-+    free_dentry (de);
-+    devfs_put (dir);
-+    if ( !S_ISDIR (de->mode) ) return;
-+    while (TRUE)  /*  Recursively unregister: this is a stack chomper  */
-+    {
-+      struct devfs_entry *child;
-+
-+      write_lock (&de->u.dir.lock);
-+      de->u.dir.no_more_additions = TRUE;
-+      child = de->u.dir.first;
-+      VERIFY_ENTRY (child);
-+      _devfs_unregister (de, child);
-+      if (!child) break;
-+      DPRINTK (DEBUG_UNREGISTER, "(%s): child: %p  refcount: %d\n",
-+               child->name, child, atomic_read (&child->refcount) );
-+      devfs_put (child);
-+    }
-+}   /*  End Function _devfs_unregister  */
-+
-+
-+/**
-+ *    devfs_unregister - Unregister a device entry.
-+ *    @de: A handle previously created by devfs_register() or returned from
-+ *            devfs_get_handle(). If this is %NULL the routine does nothing.
-+ */
-+
-+void devfs_unregister (devfs_handle_t de)
-+{
-+    VERIFY_ENTRY (de);
-+    if ( (de == NULL) || (de->parent == NULL) ) return;
-+    DPRINTK (DEBUG_UNREGISTER, "(%s): de: %p  refcount: %d\n",
-+           de->name, de, atomic_read (&de->refcount) );
-+    write_lock (&de->parent->u.dir.lock);
-+    _devfs_unregister (de->parent, de);
-+    devfs_put (de);
-+}   /*  End Function devfs_unregister  */
-+
-+static int devfs_do_symlink (devfs_handle_t dir, const char *name,
-+                           unsigned int flags, const char *link,
-+                           devfs_handle_t *handle, void *info)
-+{
-+    int err;
-+    unsigned int linklength;
-+    char *newlink;
-+    struct devfs_entry *de;
-+
-+    if (handle != NULL) *handle = NULL;
-+    if (name == NULL)
-+    {
-+      PRINTK ("(): NULL name pointer\n");
-+      return -EINVAL;
-+    }
-+    if (link == NULL)
-+    {
-+      PRINTK ("(%s): NULL link pointer\n", name);
-+      return -EINVAL;
-+    }
-+    linklength = strlen (link);
-+    if ( ( newlink = kmalloc (linklength + 1, GFP_KERNEL) ) == NULL )
-+      return -ENOMEM;
-+    memcpy (newlink, link, linklength);
-+    newlink[linklength] = '\0';
-+    if ( ( de = _devfs_prepare_leaf (&dir, name, S_IFLNK | S_IRUGO | S_IXUGO) )
-+       == NULL )
-+    {
-+      PRINTK ("(%s): could not prepare leaf\n", name);
-+      kfree (newlink);
-+      return -ENOTDIR;
-+    }
-+    de->info = info;
-+    de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
-+    de->u.symlink.linkname = newlink;
-+    de->u.symlink.length = linklength;
-+    if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 )
-+    {
-+      PRINTK ("(%s): could not append to parent, err: %d\n", name, err);
-+      devfs_put (dir);
-+      return err;
-+    }
-+    devfs_put (dir);
-+#ifdef CONFIG_DEVFS_DEBUG
-+    spin_lock (&stat_lock);
-+    stat_num_bytes += linklength + 1;
-+    spin_unlock (&stat_lock);
-+#endif
-+    if (handle != NULL) *handle = de;
-+    return 0;
-+}   /*  End Function devfs_do_symlink  */
-+
-+
-+/**
-+ *    devfs_mk_symlink Create a symbolic link in the devfs namespace.
-+ *    @dir: The handle to the parent devfs directory entry. If this is %NULL the
-+ *            new name is relative to the root of the devfs.
-+ *    @name: The name of the entry.
-+ *    @flags: A set of bitwise-ORed flags (DEVFS_FL_*).
-+ *    @link: The destination name.
-+ *    @handle: The handle to the symlink entry is written here. This may be %NULL.
-+ *    @info: An arbitrary pointer which will be associated with the entry.
-+ *
-+ *    Returns 0 on success, else a negative error code is returned.
-+ */
-+
-+int devfs_mk_symlink (devfs_handle_t dir, const char *name, unsigned int flags,
-+                    const char *link, devfs_handle_t *handle, void *info)
-+{
-+    int err;
-+    devfs_handle_t de;
-+
-+    if (handle != NULL) *handle = NULL;
-+    DPRINTK (DEBUG_REGISTER, "(%s)\n", name);
-+    err = devfs_do_symlink (dir, name, flags, link, &de, info);
-+    if (err) return err;
-+    if (handle == NULL) de->vfs_deletable = TRUE;
-+    else *handle = de;
-+    devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);
-+    return 0;
-+}   /*  End Function devfs_mk_symlink  */
-+
-+
-+/**
-+ *    devfs_mk_dir - Create a directory in the devfs namespace.
-+ *    @dir: The handle to the parent devfs directory entry. If this is %NULL the
-+ *            new name is relative to the root of the devfs.
-+ *    @name: The name of the entry.
-+ *    @info: An arbitrary pointer which will be associated with the entry.
-+ *
-+ *    Use of this function is optional. The devfs_register() function
-+ *    will automatically create intermediate directories as needed. This function
-+ *    is provided for efficiency reasons, as it provides a handle to a directory.
-+ *    Returns a handle which may later be used in a call to devfs_unregister().
-+ *    On failure %NULL is returned.
-+ */
-+
-+devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info)
-+{
-+    int err;
-+    struct devfs_entry *de, *old;
-+
-+    if (name == NULL)
-+    {
-+      PRINTK ("(): NULL name pointer\n");
-+      return NULL;
-+    }
-+    if ( ( de = _devfs_prepare_leaf (&dir, name, MODE_DIR) ) == NULL )
-+    {
-+      PRINTK ("(%s): could not prepare leaf\n", name);
-+      return NULL;
-+    }
-+    de->info = info;
-+    if ( ( err = _devfs_append_entry (dir, de, FALSE, &old) ) != 0 )
-+    {
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,1)
-+      if ( old && S_ISDIR (old->mode) )
-+      {
-+          PRINTK ("(%s): using old entry in dir: %p \"%s\"\n",
-+                  name, dir, dir->name);
-+          old->vfs_deletable = FALSE;
-+          devfs_put (dir);
-+          return old;
-+      }
-+#endif
-+      PRINTK ("(%s): could not append to dir: %p \"%s\", err: %d\n",
-+              name, dir, dir->name, err);
-+      devfs_put (old);
-+      devfs_put (dir);
-+      return NULL;
-+    }
-+    DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\"\n",
-+           name, de, dir, dir->name);
-+    devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, 0);
-+    devfs_put (dir);
-+    return de;
-+}   /*  End Function devfs_mk_dir  */
-+
-+
-+/**
-+ *    devfs_get_handle - Find the handle of a devfs entry.
-+ *    @dir: The handle to the parent devfs directory entry. If this is %NULL the
-+ *            name is relative to the root of the devfs.
-+ *    @name: The name of the entry.
-+ *    @major: The major number. This is used if @name is %NULL.
-+ *    @minor: The minor number. This is used if @name is %NULL.
-+ *    @type: The type of special file to search for. This may be either
-+ *            %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK.
-+ *    @traverse_symlinks: If %TRUE then symlink entries in the devfs namespace are
-+ *            traversed. Symlinks pointing out of the devfs namespace will cause a
-+ *            failure. Symlink traversal consumes stack space.
-+ *
-+ *    Returns a handle which may later be used in a call to
-+ *    devfs_unregister(), devfs_get_flags(), or devfs_set_flags(). A
-+ *    subsequent devfs_put() is required to decrement the refcount.
-+ *    On failure %NULL is returned.
-+ */
-+
-+devfs_handle_t devfs_get_handle (devfs_handle_t dir, const char *name,
-+                               unsigned int major, unsigned int minor,
-+                               char type, int traverse_symlinks)
-+{
-+    if ( (name != NULL) && (name[0] == '\0') ) name = NULL;
-+    return _devfs_find_entry (dir, name, major, minor, type,traverse_symlinks);
-+}   /*  End Function devfs_get_handle  */
-+
-+
-+/*  Compatibility function. Will be removed in sometime in 2.5  */
-+
-+devfs_handle_t devfs_find_handle (devfs_handle_t dir, const char *name,
-+                                unsigned int major, unsigned int minor,
-+                                char type, int traverse_symlinks)
-+{
-+    devfs_handle_t de;
-+
-+    de = devfs_get_handle (dir, name, major, minor, type, traverse_symlinks);
-+    devfs_put (de);
-+    return de;
-+}   /*  End Function devfs_find_handle  */
-+
-+
-+/**
-+ *    devfs_get_flags - Get the flags for a devfs entry.
-+ *    @de: The handle to the device entry.
-+ *    @flags: The flags are written here.
-+ *
-+ *    Returns 0 on success, else a negative error code.
-+ */
-+
-+int devfs_get_flags (devfs_handle_t de, unsigned int *flags)
-+{
-+    unsigned int fl = 0;
-+
-+    if (de == NULL) return -EINVAL;
-+    VERIFY_ENTRY (de);
-+    if (de->hide) fl |= DEVFS_FL_HIDE;
-+    if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
-+    {
-+      if (de->u.fcb.auto_owner) fl |= DEVFS_FL_AUTO_OWNER;
-+      if (de->u.fcb.aopen_notify) fl |= DEVFS_FL_AOPEN_NOTIFY;
-+      if (de->u.fcb.removable) fl |= DEVFS_FL_REMOVABLE;
-+    }
-+    *flags = fl;
-+    return 0;
-+}   /*  End Function devfs_get_flags  */
-+
-+
-+/*
-+ *    devfs_set_flags - Set the flags for a devfs entry.
-+ *    @de: The handle to the device entry.
-+ *    @flags: The flags to set. Unset flags are cleared.
-+ *
-+ *    Returns 0 on success, else a negative error code.
-+ */
-+
-+int devfs_set_flags (devfs_handle_t de, unsigned int flags)
-+{
-+    if (de == NULL) return -EINVAL;
-+    VERIFY_ENTRY (de);
-+    DPRINTK (DEBUG_SET_FLAGS, "(%s): flags: %x\n", de->name, flags);
-+    de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
-+    if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
-+    {
-+      de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE;
-+      de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE:FALSE;
-+    }
-+    return 0;
-+}   /*  End Function devfs_set_flags  */
-+
-+
-+/**
-+ *    devfs_get_maj_min - Get the major and minor numbers for a devfs entry.
-+ *    @de: The handle to the device entry.
-+ *    @major: The major number is written here. This may be %NULL.
-+ *    @minor: The minor number is written here. This may be %NULL.
-+ *
-+ *    Returns 0 on success, else a negative error code.
-+ */
-+
-+int devfs_get_maj_min (devfs_handle_t de, unsigned int *major,
-+                     unsigned int *minor)
-+{
-+    if (de == NULL) return -EINVAL;
-+    VERIFY_ENTRY (de);
-+    if ( S_ISDIR (de->mode) ) return -EISDIR;
-+    if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) ) return -EINVAL;
-+    if (major != NULL) *major = de->u.fcb.u.device.major;
-+    if (minor != NULL) *minor = de->u.fcb.u.device.minor;
-+    return 0;
-+}   /*  End Function devfs_get_maj_min  */
-+
-+
-+/**
-+ *    devfs_get_handle_from_inode - Get the devfs handle for a VFS inode.
-+ *    @inode: The VFS inode.
-+ *
-+ *    Returns the devfs handle on success, else %NULL.
-+ */
-+
-+devfs_handle_t devfs_get_handle_from_inode (struct inode *inode)
-+{
-+    if (!inode || !inode->i_sb) return NULL;
-+    if (inode->i_sb->s_magic != DEVFS_SUPER_MAGIC) return NULL;
-+    return get_devfs_entry_from_vfs_inode (inode);
-+}   /*  End Function devfs_get_handle_from_inode  */
-+
-+
-+/**
-+ *    devfs_generate_path - Generate a pathname for an entry, relative to the devfs root.
-+ *    @de: The devfs entry.
-+ *    @path: The buffer to write the pathname to. The pathname and '\0'
-+ *            terminator will be written at the end of the buffer.
-+ *    @buflen: The length of the buffer.
-+ *
-+ *    Returns the offset in the buffer where the pathname starts on success,
-+ *    else a negative error code.
-+ */
-+
-+int devfs_generate_path (devfs_handle_t de, char *path, int buflen)
-+{
-+    int pos;
-+#define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name )
-+
-+    if (de == NULL) return -EINVAL;
-+    VERIFY_ENTRY (de);
-+    if (de->namelen >= buflen) return -ENAMETOOLONG; /*  Must be first       */
-+    path[buflen - 1] = '\0';
-+    if (de->parent == NULL) return buflen - 1;       /*  Don't prepend root  */
-+    pos = buflen - de->namelen - 1;
-+    memcpy (path + pos, NAMEOF (de), de->namelen);
-+    for (de = de->parent; de->parent != NULL; de = de->parent)
-+    {
-+      if (pos - de->namelen - 1 < 0) return -ENAMETOOLONG;
-+      path[--pos] = '/';
-+      pos -= de->namelen;
-+      memcpy (path + pos, NAMEOF (de), de->namelen);
-+    }
-+    return pos;
-+}   /*  End Function devfs_generate_path  */
-+
-+
-+/**
-+ *    devfs_get_ops - Get the device operations for a devfs entry.
-+ *    @de: The handle to the device entry.
-+ *
-+ *    Returns a pointer to the device operations on success, else NULL.
-+ *    The use count for the module owning the operations will be incremented.
-+ */
-+
-+void *devfs_get_ops (devfs_handle_t de)
-+{
-+    struct module *owner;
-+
-+    if (de == NULL) return NULL;
-+    VERIFY_ENTRY (de);
-+    if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) )
-+      return NULL;
-+    if (de->u.fcb.ops == NULL) return NULL;
-+    read_lock (&de->parent->u.dir.lock);  /*  Prevent module from unloading  */
-+    if (de->next == de) owner = NULL;     /*  Ops pointer is already stale   */
-+    else if ( S_ISCHR (de->mode) || S_ISREG (de->mode) )
-+      owner = ( (struct file_operations *) de->u.fcb.ops )->owner;
-+    else owner = ( (struct block_device_operations *) de->u.fcb.ops )->owner;
-+    if ( (de->next == de) || !try_inc_mod_count (owner) )
-+    {   /*  Entry is already unhooked or module is unloading  */
-+      read_unlock (&de->parent->u.dir.lock);
-+      return NULL;
-+    }
-+    read_unlock (&de->parent->u.dir.lock);  /*  Module can continue unloading*/
-+    return de->u.fcb.ops;
-+}   /*  End Function devfs_get_ops  */
-+
-+
-+/**
-+ *    devfs_put_ops - Put the device operations for a devfs entry.
-+ *    @de: The handle to the device entry.
-+ *
-+ *    The use count for the module owning the operations will be decremented.
-+ */
-+
-+void devfs_put_ops (devfs_handle_t de)
-+{
-+    struct module *owner;
-+
-+    if (de == NULL) return;
-+    VERIFY_ENTRY (de);
-+    if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) )
-+      return;
-+    if (de->u.fcb.ops == NULL) return;
-+    if ( S_ISCHR (de->mode) || S_ISREG (de->mode) )
-+      owner = ( (struct file_operations *) de->u.fcb.ops )->owner;
-+    else owner = ( (struct block_device_operations *) de->u.fcb.ops )->owner;
-+    if (owner) __MOD_DEC_USE_COUNT (owner);
-+}   /*  End Function devfs_put_ops  */
-+
-+
-+/**
-+ *    devfs_set_file_size - Set the file size for a devfs regular file.
-+ *    @de: The handle to the device entry.
-+ *    @size: The new file size.
-+ *
-+ *    Returns 0 on success, else a negative error code.
-+ */
-+
-+int devfs_set_file_size (devfs_handle_t de, unsigned long size)
-+{
-+    if (de == NULL) return -EINVAL;
-+    VERIFY_ENTRY (de);
-+    if ( !S_ISREG (de->mode) ) return -EINVAL;
-+    if (de->u.fcb.u.file.size == size) return 0;
-+    de->u.fcb.u.file.size = size;
-+    if (de->inode.dentry == NULL) return 0;
-+    if (de->inode.dentry->d_inode == NULL) return 0;
-+    de->inode.dentry->d_inode->i_size = size;
-+    return 0;
-+}   /*  End Function devfs_set_file_size  */
-+
-+
-+/**
-+ *    devfs_get_info - Get the info pointer written to private_data of @de upon open.
-+ *    @de: The handle to the device entry.
-+ *
-+ *    Returns the info pointer.
-+ */
-+void *devfs_get_info (devfs_handle_t de)
-+{
-+    if (de == NULL) return NULL;
-+    VERIFY_ENTRY (de);
-+    return de->info;
-+}   /*  End Function devfs_get_info  */
-+
-+
-+/**
-+ *    devfs_set_info - Set the info pointer written to private_data upon open.
-+ *    @de: The handle to the device entry.
-+ *    @info: pointer to the data
-+ *
-+ *    Returns 0 on success, else a negative error code.
-+ */
-+int devfs_set_info (devfs_handle_t de, void *info)
-+{
-+    if (de == NULL) return -EINVAL;
-+    VERIFY_ENTRY (de);
-+    de->info = info;
-+    return 0;
-+}   /*  End Function devfs_set_info  */
-+
-+
-+/**
-+ *    devfs_get_parent - Get the parent device entry.
-+ *    @de: The handle to the device entry.
-+ *
-+ *    Returns the parent device entry if it exists, else %NULL.
-+ */
-+devfs_handle_t devfs_get_parent (devfs_handle_t de)
-+{
-+    if (de == NULL) return NULL;
-+    VERIFY_ENTRY (de);
-+    return de->parent;
-+}   /*  End Function devfs_get_parent  */
-+
-+
-+/**
-+ *    devfs_get_first_child - Get the first leaf node in a directory.
-+ *    @de: The handle to the device entry.
-+ *
-+ *    Returns the leaf node device entry if it exists, else %NULL.
-+ */
-+
-+devfs_handle_t devfs_get_first_child (devfs_handle_t de)
-+{
-+    if (de == NULL) return NULL;
-+    VERIFY_ENTRY (de);
-+    if ( !S_ISDIR (de->mode) ) return NULL;
-+    return de->u.dir.first;
-+}   /*  End Function devfs_get_first_child  */
-+
-+
-+/**
-+ *    devfs_get_next_sibling - Get the next sibling leaf node. for a device entry.
-+ *    @de: The handle to the device entry.
-+ *
-+ *    Returns the leaf node device entry if it exists, else %NULL.
-+ */
-+
-+devfs_handle_t devfs_get_next_sibling (devfs_handle_t de)
-+{
-+    if (de == NULL) return NULL;
-+    VERIFY_ENTRY (de);
-+    return de->next;
-+}   /*  End Function devfs_get_next_sibling  */
-+
-+
-+/**
-+ *    devfs_auto_unregister - Configure a devfs entry to be automatically unregistered.
-+ *    @master: The master devfs entry. Only one slave may be registered.
-+ *    @slave: The devfs entry which will be automatically unregistered when the
-+ *            master entry is unregistered. It is illegal to call devfs_unregister()
-+ *            on this entry.
-+ */
-+
-+void devfs_auto_unregister (devfs_handle_t master, devfs_handle_t slave)
-+{
-+    if (master == NULL) return;
-+    VERIFY_ENTRY (master);
-+    VERIFY_ENTRY (slave);
-+    if (master->slave != NULL)
-+    {
-+      /*  Because of the dumbness of the layers above, ignore duplicates  */
-+      if (master->slave == slave) return;
-+      PRINTK ("(%s): only one slave allowed\n", master->name);
-+      OOPS ("():  old slave: \"%s\"  new slave: \"%s\"\n",
-+            master->slave->name, slave->name);
-+    }
-+    master->slave = slave;
-+}   /*  End Function devfs_auto_unregister  */
-+
-+
-+/**
-+ *    devfs_get_unregister_slave - Get the slave entry which will be automatically unregistered.
-+ *    @master: The master devfs entry.
-+ *
-+ *    Returns the slave which will be unregistered when @master is unregistered.
-+ */
-+
-+devfs_handle_t devfs_get_unregister_slave (devfs_handle_t master)
-+{
-+    if (master == NULL) return NULL;
-+    VERIFY_ENTRY (master);
-+    return master->slave;
-+}   /*  End Function devfs_get_unregister_slave  */
-+
-+
-+/**
-+ *    devfs_get_name - Get the name for a device entry in its parent directory.
-+ *    @de: The handle to the device entry.
-+ *    @namelen: The length of the name is written here. This may be %NULL.
-+ *
-+ *    Returns the name on success, else %NULL.
-+ */
-+
-+const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen)
-+{
-+    if (de == NULL) return NULL;
-+    VERIFY_ENTRY (de);
-+    if (namelen != NULL) *namelen = de->namelen;
-+    return de->name;
-+}   /*  End Function devfs_get_name  */
-+
-+
-+/**
-+ *    devfs_register_chrdev - Optionally register a conventional character driver.
-+ *    @major: The major number for the driver.
-+ *    @name: The name of the driver (as seen in /proc/devices).
-+ *    @fops: The &file_operations structure pointer.
-+ *
-+ *    This function will register a character driver provided the "devfs=only"
-+ *    option was not provided at boot time.
-+ *    Returns 0 on success, else a negative error code on failure.
-+ */
-+
-+int devfs_register_chrdev (unsigned int major, const char *name,
-+                         struct file_operations *fops)
-+{
-+    if (boot_options & OPTION_ONLY) return 0;
-+    return register_chrdev (major, name, fops);
-+}   /*  End Function devfs_register_chrdev  */
-+
-+
-+/**
-+ *    devfs_register_blkdev - Optionally register a conventional block driver.
-+ *    @major: The major number for the driver.
-+ *    @name: The name of the driver (as seen in /proc/devices).
-+ *    @bdops: The &block_device_operations structure pointer.
-+ *
-+ *    This function will register a block driver provided the "devfs=only"
-+ *    option was not provided at boot time.
-+ *    Returns 0 on success, else a negative error code on failure.
-+ */
-+
-+int devfs_register_blkdev (unsigned int major, const char *name,
-+                         struct block_device_operations *bdops)
-+{
-+    if (boot_options & OPTION_ONLY) return 0;
-+    return register_blkdev (major, name, bdops);
-+}   /*  End Function devfs_register_blkdev  */
-+
-+
-+/**
-+ *    devfs_unregister_chrdev - Optionally unregister a conventional character driver.
-+ *    @major: The major number for the driver.
-+ *    @name: The name of the driver (as seen in /proc/devices).
-+ *
-+ *    This function will unregister a character driver provided the "devfs=only"
-+ *    option was not provided at boot time.
-+ *    Returns 0 on success, else a negative error code on failure.
-+ */
-+
-+int devfs_unregister_chrdev (unsigned int major, const char *name)
-+{
-+    if (boot_options & OPTION_ONLY) return 0;
-+    return unregister_chrdev (major, name);
-+}   /*  End Function devfs_unregister_chrdev  */
-+
-+
-+/**
-+ *    devfs_unregister_blkdev - Optionally unregister a conventional block driver.
-+ *    @major: The major number for the driver.
-+ *    @name: The name of the driver (as seen in /proc/devices).
-+ *
-+ *    This function will unregister a block driver provided the "devfs=only"
-+ *    option was not provided at boot time.
-+ *    Returns 0 on success, else a negative error code on failure.
-+ */
-+
-+int devfs_unregister_blkdev (unsigned int major, const char *name)
-+{
-+    if (boot_options & OPTION_ONLY) return 0;
-+    return unregister_blkdev (major, name);
-+}   /*  End Function devfs_unregister_blkdev  */
-+
-+/**
-+ *    devfs_setup - Process kernel boot options.
-+ *    @str: The boot options after the "devfs=".
-+ */
-+
-+static int __init devfs_setup (char *str)
-+{
-+    static struct
-+    {
-+      char *name;
-+      unsigned int mask;
-+      unsigned int *opt;
-+    } devfs_options_tab[] __initdata =
-+    {
-+#ifdef CONFIG_DEVFS_DEBUG
-+      {"dall",      DEBUG_ALL,          &devfs_debug_init},
-+      {"dmod",      DEBUG_MODULE_LOAD,  &devfs_debug_init},
-+      {"dreg",      DEBUG_REGISTER,     &devfs_debug_init},
-+      {"dunreg",    DEBUG_UNREGISTER,   &devfs_debug_init},
-+      {"dfree",     DEBUG_FREE,         &devfs_debug_init},
-+      {"diget",     DEBUG_I_GET,        &devfs_debug_init},
-+      {"dchange",   DEBUG_SET_FLAGS,    &devfs_debug_init},
-+      {"dsread",    DEBUG_S_READ,       &devfs_debug_init},
-+      {"dichange",  DEBUG_I_CHANGE,     &devfs_debug_init},
-+      {"dimknod",   DEBUG_I_MKNOD,      &devfs_debug_init},
-+      {"dilookup",  DEBUG_I_LOOKUP,     &devfs_debug_init},
-+      {"diunlink",  DEBUG_I_UNLINK,     &devfs_debug_init},
-+#endif  /*  CONFIG_DEVFS_DEBUG  */
-+      {"only",      OPTION_ONLY,        &boot_options},
-+      {"mount",     OPTION_MOUNT,       &boot_options},
-+      {NULL,        0,                  NULL}
-+    };
-+
-+    while ( (*str != '\0') && !isspace (*str) )
-+    {
-+      int i, found = 0, invert = 0;
-+
-+      if (strncmp (str, "no", 2) == 0)
-+      {
-+          invert = 1;
-+          str += 2;
-+      }
-+      for (i = 0; devfs_options_tab[i].name != NULL; i++)
-+      {
-+          int len = strlen (devfs_options_tab[i].name);
-+
-+          if (strncmp (str, devfs_options_tab[i].name, len) == 0)
-+          {
-+              if (invert)
-+                  *devfs_options_tab[i].opt &= ~devfs_options_tab[i].mask;
-+              else
-+                  *devfs_options_tab[i].opt |= devfs_options_tab[i].mask;
-+              str += len;
-+              found = 1;
-+              break;
-+          }
-+      }
-+      if (!found) return 0;       /*  No match         */
-+      if (*str != ',') return 0;  /*  No more options  */
-+      ++str;
-+    }
-+    return 1;
-+}   /*  End Function devfs_setup  */
-+
-+__setup("devfs=", devfs_setup);
-+
-+EXPORT_SYMBOL(devfs_put);
-+EXPORT_SYMBOL(devfs_register);
-+EXPORT_SYMBOL(devfs_unregister);
-+EXPORT_SYMBOL(devfs_mk_symlink);
-+EXPORT_SYMBOL(devfs_mk_dir);
-+EXPORT_SYMBOL(devfs_get_handle);
-+EXPORT_SYMBOL(devfs_find_handle);
-+EXPORT_SYMBOL(devfs_get_flags);
-+EXPORT_SYMBOL(devfs_set_flags);
-+EXPORT_SYMBOL(devfs_get_maj_min);
-+EXPORT_SYMBOL(devfs_get_handle_from_inode);
-+EXPORT_SYMBOL(devfs_generate_path);
-+EXPORT_SYMBOL(devfs_get_ops);
-+EXPORT_SYMBOL(devfs_set_file_size);
-+EXPORT_SYMBOL(devfs_get_info);
-+EXPORT_SYMBOL(devfs_set_info);
-+EXPORT_SYMBOL(devfs_get_parent);
-+EXPORT_SYMBOL(devfs_get_first_child);
-+EXPORT_SYMBOL(devfs_get_next_sibling);
-+EXPORT_SYMBOL(devfs_auto_unregister);
-+EXPORT_SYMBOL(devfs_get_unregister_slave);
-+EXPORT_SYMBOL(devfs_get_name);
-+EXPORT_SYMBOL(devfs_register_chrdev);
-+EXPORT_SYMBOL(devfs_register_blkdev);
-+EXPORT_SYMBOL(devfs_unregister_chrdev);
-+EXPORT_SYMBOL(devfs_unregister_blkdev);
-+
-+
-+/**
-+ *    try_modload - Notify devfsd of an inode lookup by a non-devfsd process.
-+ *    @parent: The parent devfs entry.
-+ *    @fs_info: The filesystem info.
-+ *    @name: The device name.
-+ *    @namelen: The number of characters in @name.
-+ *    @buf: A working area that will be used. This must not go out of scope
-+ *            until devfsd is idle again.
-+ *
-+ *    Returns 0 on success (event was queued), else a negative error code.
-+ */
-+
-+static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info,
-+                      const char *name, unsigned namelen,
-+                      struct devfs_entry *buf)
-+{
-+    if ( !( fs_info->devfsd_event_mask & (1 << DEVFSD_NOTIFY_LOOKUP) ) )
-+      return -ENOENT;
-+    if ( is_devfsd_or_child (fs_info) ) return -ENOENT;
-+    memset (buf, 0, sizeof *buf);
-+    atomic_set (&buf->refcount, 1);
-+    buf->parent = parent;
-+    buf->namelen = namelen;
-+    buf->u.name = name;
-+    WRITE_ENTRY_MAGIC (buf, MAGIC_VALUE);
-+    if ( !devfsd_notify_de (buf, DEVFSD_NOTIFY_LOOKUP, 0,
-+                          current->euid, current->egid, fs_info, 0) )
-+      return -ENOENT;
-+    /*  Possible success: event has been queued  */
-+    return 0;
-+}   /*  End Function try_modload  */
-+
-+
-+/**
-+ *    check_disc_changed - Check if a removable disc was changed.
-+ *    @de: The device.
-+ *
-+ *    Returns 1 if the media was changed, else 0.
-+ *
-+ *    This function may block, and may indirectly cause the parent directory
-+ *    contents to be changed due to partition re-reading.
-+ */
-+
-+static int check_disc_changed (struct devfs_entry *de)
-+{
-+    int tmp;
-+    int retval = 0;
-+    kdev_t dev = mk_kdev (de->u.fcb.u.device.major, de->u.fcb.u.device.minor);
-+    struct block_device_operations *bdops;
-+    extern int warn_no_part;
-+
-+    if ( !S_ISBLK (de->mode) ) return 0;
-+    bdops = devfs_get_ops (de);
-+    if (!bdops) return 0;
-+    if (bdops->check_media_change == NULL) goto out;
-+    if ( !bdops->check_media_change (dev) ) goto out;
-+    retval = 1;
-+    printk (KERN_DEBUG "VFS: Disk change detected on device %s\n",
-+           kdevname (dev) );
-+    if ( invalidate_device (dev, 0) )
-+      printk (KERN_WARNING "VFS: busy inodes on changed media..\n");
-+    /*  Ugly hack to disable messages about unable to read partition table  */
-+    tmp = warn_no_part;
-+    warn_no_part = 0;
-+    if (bdops->revalidate) bdops->revalidate (dev);
-+    warn_no_part = tmp;
-+out:
-+    devfs_put_ops (de);
-+    return retval;
-+}   /*  End Function check_disc_changed  */
-+
-+
-+/**
-+ *    scan_dir_for_removable - Scan a directory for removable media devices and check media.
-+ *    @dir: The directory.
-+ *
-+ *    This function may block, and may indirectly cause the directory
-+ *    contents to be changed due to partition re-reading. The directory will
-+ *    be locked for reading.
-+ */
-+
-+static void scan_dir_for_removable (struct devfs_entry *dir)
-+{
-+    struct devfs_entry *de;
-+
-+    read_lock (&dir->u.dir.lock);
-+    if (dir->u.dir.num_removable < 1) de = NULL;
-+    else
-+    {
-+      for (de = dir->u.dir.first; de != NULL; de = de->next)
-+      {
-+          if (S_ISBLK (de->mode) && de->u.fcb.removable) break;
-+      }
-+      devfs_get (de);
-+    }
-+    read_unlock (&dir->u.dir.lock);
-+    if (de) check_disc_changed (de);
-+    devfs_put (de);
-+}   /*  End Function scan_dir_for_removable  */
-+
-+/**
-+ *    get_removable_partition - Get removable media partition.
-+ *    @dir: The parent directory.
-+ *    @name: The name of the entry.
-+ *    @namelen: The number of characters in <<name>>.
-+ *
-+ *    Returns 1 if the media was changed, else 0.
-+ *
-+ *    This function may block, and may indirectly cause the directory
-+ *    contents to be changed due to partition re-reading. The directory must
-+ *    be locked for reading upon entry, and will be unlocked upon exit.
-+ */
-+
-+static int get_removable_partition (struct devfs_entry *dir, const char *name,
-+                                  unsigned int namelen)
-+{
-+    int retval;
-+    struct devfs_entry *de;
-+
-+    if (dir->u.dir.num_removable < 1)
-+    {
-+      read_unlock (&dir->u.dir.lock);
-+      return 0;
-+    }
-+    for (de = dir->u.dir.first; de != NULL; de = de->next)
-+    {
-+      if (!S_ISBLK (de->mode) || !de->u.fcb.removable) continue;
-+      if (strcmp (de->name, "disc") == 0) break;
-+      /*  Support for names where the partition is appended to the disc name
-+       */
-+      if (de->namelen >= namelen) continue;
-+      if (strncmp (de->name, name, de->namelen) == 0) break;
-+    }
-+    devfs_get (de);
-+    read_unlock (&dir->u.dir.lock);
-+    retval = de ? check_disc_changed (de) : 0;
-+    devfs_put (de);
-+    return retval;
-+}   /*  End Function get_removable_partition  */
-+
-+
-+/*  Superblock operations follow  */
-+
-+static struct inode_operations devfs_iops;
-+static struct inode_operations devfs_dir_iops;
-+static struct file_operations devfs_fops;
-+static struct file_operations devfs_dir_fops;
-+static struct inode_operations devfs_symlink_iops;
-+
-+static int devfs_notify_change (struct dentry *dentry, struct iattr *iattr)
-+{
-+    int retval;
-+    struct devfs_entry *de;
-+    struct inode *inode = dentry->d_inode;
-+    struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
-+
-+    de = get_devfs_entry_from_vfs_inode (inode);
-+    if (de == NULL) return -ENODEV;
-+    retval = inode_change_ok (inode, iattr);
-+    if (retval != 0) return retval;
-+    retval = inode_setattr (inode, iattr);
-+    if (retval != 0) return retval;
-+    DPRINTK (DEBUG_I_CHANGE, "(%d): VFS inode: %p  devfs_entry: %p\n",
-+           (int) inode->i_ino, inode, de);
-+    DPRINTK (DEBUG_I_CHANGE, "():   mode: 0%o  uid: %d  gid: %d\n",
-+           (int) inode->i_mode, (int) inode->i_uid, (int) inode->i_gid);
-+    /*  Inode is not on hash chains, thus must save permissions here rather
-+      than in a write_inode() method  */
-+    if ( ( !S_ISREG (inode->i_mode) && !S_ISCHR (inode->i_mode) &&
-+         !S_ISBLK (inode->i_mode) ) || !de->u.fcb.auto_owner )
-+    {
-+      de->mode = inode->i_mode;
-+      de->inode.uid = inode->i_uid;
-+      de->inode.gid = inode->i_gid;
-+    }
-+    de->inode.atime = inode->i_atime;
-+    de->inode.mtime = inode->i_mtime;
-+    de->inode.ctime = inode->i_ctime;
-+    if ( ( iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID) ) &&
-+       !is_devfsd_or_child (fs_info) )
-+      devfsd_notify_de (de, DEVFSD_NOTIFY_CHANGE, inode->i_mode,
-+                        inode->i_uid, inode->i_gid, fs_info, 0);
-+    return 0;
-+}   /*  End Function devfs_notify_change  */
-+
-+static int devfs_statfs (struct super_block *sb, struct statfs *buf)
-+{
-+    buf->f_type = DEVFS_SUPER_MAGIC;
-+    buf->f_bsize = FAKE_BLOCK_SIZE;
-+    buf->f_bfree = 0;
-+    buf->f_bavail = 0;
-+    buf->f_ffree = 0;
-+    buf->f_namelen = NAME_MAX;
-+    return 0;
-+}   /*  End Function devfs_statfs  */
-+
-+static void devfs_clear_inode (struct inode *inode)
-+{
-+    if ( S_ISBLK (inode->i_mode) ) bdput (inode->i_bdev);
-+}   /*  End Function devfs_clear_inode  */
-+
-+static struct super_operations devfs_sops =
-+{ 
-+    put_inode:     force_delete,
-+    clear_inode:   devfs_clear_inode,
-+    statfs:        devfs_statfs,
-+};
-+
-+
-+/**
-+ *    _devfs_get_vfs_inode - Get a VFS inode.
-+ *    @sb: The super block.
-+ *    @de: The devfs inode.
-+ *    @dentry: The dentry to register with the devfs inode.
-+ *
-+ *    Returns the inode on success, else %NULL. An implicit devfs_get() is
-+ *       performed if the inode is created.
-+ */
-+
-+static struct inode *_devfs_get_vfs_inode (struct super_block *sb,
-+                                         struct devfs_entry *de,
-+                                         struct dentry *dentry)
-+{
-+    int is_fcb = FALSE;
-+    struct inode *inode;
-+
-+    if (de->prev == de) return NULL;  /*  Quick check to see if unhooked  */
-+    if ( ( inode = new_inode (sb) ) == NULL )
-+    {
-+      PRINTK ("(%s): new_inode() failed, de: %p\n", de->name, de);
-+      return NULL;
-+    }
-+    if (de->parent)
-+    {
-+      read_lock (&de->parent->u.dir.lock);
-+      if (de->prev != de) de->inode.dentry = dentry; /*      Not unhooked  */
-+      read_unlock (&de->parent->u.dir.lock);
-+    }
-+    else de->inode.dentry = dentry;             /*  Root: no locking needed  */
-+    if (de->inode.dentry != dentry)
-+    {   /*  Must have been unhooked  */
-+      iput (inode);
-+      return NULL;
-+    }
-+    inode->u.generic_ip = devfs_get (de);
-+    inode->i_ino = de->inode.ino;
-+    DPRINTK (DEBUG_I_GET, "(%d): VFS inode: %p  devfs_entry: %p\n",
-+           (int) inode->i_ino, inode, de);
-+    inode->i_blocks = 0;
-+    inode->i_blksize = FAKE_BLOCK_SIZE;
-+    inode->i_op = &devfs_iops;
-+    inode->i_fop = &devfs_fops;
-+    inode->i_rdev = NODEV;
-+    if ( S_ISCHR (de->mode) )
-+    {
-+      inode->i_rdev = mk_kdev (de->u.fcb.u.device.major,
-+                               de->u.fcb.u.device.minor);
-+      inode->i_cdev = cdget ( kdev_t_to_nr (inode->i_rdev) );
-+      is_fcb = TRUE;
-+    }
-+    else if ( S_ISBLK (de->mode) )
-+    {
-+      inode->i_rdev = mk_kdev (de->u.fcb.u.device.major,
-+                               de->u.fcb.u.device.minor);
-+      if (bd_acquire (inode) == 0)
-+      {
-+          if (!inode->i_bdev->bd_op && de->u.fcb.ops)
-+              inode->i_bdev->bd_op = de->u.fcb.ops;
-+      }
-+      else PRINTK ("(%d): no block device from bdget()\n",(int)inode->i_ino);
-+      is_fcb = TRUE;
-+    }
-+    else if ( S_ISFIFO (de->mode) ) inode->i_fop = &def_fifo_fops;
-+    else if ( S_ISREG (de->mode) )
-+    {
-+      inode->i_size = de->u.fcb.u.file.size;
-+      is_fcb = TRUE;
-+    }
-+    else if ( S_ISDIR (de->mode) )
-+    {
-+      inode->i_op = &devfs_dir_iops;
-+      inode->i_fop = &devfs_dir_fops;
-+    }
-+    else if ( S_ISLNK (de->mode) )
-+    {
-+      inode->i_op = &devfs_symlink_iops;
-+      inode->i_size = de->u.symlink.length;
-+    }
-+    if (is_fcb && de->u.fcb.auto_owner)
-+      inode->i_mode = (de->mode & S_IFMT) | S_IRUGO | S_IWUGO;
-+    else inode->i_mode = de->mode;
-+    inode->i_uid = de->inode.uid;
-+    inode->i_gid = de->inode.gid;
-+    inode->i_atime = de->inode.atime;
-+    inode->i_mtime = de->inode.mtime;
-+    inode->i_ctime = de->inode.ctime;
-+    DPRINTK (DEBUG_I_GET, "():   mode: 0%o  uid: %d  gid: %d\n",
-+           (int) inode->i_mode, (int) inode->i_uid, (int) inode->i_gid);
-+    return inode;
-+}   /*  End Function _devfs_get_vfs_inode  */
-+
-+
-+/*  File operations for device entries follow  */
-+
-+static int devfs_readdir (struct file *file, void *dirent, filldir_t filldir)
-+{
-+    int err, count;
-+    int stored = 0;
-+    struct fs_info *fs_info;
-+    struct devfs_entry *parent, *de, *next = NULL;
-+    struct inode *inode = file->f_dentry->d_inode;
-+
-+    fs_info = inode->i_sb->u.generic_sbp;
-+    parent = get_devfs_entry_from_vfs_inode (file->f_dentry->d_inode);
-+    if ( (long) file->f_pos < 0 ) return -EINVAL;
-+    DPRINTK (DEBUG_F_READDIR, "(%s): fs_info: %p  pos: %ld\n",
-+           parent->name, fs_info, (long) file->f_pos);
-+    switch ( (long) file->f_pos )
-+    {
-+      case 0:
-+      scan_dir_for_removable (parent);
-+      err = (*filldir) (dirent, "..", 2, file->f_pos,
-+                        file->f_dentry->d_parent->d_inode->i_ino, DT_DIR);
-+      if (err == -EINVAL) break;
-+      if (err < 0) return err;
-+      file->f_pos++;
-+      ++stored;
-+      /*  Fall through  */
-+      case 1:
-+      err = (*filldir) (dirent, ".", 1, file->f_pos, inode->i_ino, DT_DIR);
-+      if (err == -EINVAL) break;
-+      if (err < 0) return err;
-+      file->f_pos++;
-+      ++stored;
-+      /*  Fall through  */
-+      default:
-+      /*  Skip entries  */
-+      count = file->f_pos - 2;
-+      read_lock (&parent->u.dir.lock);
-+      for (de = parent->u.dir.first; de && (count > 0); de = de->next)
-+          if ( !IS_HIDDEN (de) ) --count;
-+      devfs_get (de);
-+      read_unlock (&parent->u.dir.lock);
-+      /*  Now add all remaining entries  */
-+      while (de)
-+      {
-+          if ( IS_HIDDEN (de) ) err = 0;
-+          else
-+          {
-+              err = (*filldir) (dirent, de->name, de->namelen,
-+                                file->f_pos, de->inode.ino, de->mode >> 12);
-+              if (err >= 0)
-+              {
-+                  file->f_pos++;
-+                  ++stored;
-+              }
-+          }
-+          read_lock (&parent->u.dir.lock);
-+          next = devfs_get (de->next);
-+          read_unlock (&parent->u.dir.lock);
-+          devfs_put (de);
-+          de = next;
-+          if (err == -EINVAL) break;
-+          if (err < 0) return err;
-+      }
-+      break;
-+    }
-+    return stored;
-+}   /*  End Function devfs_readdir  */
-+
-+static int devfs_open (struct inode *inode, struct file *file)
-+{
-+    int err;
-+    struct fcb_type *df;
-+    struct devfs_entry *de;
-+    struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
-+
-+    de = get_devfs_entry_from_vfs_inode (inode);
-+    if (de == NULL) return -ENODEV;
-+    if ( S_ISDIR (de->mode) ) return 0;
-+    df = &de->u.fcb;
-+    file->private_data = de->info;
-+    if ( S_ISBLK (inode->i_mode) )
-+    {
-+      file->f_op = &def_blk_fops;
-+      if (df->ops) inode->i_bdev->bd_op = df->ops;
-+      err = def_blk_fops.open (inode, file);
-+    }
-+    else
-+    {
-+      file->f_op = fops_get ( (struct file_operations *) df->ops );
-+      if (file->f_op)
-+      {
-+          lock_kernel ();
-+          err = file->f_op->open ? (*file->f_op->open) (inode, file) : 0;
-+          unlock_kernel ();
-+      }
-+      else
-+      {   /*  Fallback to legacy scheme  */
-+          if ( S_ISCHR (inode->i_mode) ) err = chrdev_open (inode, file);
-+          else err = -ENODEV;
-+      }
-+    }
-+    if (err < 0) return err;
-+    /*  Open was successful  */
-+    if (df->open) return 0;
-+    df->open = TRUE;  /*  This is the first open  */
-+    if (df->auto_owner)
-+    {
-+      /*  Change the ownership/protection to what driver specified  */
-+      inode->i_mode = de->mode;
-+      inode->i_uid = current->euid;
-+      inode->i_gid = current->egid;
-+    }
-+    if ( df->aopen_notify && !is_devfsd_or_child (fs_info) )
-+      devfsd_notify_de (de, DEVFSD_NOTIFY_ASYNC_OPEN, inode->i_mode,
-+                        current->euid, current->egid, fs_info, 0);
-+    return 0;
-+}   /*  End Function devfs_open  */
-+
-+static struct file_operations devfs_fops =
-+{
-+    open:    devfs_open,
-+};
-+
-+static struct file_operations devfs_dir_fops =
-+{
-+    read:    generic_read_dir,
-+    readdir: devfs_readdir,
-+    open:    devfs_open,
-+};
-+
-+
-+/*  Dentry operations for device entries follow  */
-+
-+
-+/**
-+ *    devfs_d_release - Callback for when a dentry is freed.
-+ *    @dentry: The dentry.
-+ */
-+
-+static void devfs_d_release (struct dentry *dentry)
-+{
-+    DPRINTK (DEBUG_D_RELEASE, "(%p): inode: %p\n", dentry, dentry->d_inode);
-+}   /*  End Function devfs_d_release  */
-+
-+/**
-+ *    devfs_d_iput - Callback for when a dentry loses its inode.
-+ *    @dentry: The dentry.
-+ *    @inode: The inode.
-+ */
-+
-+static void devfs_d_iput (struct dentry *dentry, struct inode *inode)
-+{
-+    struct devfs_entry *de;
-+
-+    de = get_devfs_entry_from_vfs_inode (inode);
-+    DPRINTK (DEBUG_D_IPUT,"(%s): dentry: %p inode: %p de: %p de->dentry: %p\n",
-+           de->name, dentry, inode, de, de->inode.dentry);
-+    if ( de->inode.dentry && (de->inode.dentry != dentry) )
-+      OOPS ("(%s): de: %p dentry: %p de->dentry: %p\n",
-+            de->name, de, dentry, de->inode.dentry);
-+    de->inode.dentry = NULL;
-+    iput (inode);
-+    devfs_put (de);
-+}   /*  End Function devfs_d_iput  */
-+
-+static int devfs_d_delete (struct dentry *dentry);
-+
-+static struct dentry_operations devfs_dops =
-+{
-+    d_delete:     devfs_d_delete,
-+    d_release:    devfs_d_release,
-+    d_iput:       devfs_d_iput,
-+};
-+
-+static int devfs_d_revalidate_wait (struct dentry *dentry, int flags);
-+
-+static struct dentry_operations devfs_wait_dops =
-+{
-+    d_delete:     devfs_d_delete,
-+    d_release:    devfs_d_release,
-+    d_iput:       devfs_d_iput,
-+    d_revalidate: devfs_d_revalidate_wait,
-+};
-+
-+/**
-+ *    devfs_d_delete - Callback for when all files for a dentry are closed.
-+ *    @dentry: The dentry.
-+ */
-+
-+static int devfs_d_delete (struct dentry *dentry)
-+{
-+    struct inode *inode = dentry->d_inode;
-+    struct devfs_entry *de;
-+    struct fs_info *fs_info;
-+
-+    if (dentry->d_op == &devfs_wait_dops) dentry->d_op = &devfs_dops;
-+    /*  Unhash dentry if negative (has no inode)  */
-+    if (inode == NULL)
-+    {
-+      DPRINTK (DEBUG_D_DELETE, "(%p): dropping negative dentry\n", dentry);
-+      return 1;
-+    }
-+    fs_info = inode->i_sb->u.generic_sbp;
-+    de = get_devfs_entry_from_vfs_inode (inode);
-+    DPRINTK (DEBUG_D_DELETE, "(%p): inode: %p  devfs_entry: %p\n",
-+           dentry, inode, de);
-+    if (de == NULL) return 0;
-+    if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) )
-+      return 0;
-+    if (!de->u.fcb.open) return 0;
-+    de->u.fcb.open = FALSE;
-+    if (de->u.fcb.aopen_notify)
-+      devfsd_notify_de (de, DEVFSD_NOTIFY_CLOSE, inode->i_mode,
-+                        current->euid, current->egid, fs_info, 1);
-+    if (!de->u.fcb.auto_owner) return 0;
-+    /*  Change the ownership/protection back  */
-+    inode->i_mode = (de->mode & S_IFMT) | S_IRUGO | S_IWUGO;
-+    inode->i_uid = de->inode.uid;
-+    inode->i_gid = de->inode.gid;
-+    return 0;
-+}   /*  End Function devfs_d_delete  */
-+
-+struct devfs_lookup_struct
-+{
-+    devfs_handle_t de;
-+    wait_queue_head_t wait_queue;
-+};
-+
-+static int devfs_d_revalidate_wait (struct dentry *dentry, int flags)
-+{
-+    struct inode *dir = dentry->d_parent->d_inode;
-+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
-+    devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir);
-+    struct devfs_lookup_struct *lookup_info = dentry->d_fsdata;
-+    DECLARE_WAITQUEUE (wait, current);
-+
-+    if ( is_devfsd_or_child (fs_info) )
-+    {
-+      devfs_handle_t de = lookup_info->de;
-+      struct inode *inode;
-+
-+      DPRINTK (DEBUG_I_LOOKUP,
-+               "(%s): dentry: %p inode: %p de: %p by: \"%s\"\n",
-+               dentry->d_name.name, dentry, dentry->d_inode, de,
-+               current->comm);
-+      if (dentry->d_inode) return 1;
-+      if (de == NULL)
-+      {
-+          read_lock (&parent->u.dir.lock);
-+          de = _devfs_search_dir (parent, dentry->d_name.name,
-+                                  dentry->d_name.len);
-+          read_unlock (&parent->u.dir.lock);
-+          if (de == NULL) return 1;
-+          lookup_info->de = de;
-+      }
-+      /*  Create an inode, now that the driver information is available  */
-+      inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry);
-+      if (!inode) return 1;
-+      DPRINTK (DEBUG_I_LOOKUP,
-+               "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n",
-+               de->name, de->inode.ino, inode, de, current->comm);
-+      d_instantiate (dentry, inode);
-+      return 1;
-+    }
-+    if (lookup_info == NULL) return 1;  /*  Early termination  */
-+    read_lock (&parent->u.dir.lock);
-+    if (dentry->d_fsdata)
-+    {
-+      add_wait_queue (&lookup_info->wait_queue, &wait);
-+      current->state = TASK_UNINTERRUPTIBLE;
-+      read_unlock (&parent->u.dir.lock);
-+      schedule ();
-+    }
-+    else read_unlock (&parent->u.dir.lock);
-+    return 1;
-+}   /*  End Function devfs_d_revalidate_wait  */
-+
-+
-+/*  Inode operations for device entries follow  */
-+
-+static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry)
-+{
-+    struct devfs_entry tmp;  /*  Must stay in scope until devfsd idle again  */
-+    struct devfs_lookup_struct lookup_info;
-+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
-+    struct devfs_entry *parent, *de;
-+    struct inode *inode;
-+    struct dentry *retval = NULL;
-+
-+    /*  Set up the dentry operations before anything else, to ensure cleaning
-+      up on any error  */
-+    dentry->d_op = &devfs_dops;
-+    /*  First try to get the devfs entry for this directory  */
-+    parent = get_devfs_entry_from_vfs_inode (dir);
-+    DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p parent: %p by: \"%s\"\n",
-+           dentry->d_name.name, dentry, parent, current->comm);
-+    if (parent == NULL) return ERR_PTR (-ENOENT);
-+    read_lock (&parent->u.dir.lock);
-+    de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len);
-+    if (de) read_unlock (&parent->u.dir.lock);
-+    else
-+    {   /*  Try re-reading the partition (media may have changed)  */
-+      if ( get_removable_partition (parent, dentry->d_name.name,
-+                                    dentry->d_name.len) )  /*  Unlocks  */
-+      {   /*  Media did change  */
-+          read_lock (&parent->u.dir.lock);
-+          de = _devfs_search_dir (parent, dentry->d_name.name,
-+                                  dentry->d_name.len);
-+          read_unlock (&parent->u.dir.lock);
-+      }
-+    }
-+    lookup_info.de = de;
-+    init_waitqueue_head (&lookup_info.wait_queue);
-+    dentry->d_fsdata = &lookup_info;
-+    if (de == NULL)
-+    {   /*  Try with devfsd. For any kind of failure, leave a negative dentry
-+          so someone else can deal with it (in the case where the sysadmin
-+          does a mknod()). It's important to do this before hashing the
-+          dentry, so that the devfsd queue is filled before revalidates
-+          can start  */
-+      if (try_modload (parent, fs_info,
-+                       dentry->d_name.name, dentry->d_name.len, &tmp) < 0)
-+      {   /*  Lookup event was not queued to devfsd  */
-+          d_add (dentry, NULL);
-+          return NULL;
-+      }
-+    }
-+    dentry->d_op = &devfs_wait_dops;
-+    d_add (dentry, NULL);  /*  Open the floodgates  */
-+    /*  Unlock directory semaphore, which will release any waiters. They
-+      will get the hashed dentry, and may be forced to wait for
-+      revalidation  */
-+    up (&dir->i_sem);
-+    wait_for_devfsd_finished (fs_info);  /*  If I'm not devfsd, must wait  */
-+    down (&dir->i_sem);      /*  Grab it again because them's the rules  */
-+    de = lookup_info.de;
-+    /*  If someone else has been so kind as to make the inode, we go home
-+      early  */
-+    if (dentry->d_inode) goto out;
-+    if (de == NULL)
-+    {
-+      read_lock (&parent->u.dir.lock);
-+      de = _devfs_search_dir (parent, dentry->d_name.name,
-+                              dentry->d_name.len);
-+      read_unlock (&parent->u.dir.lock);
-+      if (de == NULL) goto out;
-+      /*  OK, there's an entry now, but no VFS inode yet  */
-+    }
-+    /*  Create an inode, now that the driver information is available  */
-+    inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry);
-+    if (!inode)
-+    {
-+      retval = ERR_PTR (-ENOMEM);
-+      goto out;
-+    }
-+    DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n",
-+           de->name, de->inode.ino, inode, de, current->comm);
-+    d_instantiate (dentry, inode);
-+out:
-+    dentry->d_op = &devfs_dops;
-+    dentry->d_fsdata = NULL;
-+    write_lock (&parent->u.dir.lock);
-+    wake_up (&lookup_info.wait_queue);
-+    write_unlock (&parent->u.dir.lock);
-+    devfs_put (de);
-+    return retval;
-+}   /*  End Function devfs_lookup  */
-+
-+static int devfs_unlink (struct inode *dir, struct dentry *dentry)
-+{
-+    int unhooked;
-+    struct devfs_entry *de;
-+    struct inode *inode = dentry->d_inode;
-+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
-+
-+    de = get_devfs_entry_from_vfs_inode (inode);
-+    DPRINTK (DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de);
-+    if (de == NULL) return -ENOENT;
-+    if (!de->vfs_deletable) return -EPERM;
-+    write_lock (&de->parent->u.dir.lock);
-+    unhooked = _devfs_unhook (de);
-+    write_unlock (&de->parent->u.dir.lock);
-+    if (!unhooked) return -ENOENT;
-+    if ( !is_devfsd_or_child (fs_info) )
-+      devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
-+                        inode->i_uid, inode->i_gid, fs_info, 0);
-+    free_dentry (de);
-+    devfs_put (de);
-+    return 0;
-+}   /*  End Function devfs_unlink  */
-+
-+static int devfs_symlink (struct inode *dir, struct dentry *dentry,
-+                        const char *symname)
-+{
-+    int err;
-+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
-+    struct devfs_entry *parent, *de;
-+    struct inode *inode;
-+
-+    /*  First try to get the devfs entry for this directory  */
-+    parent = get_devfs_entry_from_vfs_inode (dir);
-+    if (parent == NULL) return -ENOENT;
-+    err = devfs_do_symlink (parent, dentry->d_name.name, DEVFS_FL_NONE,
-+                          symname, &de, NULL);
-+    DPRINTK (DEBUG_DISABLED, "(%s): errcode from <devfs_do_symlink>: %d\n",
-+           dentry->d_name.name, err);
-+    if (err < 0) return err;
-+    de->vfs_deletable = TRUE;
-+    de->inode.uid = current->euid;
-+    de->inode.gid = current->egid;
-+    de->inode.atime = CURRENT_TIME;
-+    de->inode.mtime = CURRENT_TIME;
-+    de->inode.ctime = CURRENT_TIME;
-+    if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
-+      return -ENOMEM;
-+    DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p  dentry: %p\n",
-+           dentry->d_name.name, de->inode.ino, inode, dentry);
-+    d_instantiate (dentry, inode);
-+    if ( !is_devfsd_or_child (fs_info) )
-+      devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
-+                        inode->i_uid, inode->i_gid, fs_info, 0);
-+    return 0;
-+}   /*  End Function devfs_symlink  */
-+
-+static int devfs_mkdir (struct inode *dir, struct dentry *dentry, int mode)
-+{
-+    int err;
-+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
-+    struct devfs_entry *parent, *de;
-+    struct inode *inode;
-+
-+    mode = (mode & ~S_IFMT) | S_IFDIR;  /*  VFS doesn't pass S_IFMT part  */
-+    parent = get_devfs_entry_from_vfs_inode (dir);
-+    if (parent == NULL) return -ENOENT;
-+    de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
-+    if (!de) return -ENOMEM;
-+    de->vfs_deletable = TRUE;
-+    if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
-+      return err;
-+    de->inode.uid = current->euid;
-+    de->inode.gid = current->egid;
-+    de->inode.atime = CURRENT_TIME;
-+    de->inode.mtime = CURRENT_TIME;
-+    de->inode.ctime = CURRENT_TIME;
-+    if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
-+      return -ENOMEM;
-+    DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p  dentry: %p\n",
-+           dentry->d_name.name, de->inode.ino, inode, dentry);
-+    d_instantiate (dentry, inode);
-+    if ( !is_devfsd_or_child (fs_info) )
-+      devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
-+                        inode->i_uid, inode->i_gid, fs_info, 0);
-+    return 0;
-+}   /*  End Function devfs_mkdir  */
-+
-+static int devfs_rmdir (struct inode *dir, struct dentry *dentry)
-+{
-+    int err = 0;
-+    struct devfs_entry *de;
-+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
-+    struct inode *inode = dentry->d_inode;
-+
-+    if (dir->i_sb->u.generic_sbp != inode->i_sb->u.generic_sbp) return -EINVAL;
-+    de = get_devfs_entry_from_vfs_inode (inode);
-+    if (de == NULL) return -ENOENT;
-+    if ( !S_ISDIR (de->mode) ) return -ENOTDIR;
-+    if (!de->vfs_deletable) return -EPERM;
-+    /*  First ensure the directory is empty and will stay that way  */
-+    write_lock (&de->u.dir.lock);
-+    if (de->u.dir.first) err = -ENOTEMPTY;
-+    else de->u.dir.no_more_additions = TRUE;
-+    write_unlock (&de->u.dir.lock);
-+    if (err) return err;
-+    /*  Now unhook the directory from it's parent  */
-+    write_lock (&de->parent->u.dir.lock);
-+    if ( !_devfs_unhook (de) ) err = -ENOENT;
-+    write_unlock (&de->parent->u.dir.lock);
-+    if (err) return err;
-+    if ( !is_devfsd_or_child (fs_info) )
-+      devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
-+                        inode->i_uid, inode->i_gid, fs_info, 0);
-+    free_dentry (de);
-+    devfs_put (de);
-+    return 0;
-+}   /*  End Function devfs_rmdir  */
-+
-+static int devfs_mknod (struct inode *dir, struct dentry *dentry, int mode,
-+                      int rdev)
-+{
-+    int err;
-+    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
-+    struct devfs_entry *parent, *de;
-+    struct inode *inode;
-+
-+    DPRINTK (DEBUG_I_MKNOD, "(%s): mode: 0%o  dev: %d\n",
-+           dentry->d_name.name, mode, rdev);
-+    parent = get_devfs_entry_from_vfs_inode (dir);
-+    if (parent == NULL) return -ENOENT;
-+    de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
-+    if (!de) return -ENOMEM;
-+    de->vfs_deletable = TRUE;
-+    if ( S_ISBLK (mode) || S_ISCHR (mode) )
-+    {
-+      de->u.fcb.u.device.major = MAJOR (rdev);
-+      de->u.fcb.u.device.minor = MINOR (rdev);
-+    }
-+    if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
-+      return err;
-+    de->inode.uid = current->euid;
-+    de->inode.gid = current->egid;
-+    de->inode.atime = CURRENT_TIME;
-+    de->inode.mtime = CURRENT_TIME;
-+    de->inode.ctime = CURRENT_TIME;
-+    if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
-+      return -ENOMEM;
-+    DPRINTK (DEBUG_I_MKNOD, ":   new VFS inode(%u): %p  dentry: %p\n",
-+           de->inode.ino, inode, dentry);
-+    d_instantiate (dentry, inode);
-+    if ( !is_devfsd_or_child (fs_info) )
-+      devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
-+                        inode->i_uid, inode->i_gid, fs_info, 0);
-+    return 0;
-+}   /*  End Function devfs_mknod  */
-+
-+static int devfs_readlink (struct dentry *dentry, char *buffer, int buflen)
-+{
-+    int err;
-+    struct devfs_entry *de;
-+
-+    de = get_devfs_entry_from_vfs_inode (dentry->d_inode);
-+    if (!de) return -ENODEV;
-+    err = vfs_readlink (dentry, buffer, buflen, de->u.symlink.linkname);
-+    return err;
-+}   /*  End Function devfs_readlink  */
-+
-+static int devfs_follow_link (struct dentry *dentry, struct nameidata *nd)
-+{
-+    int err;
-+    struct devfs_entry *de;
-+
-+    de = get_devfs_entry_from_vfs_inode (dentry->d_inode);
-+    if (!de) return -ENODEV;
-+    err = vfs_follow_link (nd, de->u.symlink.linkname);
-+    return err;
-+}   /*  End Function devfs_follow_link  */
-+
-+static struct inode_operations devfs_iops =
-+{
-+    setattr:        devfs_notify_change,
-+};
-+
-+static struct inode_operations devfs_dir_iops =
-+{
-+    lookup:         devfs_lookup,
-+    unlink:         devfs_unlink,
-+    symlink:        devfs_symlink,
-+    mkdir:          devfs_mkdir,
-+    rmdir:          devfs_rmdir,
-+    mknod:          devfs_mknod,
-+    setattr:        devfs_notify_change,
-+};
-+
-+static struct inode_operations devfs_symlink_iops =
-+{
-+    readlink:       devfs_readlink,
-+    follow_link:    devfs_follow_link,
-+    setattr:        devfs_notify_change,
-+};
-+
-+static struct super_block *devfs_read_super (struct super_block *sb,
-+                                           void *data, int silent)
-+{
-+    struct inode *root_inode = NULL;
-+
-+    if (_devfs_get_root_entry () == NULL) goto out_no_root;
-+    atomic_set (&fs_info.devfsd_overrun_count, 0);
-+    init_waitqueue_head (&fs_info.devfsd_wait_queue);
-+    init_waitqueue_head (&fs_info.revalidate_wait_queue);
-+    fs_info.sb = sb;
-+    sb->u.generic_sbp = &fs_info;
-+    sb->s_blocksize = 1024;
-+    sb->s_blocksize_bits = 10;
-+    sb->s_magic = DEVFS_SUPER_MAGIC;
-+    sb->s_op = &devfs_sops;
-+    if ( ( root_inode = _devfs_get_vfs_inode (sb, root_entry, NULL) ) == NULL )
-+      goto out_no_root;
-+    sb->s_root = d_alloc_root (root_inode);
-+    if (!sb->s_root) goto out_no_root;
-+    DPRINTK (DEBUG_S_READ, "(): made devfs ptr: %p\n", sb->u.generic_sbp);
-+    return sb;
-+
-+out_no_root:
-+    PRINTK ("(): get root inode failed\n");
-+    if (root_inode) iput (root_inode);
-+    return NULL;
-+}   /*  End Function devfs_read_super  */
-+
-+
-+static DECLARE_FSTYPE (devfs_fs_type, DEVFS_NAME, devfs_read_super, FS_SINGLE);
-+
-+
-+/*  File operations for devfsd follow  */
-+
-+static ssize_t devfsd_read (struct file *file, char *buf, size_t len,
-+                          loff_t *ppos)
-+{
-+    int done = FALSE;
-+    int ival;
-+    loff_t pos, devname_offset, tlen, rpos;
-+    devfs_handle_t de;
-+    struct devfsd_buf_entry *entry;
-+    struct fs_info *fs_info = file->f_dentry->d_inode->i_sb->u.generic_sbp;
-+    struct devfsd_notify_struct *info = fs_info->devfsd_info;
-+    DECLARE_WAITQUEUE (wait, current);
-+
-+    /*  Can't seek (pread) on this device  */
-+    if (ppos != &file->f_pos) return -ESPIPE;
-+    /*  Verify the task has grabbed the queue  */
-+    if (fs_info->devfsd_task != current) return -EPERM;
-+    info->major = 0;
-+    info->minor = 0;
-+    /*  Block for a new entry  */
-+    add_wait_queue (&fs_info->devfsd_wait_queue, &wait);
-+    current->state = TASK_INTERRUPTIBLE;
-+    while ( devfsd_queue_empty (fs_info) )
-+    {
-+      fs_info->devfsd_sleeping = TRUE;
-+      wake_up (&fs_info->revalidate_wait_queue);
-+      schedule ();
-+      fs_info->devfsd_sleeping = FALSE;
-+      if ( signal_pending (current) )
-+      {
-+          remove_wait_queue (&fs_info->devfsd_wait_queue, &wait);
-+          current->state = TASK_RUNNING;
-+          return -EINTR;
-+      }
-+      set_current_state (TASK_INTERRUPTIBLE);
-+    }
-+    remove_wait_queue (&fs_info->devfsd_wait_queue, &wait);
-+    current->state = TASK_RUNNING;
-+    /*  Now play with the data  */
-+    ival = atomic_read (&fs_info->devfsd_overrun_count);
-+    info->overrun_count = ival;
-+    entry = fs_info->devfsd_first_event;
-+    info->type = entry->type;
-+    info->mode = entry->mode;
-+    info->uid = entry->uid;
-+    info->gid = entry->gid;
-+    de = entry->de;
-+    if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) )
-+    {
-+      info->major = de->u.fcb.u.device.major;
-+      info->minor = de->u.fcb.u.device.minor;
-+    }
-+    pos = devfs_generate_path (de, info->devname, DEVFS_PATHLEN);
-+    if (pos < 0) return pos;
-+    info->namelen = DEVFS_PATHLEN - pos - 1;
-+    if (info->mode == 0) info->mode = de->mode;
-+    devname_offset = info->devname - (char *) info;
-+    rpos = *ppos;
-+    if (rpos < devname_offset)
-+    {
-+      /*  Copy parts of the header  */
-+      tlen = devname_offset - rpos;
-+      if (tlen > len) tlen = len;
-+      if ( copy_to_user (buf, (char *) info + rpos, tlen) )
-+      {
-+          return -EFAULT;
-+      }
-+      rpos += tlen;
-+      buf += tlen;
-+      len -= tlen;
-+    }
-+    if ( (rpos >= devname_offset) && (len > 0) )
-+    {
-+      /*  Copy the name  */
-+      tlen = info->namelen + 1;
-+      if (tlen > len) tlen = len;
-+      else done = TRUE;
-+      if ( copy_to_user (buf, info->devname + pos + rpos - devname_offset,
-+                         tlen) )
-+      {
-+          return -EFAULT;
-+      }
-+      rpos += tlen;
-+    }
-+    tlen = rpos - *ppos;
-+    if (done)
-+    {
-+      devfs_handle_t parent;
-+
-+      spin_lock (&fs_info->devfsd_buffer_lock);
-+      fs_info->devfsd_first_event = entry->next;
-+      if (entry->next == NULL) fs_info->devfsd_last_event = NULL;
-+      spin_unlock (&fs_info->devfsd_buffer_lock);
-+      for (; de != NULL; de = parent)
-+      {
-+          parent = de->parent;
-+          devfs_put (de);
-+      }
-+      kmem_cache_free (devfsd_buf_cache, entry);
-+      if (ival > 0) atomic_sub (ival, &fs_info->devfsd_overrun_count);
-+      *ppos = 0;
-+    }
-+    else *ppos = rpos;
-+    return tlen;
-+}   /*  End Function devfsd_read  */
-+
-+static int devfsd_ioctl (struct inode *inode, struct file *file,
-+                       unsigned int cmd, unsigned long arg)
-+{
-+    int ival;
-+    struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
-+
-+    switch (cmd)
-+    {
-+      case DEVFSDIOC_GET_PROTO_REV:
-+      ival = DEVFSD_PROTOCOL_REVISION_KERNEL;
-+      if ( copy_to_user ( (void *)arg, &ival, sizeof ival ) ) return -EFAULT;
-+      break;
-+      case DEVFSDIOC_SET_EVENT_MASK:
-+      /*  Ensure only one reader has access to the queue. This scheme will
-+          work even if the global kernel lock were to be removed, because it
-+          doesn't matter who gets in first, as long as only one gets it  */
-+      if (fs_info->devfsd_task == NULL)
-+      {
-+          static spinlock_t lock = SPIN_LOCK_UNLOCKED;
-+
-+          if ( !spin_trylock (&lock) ) return -EBUSY;
-+          if (fs_info->devfsd_task != NULL)
-+          {   /*  We lost the race...  */
-+              spin_unlock (&lock);
-+              return -EBUSY;
-+          }
-+          fs_info->devfsd_task = current;
-+          spin_unlock (&lock);
-+          fs_info->devfsd_pgrp = (current->pgrp == current->pid) ?
-+              current->pgrp : 0;
-+          fs_info->devfsd_file = file;
-+          fs_info->devfsd_info = kmalloc (sizeof *fs_info->devfsd_info,
-+                                          GFP_KERNEL);
-+          if (!fs_info->devfsd_info)
-+          {
-+              devfsd_close (inode, file);
-+              return -ENOMEM;
-+          }
-+      }
-+      else if (fs_info->devfsd_task != current) return -EBUSY;
-+      fs_info->devfsd_event_mask = arg;  /*  Let the masses come forth  */
-+      break;
-+      case DEVFSDIOC_RELEASE_EVENT_QUEUE:
-+      if (fs_info->devfsd_file != file) return -EPERM;
-+      return devfsd_close (inode, file);
-+      /*break;*/
-+#ifdef CONFIG_DEVFS_DEBUG
-+      case DEVFSDIOC_SET_DEBUG_MASK:
-+      if ( copy_from_user (&ival, (void *) arg, sizeof ival) )return -EFAULT;
-+      devfs_debug = ival;
-+      break;
-+#endif
-+      default:
-+      return -ENOIOCTLCMD;
-+    }
-+    return 0;
-+}   /*  End Function devfsd_ioctl  */
-+
-+static int devfsd_close (struct inode *inode, struct file *file)
-+{
-+    struct devfsd_buf_entry *entry, *next;
-+    struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
-+
-+    if (fs_info->devfsd_file != file) return 0;
-+    fs_info->devfsd_event_mask = 0;
-+    fs_info->devfsd_file = NULL;
-+    spin_lock (&fs_info->devfsd_buffer_lock);
-+    entry = fs_info->devfsd_first_event;
-+    fs_info->devfsd_first_event = NULL;
-+    fs_info->devfsd_last_event = NULL;
-+    if (fs_info->devfsd_info)
-+    {
-+      kfree (fs_info->devfsd_info);
-+      fs_info->devfsd_info = NULL;
-+    }
-+    spin_unlock (&fs_info->devfsd_buffer_lock);
-+    fs_info->devfsd_pgrp = 0;
-+    fs_info->devfsd_task = NULL;
-+    wake_up (&fs_info->revalidate_wait_queue);
-+    for (; entry; entry = next)
-+    {
-+      next = entry->next;
-+      kmem_cache_free (devfsd_buf_cache, entry);
-+    }
-+    return 0;
-+}   /*  End Function devfsd_close  */
-+
-+#ifdef CONFIG_DEVFS_DEBUG
-+static ssize_t stat_read (struct file *file, char *buf, size_t len,
-+                        loff_t *ppos)
-+{
-+    ssize_t num;
-+    char txt[80];
-+
-+    num = sprintf (txt, "Number of entries: %u  number of bytes: %u\n",
-+                 stat_num_entries, stat_num_bytes) + 1;
-+    /*  Can't seek (pread) on this device  */
-+    if (ppos != &file->f_pos) return -ESPIPE;
-+    if (*ppos >= num) return 0;
-+    if (*ppos + len > num) len = num - *ppos;
-+    if ( copy_to_user (buf, txt + *ppos, len) ) return -EFAULT;
-+    *ppos += len;
-+    return len;
-+}   /*  End Function stat_read  */
-+#endif
-+
-+
-+static int __init init_devfs_fs (void)
-+{
-+    int err;
-+
-+    printk (KERN_INFO "%s: v%s Richard Gooch (rgooch@atnf.csiro.au)\n",
-+          DEVFS_NAME, DEVFS_VERSION);
-+    devfsd_buf_cache = kmem_cache_create ("devfsd_event",
-+                                        sizeof (struct devfsd_buf_entry),
-+                                        0, 0, NULL, NULL);
-+    if (!devfsd_buf_cache) OOPS ("(): unable to allocate event slab\n");
-+#ifdef CONFIG_DEVFS_DEBUG
-+    devfs_debug = devfs_debug_init;
-+    printk (KERN_INFO "%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug);
-+#endif
-+    printk (KERN_INFO "%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options);
-+    err = register_filesystem (&devfs_fs_type);
-+    if (!err)
-+    {
-+      struct vfsmount *devfs_mnt = kern_mount (&devfs_fs_type);
-+      err = PTR_ERR (devfs_mnt);
-+      if ( !IS_ERR (devfs_mnt) ) err = 0;
-+    }
-+    return err;
-+}   /*  End Function init_devfs_fs  */
-+
-+void __init mount_devfs_fs (void)
-+{
-+    int err;
-+
-+    if ( !(boot_options & OPTION_MOUNT) ) return;
-+    err = do_mount ("none", "/dev", "devfs", 0, "");
-+    if (err == 0) printk (KERN_INFO "Mounted devfs on /dev\n");
-+    else PRINTK ("(): unable to mount devfs, err: %d\n", err);
-+}   /*  End Function mount_devfs_fs  */
-+
-+module_init(init_devfs_fs)
---- /dev/null  2003-01-30 18:24:37.000000000 +0800
-+++ linux-2.4.19-hp3_pnnl1-root/fs/super.c     2003-04-15 13:21:57.000000000 +0800
-@@ -0,0 +1,926 @@
-+/*
-+ *  linux/fs/super.c
-+ *
-+ *  Copyright (C) 1991, 1992  Linus Torvalds
-+ *
-+ *  super.c contains code to handle: - mount structures
-+ *                                   - super-block tables
-+ *                                   - filesystem drivers list
-+ *                                   - mount system call
-+ *                                   - umount system call
-+ *                                   - ustat system call
-+ *
-+ * GK 2/5/95  -  Changed to support mounting the root fs via NFS
-+ *
-+ *  Added kerneld support: Jacques Gelinas and Bjorn Ekwall
-+ *  Added change_root: Werner Almesberger & Hans Lermen, Feb '96
-+ *  Added options to /proc/mounts:
-+ *    Torbjörn Lindh (torbjorn.lindh@gopta.se), April 14, 1996.
-+ *  Added devfs support: Richard Gooch <rgooch@atnf.csiro.au>, 13-JAN-1998
-+ *  Heavily rewritten for 'one fs - one tree' dcache architecture. AV, Mar 2000
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/slab.h>
-+#include <linux/locks.h>
-+#include <linux/smp_lock.h>
-+#include <linux/devfs_fs_kernel.h>
-+#include <linux/major.h>
-+#include <linux/acct.h>
-+#include <linux/quotaops.h>
-+
-+#include <asm/uaccess.h>
-+
-+#include <linux/kmod.h>
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+
-+LIST_HEAD(super_blocks);
-+spinlock_t sb_lock = SPIN_LOCK_UNLOCKED;
-+
-+/* 
-+ * lock/unlockfs grab a read lock on s_umount, but you need this lock to 
-+ * make sure no lockfs runs are in progress before inserting/removing 
-+ * supers from the list.  
-+ */
-+static DECLARE_MUTEX(lockfs_sem);
-+
-+/*
-+ * Handling of filesystem drivers list.
-+ * Rules:
-+ *    Inclusion to/removals from/scanning of list are protected by spinlock.
-+ *    During the unload module must call unregister_filesystem().
-+ *    We can access the fields of list element if:
-+ *            1) spinlock is held or
-+ *            2) we hold the reference to the module.
-+ *    The latter can be guaranteed by call of try_inc_mod_count(); if it
-+ *    returned 0 we must skip the element, otherwise we got the reference.
-+ *    Once the reference is obtained we can drop the spinlock.
-+ */
-+
-+static struct file_system_type *file_systems;
-+static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED;
-+
-+/* WARNING: This can be used only if we _already_ own a reference */
-+static void get_filesystem(struct file_system_type *fs)
-+{
-+      if (fs->owner)
-+              __MOD_INC_USE_COUNT(fs->owner);
-+}
-+
-+static void put_filesystem(struct file_system_type *fs)
-+{
-+      if (fs->owner)
-+              __MOD_DEC_USE_COUNT(fs->owner);
-+}
-+
-+static struct file_system_type **find_filesystem(const char *name)
-+{
-+      struct file_system_type **p;
-+      for (p=&file_systems; *p; p=&(*p)->next)
-+              if (strcmp((*p)->name,name) == 0)
-+                      break;
-+      return p;
-+}
-+
-+/**
-+ *    register_filesystem - register a new filesystem
-+ *    @fs: the file system structure
-+ *
-+ *    Adds the file system passed to the list of file systems the kernel
-+ *    is aware of for mount and other syscalls. Returns 0 on success,
-+ *    or a negative errno code on an error.
-+ *
-+ *    The &struct file_system_type that is passed is linked into the kernel 
-+ *    structures and must not be freed until the file system has been
-+ *    unregistered.
-+ */
-+ 
-+int register_filesystem(struct file_system_type * fs)
-+{
-+      int res = 0;
-+      struct file_system_type ** p;
-+
-+      if (!fs)
-+              return -EINVAL;
-+      if (fs->next)
-+              return -EBUSY;
-+      INIT_LIST_HEAD(&fs->fs_supers);
-+      write_lock(&file_systems_lock);
-+      p = find_filesystem(fs->name);
-+      if (*p)
-+              res = -EBUSY;
-+      else
-+              *p = fs;
-+      write_unlock(&file_systems_lock);
-+      return res;
-+}
-+
-+/**
-+ *    unregister_filesystem - unregister a file system
-+ *    @fs: filesystem to unregister
-+ *
-+ *    Remove a file system that was previously successfully registered
-+ *    with the kernel. An error is returned if the file system is not found.
-+ *    Zero is returned on a success.
-+ *    
-+ *    Once this function has returned the &struct file_system_type structure
-+ *    may be freed or reused.
-+ */
-+ 
-+int unregister_filesystem(struct file_system_type * fs)
-+{
-+      struct file_system_type ** tmp;
-+
-+      write_lock(&file_systems_lock);
-+      tmp = &file_systems;
-+      while (*tmp) {
-+              if (fs == *tmp) {
-+                      *tmp = fs->next;
-+                      fs->next = NULL;
-+                      write_unlock(&file_systems_lock);
-+                      return 0;
-+              }
-+              tmp = &(*tmp)->next;
-+      }
-+      write_unlock(&file_systems_lock);
-+      return -EINVAL;
-+}
-+
-+static int fs_index(const char * __name)
-+{
-+      struct file_system_type * tmp;
-+      char * name;
-+      int err, index;
-+
-+      name = getname(__name);
-+      err = PTR_ERR(name);
-+      if (IS_ERR(name))
-+              return err;
-+
-+      err = -EINVAL;
-+      read_lock(&file_systems_lock);
-+      for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
-+              if (strcmp(tmp->name,name) == 0) {
-+                      err = index;
-+                      break;
-+              }
-+      }
-+      read_unlock(&file_systems_lock);
-+      putname(name);
-+      return err;
-+}
-+
-+static int fs_name(unsigned int index, char * buf)
-+{
-+      struct file_system_type * tmp;
-+      int len, res;
-+
-+      read_lock(&file_systems_lock);
-+      for (tmp = file_systems; tmp; tmp = tmp->next, index--)
-+              if (index <= 0 && try_inc_mod_count(tmp->owner))
-+                              break;
-+      read_unlock(&file_systems_lock);
-+      if (!tmp)
-+              return -EINVAL;
-+
-+      /* OK, we got the reference, so we can safely block */
-+      len = strlen(tmp->name) + 1;
-+      res = copy_to_user(buf, tmp->name, len) ? -EFAULT : 0;
-+      put_filesystem(tmp);
-+      return res;
-+}
-+
-+static int fs_maxindex(void)
-+{
-+      struct file_system_type * tmp;
-+      int index;
-+
-+      read_lock(&file_systems_lock);
-+      for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next, index++)
-+              ;
-+      read_unlock(&file_systems_lock);
-+      return index;
-+}
-+
-+/*
-+ * Whee.. Weird sysv syscall. 
-+ */
-+asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
-+{
-+      int retval = -EINVAL;
-+
-+      switch (option) {
-+              case 1:
-+                      retval = fs_index((const char *) arg1);
-+                      break;
-+
-+              case 2:
-+                      retval = fs_name(arg1, (char *) arg2);
-+                      break;
-+
-+              case 3:
-+                      retval = fs_maxindex();
-+                      break;
-+      }
-+      return retval;
-+}
-+
-+int get_filesystem_list(char * buf)
-+{
-+      int len = 0;
-+      struct file_system_type * tmp;
-+
-+      read_lock(&file_systems_lock);
-+      tmp = file_systems;
-+      while (tmp && len < PAGE_SIZE - 80) {
-+              len += sprintf(buf+len, "%s\t%s\n",
-+                      (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev",
-+                      tmp->name);
-+              tmp = tmp->next;
-+      }
-+      read_unlock(&file_systems_lock);
-+      return len;
-+}
-+
-+struct file_system_type *get_fs_type(const char *name)
-+{
-+      struct file_system_type *fs;
-+      
-+      read_lock(&file_systems_lock);
-+      fs = *(find_filesystem(name));
-+      if (fs && !try_inc_mod_count(fs->owner))
-+              fs = NULL;
-+      read_unlock(&file_systems_lock);
-+      if (!fs && (request_module(name) == 0)) {
-+              read_lock(&file_systems_lock);
-+              fs = *(find_filesystem(name));
-+              if (fs && !try_inc_mod_count(fs->owner))
-+                      fs = NULL;
-+              read_unlock(&file_systems_lock);
-+      }
-+      return fs;
-+}
-+
-+/**
-+ *    alloc_super     -       create new superblock
-+ *
-+ *    Allocates and initializes a new &struct super_block.  alloc_super()
-+ *    returns a pointer new superblock or %NULL if allocation had failed.
-+ */
-+static struct super_block *alloc_super(void)
-+{
-+      static struct super_operations empty_sops = {};
-+      struct super_block *s = kmalloc(sizeof(struct super_block),  GFP_USER);
-+      if (s) {
-+              memset(s, 0, sizeof(struct super_block));
-+              INIT_LIST_HEAD(&s->s_dirty);
-+              INIT_LIST_HEAD(&s->s_locked_inodes);
-+              INIT_LIST_HEAD(&s->s_files);
-+              INIT_LIST_HEAD(&s->s_instances);
-+              init_rwsem(&s->s_umount);
-+              sema_init(&s->s_lock, 1);
-+              down_write(&s->s_umount);
-+              s->s_count = S_BIAS;
-+              atomic_set(&s->s_active, 1);
-+              sema_init(&s->s_vfs_rename_sem,1);
-+              sema_init(&s->s_nfsd_free_path_sem,1);
-+              sema_init(&s->s_dquot.dqio_sem, 1);
-+              sema_init(&s->s_dquot.dqoff_sem, 1);
-+              s->s_maxbytes = MAX_NON_LFS;
-+              s->s_op = &empty_sops;
-+              s->dq_op = sb_dquot_ops;
-+              s->s_qcop = sb_quotactl_ops;
-+      }
-+      return s;
-+}
-+
-+/**
-+ *    destroy_super   -       frees a superblock
-+ *    @s: superblock to free
-+ *
-+ *    Frees a superblock.
-+ */
-+static inline void destroy_super(struct super_block *s)
-+{
-+      kfree(s);
-+}
-+
-+/* Superblock refcounting  */
-+
-+/**
-+ *    deactivate_super        -       turn an active reference into temporary
-+ *    @s: superblock to deactivate
-+ *
-+ *    Turns an active reference into temporary one.  Returns 0 if there are
-+ *    other active references, 1 if we had deactivated the last one.
-+ */
-+static inline int deactivate_super(struct super_block *s)
-+{
-+      if (!atomic_dec_and_lock(&s->s_active, &sb_lock))
-+              return 0;
-+      s->s_count -= S_BIAS-1;
-+      spin_unlock(&sb_lock);
-+      return 1;
-+}
-+
-+/**
-+ *    put_super       -       drop a temporary reference to superblock
-+ *    @s: superblock in question
-+ *
-+ *    Drops a temporary reference, frees superblock if there's no
-+ *    references left.
-+ */
-+static inline void put_super(struct super_block *s)
-+{
-+      spin_lock(&sb_lock);
-+      if (!--s->s_count)
-+              destroy_super(s);
-+      spin_unlock(&sb_lock);
-+}
-+
-+/**
-+ *    grab_super      - acquire an active reference
-+ *    @s      - reference we are trying to make active
-+ *
-+ *    Tries to acquire an active reference.  grab_super() is used when we
-+ *    had just found a superblock in super_blocks or fs_type->fs_supers
-+ *    and want to turn it into a full-blown active reference.  grab_super()
-+ *    is called with sb_lock held and drops it.  Returns 1 in case of
-+ *    success, 0 if we had failed (superblock contents was already dead or
-+ *    dying when grab_super() had been called).
-+ */
-+static int grab_super(struct super_block *s)
-+{
-+      s->s_count++;
-+      spin_unlock(&sb_lock);
-+      down_write(&s->s_umount);
-+      if (s->s_root) {
-+              spin_lock(&sb_lock);
-+              if (s->s_count > S_BIAS) {
-+                      atomic_inc(&s->s_active);
-+                      s->s_count--;
-+                      spin_unlock(&sb_lock);
-+                      return 1;
-+              }
-+              spin_unlock(&sb_lock);
-+      }
-+      up_write(&s->s_umount);
-+      put_super(s);
-+      return 0;
-+}
-+ 
-+/**
-+ *    insert_super    -       put superblock on the lists
-+ *    @s:     superblock in question
-+ *    @type:  filesystem type it will belong to
-+ *
-+ *    Associates superblock with fs type and puts it on per-type and global
-+ *    superblocks' lists.  Should be called with sb_lock held; drops it.
-+ */
-+static void insert_super(struct super_block *s, struct file_system_type *type)
-+{
-+      s->s_type = type;
-+      list_add(&s->s_list, super_blocks.prev);
-+      list_add(&s->s_instances, &type->fs_supers);
-+      spin_unlock(&sb_lock);
-+      get_filesystem(type);
-+}
-+
-+static void put_anon_dev(kdev_t dev);
-+
-+/**
-+ *    remove_super    -       makes superblock unreachable
-+ *    @s:     superblock in question
-+ *
-+ *    Removes superblock from the lists, unlocks it, drop the reference
-+ *    and releases the hosting device.  @s should have no active
-+ *    references by that time and after remove_super() it's essentially
-+ *    in rundown mode - all remaining references are temporary, no new
-+ *    reference of any sort are going to appear and all holders of
-+ *    temporary ones will eventually drop them.  At that point superblock
-+ *    itself will be destroyed; all its contents is already gone.
-+ */
-+static void remove_super(struct super_block *s)
-+{
-+      kdev_t dev = s->s_dev;
-+      struct block_device *bdev = s->s_bdev;
-+      struct file_system_type *fs = s->s_type;
-+
-+      spin_lock(&sb_lock);
-+      list_del(&s->s_list);
-+      list_del(&s->s_instances);
-+      spin_unlock(&sb_lock);
-+      up_write(&s->s_umount);
-+      put_super(s);
-+      put_filesystem(fs);
-+      if (bdev)
-+              blkdev_put(bdev, BDEV_FS);
-+      else
-+              put_anon_dev(dev);
-+}
-+
-+struct vfsmount *alloc_vfsmnt(char *name);
-+void free_vfsmnt(struct vfsmount *mnt);
-+
-+static inline struct super_block * find_super(kdev_t dev)
-+{
-+      struct list_head *p;
-+
-+      list_for_each(p, &super_blocks) {
-+              struct super_block * s = sb_entry(p);
-+              if (s->s_dev == dev) {
-+                      s->s_count++;
-+                      return s;
-+              }
-+      }
-+      return NULL;
-+}
-+
-+void drop_super(struct super_block *sb)
-+{
-+      up_read(&sb->s_umount);
-+      put_super(sb);
-+}
-+
-+static void write_super_lockfs(struct super_block *sb)
-+{
-+      lock_super(sb);
-+      if (sb->s_root && sb->s_op) {
-+              if (sb->s_dirt && sb->s_op->write_super)
-+                      sb->s_op->write_super(sb);
-+              if (sb->s_op->write_super_lockfs) {
-+                      sb->s_op->write_super_lockfs(sb);
-+              }
-+      }
-+      unlock_super(sb);
-+}
-+
-+static inline void write_super(struct super_block *sb)
-+{
-+      lock_super(sb);
-+      if (sb->s_root && sb->s_dirt)
-+              if (sb->s_op && sb->s_op->write_super)
-+                      sb->s_op->write_super(sb);
-+      unlock_super(sb);
-+}
-+
-+/*
-+ * Note: check the dirty flag before waiting, so we don't
-+ * hold up the sync while mounting a device. (The newly
-+ * mounted device won't need syncing.)
-+ */
-+void sync_supers(kdev_t dev)
-+{
-+      struct super_block * sb;
-+
-+      if (dev) {
-+              sb = get_super(dev);
-+              if (sb) {
-+                      if (sb->s_dirt)
-+                              write_super(sb);
-+                      drop_super(sb);
-+              }
-+              return;
-+      }
-+restart:
-+      spin_lock(&sb_lock);
-+      sb = sb_entry(super_blocks.next);
-+      while (sb != sb_entry(&super_blocks))
-+              if (sb->s_dirt) {
-+                      sb->s_count++;
-+                      spin_unlock(&sb_lock);
-+                      down_read(&sb->s_umount);
-+                      write_super(sb);
-+                      drop_super(sb);
-+                      goto restart;
-+              } else
-+                      sb = sb_entry(sb->s_list.next);
-+      spin_unlock(&sb_lock);
-+}
-+
-+/*
-+ * Note: don't check the dirty flag before waiting, we want the lock
-+ * to happen every time this is called.  dev must be non-zero
-+ */
-+void sync_supers_lockfs(kdev_t dev)
-+{
-+      struct super_block * sb;
-+
-+      down(&lockfs_sem) ;
-+      if (dev) {
-+              sb = get_super(dev);
-+              if (sb) {
-+                      write_super_lockfs(sb);
-+                      drop_super(sb);
-+              }
-+      }
-+}
-+
-+void unlockfs(kdev_t dev)
-+{
-+      struct super_block * sb;
-+
-+      if (dev) {
-+              sb = get_super(dev);
-+              if (sb) {
-+                      if (sb->s_op && sb->s_op->unlockfs)
-+                              sb->s_op->unlockfs(sb) ;
-+                      drop_super(sb);
-+              }
-+      }
-+      up(&lockfs_sem) ;
-+}
-+
-+/**
-+ *    get_super       -       get the superblock of a device
-+ *    @dev: device to get the superblock for
-+ *    
-+ *    Scans the superblock list and finds the superblock of the file system
-+ *    mounted on the device given. %NULL is returned if no match is found.
-+ */
-+ 
-+struct super_block * get_super(kdev_t dev)
-+{
-+      struct super_block * s;
-+
-+      if (!dev)
-+              return NULL;
-+restart:
-+      spin_lock(&sb_lock);
-+      s = find_super(dev);
-+      if (s) {
-+              spin_unlock(&sb_lock);
-+              down_read(&s->s_umount);
-+              if (s->s_root)
-+                      return s;
-+              drop_super(s);
-+              goto restart;
-+      }
-+      spin_unlock(&sb_lock);
-+      return NULL;
-+}
-+
-+asmlinkage long sys_ustat(dev_t dev, struct ustat * ubuf)
-+{
-+        struct super_block *s;
-+        struct ustat tmp;
-+        struct statfs sbuf;
-+      int err = -EINVAL;
-+
-+        s = get_super(to_kdev_t(dev));
-+        if (s == NULL)
-+                goto out;
-+      err = vfs_statfs(s, &sbuf);
-+      drop_super(s);
-+      if (err)
-+              goto out;
-+
-+        memset(&tmp,0,sizeof(struct ustat));
-+        tmp.f_tfree = sbuf.f_bfree;
-+        tmp.f_tinode = sbuf.f_ffree;
-+
-+        err = copy_to_user(ubuf,&tmp,sizeof(struct ustat)) ? -EFAULT : 0;
-+out:
-+      return err;
-+}
-+
-+/**
-+ *    do_remount_sb   -       asks filesystem to change mount options.
-+ *    @sb:    superblock in question
-+ *    @flags: numeric part of options
-+ *    @data:  the rest of options
-+ *
-+ *    Alters the mount options of a mounted file system.
-+ */
-+int do_remount_sb(struct super_block *sb, int flags, void *data)
-+{
-+      int retval;
-+      
-+      if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
-+              return -EACCES;
-+              /*flags |= MS_RDONLY;*/
-+      if (flags & MS_RDONLY)
-+              acct_auto_close(sb->s_dev);
-+      shrink_dcache_sb(sb);
-+      fsync_super(sb);
-+      /* If we are remounting RDONLY, make sure there are no rw files open */
-+      if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
-+              if (!fs_may_remount_ro(sb))
-+                      return -EBUSY;
-+      if (sb->s_op && sb->s_op->remount_fs) {
-+              lock_super(sb);
-+              retval = sb->s_op->remount_fs(sb, &flags, data);
-+              unlock_super(sb);
-+              if (retval)
-+                      return retval;
-+      }
-+      sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
-+      return 0;
-+}
-+
-+/*
-+ * Unnamed block devices are dummy devices used by virtual
-+ * filesystems which don't use real block-devices.  -- jrs
-+ */
-+
-+enum {Max_anon = 256};
-+static unsigned long unnamed_dev_in_use[Max_anon/(8*sizeof(unsigned long))];
-+static spinlock_t unnamed_dev_lock = SPIN_LOCK_UNLOCKED;/* protects the above */
-+
-+/**
-+ *    put_anon_dev    -       release anonymous device number.
-+ *    @dev:   device in question
-+ */
-+static void put_anon_dev(kdev_t dev)
-+{
-+      spin_lock(&unnamed_dev_lock);
-+      clear_bit(MINOR(dev), unnamed_dev_in_use);
-+      spin_unlock(&unnamed_dev_lock);
-+}
-+
-+/**
-+ *    get_anon_super  -       allocate a superblock for non-device fs
-+ *    @type:          filesystem type
-+ *    @compare:       check if existing superblock is what we want
-+ *    @data:          argument for @compare.
-+ *
-+ *    get_anon_super is a helper for non-blockdevice filesystems.
-+ *    It either finds and returns one of the superblocks of given type
-+ *    (if it can find one that would satisfy caller) or creates a new
-+ *    one.  In the either case we return an active reference to superblock
-+ *    with ->s_umount locked.  If superblock is new it gets a new
-+ *    anonymous device allocated for it and is inserted into lists -
-+ *    other initialization is left to caller.
-+ *
-+ *    Rather than duplicating all that logics every time when
-+ *    we want something that doesn't fit "nodev" and "single" we pull
-+ *    the relevant code into common helper and let get_sb_...() call
-+ *    it.
-+ *
-+ *    NB: get_sb_...() is going to become an fs type method, with
-+ *    current ->read_super() becoming a callback used by common instances.
-+ */
-+struct super_block *get_anon_super(struct file_system_type *type,
-+      int (*compare)(struct super_block *,void *), void *data)
-+{
-+      struct super_block *s = alloc_super();
-+      kdev_t dev;
-+      struct list_head *p;
-+
-+      if (!s)
-+              return ERR_PTR(-ENOMEM);
-+
-+retry:
-+      spin_lock(&sb_lock);
-+      if (compare) list_for_each(p, &type->fs_supers) {
-+              struct super_block *old;
-+              old = list_entry(p, struct super_block, s_instances);
-+              if (!compare(old, data))
-+                      continue;
-+              if (!grab_super(old))
-+                      goto retry;
-+              destroy_super(s);
-+              return old;
-+      }
-+
-+      spin_lock(&unnamed_dev_lock);
-+      dev = find_first_zero_bit(unnamed_dev_in_use, Max_anon);
-+      if (dev == Max_anon) {
-+              spin_unlock(&unnamed_dev_lock);
-+              spin_unlock(&sb_lock);
-+              destroy_super(s);
-+              return ERR_PTR(-EMFILE);
-+      }
-+      set_bit(dev, unnamed_dev_in_use);
-+      spin_unlock(&unnamed_dev_lock);
-+
-+      s->s_dev = dev;
-+      insert_super(s, type);
-+      return s;
-+}
-+
-+static struct super_block *get_sb_bdev(struct file_system_type *fs_type,
-+      int flags, char *dev_name, void * data)
-+{
-+      struct inode *inode;
-+      struct block_device *bdev;
-+      struct block_device_operations *bdops;
-+      devfs_handle_t de;
-+      struct super_block * s;
-+      struct nameidata nd;
-+      struct list_head *p;
-+      kdev_t dev;
-+      int error = 0;
-+      mode_t mode = FMODE_READ; /* we always need it ;-) */
-+
-+      /* What device it is? */
-+      if (!dev_name || !*dev_name)
-+              return ERR_PTR(-EINVAL);
-+      if (path_init(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
-+              error = path_walk(dev_name, &nd);
-+      if (error)
-+              return ERR_PTR(error);
-+      inode = nd.dentry->d_inode;
-+      error = -ENOTBLK;
-+      if (!S_ISBLK(inode->i_mode))
-+              goto out;
-+      error = -EACCES;
-+      if (nd.mnt->mnt_flags & MNT_NODEV)
-+              goto out;
-+      bd_acquire(inode);
-+      bdev = inode->i_bdev;
-+      de = devfs_get_handle_from_inode (inode);
-+      bdops = devfs_get_ops (de);         /*  Increments module use count  */
-+      if (bdops) bdev->bd_op = bdops;
-+      /* Done with lookups, semaphore down */
-+      dev = to_kdev_t(bdev->bd_dev);
-+      if (!(flags & MS_RDONLY))
-+              mode |= FMODE_WRITE;
-+      error = blkdev_get(bdev, mode, 0, BDEV_FS);
-+      devfs_put_ops (de);   /*  Decrement module use count now we're safe  */
-+      if (error)
-+              goto out;
-+      check_disk_change(dev);
-+      error = -EACCES;
-+      if (!(flags & MS_RDONLY) && is_read_only(dev))
-+              goto out1;
-+
-+      error = -ENOMEM;
-+      s = alloc_super();
-+      if (!s)
-+              goto out1;
-+
-+      error = -EBUSY;
-+      down(&lockfs_sem);
-+restart:
-+      spin_lock(&sb_lock);
-+
-+      list_for_each(p, &super_blocks) {
-+              struct super_block *old = sb_entry(p);
-+              if (old->s_dev != dev)
-+                      continue;
-+              if (old->s_type != fs_type ||
-+                  ((flags ^ old->s_flags) & MS_RDONLY)) {
-+                      spin_unlock(&sb_lock);
-+                      destroy_super(s);
-+                      up(&lockfs_sem);
-+                      goto out1;
-+              }
-+              if (!grab_super(old))
-+                      goto restart;
-+              destroy_super(s);
-+              blkdev_put(bdev, BDEV_FS);
-+              path_release(&nd);
-+              up(&lockfs_sem);
-+              return old;
-+      }
-+      s->s_dev = dev;
-+      s->s_bdev = bdev;
-+      s->s_flags = flags;
-+      insert_super(s, fs_type);
-+      up(&lockfs_sem);
-+      if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0))
-+              goto Einval;
-+      s->s_flags |= MS_ACTIVE;
-+      path_release(&nd);
-+      return s;
-+
-+Einval:
-+      deactivate_super(s);
-+      remove_super(s);
-+      error = -EINVAL;
-+      goto out;
-+out1:
-+      blkdev_put(bdev, BDEV_FS);
-+out:
-+      path_release(&nd);
-+      return ERR_PTR(error);
-+}
-+
-+static struct super_block *get_sb_nodev(struct file_system_type *fs_type,
-+      int flags, char *dev_name, void *data)
-+{
-+      struct super_block *s = get_anon_super(fs_type, NULL, NULL);
-+
-+      if (IS_ERR(s))
-+              return s;
-+
-+      s->s_flags = flags;
-+      if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) {
-+              deactivate_super(s);
-+              remove_super(s);
-+              return ERR_PTR(-EINVAL);
-+      }
-+      s->s_flags |= MS_ACTIVE;
-+      return s;
-+}
-+
-+static int compare_single(struct super_block *s, void *p)
-+{
-+      return 1;
-+}
-+
-+static struct super_block *get_sb_single(struct file_system_type *fs_type,
-+      int flags, char *dev_name, void *data)
-+{
-+      struct super_block *s = get_anon_super(fs_type, compare_single, NULL);
-+
-+      if (IS_ERR(s))
-+              return s;
-+      if (!s->s_root) {
-+              s->s_flags = flags;
-+              if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) {
-+                      deactivate_super(s);
-+                      remove_super(s);
-+                      return ERR_PTR(-EINVAL);
-+              }
-+              s->s_flags |= MS_ACTIVE;
-+      }
-+      do_remount_sb(s, flags, data);
-+      return s;
-+}
-+
-+struct vfsmount *
-+do_kern_mount(const char *fstype, int flags, char *name, void *data)
-+{
-+      struct file_system_type *type = get_fs_type(fstype);
-+      struct super_block *sb = ERR_PTR(-ENOMEM);
-+      struct vfsmount *mnt;
-+
-+      if (!type)
-+              return ERR_PTR(-ENODEV);
-+
-+      mnt = alloc_vfsmnt(name);
-+      if (!mnt)
-+              goto out;
-+      if (type->fs_flags & FS_REQUIRES_DEV)
-+              sb = get_sb_bdev(type, flags, name, data);
-+      else if (type->fs_flags & FS_SINGLE)
-+              sb = get_sb_single(type, flags, name, data);
-+      else
-+              sb = get_sb_nodev(type, flags, name, data);
-+      if (IS_ERR(sb))
-+              goto out_mnt;
-+      if (type->fs_flags & FS_NOMOUNT)
-+              sb->s_flags |= MS_NOUSER;
-+      mnt->mnt_sb = sb;
-+      mnt->mnt_root = dget(sb->s_root);
-+      mnt->mnt_mountpoint = sb->s_root;
-+      mnt->mnt_parent = mnt;
-+      up_write(&sb->s_umount);
-+      put_filesystem(type);
-+      return mnt;
-+out_mnt:
-+      free_vfsmnt(mnt);
-+out:
-+      put_filesystem(type);
-+      return (struct vfsmount *)sb;
-+}
-+
-+void kill_super(struct super_block *sb)
-+{
-+      struct dentry *root = sb->s_root;
-+      struct file_system_type *fs = sb->s_type;
-+      struct super_operations *sop = sb->s_op;
-+
-+      if (!deactivate_super(sb))
-+              return;
-+
-+      down(&lockfs_sem);
-+      down_write(&sb->s_umount);
-+      up(&lockfs_sem);
-+
-+      sb->s_root = NULL;
-+      /* Need to clean after the sucker */
-+      if (fs->fs_flags & FS_LITTER)
-+              d_genocide(root);
-+      shrink_dcache_parent(root);
-+      dput(root);
-+      fsync_super(sb);
-+      lock_super(sb);
-+      lock_kernel();
-+      sb->s_flags &= ~MS_ACTIVE;
+               drop_super(sb);
+       }
+       invalidate_buffers(dev);
+--- linux-rh-2.4.20-8/fs/super.c~invalidate_show       2003-04-11 14:04:57.000000000 +0800
++++ linux-rh-2.4.20-8-root/fs/super.c  2003-04-16 20:59:35.000000000 +0800
+@@ -943,7 +943,7 @@ void kill_super(struct super_block *sb)
+       lock_super(sb);
+       lock_kernel();
+       sb->s_flags &= ~MS_ACTIVE;
+-      invalidate_inodes(sb);  /* bad name - it should be evict_inodes() */
 +      invalidate_inodes(sb, 0);  /* bad name - it should be evict_inodes() */
-+      if (sop) {
-+              if (sop->write_super && sb->s_dirt)
-+                      sop->write_super(sb);
-+              if (sop->put_super)
-+                      sop->put_super(sb);
-+      }
-+
-+      /* Forget any remaining inodes */
+       if (sop) {
+               if (sop->write_super && sb->s_dirt)
+                       sop->write_super(sb);
+@@ -952,7 +952,7 @@ void kill_super(struct super_block *sb)
+       }
+       /* Forget any remaining inodes */
+-      if (invalidate_inodes(sb)) {
 +      if (invalidate_inodes(sb, 1)) {
-+              printk(KERN_ERR "VFS: Busy inodes after unmount. "
-+                      "Self-destruct in 5 seconds.  Have a nice day...\n");
-+      }
-+
-+      unlock_kernel();
-+      unlock_super(sb);
-+      remove_super(sb);
-+}
-+
-+struct vfsmount *kern_mount(struct file_system_type *type)
-+{
-+      return do_kern_mount(type->name, 0, (char *)type->name, NULL);
-+}
---- /dev/null  2003-01-30 18:24:37.000000000 +0800
-+++ linux-2.4.19-hp3_pnnl1-root/include/linux/fs.h     2003-04-15 13:21:57.000000000 +0800
-@@ -0,0 +1,1709 @@
-+#ifndef _LINUX_FS_H
-+#define _LINUX_FS_H
-+
-+/*
-+ * This file has definitions for some important file table
-+ * structures etc.
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/linkage.h>
-+#include <linux/limits.h>
-+#include <linux/wait.h>
-+#include <linux/types.h>
-+#include <linux/vfs.h>
-+#include <linux/net.h>
-+#include <linux/kdev_t.h>
-+#include <linux/ioctl.h>
-+#include <linux/list.h>
-+#include <linux/dcache.h>
-+#include <linux/stat.h>
-+#include <linux/cache.h>
-+#include <linux/stddef.h>
-+#include <linux/string.h>
-+
-+#include <asm/atomic.h>
-+#include <asm/bitops.h>
-+
-+struct poll_table_struct;
-+
-+
-+/*
-+ * It's silly to have NR_OPEN bigger than NR_FILE, but you can change
-+ * the file limit at runtime and only root can increase the per-process
-+ * nr_file rlimit, so it's safe to set up a ridiculously high absolute
-+ * upper limit on files-per-process.
-+ *
-+ * Some programs (notably those using select()) may have to be 
-+ * recompiled to take full advantage of the new limits..  
-+ */
-+
-+/* Fixed constants first: */
-+#undef NR_OPEN
-+#define NR_OPEN (1024*1024)   /* Absolute upper limit on fd num */
-+#define INR_OPEN 1024         /* Initial setting for nfile rlimits */
-+
-+#define BLOCK_SIZE_BITS 10
-+#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
-+
-+/* And dynamically-tunable limits and defaults: */
-+struct files_stat_struct {
-+      int nr_files;           /* read only */
-+      int nr_free_files;      /* read only */
-+      int max_files;          /* tunable */
-+};
-+extern struct files_stat_struct files_stat;
-+
-+struct inodes_stat_t {
-+      int nr_inodes;
-+      int nr_unused;
-+      int dummy[5];
-+};
-+extern struct inodes_stat_t inodes_stat;
-+
-+extern int leases_enable, dir_notify_enable, lease_break_time;
-+
-+#define NR_FILE  8192 /* this can well be larger on a larger system */
-+#define NR_RESERVED_FILES 10 /* reserved for root */
-+#define NR_SUPER 256
-+
-+#define MAY_EXEC 1
-+#define MAY_WRITE 2
-+#define MAY_READ 4
-+
-+#define FMODE_READ 1
-+#define FMODE_WRITE 2
-+
-+#define READ 0
-+#define WRITE 1
-+#define READA 2               /* read-ahead  - don't block if no resources */
-+#define SPECIAL 4     /* For non-blockdevice requests in request queue */
-+
-+#define SEL_IN                1
-+#define SEL_OUT               2
-+#define SEL_EX                4
-+
-+/* public flags for file_system_type */
-+#define FS_REQUIRES_DEV 1 
-+#define FS_NO_DCACHE  2 /* Only dcache the necessary things. */
-+#define FS_NO_PRELIM  4 /* prevent preloading of dentries, even if
-+                         * FS_NO_DCACHE is not set.
-+                         */
-+#define FS_SINGLE     8 /* Filesystem that can have only one superblock */
-+#define FS_NOMOUNT    16 /* Never mount from userland */
-+#define FS_LITTER     32 /* Keeps the tree in dcache */
-+#define FS_ODD_RENAME 32768   /* Temporary stuff; will go away as soon
-+                                * as nfs_rename() will be cleaned up
-+                                */
-+/*
-+ * These are the fs-independent mount-flags: up to 32 flags are supported
-+ */
-+#define MS_RDONLY      1      /* Mount read-only */
-+#define MS_NOSUID      2      /* Ignore suid and sgid bits */
-+#define MS_NODEV       4      /* Disallow access to device special files */
-+#define MS_NOEXEC      8      /* Disallow program execution */
-+#define MS_SYNCHRONOUS        16      /* Writes are synced at once */
-+#define MS_REMOUNT    32      /* Alter flags of a mounted FS */
-+#define MS_MANDLOCK   64      /* Allow mandatory locks on an FS */
-+#define MS_NOATIME    1024    /* Do not update access times. */
-+#define MS_NODIRATIME 2048    /* Do not update directory access times */
-+#define MS_BIND               4096
-+#define MS_MOVE               8192
-+#define MS_REC                16384
-+#define MS_VERBOSE    32768
-+#define MS_POSIXACL   65536   /* VFS does not apply the umask */
-+#define MS_ACTIVE     (1<<30)
-+#define MS_NOUSER     (1<<31)
-+
-+/*
-+ * Superblock flags that can be altered by MS_REMOUNT
-+ */
-+#define MS_RMT_MASK   (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME|\
-+                       MS_NODIRATIME)
-+
-+/*
-+ * Old magic mount flag and mask
-+ */
-+#define MS_MGC_VAL 0xC0ED0000
-+#define MS_MGC_MSK 0xffff0000
-+
-+/* Inode flags - they have nothing to superblock flags now */
-+
-+#define S_SYNC                1       /* Writes are synced at once */
-+#define S_NOATIME     2       /* Do not update access times */
-+#define S_QUOTA               4       /* Quota initialized for file */
-+#define S_APPEND      8       /* Append-only file */
-+#define S_IMMUTABLE   16      /* Immutable file */
-+#define S_DEAD                32      /* removed, but still open directory */
-+#define S_NOQUOTA     64      /* Inode is not counted to quota */
-+
-+/*
-+ * Note that nosuid etc flags are inode-specific: setting some file-system
-+ * flags just means all the inodes inherit those flags by default. It might be
-+ * possible to override it selectively if you really wanted to with some
-+ * ioctl() that is not currently implemented.
-+ *
-+ * Exception: MS_RDONLY is always applied to the entire file system.
-+ *
-+ * Unfortunately, it is possible to change a filesystems flags with it mounted
-+ * with files in use.  This means that all of the inodes will not have their
-+ * i_flags updated.  Hence, i_flags no longer inherit the superblock mount
-+ * flags, so these have to be checked separately. -- rmk@arm.uk.linux.org
-+ */
-+#define __IS_FLG(inode,flg) ((inode)->i_sb->s_flags & (flg))
-+
-+#define IS_RDONLY(inode) ((inode)->i_sb->s_flags & MS_RDONLY)
-+#define IS_SYNC(inode)                (__IS_FLG(inode, MS_SYNCHRONOUS) || ((inode)->i_flags & S_SYNC))
-+#define IS_MANDLOCK(inode)    __IS_FLG(inode, MS_MANDLOCK)
-+
-+#define IS_QUOTAINIT(inode)   ((inode)->i_flags & S_QUOTA)
-+#define IS_NOQUOTA(inode)     ((inode)->i_flags & S_NOQUOTA)
-+#define IS_APPEND(inode)      ((inode)->i_flags & S_APPEND)
-+#define IS_IMMUTABLE(inode)   ((inode)->i_flags & S_IMMUTABLE)
-+#define IS_NOATIME(inode)     (__IS_FLG(inode, MS_NOATIME) || ((inode)->i_flags & S_NOATIME))
-+#define IS_NODIRATIME(inode)  __IS_FLG(inode, MS_NODIRATIME)
-+#define IS_POSIXACL(inode)    __IS_FLG(inode, MS_POSIXACL)
-+
-+#define IS_DEADDIR(inode)     ((inode)->i_flags & S_DEAD)
-+
-+/* the read-only stuff doesn't really belong here, but any other place is
-+   probably as bad and I don't want to create yet another include file. */
-+
-+#define BLKROSET   _IO(0x12,93)       /* set device read-only (0 = read-write) */
-+#define BLKROGET   _IO(0x12,94)       /* get read-only status (0 = read_write) */
-+#define BLKRRPART  _IO(0x12,95)       /* re-read partition table */
-+#define BLKGETSIZE _IO(0x12,96)       /* return device size /512 (long *arg) */
-+#define BLKFLSBUF  _IO(0x12,97)       /* flush buffer cache */
-+#define BLKRASET   _IO(0x12,98)       /* Set read ahead for block device */
-+#define BLKRAGET   _IO(0x12,99)       /* get current read ahead setting */
-+#define BLKFRASET  _IO(0x12,100)/* set filesystem (mm/filemap.c) read-ahead */
-+#define BLKFRAGET  _IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */
-+#define BLKSECTSET _IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */
-+#define BLKSECTGET _IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */
-+#define BLKSSZGET  _IO(0x12,104)/* get block device sector size */
-+#if 0
-+#define BLKPG      _IO(0x12,105)/* See blkpg.h */
-+#define BLKELVGET  _IOR(0x12,106,sizeof(blkelv_ioctl_arg_t))/* elevator get */
-+#define BLKELVSET  _IOW(0x12,107,sizeof(blkelv_ioctl_arg_t))/* elevator set */
-+/* This was here just to show that the number is taken -
-+   probably all these _IO(0x12,*) ioctls should be moved to blkpg.h. */
-+#endif
-+/* A jump here: 108-111 have been used for various private purposes. */
-+#define BLKBSZGET  _IOR(0x12,112,sizeof(int))
-+#define BLKBSZSET  _IOW(0x12,113,sizeof(int))
-+#define BLKGETSIZE64 _IOR(0x12,114,sizeof(u64))       /* return device size in bytes (u64 *arg) */
-+
-+#define BMAP_IOCTL 1          /* obsolete - kept for compatibility */
-+#define FIBMAP           _IO(0x00,1)  /* bmap access */
-+#define FIGETBSZ   _IO(0x00,2)        /* get the block size used for bmap */
-+
-+#ifdef __KERNEL__
-+
-+#include <asm/semaphore.h>
-+#include <asm/byteorder.h>
-+
-+extern void update_atime (struct inode *);
-+#define UPDATE_ATIME(inode) update_atime (inode)
-+
-+extern void buffer_init(unsigned long);
-+extern void inode_init(unsigned long);
-+extern void mnt_init(unsigned long);
-+
-+/* bh state bits */
-+enum bh_state_bits {
-+      BH_Uptodate,    /* 1 if the buffer contains valid data */
-+      BH_Dirty,       /* 1 if the buffer is dirty */
-+      BH_Lock,        /* 1 if the buffer is locked */
-+      BH_Req,         /* 0 if the buffer has been invalidated */
-+      BH_Mapped,      /* 1 if the buffer has a disk mapping */
-+      BH_New,         /* 1 if the buffer is new and not yet written out */
-+      BH_Async,       /* 1 if the buffer is under end_buffer_io_async I/O */
-+      BH_Wait_IO,     /* 1 if we should write out this buffer */
-+      BH_Launder,     /* 1 if we can throttle on this buffer */
-+      BH_JBD,         /* 1 if it has an attached journal_head */
-+      BH_Delay,       /* 1 if the buffer is delayed allocate */
-+
-+      BH_PrivateStart,/* not a state bit, but the first bit available
-+                       * for private allocation by other entities
-+                       */
-+};
-+
-+#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
-+
-+/*
-+ * Try to keep the most commonly used fields in single cache lines (16
-+ * bytes) to improve performance.  This ordering should be
-+ * particularly beneficial on 32-bit processors.
-+ * 
-+ * We use the first 16 bytes for the data which is used in searches
-+ * over the block hash lists (ie. getblk() and friends).
-+ * 
-+ * The second 16 bytes we use for lru buffer scans, as used by
-+ * sync_buffers() and refill_freelist().  -- sct
-+ */
-+struct buffer_head {
-+      /* First cache line: */
-+      struct buffer_head *b_next;     /* Hash queue list */
-+      unsigned long b_blocknr;        /* block number */
-+      unsigned short b_size;          /* block size */
-+      unsigned short b_list;          /* List that this buffer appears */
-+      kdev_t b_dev;                   /* device (B_FREE = free) */
-+
-+      atomic_t b_count;               /* users using this block */
-+      kdev_t b_rdev;                  /* Real device */
-+      unsigned long b_state;          /* buffer state bitmap (see above) */
-+      unsigned long b_flushtime;      /* Time when (dirty) buffer should be written */
-+
-+      struct buffer_head *b_next_free;/* lru/free list linkage */
-+      struct buffer_head *b_prev_free;/* doubly linked list of buffers */
-+      struct buffer_head *b_this_page;/* circular list of buffers in one page */
-+      struct buffer_head *b_reqnext;  /* request queue */
-+
-+      struct buffer_head **b_pprev;   /* doubly linked list of hash-queue */
-+      char * b_data;                  /* pointer to data block */
-+      struct page *b_page;            /* the page this bh is mapped to */
-+      void (*b_end_io)(struct buffer_head *bh, int uptodate); /* I/O completion */
-+      void *b_private;                /* reserved for b_end_io */
-+
-+      unsigned long b_rsector;        /* Real buffer location on disk */
-+      wait_queue_head_t b_wait;
-+
-+      struct inode *       b_inode;
-+      struct list_head     b_inode_buffers;   /* doubly linked list of inode dirty buffers */
-+};
-+
-+typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
-+void init_buffer(struct buffer_head *, bh_end_io_t *, void *);
-+
-+#define __buffer_state(bh, state)     (((bh)->b_state & (1UL << BH_##state)) != 0)
-+
-+#define buffer_uptodate(bh)   __buffer_state(bh,Uptodate)
-+#define buffer_dirty(bh)      __buffer_state(bh,Dirty)
-+#define buffer_locked(bh)     __buffer_state(bh,Lock)
-+#define buffer_req(bh)                __buffer_state(bh,Req)
-+#define buffer_mapped(bh)     __buffer_state(bh,Mapped)
-+#define buffer_new(bh)                __buffer_state(bh,New)
-+#define buffer_async(bh)      __buffer_state(bh,Async)
-+#define buffer_launder(bh)    __buffer_state(bh,Launder)
-+#define buffer_delay(bh)      __buffer_state(bh,Delay)
-+
-+#define bh_offset(bh)         ((unsigned long)(bh)->b_data & ~PAGE_MASK)
-+
-+extern void set_bh_page(struct buffer_head *bh, struct page *page, unsigned long offset);
-+
-+#define touch_buffer(bh)      mark_page_accessed(bh->b_page)
-+
-+
-+#include <linux/pipe_fs_i.h>
-+#include <linux/minix_fs_i.h>
-+#include <linux/ext2_fs_i.h>
-+#include <linux/ext3_fs_i.h>
-+#include <linux/hpfs_fs_i.h>
-+#include <linux/ntfs_fs_i.h>
-+#include <linux/msdos_fs_i.h>
-+#include <linux/umsdos_fs_i.h>
-+#include <linux/iso_fs_i.h>
-+#include <linux/nfs_fs_i.h>
-+#include <linux/sysv_fs_i.h>
-+#include <linux/affs_fs_i.h>
-+#include <linux/ufs_fs_i.h>
-+#include <linux/efs_fs_i.h>
-+#include <linux/coda_fs_i.h>
-+#include <linux/romfs_fs_i.h>
-+#include <linux/shmem_fs.h>
-+#include <linux/smb_fs_i.h>
-+#include <linux/hfs_fs_i.h>
-+#include <linux/adfs_fs_i.h>
-+#include <linux/qnx4_fs_i.h>
-+#include <linux/reiserfs_fs_i.h>
-+#include <linux/bfs_fs_i.h>
-+#include <linux/udf_fs_i.h>
-+#include <linux/ncp_fs_i.h>
-+#include <linux/proc_fs_i.h>
-+#include <linux/usbdev_fs_i.h>
-+#include <linux/jffs2_fs_i.h>
-+#include <linux/cramfs_fs_sb.h>
-+
-+/*
-+ * Attribute flags.  These should be or-ed together to figure out what
-+ * has been changed!
-+ */
-+#define ATTR_MODE     1
-+#define ATTR_UID      2
-+#define ATTR_GID      4
-+#define ATTR_SIZE     8
-+#define ATTR_ATIME    16
-+#define ATTR_MTIME    32
-+#define ATTR_CTIME    64
-+#define ATTR_ATIME_SET        128
-+#define ATTR_MTIME_SET        256
-+#define ATTR_FORCE    512     /* Not a change, but a change it */
-+#define ATTR_ATTR_FLAG        1024
-+#define ATTR_RAW      2048    /* file system, not vfs will massage attrs */
-+#define ATTR_FROM_OPEN        4096    /* called from open path, ie O_TRUNC */
-+
-+/*
-+ * This is the Inode Attributes structure, used for notify_change().  It
-+ * uses the above definitions as flags, to know which values have changed.
-+ * Also, in this manner, a Filesystem can look at only the values it cares
-+ * about.  Basically, these are the attributes that the VFS layer can
-+ * request to change from the FS layer.
-+ *
-+ * Derek Atkins <warlord@MIT.EDU> 94-10-20
-+ */
-+struct iattr {
-+      unsigned int    ia_valid;
-+      umode_t         ia_mode;
-+      uid_t           ia_uid;
-+      gid_t           ia_gid;
-+      loff_t          ia_size;
-+      time_t          ia_atime;
-+      time_t          ia_mtime;
-+      time_t          ia_ctime;
-+      unsigned int    ia_attr_flags;
-+};
-+
-+/*
-+ * This is the inode attributes flag definitions
-+ */
-+#define ATTR_FLAG_SYNCRONOUS  1       /* Syncronous write */
-+#define ATTR_FLAG_NOATIME     2       /* Don't update atime */
-+#define ATTR_FLAG_APPEND      4       /* Append-only file */
-+#define ATTR_FLAG_IMMUTABLE   8       /* Immutable file */
-+#define ATTR_FLAG_NODIRATIME  16      /* Don't update atime for directory */
-+
-+/*
-+ * Includes for diskquotas and mount structures.
-+ */
-+#include <linux/quota.h>
-+#include <linux/mount.h>
-+
-+/*
-+ * oh the beauties of C type declarations.
-+ */
-+struct page;
-+struct address_space;
-+struct kiobuf;
-+
-+struct address_space_operations {
-+      int (*writepage)(struct page *);
-+      int (*readpage)(struct file *, struct page *);
-+      int (*sync_page)(struct page *);
-+      /*
-+       * ext3 requires that a successful prepare_write() call be followed
-+       * by a commit_write() call - they must be balanced
-+       */
-+      int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
-+      int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
-+      /* Unfortunately this kludge is needed for FIBMAP. Don't use it */
-+      int (*bmap)(struct address_space *, long);
-+      int (*flushpage) (struct page *, unsigned long);
-+      int (*releasepage) (struct page *, int);
-+#define KERNEL_HAS_O_DIRECT /* this is for modules out of the kernel */
-+      int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int);
-+};
-+
-+struct address_space {
-+      struct list_head        clean_pages;    /* list of clean pages */
-+      struct list_head        dirty_pages;    /* list of dirty pages */
-+      struct list_head        locked_pages;   /* list of locked pages */
-+      unsigned long           nrpages;        /* number of total pages */
-+      struct address_space_operations *a_ops; /* methods */
-+      struct inode            *host;          /* owner: inode, block_device */
-+      struct vm_area_struct   *i_mmap;        /* list of private mappings */
-+      struct vm_area_struct   *i_mmap_shared; /* list of shared mappings */
-+      spinlock_t              i_shared_lock;  /* and spinlock protecting it */
-+      int                     gfp_mask;       /* how to allocate the pages */
-+};
-+
-+struct char_device {
-+      struct list_head        hash;
-+      atomic_t                count;
-+      dev_t                   dev;
-+      atomic_t                openers;
-+      struct semaphore        sem;
-+};
-+
-+struct block_device {
-+      struct list_head        bd_hash;
-+      atomic_t                bd_count;
-+      struct inode *          bd_inode;
-+      dev_t                   bd_dev;  /* not a kdev_t - it's a search key */
-+      int                     bd_openers;
-+      const struct block_device_operations *bd_op;
-+      struct semaphore        bd_sem; /* open/close mutex */
-+      struct list_head        bd_inodes;
-+};
-+
-+struct inode {
-+      struct list_head        i_hash;
-+      struct list_head        i_list;
-+      struct list_head        i_dentry;
-+      
-+      struct list_head        i_dirty_buffers;
-+      struct list_head        i_dirty_data_buffers;
-+
-+      unsigned long           i_ino;
-+      atomic_t                i_count;
-+      kdev_t                  i_dev;
-+      umode_t                 i_mode;
-+      nlink_t                 i_nlink;
-+      uid_t                   i_uid;
-+      gid_t                   i_gid;
-+      kdev_t                  i_rdev;
-+      loff_t                  i_size;
-+      time_t                  i_atime;
-+      time_t                  i_mtime;
-+      time_t                  i_ctime;
-+      unsigned int            i_blkbits;
-+      unsigned long           i_blksize;
-+      unsigned long           i_blocks;
-+      unsigned long           i_version;
-+      unsigned short          i_bytes;
-+      struct semaphore        i_sem;
-+      struct semaphore        i_zombie;
-+      struct inode_operations *i_op;
-+      struct file_operations  *i_fop; /* former ->i_op->default_file_ops */
-+      struct super_block      *i_sb;
-+      wait_queue_head_t       i_wait;
-+      struct file_lock        *i_flock;
-+      struct address_space    *i_mapping;
-+      struct address_space    i_data;
-+      struct dquot            *i_dquot[MAXQUOTAS];
-+      /* These three should probably be a union */
-+      struct list_head        i_devices;
-+      struct pipe_inode_info  *i_pipe;
-+      struct block_device     *i_bdev;
-+      struct char_device      *i_cdev;
-+
-+      unsigned long           i_dnotify_mask; /* Directory notify events */
-+      struct dnotify_struct   *i_dnotify; /* for directory notifications */
-+
-+      unsigned long           i_state;
-+
-+      unsigned int            i_flags;
-+      unsigned char           i_sock;
-+
-+      atomic_t                i_writecount;
-+      unsigned int            i_attr_flags;
-+      __u32                   i_generation;
-+      union {
-+              struct minix_inode_info         minix_i;
-+              struct ext2_inode_info          ext2_i;
-+              struct ext3_inode_info          ext3_i;
-+              struct hpfs_inode_info          hpfs_i;
-+              struct ntfs_inode_info          ntfs_i;
-+              struct msdos_inode_info         msdos_i;
-+              struct umsdos_inode_info        umsdos_i;
-+              struct iso_inode_info           isofs_i;
-+              struct nfs_inode_info           nfs_i;
-+              struct sysv_inode_info          sysv_i;
-+              struct affs_inode_info          affs_i;
-+              struct ufs_inode_info           ufs_i;
-+              struct efs_inode_info           efs_i;
-+              struct romfs_inode_info         romfs_i;
-+              struct shmem_inode_info         shmem_i;
-+              struct coda_inode_info          coda_i;
-+              struct smb_inode_info           smbfs_i;
-+              struct hfs_inode_info           hfs_i;
-+              struct adfs_inode_info          adfs_i;
-+              struct qnx4_inode_info          qnx4_i;
-+              struct reiserfs_inode_info      reiserfs_i;
-+              struct bfs_inode_info           bfs_i;
-+              struct udf_inode_info           udf_i;
-+              struct ncp_inode_info           ncpfs_i;
-+              struct proc_inode_info          proc_i;
-+              struct socket                   socket_i;
-+              struct usbdev_inode_info        usbdev_i;
-+              struct jffs2_inode_info         jffs2_i;
-+              void                            *generic_ip;
-+      } u;
-+};
-+
-+static inline void inode_add_bytes(struct inode *inode, loff_t bytes)
-+{
-+      inode->i_blocks += bytes >> 9;
-+      bytes &= 511;
-+      inode->i_bytes += bytes;
-+      if (inode->i_bytes >= 512) {
-+              inode->i_blocks++;
-+              inode->i_bytes -= 512;
-+      }
-+}
-+
-+static inline void inode_sub_bytes(struct inode *inode, loff_t bytes)
-+{
-+      inode->i_blocks -= bytes >> 9;
-+      bytes &= 511;
-+      if (inode->i_bytes < bytes) {
-+              inode->i_blocks--;
-+              inode->i_bytes += 512;
-+      }
-+      inode->i_bytes -= bytes;
-+}
-+
-+static inline loff_t inode_get_bytes(struct inode *inode)
-+{
-+      return (((loff_t)inode->i_blocks) << 9) + inode->i_bytes;
-+}
-+
-+static inline void inode_set_bytes(struct inode *inode, loff_t bytes)
-+{
-+      inode->i_blocks = bytes >> 9;
-+      inode->i_bytes = bytes & 511;
-+}
-+
-+struct fown_struct {
-+      int pid;                /* pid or -pgrp where SIGIO should be sent */
-+      uid_t uid, euid;        /* uid/euid of process setting the owner */
-+      int signum;             /* posix.1b rt signal to be delivered on IO */
-+};
-+
-+struct file {
-+      struct list_head        f_list;
-+      struct dentry           *f_dentry;
-+      struct vfsmount         *f_vfsmnt;
-+      struct file_operations  *f_op;
-+      atomic_t                f_count;
-+      unsigned int            f_flags;
-+      mode_t                  f_mode;
-+      loff_t                  f_pos;
-+      unsigned long           f_reada, f_ramax, f_raend, f_ralen, f_rawin;
-+      struct fown_struct      f_owner;
-+      unsigned int            f_uid, f_gid;
-+      int                     f_error;
-+
-+      unsigned long           f_version;
-+
-+      /* needed for tty driver, and maybe others */
-+      void                    *private_data;
-+      struct lookup_intent    *f_intent;
-+
-+      /* preallocated helper kiobuf to speedup O_DIRECT */
-+      struct kiobuf           *f_iobuf;
-+      long                    f_iobuf_lock;
-+};
-+extern spinlock_t files_lock;
-+#define file_list_lock() spin_lock(&files_lock);
-+#define file_list_unlock() spin_unlock(&files_lock);
-+
-+#define get_file(x)   atomic_inc(&(x)->f_count)
-+#define file_count(x) atomic_read(&(x)->f_count)
-+
-+extern int init_private_file(struct file *, struct dentry *, int);
-+
-+#define       MAX_NON_LFS     ((1UL<<31) - 1)
-+
-+/* Page cache limit. The filesystems should put that into their s_maxbytes 
-+   limits, otherwise bad things can happen in VM. */ 
-+#if BITS_PER_LONG==32
-+#define MAX_LFS_FILESIZE      (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1) 
-+#elif BITS_PER_LONG==64
-+#define MAX_LFS_FILESIZE      0x7fffffffffffffff
-+#endif
-+#define BLKGETLASTSECT  _IO(0x12,108) /* get last sector of block device */
-+#define BLKSETLASTSECT  _IO(0x12,109) /* get last sector of block device */
-+
-+#define FL_POSIX      1
-+#define FL_FLOCK      2
-+#define FL_BROKEN     4       /* broken flock() emulation */
-+#define FL_ACCESS     8       /* for processes suspended by mandatory locking */
-+#define FL_LOCKD      16      /* lock held by rpc.lockd */
-+#define FL_LEASE      32      /* lease held on this file */
-+
-+/*
-+ * The POSIX file lock owner is determined by
-+ * the "struct files_struct" in the thread group
-+ * (or NULL for no owner - BSD locks).
-+ *
-+ * Lockd stuffs a "host" pointer into this.
-+ */
-+typedef struct files_struct *fl_owner_t;
-+
-+struct file_lock {
-+      struct file_lock *fl_next;      /* singly linked list for this inode  */
-+      struct list_head fl_link;       /* doubly linked list of all locks */
-+      struct list_head fl_block;      /* circular list of blocked processes */
-+      fl_owner_t fl_owner;
-+      unsigned int fl_pid;
-+      wait_queue_head_t fl_wait;
-+      struct file *fl_file;
-+      unsigned char fl_flags;
-+      unsigned char fl_type;
-+      loff_t fl_start;
-+      loff_t fl_end;
-+
-+      void (*fl_notify)(struct file_lock *);  /* unblock callback */
-+      void (*fl_insert)(struct file_lock *);  /* lock insertion callback */
-+      void (*fl_remove)(struct file_lock *);  /* lock removal callback */
-+
-+      struct fasync_struct *  fl_fasync; /* for lease break notifications */
-+
-+      union {
-+              struct nfs_lock_info    nfs_fl;
-+      } fl_u;
-+};
-+
-+/* The following constant reflects the upper bound of the file/locking space */
-+#ifndef OFFSET_MAX
-+#define INT_LIMIT(x)  (~((x)1 << (sizeof(x)*8 - 1)))
-+#define OFFSET_MAX    INT_LIMIT(loff_t)
-+#define OFFT_OFFSET_MAX       INT_LIMIT(off_t)
-+#endif
-+
-+extern struct list_head file_lock_list;
-+
-+#include <linux/fcntl.h>
-+
-+extern int fcntl_getlk(unsigned int, struct flock *);
-+extern int fcntl_setlk(unsigned int, unsigned int, struct flock *);
-+
-+extern int fcntl_getlk64(unsigned int, struct flock64 *);
-+extern int fcntl_setlk64(unsigned int, unsigned int, struct flock64 *);
-+
-+/* fs/locks.c */
-+extern void locks_init_lock(struct file_lock *);
-+extern void locks_copy_lock(struct file_lock *, struct file_lock *);
-+extern void locks_remove_posix(struct file *, fl_owner_t);
-+extern void locks_remove_flock(struct file *);
-+extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
-+extern int posix_lock_file(struct file *, struct file_lock *, unsigned int);
-+extern void posix_block_lock(struct file_lock *, struct file_lock *);
-+extern void posix_unblock_lock(struct file_lock *);
-+extern int posix_locks_deadlock(struct file_lock *, struct file_lock *);
-+extern int __get_lease(struct inode *inode, unsigned int flags);
-+extern time_t lease_get_mtime(struct inode *);
-+extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
-+extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
-+
-+struct fasync_struct {
-+      int     magic;
-+      int     fa_fd;
-+      struct  fasync_struct   *fa_next; /* singly linked list */
-+      struct  file            *fa_file;
-+};
-+
-+#define FASYNC_MAGIC 0x4601
-+
-+/* SMP safe fasync helpers: */
-+extern int fasync_helper(int, struct file *, int, struct fasync_struct **);
-+/* can be called from interrupts */
-+extern void kill_fasync(struct fasync_struct **, int, int);
-+/* only for net: no internal synchronization */
-+extern void __kill_fasync(struct fasync_struct *, int, int);
-+
-+struct nameidata {
-+      struct dentry *dentry;
-+      struct vfsmount *mnt;
-+      struct qstr last;
-+      unsigned int flags;
-+      int last_type;
-+};
-+
-+/*
-+ *    Umount options
-+ */
-+
-+#define MNT_FORCE     0x00000001      /* Attempt to forcibily umount */
-+#define MNT_DETACH    0x00000002      /* Just detach from the tree */
-+
-+#include <linux/minix_fs_sb.h>
-+#include <linux/ext2_fs_sb.h>
-+#include <linux/ext3_fs_sb.h>
-+#include <linux/hpfs_fs_sb.h>
-+#include <linux/ntfs_fs_sb.h>
-+#include <linux/msdos_fs_sb.h>
-+#include <linux/iso_fs_sb.h>
-+#include <linux/nfs_fs_sb.h>
-+#include <linux/sysv_fs_sb.h>
-+#include <linux/affs_fs_sb.h>
-+#include <linux/ufs_fs_sb.h>
-+#include <linux/efs_fs_sb.h>
-+#include <linux/romfs_fs_sb.h>
-+#include <linux/smb_fs_sb.h>
-+#include <linux/hfs_fs_sb.h>
-+#include <linux/adfs_fs_sb.h>
-+#include <linux/qnx4_fs_sb.h>
-+#include <linux/reiserfs_fs_sb.h>
-+#include <linux/bfs_fs_sb.h>
-+#include <linux/udf_fs_sb.h>
-+#include <linux/ncp_fs_sb.h>
-+#include <linux/usbdev_fs_sb.h>
-+#include <linux/cramfs_fs_sb.h>
-+#include <linux/jffs2_fs_sb.h>
-+
-+extern struct list_head super_blocks;
-+extern spinlock_t sb_lock;
-+
-+#define sb_entry(list)        list_entry((list), struct super_block, s_list)
-+#define S_BIAS (1<<30)
-+struct super_block {
-+      struct list_head        s_list;         /* Keep this first */
-+      kdev_t                  s_dev;
-+      unsigned long           s_blocksize;
-+      unsigned char           s_blocksize_bits;
-+      unsigned char           s_dirt;
-+      unsigned long long      s_maxbytes;     /* Max file size */
-+      struct file_system_type *s_type;
-+      struct super_operations *s_op;
-+      struct dquot_operations *dq_op;
-+      struct quotactl_ops     *s_qcop;
-+      unsigned long           s_flags;
-+      unsigned long           s_magic;
-+      struct dentry           *s_root;
-+      struct rw_semaphore     s_umount;
-+      struct semaphore        s_lock;
-+      int                     s_count;
-+      atomic_t                s_active;
-+
-+      struct list_head        s_dirty;        /* dirty inodes */
-+      struct list_head        s_locked_inodes;/* inodes being synced */
-+      struct list_head        s_files;
-+
-+      struct block_device     *s_bdev;
-+      struct list_head        s_instances;
-+      struct quota_info       s_dquot;        /* Diskquota specific options */
-+
-+      union {
-+              struct minix_sb_info    minix_sb;
-+              struct ext2_sb_info     ext2_sb;
-+              struct ext3_sb_info     ext3_sb;
-+              struct hpfs_sb_info     hpfs_sb;
-+              struct ntfs_sb_info     ntfs_sb;
-+              struct msdos_sb_info    msdos_sb;
-+              struct isofs_sb_info    isofs_sb;
-+              struct nfs_sb_info      nfs_sb;
-+              struct sysv_sb_info     sysv_sb;
-+              struct affs_sb_info     affs_sb;
-+              struct ufs_sb_info      ufs_sb;
-+              struct efs_sb_info      efs_sb;
-+              struct shmem_sb_info    shmem_sb;
-+              struct romfs_sb_info    romfs_sb;
-+              struct smb_sb_info      smbfs_sb;
-+              struct hfs_sb_info      hfs_sb;
-+              struct adfs_sb_info     adfs_sb;
-+              struct qnx4_sb_info     qnx4_sb;
-+              struct reiserfs_sb_info reiserfs_sb;
-+              struct bfs_sb_info      bfs_sb;
-+              struct udf_sb_info      udf_sb;
-+              struct ncp_sb_info      ncpfs_sb;
-+              struct usbdev_sb_info   usbdevfs_sb;
-+              struct jffs2_sb_info    jffs2_sb;
-+              struct cramfs_sb_info   cramfs_sb;
-+              void                    *generic_sbp;
-+      } u;
-+      /*
-+       * The next field is for VFS *only*. No filesystems have any business
-+       * even looking at it. You had been warned.
-+       */
-+      struct semaphore s_vfs_rename_sem;      /* Kludge */
-+
-+      /* The next field is used by knfsd when converting a (inode number based)
-+       * file handle into a dentry. As it builds a path in the dcache tree from
-+       * the bottom up, there may for a time be a subpath of dentrys which is not
-+       * connected to the main tree.  This semaphore ensure that there is only ever
-+       * one such free path per filesystem.  Note that unconnected files (or other
-+       * non-directories) are allowed, but not unconnected diretories.
-+       */
-+      struct semaphore s_nfsd_free_path_sem;
-+};
-+
-+/*
-+ * VFS helper functions..
-+ */
-+extern int vfs_create(struct inode *, struct dentry *, int);
-+extern int vfs_mkdir(struct inode *, struct dentry *, int);
-+extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
-+extern int vfs_symlink(struct inode *, struct dentry *, const char *);
-+extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
-+extern int vfs_rmdir(struct inode *, struct dentry *);
-+extern int vfs_unlink(struct inode *, struct dentry *);
-+int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
-+              struct inode *new_dir, struct dentry *new_dentry,
-+              struct lookup_intent *it);
-+
-+/*
-+ * File types
-+ */
-+#define DT_UNKNOWN    0
-+#define DT_FIFO               1
-+#define DT_CHR                2
-+#define DT_DIR                4
-+#define DT_BLK                6
-+#define DT_REG                8
-+#define DT_LNK                10
-+#define DT_SOCK               12
-+#define DT_WHT                14
-+
-+/*
-+ * This is the "filldir" function type, used by readdir() to let
-+ * the kernel specify what kind of dirent layout it wants to have.
-+ * This allows the kernel to read directories into kernel space or
-+ * to have different dirent layouts depending on the binary type.
-+ */
-+typedef int (*filldir_t)(void *, const char *, int, loff_t, ino_t, unsigned);
-+
-+struct block_device_operations {
-+      int (*open) (struct inode *, struct file *);
-+      int (*release) (struct inode *, struct file *);
-+      int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
-+      int (*check_media_change) (kdev_t);
-+      int (*revalidate) (kdev_t);
-+      struct module *owner;
-+};
-+
-+/*
-+ * NOTE:
-+ * read, write, poll, fsync, readv, writev can be called
-+ *   without the big kernel lock held in all filesystems.
-+ */
-+struct file_operations {
-+      struct module *owner;
-+      loff_t (*llseek) (struct file *, loff_t, int);
-+      ssize_t (*read) (struct file *, char *, size_t, loff_t *);
-+      ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
-+      int (*readdir) (struct file *, void *, filldir_t);
-+      unsigned int (*poll) (struct file *, struct poll_table_struct *);
-+      int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
-+      int (*mmap) (struct file *, struct vm_area_struct *);
-+      int (*open) (struct inode *, struct file *);
-+      int (*flush) (struct file *);
-+      int (*release) (struct inode *, struct file *);
-+      int (*fsync) (struct file *, struct dentry *, int datasync);
-+      int (*fasync) (int, struct file *, int);
-+      int (*lock) (struct file *, int, struct file_lock *);
-+      ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
-+      ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
-+      ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
-+      unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
-+};
-+
-+struct inode_operations {
-+      int (*create) (struct inode *,struct dentry *,int);
-+      struct dentry * (*lookup) (struct inode *,struct dentry *);
-+      struct dentry * (*lookup2) (struct inode *,struct dentry *, struct lookup_intent *);
-+      int (*link) (struct dentry *,struct inode *,struct dentry *);
-+      int (*link2) (struct inode *,struct inode *, const char *, int);
-+      int (*unlink) (struct inode *,struct dentry *);
-+      int (*unlink2) (struct inode *, const char *, int);
-+      int (*symlink) (struct inode *,struct dentry *,const char *);
-+      int (*symlink2) (struct inode *, const char *, int, const char *);
-+      int (*mkdir) (struct inode *,struct dentry *,int);
-+      int (*mkdir2) (struct inode *, const char *, int,int);
-+      int (*rmdir) (struct inode *,struct dentry *);
-+      int (*rmdir2) (struct inode *, const char *, int);
-+      int (*mknod) (struct inode *,struct dentry *,int,int);
-+      int (*mknod2) (struct inode *, const char *, int,int,int);
-+      int (*rename) (struct inode *, struct dentry *,
-+                      struct inode *, struct dentry *);
-+      int (*rename2) (struct inode *, struct inode *,
-+                      const char *oldname, int oldlen,
-+                      const char *newname, int newlen);
-+      int (*readlink) (struct dentry *, char *,int);
-+      int (*follow_link) (struct dentry *, struct nameidata *);
-+      int (*follow_link2) (struct dentry *, struct nameidata *,
-+                           struct lookup_intent *it);
-+      void (*truncate) (struct inode *);
-+      int (*permission) (struct inode *, int);
-+      int (*revalidate) (struct dentry *);
-+      int (*setattr) (struct dentry *, struct iattr *);
-+      int (*setattr_raw) (struct inode *, struct iattr *);
-+      int (*getattr) (struct dentry *, struct iattr *);
-+      int (*setxattr) (struct dentry *, const char *, void *, size_t, int);
-+      ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
-+      ssize_t (*listxattr) (struct dentry *, char *, size_t);
-+      int (*removexattr) (struct dentry *, const char *);
-+};
-+
-+struct seq_file;
-+
-+/*
-+ * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called
-+ * without the big kernel lock held in all filesystems.
-+ */
-+struct super_operations {
-+      struct inode *(*alloc_inode)(struct super_block *sb);
-+      void (*destroy_inode)(struct inode *);
-+
-+      void (*read_inode) (struct inode *);
-+  
-+      /* reiserfs kludge.  reiserfs needs 64 bits of information to
-+      ** find an inode.  We are using the read_inode2 call to get
-+      ** that information.  We don't like this, and are waiting on some
-+      ** VFS changes for the real solution.
-+      ** iget4 calls read_inode2, iff it is defined
-+      */
-+      void (*read_inode2) (struct inode *, void *) ;
-+      void (*dirty_inode) (struct inode *);
-+      void (*write_inode) (struct inode *, int);
-+      void (*put_inode) (struct inode *);
-+      void (*delete_inode) (struct inode *);
-+      void (*put_super) (struct super_block *);
-+      void (*write_super) (struct super_block *);
-+      void (*write_super_lockfs) (struct super_block *);
-+      void (*unlockfs) (struct super_block *);
-+      int (*statfs) (struct super_block *, struct statfs *);
-+      int (*remount_fs) (struct super_block *, int *, char *);
-+      void (*clear_inode) (struct inode *);
-+      void (*umount_begin) (struct super_block *);
-+
-+      /* Following are for knfsd to interact with "interesting" filesystems
-+       * Currently just reiserfs, but possibly FAT and others later
-+       *
-+       * fh_to_dentry is given a filehandle fragement with length, and a type flag
-+       *   and must return a dentry for the referenced object or, if "parent" is
-+       *   set, a dentry for the parent of the object.
-+       *   If a dentry cannot be found, a "root" dentry should be created and
-+       *   flaged as DCACHE_NFSD_DISCONNECTED. nfsd_iget is an example implementation.
-+       *
-+       * dentry_to_fh is given a dentry and must generate the filesys specific
-+       *   part of the file handle.  Available length is passed in *lenp and used
-+       *   length should be returned therein.
-+       *   If need_parent is set, then dentry_to_fh should encode sufficient information
-+       *   to find the (current) parent.
-+       *   dentry_to_fh should return a 1byte "type" which will be passed back in
-+       *   the fhtype arguement to fh_to_dentry.  Type of 0 is reserved.
-+       *   If filesystem was exportable before the introduction of fh_to_dentry,
-+       *   types 1 and 2 should be used is that same way as the generic code.
-+       *   Type 255 means error.
-+       *
-+       * Lengths are in units of 4bytes, not bytes.
-+       */
-+      struct dentry * (*fh_to_dentry)(struct super_block *sb, __u32 *fh, int len, int fhtype, int parent);
-+      int (*dentry_to_fh)(struct dentry *, __u32 *fh, int *lenp, int need_parent);
-+      int (*show_options)(struct seq_file *, struct vfsmount *);
-+};
-+
-+/* Inode state bits.. */
-+#define I_DIRTY_SYNC          1 /* Not dirty enough for O_DATASYNC */
-+#define I_DIRTY_DATASYNC      2 /* Data-related inode changes pending */
-+#define I_DIRTY_PAGES         4 /* Data-related inode changes pending */
-+#define I_LOCK                        8
-+#define I_FREEING             16
-+#define I_CLEAR                       32
-+#define I_NEW                 64
-+
-+#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
-+
-+extern void __mark_inode_dirty(struct inode *, int);
-+static inline void mark_inode_dirty(struct inode *inode)
-+{
-+      __mark_inode_dirty(inode, I_DIRTY);
-+}
-+
-+static inline void mark_inode_dirty_sync(struct inode *inode)
-+{
-+      __mark_inode_dirty(inode, I_DIRTY_SYNC);
-+}
-+
-+static inline void mark_inode_dirty_pages(struct inode *inode)
-+{
-+      __mark_inode_dirty(inode, I_DIRTY_PAGES);
-+}
-+
-+struct file_system_type {
-+      const char *name;
-+      int fs_flags;
-+      struct super_block *(*read_super) (struct super_block *, void *, int);
-+      struct module *owner;
-+      struct file_system_type * next;
-+      struct list_head fs_supers;
-+};
-+
-+#define DECLARE_FSTYPE(var,type,read,flags) \
-+struct file_system_type var = { \
-+      name:           type, \
-+      read_super:     read, \
-+      fs_flags:       flags, \
-+      owner:          THIS_MODULE, \
-+}
-+
-+#define DECLARE_FSTYPE_DEV(var,type,read) \
-+      DECLARE_FSTYPE(var,type,read,FS_REQUIRES_DEV)
-+
-+/* Alas, no aliases. Too much hassle with bringing module.h everywhere */
-+#define fops_get(fops) \
-+      (((fops) && (fops)->owner)      \
-+              ? ( try_inc_mod_count((fops)->owner) ? (fops) : NULL ) \
-+              : (fops))
-+
-+#define fops_put(fops) \
-+do {  \
-+      if ((fops) && (fops)->owner) \
-+              __MOD_DEC_USE_COUNT((fops)->owner);     \
-+} while(0)
-+
-+extern int register_filesystem(struct file_system_type *);
-+extern int unregister_filesystem(struct file_system_type *);
-+extern struct vfsmount *kern_mount(struct file_system_type *);
-+extern int may_umount(struct vfsmount *);
-+extern long do_mount(char *, char *, char *, unsigned long, void *);
-+struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data);
-+extern void umount_tree(struct vfsmount *);
-+
-+#define kern_umount mntput
-+
-+extern int vfs_statfs(struct super_block *, struct statfs *);
-+
-+/* Return value for VFS lock functions - tells locks.c to lock conventionally
-+ * REALLY kosha for root NFS and nfs_lock
-+ */ 
-+#define LOCK_USE_CLNT 1
-+
-+#define FLOCK_VERIFY_READ  1
-+#define FLOCK_VERIFY_WRITE 2
-+
-+extern int locks_mandatory_locked(struct inode *);
-+extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t);
-+
-+/*
-+ * Candidates for mandatory locking have the setgid bit set
-+ * but no group execute bit -  an otherwise meaningless combination.
-+ */
-+#define MANDATORY_LOCK(inode) \
-+      (IS_MANDLOCK(inode) && ((inode)->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
-+
-+static inline int locks_verify_locked(struct inode *inode)
-+{
-+      if (MANDATORY_LOCK(inode))
-+              return locks_mandatory_locked(inode);
-+      return 0;
-+}
-+
-+static inline int locks_verify_area(int read_write, struct inode *inode,
-+                                  struct file *filp, loff_t offset,
-+                                  size_t count)
-+{
-+      if (inode->i_flock && MANDATORY_LOCK(inode))
-+              return locks_mandatory_area(read_write, inode, filp, offset, count);
-+      return 0;
-+}
-+
-+static inline int locks_verify_truncate(struct inode *inode,
-+                                  struct file *filp,
-+                                  loff_t size)
-+{
-+      if (inode->i_flock && MANDATORY_LOCK(inode))
-+              return locks_mandatory_area(
-+                      FLOCK_VERIFY_WRITE, inode, filp,
-+                      size < inode->i_size ? size : inode->i_size,
-+                      (size < inode->i_size ? inode->i_size - size
-+                       : size - inode->i_size)
-+              );
-+      return 0;
-+}
-+
-+static inline int get_lease(struct inode *inode, unsigned int mode)
-+{
-+      if (inode->i_flock && (inode->i_flock->fl_flags & FL_LEASE))
-+              return __get_lease(inode, mode);
-+      return 0;
-+}
-+
-+/* fs/open.c */
-+
-+asmlinkage long sys_open(const char *, int, int);
-+asmlinkage long sys_close(unsigned int);      /* yes, it's really unsigned */
-+extern int do_truncate(struct dentry *, loff_t start, int called_from_open);
-+
-+extern struct file *filp_open(const char *, int, int);
-+extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
-+extern int open_namei_it(const char *filename, int namei_flags, int mode,
-+                       struct nameidata *nd, struct lookup_intent *it);
-+extern struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
-+                          int flags, struct lookup_intent *it);
-+extern int filp_close(struct file *, fl_owner_t id);
-+extern char * getname(const char *);
-+
-+/* fs/dcache.c */
-+extern void vfs_caches_init(unsigned long);
-+
-+#define __getname()   kmem_cache_alloc(names_cachep, SLAB_KERNEL)
-+#define putname(name) kmem_cache_free(names_cachep, (void *)(name))
-+
-+enum {BDEV_FILE, BDEV_SWAP, BDEV_FS, BDEV_RAW};
-+extern int register_blkdev(unsigned int, const char *, struct block_device_operations *);
-+extern int unregister_blkdev(unsigned int, const char *);
-+extern struct block_device *bdget(dev_t);
-+extern int bd_acquire(struct inode *inode);
-+extern void bd_forget(struct inode *inode);
-+extern void bdput(struct block_device *);
-+extern struct char_device *cdget(dev_t);
-+extern void cdput(struct char_device *);
-+extern int blkdev_open(struct inode *, struct file *);
-+extern int blkdev_close(struct inode *, struct file *);
-+extern struct file_operations def_blk_fops;
-+extern struct address_space_operations def_blk_aops;
-+extern struct file_operations def_fifo_fops;
-+extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
-+extern int blkdev_get(struct block_device *, mode_t, unsigned, int);
-+extern int blkdev_put(struct block_device *, int);
-+
-+/* fs/devices.c */
-+extern const struct block_device_operations *get_blkfops(unsigned int);
-+extern int register_chrdev(unsigned int, const char *, struct file_operations *);
-+extern int unregister_chrdev(unsigned int, const char *);
-+extern int chrdev_open(struct inode *, struct file *);
-+extern const char * bdevname(kdev_t);
-+extern const char * cdevname(kdev_t);
-+extern const char * kdevname(kdev_t);
-+extern void init_special_inode(struct inode *, umode_t, int);
-+
-+/* Invalid inode operations -- fs/bad_inode.c */
-+extern void make_bad_inode(struct inode *);
-+extern int is_bad_inode(struct inode *);
-+
-+extern struct file_operations read_fifo_fops;
-+extern struct file_operations write_fifo_fops;
-+extern struct file_operations rdwr_fifo_fops;
-+extern struct file_operations read_pipe_fops;
-+extern struct file_operations write_pipe_fops;
-+extern struct file_operations rdwr_pipe_fops;
-+
-+extern int fs_may_remount_ro(struct super_block *);
-+
-+extern int FASTCALL(try_to_free_buffers(struct page *, unsigned int));
-+extern void refile_buffer(struct buffer_head * buf);
-+extern void create_empty_buffers(struct page *, kdev_t, unsigned long);
-+extern void end_buffer_io_sync(struct buffer_head *bh, int uptodate);
-+
-+/* reiserfs_writepage needs this */
-+extern void set_buffer_async_io(struct buffer_head *bh) ;
-+
-+#define BUF_CLEAN     0
-+#define BUF_LOCKED    1       /* Buffers scheduled for write */
-+#define BUF_DIRTY     2       /* Dirty buffers, not yet scheduled for write */
-+#define NR_LIST               3
-+
-+static inline void get_bh(struct buffer_head * bh)
-+{
-+        atomic_inc(&(bh)->b_count);
-+}
-+
-+static inline void put_bh(struct buffer_head *bh)
-+{
-+        smp_mb__before_atomic_dec();
-+        atomic_dec(&bh->b_count);
-+}
-+
-+/*
-+ * This is called by bh->b_end_io() handlers when I/O has completed.
-+ */
-+static inline void mark_buffer_uptodate(struct buffer_head * bh, int on)
-+{
-+      if (on)
-+              set_bit(BH_Uptodate, &bh->b_state);
-+      else
-+              clear_bit(BH_Uptodate, &bh->b_state);
-+}
-+
-+#define atomic_set_buffer_clean(bh) test_and_clear_bit(BH_Dirty, &(bh)->b_state)
-+
-+static inline void __mark_buffer_clean(struct buffer_head *bh)
-+{
-+      refile_buffer(bh);
-+}
-+
-+static inline void mark_buffer_clean(struct buffer_head * bh)
-+{
-+      if (atomic_set_buffer_clean(bh))
-+              __mark_buffer_clean(bh);
-+}
-+
-+extern void FASTCALL(__mark_dirty(struct buffer_head *bh));
-+extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh));
-+extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh));
-+extern void FASTCALL(buffer_insert_inode_queue(struct buffer_head *, struct inode *));
-+extern void FASTCALL(buffer_insert_inode_data_queue(struct buffer_head *, struct inode *));
-+
-+static inline int atomic_set_buffer_dirty(struct buffer_head *bh)
-+{
-+      return test_and_set_bit(BH_Dirty, &bh->b_state);
-+}
-+
-+static inline void mark_buffer_async(struct buffer_head * bh, int on)
-+{
-+      if (on)
-+              set_bit(BH_Async, &bh->b_state);
-+      else
-+              clear_bit(BH_Async, &bh->b_state);
-+}
-+
-+/*
-+ * If an error happens during the make_request, this function
-+ * has to be recalled. It marks the buffer as clean and not
-+ * uptodate, and it notifys the upper layer about the end
-+ * of the I/O.
-+ */
-+static inline void buffer_IO_error(struct buffer_head * bh)
-+{
-+      mark_buffer_clean(bh);
-+      /*
-+       * b_end_io has to clear the BH_Uptodate bitflag in the error case!
-+       */
-+      bh->b_end_io(bh, 0);
-+}
-+
-+static inline void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode)
-+{
-+      mark_buffer_dirty(bh);
-+      buffer_insert_inode_queue(bh, inode);
-+}
-+
-+extern void set_buffer_flushtime(struct buffer_head *);
-+extern void balance_dirty(void);
-+extern int check_disk_change(kdev_t);
+               printk(KERN_ERR "VFS: Busy inodes after unmount. "
+                       "Self-destruct in 5 seconds.  Have a nice day...\n");
+       }
+--- linux-rh-2.4.20-8/include/linux/fs.h~invalidate_show       2003-04-16 20:55:35.000000000 +0800
++++ linux-rh-2.4.20-8-root/include/linux/fs.h  2003-04-16 20:59:35.000000000 +0800
+@@ -1283,7 +1283,7 @@ static inline void mark_buffer_dirty_ino
+ extern void set_buffer_flushtime(struct buffer_head *);
+ extern void balance_dirty(void);
+ extern int check_disk_change(kdev_t);
+-extern int invalidate_inodes(struct super_block *);
 +extern int invalidate_inodes(struct super_block *, int);
-+extern int invalidate_device(kdev_t, int);
-+extern void invalidate_inode_pages(struct inode *);
-+extern void invalidate_inode_pages2(struct address_space *);
-+extern void invalidate_inode_buffers(struct inode *);
-+#define invalidate_buffers(dev)       __invalidate_buffers((dev), 0)
-+#define destroy_buffers(dev)  __invalidate_buffers((dev), 1)
-+extern void invalidate_bdev(struct block_device *, int);
-+extern void __invalidate_buffers(kdev_t dev, int);
-+extern void sync_inodes(kdev_t);
-+extern void sync_unlocked_inodes(void);
-+extern void write_inode_now(struct inode *, int);
-+extern int sync_buffers(kdev_t, int);
-+extern void sync_dev(kdev_t);
-+extern int fsync_dev(kdev_t);
-+extern int fsync_dev_lockfs(kdev_t);
-+extern int fsync_super(struct super_block *);
-+extern int fsync_no_super(kdev_t);
-+extern void sync_inodes_sb(struct super_block *);
-+extern int fsync_buffers_list(struct list_head *);
-+static inline int fsync_inode_buffers(struct inode *inode)
-+{
-+      return fsync_buffers_list(&inode->i_dirty_buffers);
-+}
-+static inline int fsync_inode_data_buffers(struct inode *inode)
-+{
-+      return fsync_buffers_list(&inode->i_dirty_data_buffers);
-+}
-+extern int inode_has_buffers(struct inode *);
-+extern int filemap_fdatasync(struct address_space *);
-+extern int filemap_fdatawait(struct address_space *);
-+extern void sync_supers(kdev_t);
-+extern void sync_supers_lockfs(kdev_t);
-+extern void unlockfs(kdev_t);
-+extern int bmap(struct inode *, int);
-+extern int notify_change(struct dentry *, struct iattr *);
-+extern int permission(struct inode *, int);
-+extern int vfs_permission(struct inode *, int);
-+extern int get_write_access(struct inode *);
-+extern int deny_write_access(struct file *);
-+static inline void put_write_access(struct inode * inode)
-+{
-+      atomic_dec(&inode->i_writecount);
-+}
-+static inline void allow_write_access(struct file *file)
-+{
-+      if (file)
-+              atomic_inc(&file->f_dentry->d_inode->i_writecount);
-+}
-+extern int do_pipe(int *);
-+
-+extern int open_namei(const char *, int, int, struct nameidata *);
-+
-+extern int kernel_read(struct file *, unsigned long, char *, unsigned long);
-+extern struct file * open_exec(const char *);
-+ 
-+/* fs/dcache.c -- generic fs support functions */
-+extern int is_subdir(struct dentry *, struct dentry *);
-+extern ino_t find_inode_number(struct dentry *, struct qstr *);
-+
-+/*
-+ * Kernel pointers have redundant information, so we can use a
-+ * scheme where we can return either an error code or a dentry
-+ * pointer with the same return value.
-+ *
-+ * This should be a per-architecture thing, to allow different
-+ * error and pointer decisions.
-+ */
-+static inline void *ERR_PTR(long error)
-+{
-+      return (void *) error;
-+}
-+
-+static inline long PTR_ERR(const void *ptr)
-+{
-+      return (long) ptr;
-+}
-+
-+static inline long IS_ERR(const void *ptr)
-+{
-+      return (unsigned long)ptr > (unsigned long)-1000L;
-+}
-+
-+/*
-+ * The bitmask for a lookup event:
-+ *  - follow links at the end
-+ *  - require a directory
-+ *  - ending slashes ok even for nonexistent files
-+ *  - internal "there are more path compnents" flag
-+ */
-+#define LOOKUP_FOLLOW         (1)
-+#define LOOKUP_DIRECTORY      (2)
-+#define LOOKUP_CONTINUE               (4)
-+#define LOOKUP_POSITIVE               (8)
-+#define LOOKUP_PARENT         (16)
-+#define LOOKUP_NOALT          (32)
-+/*
-+ * Type of the last component on LOOKUP_PARENT
-+ */
-+enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
-+
-+/*
-+ * "descriptor" for what we're up to with a read for sendfile().
-+ * This allows us to use the same read code yet
-+ * have multiple different users of the data that
-+ * we read from a file.
-+ *
-+ * The simplest case just copies the data to user
-+ * mode.
-+ */
-+typedef struct {
-+      size_t written;
-+      size_t count;
-+      char * buf;
-+      int error;
-+} read_descriptor_t;
-+
-+typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long);
-+
-+/* needed for stackable file system support */
-+extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
-+
-+extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *));
-+extern int FASTCALL(__user_walk_it(const char *, unsigned, struct nameidata *, struct lookup_intent *it));
-+extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *));
-+extern int FASTCALL(path_walk(const char *, struct nameidata *));
-+extern int FASTCALL(link_path_walk(const char *, struct nameidata *));
-+extern void path_release(struct nameidata *);
-+extern int follow_down(struct vfsmount **, struct dentry **);
-+extern int follow_up(struct vfsmount **, struct dentry **);
-+extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
-+extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
-+#define user_path_walk(name,nd)        __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
-+#define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
-+#define user_path_walk_it(name,nd,it)  __user_walk_it(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd, it)
-+#define user_path_walk_link_it(name,nd,it) __user_walk_it(name, LOOKUP_POSITIVE, nd, it)
-+
-+extern void inode_init_once(struct inode *);
-+extern void iput(struct inode *);
-+extern void force_delete(struct inode *);
-+extern struct inode * igrab(struct inode *);
-+extern ino_t iunique(struct super_block *, ino_t);
-+extern void unlock_new_inode(struct inode *);
-+
-+typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
-+
-+extern struct inode * iget4_locked(struct super_block *, unsigned long,
-+                                 find_inode_t, void *);
-+
-+static inline struct inode *iget4(struct super_block *sb, unsigned long ino,
-+                                find_inode_t find_actor, void *opaque)
-+{
-+      struct inode *inode = iget4_locked(sb, ino, find_actor, opaque);
-+
-+      if (inode && (inode->i_state & I_NEW)) {
-+              /*
-+               * reiserfs-specific kludge that is expected to go away ASAP.
-+               */
-+              if (sb->s_op->read_inode2)
-+                      sb->s_op->read_inode2(inode, opaque);
-+              else
-+                      sb->s_op->read_inode(inode);
-+              unlock_new_inode(inode);
-+      }
-+
-+      return inode;
-+}
-+
-+static inline struct inode *iget(struct super_block *sb, unsigned long ino)
-+{
-+      struct inode *inode = iget4_locked(sb, ino, NULL, NULL);
-+
-+      if (inode && (inode->i_state & I_NEW)) {
-+              sb->s_op->read_inode(inode);
-+              unlock_new_inode(inode);
-+      }
-+
-+      return inode;
-+}
-+
-+static inline struct inode *iget_locked(struct super_block *sb, unsigned long ino)
-+{
-+      return iget4_locked(sb, ino, NULL, NULL);
-+}
-+
-+extern void clear_inode(struct inode *);
-+extern struct inode *new_inode(struct super_block *sb);
-+extern void remove_suid(struct inode *inode);
-+
-+extern void insert_inode_hash(struct inode *);
-+extern void remove_inode_hash(struct inode *);
-+extern struct file * get_empty_filp(void);
-+extern void file_move(struct file *f, struct list_head *list);
-+extern struct buffer_head * get_hash_table(kdev_t, int, int);
-+extern struct buffer_head * getblk(kdev_t, int, int);
-+extern void ll_rw_block(int, int, struct buffer_head * bh[]);
-+extern void submit_bh(int, struct buffer_head *);
-+extern int is_read_only(kdev_t);
-+extern void __brelse(struct buffer_head *);
-+static inline void brelse(struct buffer_head *buf)
-+{
-+      if (buf)
-+              __brelse(buf);
-+}
-+extern void __bforget(struct buffer_head *);
-+static inline void bforget(struct buffer_head *buf)
-+{
-+      if (buf)
-+              __bforget(buf);
-+}
-+extern int set_blocksize(kdev_t, int);
-+extern int sb_set_blocksize(struct super_block *, int);
-+extern int sb_min_blocksize(struct super_block *, int);
-+extern struct buffer_head * bread(kdev_t, int, int);
-+static inline struct buffer_head * sb_bread(struct super_block *sb, int block)
-+{
-+      return bread(sb->s_dev, block, sb->s_blocksize);
-+}
-+static inline struct buffer_head * sb_getblk(struct super_block *sb, int block)
-+{
-+      return getblk(sb->s_dev, block, sb->s_blocksize);
-+}
-+static inline struct buffer_head * sb_get_hash_table(struct super_block *sb, int block)
-+{
-+      return get_hash_table(sb->s_dev, block, sb->s_blocksize);
-+}
-+extern void wakeup_bdflush(void);
-+extern void put_unused_buffer_head(struct buffer_head * bh);
-+extern struct buffer_head * get_unused_buffer_head(int async);
-+
-+extern int brw_page(int, struct page *, kdev_t, int [], int);
-+
-+typedef int (get_block_t)(struct inode*,long,struct buffer_head*,int);
-+
-+/* Generic buffer handling for block filesystems.. */
-+extern int try_to_release_page(struct page * page, int gfp_mask);
-+extern int discard_bh_page(struct page *, unsigned long, int);
-+#define block_flushpage(page, offset) discard_bh_page(page, offset, 1)
-+#define block_invalidate_page(page) discard_bh_page(page, 0, 0)
-+extern int block_symlink(struct inode *, const char *, int);
-+extern int block_write_full_page(struct page*, get_block_t*);
-+extern int block_read_full_page(struct page*, get_block_t*);
-+extern int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
-+extern int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*,
-+                              unsigned long *);
-+extern int generic_cont_expand(struct inode *inode, loff_t size) ;
-+extern int block_commit_write(struct page *page, unsigned from, unsigned to);
-+extern int block_sync_page(struct page *);
-+
-+int generic_block_bmap(struct address_space *, long, get_block_t *);
-+int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
-+int block_truncate_page(struct address_space *, loff_t, get_block_t *);
-+extern int generic_direct_IO(int, struct inode *, struct kiobuf *, unsigned long, int, get_block_t *);
-+extern int waitfor_one_page(struct page *);
-+extern int writeout_one_page(struct page *);
-+
-+extern int generic_file_mmap(struct file *, struct vm_area_struct *);
-+extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
-+extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
-+extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *);
-+extern ssize_t generic_file_write_nolock(struct file *, const char *, size_t, loff_t *);
-+extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t);
-+extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
-+extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
-+extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *);
-+extern int generic_file_open(struct inode * inode, struct file * filp);
-+
-+extern struct file_operations generic_ro_fops;
-+
-+extern int vfs_readlink(struct dentry *, char *, int, const char *);
-+extern int vfs_follow_link(struct nameidata *, const char *);
-+extern int vfs_follow_link_it(struct nameidata *, const char *,
-+                            struct lookup_intent *it);
-+extern int page_readlink(struct dentry *, char *, int);
-+extern int page_follow_link(struct dentry *, struct nameidata *);
-+extern struct inode_operations page_symlink_inode_operations;
-+
-+extern int vfs_readdir(struct file *, filldir_t, void *);
-+extern int dcache_dir_open(struct inode *, struct file *);
-+extern int dcache_dir_close(struct inode *, struct file *);
-+extern loff_t dcache_dir_lseek(struct file *, loff_t, int);
-+extern int dcache_dir_fsync(struct file *, struct dentry *, int);
-+extern int dcache_readdir(struct file *, void *, filldir_t);
-+extern struct file_operations dcache_dir_ops;
-+
-+extern struct file_system_type *get_fs_type(const char *name);
-+extern struct super_block *get_super(kdev_t);
-+extern void drop_super(struct super_block *sb);
-+static inline int is_mounted(kdev_t dev)
-+{
-+      struct super_block *sb = get_super(dev);
-+      if (sb) {
-+              drop_super(sb);
-+              return 1;
-+      }
-+      return 0;
-+}
-+unsigned long generate_cluster(kdev_t, int b[], int);
-+unsigned long generate_cluster_swab32(kdev_t, int b[], int);
-+extern kdev_t ROOT_DEV;
-+extern char root_device_name[];
-+
-+
-+extern void show_buffers(void);
-+
-+#ifdef CONFIG_BLK_DEV_INITRD
-+extern unsigned int real_root_dev;
-+#endif
-+
-+extern ssize_t char_read(struct file *, char *, size_t, loff_t *);
-+extern ssize_t block_read(struct file *, char *, size_t, loff_t *);
-+extern int read_ahead[];
-+
-+extern ssize_t char_write(struct file *, const char *, size_t, loff_t *);
-+extern ssize_t block_write(struct file *, const char *, size_t, loff_t *);
-+
-+extern int file_fsync(struct file *, struct dentry *, int);
-+extern int generic_buffer_fdatasync(struct inode *inode, unsigned long start_idx, unsigned long end_idx);
-+extern int generic_osync_inode(struct inode *, int);
-+#define OSYNC_METADATA (1<<0)
-+#define OSYNC_DATA (1<<1)
-+#define OSYNC_INODE (1<<2)
-+
-+extern int inode_change_ok(struct inode *, struct iattr *);
-+extern int inode_setattr(struct inode *, struct iattr *);
-+
-+/*
-+ * Common dentry functions for inclusion in the VFS
-+ * or in other stackable file systems.  Some of these
-+ * functions were in linux/fs/ C (VFS) files.
-+ *
-+ */
-+
-+/*
-+ * Locking the parent is needed to:
-+ *  - serialize directory operations
-+ *  - make sure the parent doesn't change from
-+ *    under us in the middle of an operation.
-+ *
-+ * NOTE! Right now we'd rather use a "struct inode"
-+ * for this, but as I expect things to move toward
-+ * using dentries instead for most things it is
-+ * probably better to start with the conceptually
-+ * better interface of relying on a path of dentries.
-+ */
-+static inline struct dentry *lock_parent(struct dentry *dentry)
-+{
-+      struct dentry *dir = dget(dentry->d_parent);
-+
-+      down(&dir->d_inode->i_sem);
-+      return dir;
-+}
-+
-+static inline struct dentry *get_parent(struct dentry *dentry)
-+{
-+      return dget(dentry->d_parent);
-+}
-+
-+static inline void unlock_dir(struct dentry *dir)
-+{
-+      up(&dir->d_inode->i_sem);
-+      dput(dir);
-+}
-+
-+/*
-+ * Whee.. Deadlock country. Happily there are only two VFS
-+ * operations that does this..
-+ */
-+static inline void double_down(struct semaphore *s1, struct semaphore *s2)
-+{
-+      if (s1 != s2) {
-+              if ((unsigned long) s1 < (unsigned long) s2) {
-+                      struct semaphore *tmp = s2;
-+                      s2 = s1; s1 = tmp;
-+              }
-+              down(s1);
-+      }
-+      down(s2);
-+}
-+
-+/*
-+ * Ewwwwwwww... _triple_ lock. We are guaranteed that the 3rd argument is
-+ * not equal to 1st and not equal to 2nd - the first case (target is parent of
-+ * source) would be already caught, the second is plain impossible (target is
-+ * its own parent and that case would be caught even earlier). Very messy.
-+ * I _think_ that it works, but no warranties - please, look it through.
-+ * Pox on bloody lusers who mandated overwriting rename() for directories...
-+ */
-+
-+static inline void triple_down(struct semaphore *s1,
-+                             struct semaphore *s2,
-+                             struct semaphore *s3)
-+{
-+      if (s1 != s2) {
-+              if ((unsigned long) s1 < (unsigned long) s2) {
-+                      if ((unsigned long) s1 < (unsigned long) s3) {
-+                              struct semaphore *tmp = s3;
-+                              s3 = s1; s1 = tmp;
-+                      }
-+                      if ((unsigned long) s1 < (unsigned long) s2) {
-+                              struct semaphore *tmp = s2;
-+                              s2 = s1; s1 = tmp;
-+                      }
-+              } else {
-+                      if ((unsigned long) s1 < (unsigned long) s3) {
-+                              struct semaphore *tmp = s3;
-+                              s3 = s1; s1 = tmp;
-+                      }
-+                      if ((unsigned long) s2 < (unsigned long) s3) {
-+                              struct semaphore *tmp = s3;
-+                              s3 = s2; s2 = tmp;
-+                      }
-+              }
-+              down(s1);
-+      } else if ((unsigned long) s2 < (unsigned long) s3) {
-+              struct semaphore *tmp = s3;
-+              s3 = s2; s2 = tmp;
-+      }
-+      down(s2);
-+      down(s3);
-+}
-+
-+static inline void double_up(struct semaphore *s1, struct semaphore *s2)
-+{
-+      up(s1);
-+      if (s1 != s2)
-+              up(s2);
-+}
-+
-+static inline void triple_up(struct semaphore *s1,
-+                           struct semaphore *s2,
-+                           struct semaphore *s3)
-+{
-+      up(s1);
-+      if (s1 != s2)
-+              up(s2);
-+      up(s3);
-+}
-+
-+static inline void double_lock(struct dentry *d1, struct dentry *d2)
-+{
-+      double_down(&d1->d_inode->i_sem, &d2->d_inode->i_sem);
-+}
-+
-+static inline void double_unlock(struct dentry *d1, struct dentry *d2)
-+{
-+      double_up(&d1->d_inode->i_sem,&d2->d_inode->i_sem);
-+      dput(d1);
-+      dput(d2);
-+}
-+
-+#endif /* __KERNEL__ */
-+
-+#endif /* _LINUX_FS_H */
---- linux-2.4.19-hp3_pnnl1/fs/exec.c~invalidate_show   2003-04-15 13:17:46.000000000 +0800
-+++ linux-2.4.19-hp3_pnnl1-root/fs/exec.c      2003-04-15 13:22:26.000000000 +0800
-@@ -1058,7 +1058,7 @@ int do_coredump(long signr, struct pt_re
-               goto close_fail;
-       if (!file->f_op->write)
-               goto close_fail;
--      if (do_truncate(file->f_dentry, 0) != 0)
-+      if (do_truncate(file->f_dentry, 0, 0) != 0)
-               goto close_fail;
+ extern int invalidate_device(kdev_t, int);
+ extern void invalidate_inode_pages(struct inode *);
+ extern void invalidate_inode_pages2(struct address_space *);
+--- linux-rh-2.4.20-8/fs/smbfs/inode.c~invalidate_show 2003-04-16 20:59:48.000000000 +0800
++++ linux-rh-2.4.20-8-root/fs/smbfs/inode.c    2003-04-16 21:00:43.000000000 +0800
+@@ -167,7 +167,7 @@ smb_invalidate_inodes(struct smb_sb_info
+ {
+       VERBOSE("\n");
+       shrink_dcache_sb(SB_of(server));
+-      invalidate_inodes(SB_of(server));
++      invalidate_inodes(SB_of(server), 0);
+ }
  
-       retval = binfmt->core_dump(signr, regs, file);
+ /*
 
 _