Whamcloud - gitweb
vanilla-2.4.29 support.
authorgreen <green>
Tue, 3 May 2005 21:02:00 +0000 (21:02 +0000)
committergreen <green>
Tue, 3 May 2005 21:02:00 +0000 (21:02 +0000)
12 files changed:
lustre/ChangeLog
lustre/kernel_patches/patches/ext3-delete_thread-2.4.29.patch [new file with mode: 0644]
lustre/kernel_patches/patches/ext3-ea-in-inode-2.4.29.patch [new file with mode: 0644]
lustre/kernel_patches/patches/ext3-extents-2.4.29.patch [new file with mode: 0644]
lustre/kernel_patches/patches/ext3-htree-2.4.29.patch [new file with mode: 0644]
lustre/kernel_patches/patches/invalidate_show-2.4.29.patch [new file with mode: 0644]
lustre/kernel_patches/patches/linux-2.4.29-xattr-0.8.54.patch [new file with mode: 0644]
lustre/kernel_patches/patches/nfs_export_kernel-2.4.29.patch [new file with mode: 0644]
lustre/kernel_patches/patches/nfs_export_kernel-2.4.29.patch-1 [new file with mode: 0644]
lustre/kernel_patches/patches/uml-patch-2.4.29-1.patch [new file with mode: 0644]
lustre/kernel_patches/patches/vfs_intent-2.4.29-vanilla.patch [new file with mode: 0644]
lustre/kernel_patches/series/vanilla-2.4.29 [new file with mode: 0644]

index 0b11a58..60e97ab 100644 (file)
@@ -47,6 +47,7 @@ tbd         Cluster File Systems, Inc. <info@clusterfs.com>
        - initialize blocksize for non-regular files (6062)
        - added --disable-server and --disable-client configure options (5782)
        - introduce a lookup cache for lconf to avoid repeated DB scans (6204)
+       - Vanilla 2.4.29 support
 
 2005-03-22  Cluster File Systems, Inc. <info@clusterfs.com>
        * version 1.4.1
diff --git a/lustre/kernel_patches/patches/ext3-delete_thread-2.4.29.patch b/lustre/kernel_patches/patches/ext3-delete_thread-2.4.29.patch
new file mode 100644 (file)
index 0000000..39c47a7
--- /dev/null
@@ -0,0 +1,442 @@
+Index: linux-2.4.29/fs/ext3/super.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/super.c  2005-05-03 15:53:33.047533872 +0300
++++ linux-2.4.29/fs/ext3/super.c       2005-05-03 15:54:47.192262160 +0300
+@@ -400,6 +400,127 @@
+       }
+ }
++#ifdef EXT3_DELETE_THREAD
++/*
++ * Delete inodes in a loop until there are no more to be deleted.
++ * Normally, we run in the background doing the deletes and sleeping again,
++ * and clients just add new inodes to be deleted onto the end of the list.
++ * If someone is concerned about free space (e.g. block allocation or similar)
++ * then they can sleep on s_delete_waiter_queue and be woken up when space
++ * has been freed.
++ */
++int ext3_delete_thread(void *data)
++{
++      struct super_block *sb = data;
++      struct ext3_sb_info *sbi = EXT3_SB(sb);
++      struct task_struct *tsk = current;
++
++      /* Almost like daemonize, but not quite */
++      exit_mm(current);
++      tsk->session = 1;
++      tsk->pgrp = 1;
++      tsk->tty = NULL;
++      exit_files(current);
++      reparent_to_init();
++
++      sprintf(tsk->comm, "kdelext3-%s", kdevname(sb->s_dev));
++      sigfillset(&tsk->blocked);
++
++      /*tsk->flags |= PF_KERNTHREAD;*/
++
++      INIT_LIST_HEAD(&sbi->s_delete_list);
++      wake_up(&sbi->s_delete_waiter_queue);
++      ext3_debug("delete thread on %s started\n", kdevname(sb->s_dev));
++
++      /* main loop */
++      for (;;) {
++              wait_event_interruptible(sbi->s_delete_thread_queue,
++                                       !list_empty(&sbi->s_delete_list) ||
++                                       !test_opt(sb, ASYNCDEL));
++              ext3_debug("%s woken up: %lu inodes, %lu blocks\n",
++                         tsk->comm,sbi->s_delete_inodes,sbi->s_delete_blocks);
++
++              spin_lock(&sbi->s_delete_lock);
++              if (list_empty(&sbi->s_delete_list)) {
++                      clear_opt(sbi->s_mount_opt, ASYNCDEL);
++                      memset(&sbi->s_delete_list, 0,
++                             sizeof(sbi->s_delete_list));
++                      spin_unlock(&sbi->s_delete_lock);
++                      ext3_debug("delete thread on %s exiting\n",
++                                 kdevname(sb->s_dev));
++                      wake_up(&sbi->s_delete_waiter_queue);
++                      break;
++              }
++
++              while (!list_empty(&sbi->s_delete_list)) {
++                      struct inode *inode=list_entry(sbi->s_delete_list.next,
++                                                     struct inode, i_devices);
++                      unsigned long blocks = inode->i_blocks >>
++                                                      (inode->i_blkbits - 9);
++
++                      list_del_init(&inode->i_devices);
++                      spin_unlock(&sbi->s_delete_lock);
++                      ext3_debug("%s delete ino %lu blk %lu\n",
++                                 tsk->comm, inode->i_ino, blocks);
++
++                      J_ASSERT(EXT3_I(inode)->i_state & EXT3_STATE_DELETE);
++                      J_ASSERT(inode->i_nlink == 1);
++                      inode->i_nlink = 0;
++                      iput(inode);
++
++                      spin_lock(&sbi->s_delete_lock);
++                      sbi->s_delete_blocks -= blocks;
++                      sbi->s_delete_inodes--;
++              }
++              if (sbi->s_delete_blocks != 0 || sbi->s_delete_inodes != 0) {
++                      ext3_warning(sb, __FUNCTION__,
++                                   "%lu blocks, %lu inodes on list?\n",
++                                   sbi->s_delete_blocks,sbi->s_delete_inodes);
++                      sbi->s_delete_blocks = 0;
++                      sbi->s_delete_inodes = 0;
++              }
++              spin_unlock(&sbi->s_delete_lock);
++              wake_up(&sbi->s_delete_waiter_queue);
++      }
++
++      return 0;
++}
++
++static void ext3_start_delete_thread(struct super_block *sb)
++{
++      struct ext3_sb_info *sbi = EXT3_SB(sb);
++      int rc;
++
++      spin_lock_init(&sbi->s_delete_lock);
++      init_waitqueue_head(&sbi->s_delete_thread_queue);
++      init_waitqueue_head(&sbi->s_delete_waiter_queue);
++
++      if (!test_opt(sb, ASYNCDEL))
++              return;
++
++      rc = kernel_thread(ext3_delete_thread, sb, CLONE_VM | CLONE_FILES);
++      if (rc < 0)
++              printk(KERN_ERR "EXT3-fs: cannot start delete thread: rc %d\n",
++                     rc);
++      else
++              wait_event(sbi->s_delete_waiter_queue, sbi->s_delete_list.next);
++}
++
++static void ext3_stop_delete_thread(struct ext3_sb_info *sbi)
++{
++      if (sbi->s_delete_list.next == 0)       /* thread never started */
++              return;
++
++      clear_opt(sbi->s_mount_opt, ASYNCDEL);
++      wake_up(&sbi->s_delete_thread_queue);
++      wait_event(sbi->s_delete_waiter_queue,
++                      sbi->s_delete_list.next == 0 && sbi->s_delete_inodes == 0);
++}
++#else
++#define ext3_start_delete_thread(sbi) do {} while(0)
++#define ext3_stop_delete_thread(sbi) do {} while(0)
++#endif /* EXT3_DELETE_THREAD */
++
+ void ext3_put_super (struct super_block * sb)
+ {
+       struct ext3_sb_info *sbi = EXT3_SB(sb);
+@@ -407,6 +528,9 @@
+       kdev_t j_dev = sbi->s_journal->j_dev;
+       int i;
++#ifdef EXT3_DELETE_THREAD
++      J_ASSERT(sbi->s_delete_inodes == 0);
++#endif
+       ext3_xattr_put_super(sb);
+       journal_destroy(sbi->s_journal);
+       if (!(sb->s_flags & MS_RDONLY)) {
+@@ -526,6 +650,13 @@
+                       clear_opt (*mount_options, XATTR_USER);
+               else
+ #endif
++#ifdef EXT3_DELETE_THREAD
++              if (!strcmp(this_char, "asyncdel"))
++                      set_opt(*mount_options, ASYNCDEL);
++              else if (!strcmp(this_char, "noasyncdel"))
++                      clear_opt(*mount_options, ASYNCDEL);
++              else
++#endif
+               if (!strcmp (this_char, "bsddf"))
+                       clear_opt (*mount_options, MINIX_DF);
+               else if (!strcmp (this_char, "nouid32")) {
+@@ -1244,6 +1375,7 @@
+       }
+       ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY);
++      ext3_start_delete_thread(sb);
+       EXT3_SB(sb)->s_mount_state |= EXT3_ORPHAN_FS;
+       ext3_orphan_cleanup(sb, es);
+       EXT3_SB(sb)->s_mount_state &= ~EXT3_ORPHAN_FS;
+@@ -1626,7 +1758,12 @@
+ static int ext3_sync_fs(struct super_block *sb)
+ {
+       tid_t target;
+-      
++
++      if (atomic_read(&sb->s_active) == 0) {
++              /* fs is being umounted: time to stop delete thread */
++              ext3_stop_delete_thread(EXT3_SB(sb));
++      }
++
+       sb->s_dirt = 0;
+       target = log_start_commit(EXT3_SB(sb)->s_journal, NULL);
+       log_wait_commit(EXT3_SB(sb)->s_journal, target);
+@@ -1690,6 +1827,9 @@
+       if (!parse_options(data, &tmp, sbi, &tmp, 1))
+               return -EINVAL;
++      if (!test_opt(sb, ASYNCDEL) || (*flags & MS_RDONLY))
++              ext3_stop_delete_thread(sbi);
++
+       if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
+               ext3_abort(sb, __FUNCTION__, "Abort forced by user");
+Index: linux-2.4.29/fs/ext3/inode.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/inode.c  2005-05-03 15:53:36.555000656 +0300
++++ linux-2.4.29/fs/ext3/inode.c       2005-05-03 15:53:56.901907456 +0300
+@@ -2562,6 +2562,118 @@
+       return err;
+ }
++#ifdef EXT3_DELETE_THREAD
++/* Move blocks from to-be-truncated inode over to a new inode, and delete
++ * that one from the delete thread instead.  This avoids a lot of latency
++ * when truncating large files.
++ *
++ * If we have any problem deferring the truncate, just truncate it right away.
++ * If we defer it, we also mark how many blocks it would free, so that we
++ * can keep the statfs data correct, and we know if we should sleep on the
++ * delete thread when we run out of space.
++ */
++void ext3_truncate_thread(struct inode *old_inode)
++{
++      struct ext3_sb_info *sbi = EXT3_SB(old_inode->i_sb);
++      struct ext3_inode_info *nei, *oei = EXT3_I(old_inode);
++      struct inode *new_inode;
++      handle_t *handle;
++      unsigned long blocks = old_inode->i_blocks >> (old_inode->i_blkbits-9);
++
++      if (!test_opt(old_inode->i_sb, ASYNCDEL) || !sbi->s_delete_list.next)
++              goto out_truncate;
++
++      /* XXX This is a temporary limitation for code simplicity.
++       *     We could truncate to arbitrary sizes at some later time.
++       */
++      if (old_inode->i_size != 0)
++              goto out_truncate;
++
++      /* We may want to truncate the inode immediately and not defer it */
++      if (IS_SYNC(old_inode) || blocks <= EXT3_NDIR_BLOCKS ||
++          old_inode->i_size > oei->i_disksize)
++              goto out_truncate;
++
++      /* We can't use the delete thread as-is during real orphan recovery,
++       * as we add to the orphan list here, causing ext3_orphan_cleanup()
++       * to loop endlessly.  It would be nice to do so, but needs work.
++       */
++      if (oei->i_state & EXT3_STATE_DELETE ||
++          sbi->s_mount_state & EXT3_ORPHAN_FS) {
++              ext3_debug("doing deferred inode %lu delete (%lu blocks)\n",
++                         old_inode->i_ino, blocks);
++              goto out_truncate;
++      }
++
++      ext3_discard_prealloc(old_inode);
++
++      /* old_inode   = 1
++       * new_inode   = sb + GDT + ibitmap
++       * orphan list = 1 inode/superblock for add, 2 inodes for del
++       * quota files = 2 * EXT3_SINGLEDATA_TRANS_BLOCKS
++       */
++      handle = ext3_journal_start(old_inode, 7);
++      if (IS_ERR(handle))
++              goto out_truncate;
++
++      new_inode = ext3_new_inode(handle, old_inode, old_inode->i_mode);
++      if (IS_ERR(new_inode)) {
++              ext3_debug("truncate inode %lu directly (no new inodes)\n",
++                         old_inode->i_ino);
++              goto out_journal;
++      }
++
++      nei = EXT3_I(new_inode);
++
++      down_write(&oei->truncate_sem);
++      new_inode->i_size = old_inode->i_size;
++      new_inode->i_blocks = old_inode->i_blocks;
++      new_inode->i_uid = old_inode->i_uid;
++      new_inode->i_gid = old_inode->i_gid;
++      new_inode->i_nlink = 1;
++
++      /* FIXME when we do arbitrary truncates */
++      old_inode->i_blocks = oei->i_file_acl ? old_inode->i_blksize / 512 : 0;
++      old_inode->i_mtime = old_inode->i_ctime = CURRENT_TIME;
++
++      memcpy(nei->i_data, oei->i_data, sizeof(nei->i_data));
++      memset(oei->i_data, 0, sizeof(oei->i_data));
++
++      nei->i_disksize = oei->i_disksize;
++      nei->i_state |= EXT3_STATE_DELETE;
++      up_write(&oei->truncate_sem);
++
++      if (ext3_orphan_add(handle, new_inode) < 0)
++              goto out_journal;
++
++      if (ext3_orphan_del(handle, old_inode) < 0) {
++              ext3_orphan_del(handle, new_inode);
++              iput(new_inode);
++              goto out_journal;
++      }
++
++      ext3_journal_stop(handle, old_inode);
++
++      spin_lock(&sbi->s_delete_lock);
++      J_ASSERT(list_empty(&new_inode->i_devices));
++      list_add_tail(&new_inode->i_devices, &sbi->s_delete_list);
++      sbi->s_delete_blocks += blocks;
++      sbi->s_delete_inodes++;
++      spin_unlock(&sbi->s_delete_lock);
++
++      ext3_debug("delete inode %lu (%lu blocks) by thread\n",
++                 new_inode->i_ino, blocks);
++
++      wake_up(&sbi->s_delete_thread_queue);
++      return;
++
++out_journal:
++      ext3_journal_stop(handle, old_inode);
++out_truncate:
++      ext3_truncate(old_inode);
++}
++#endif /* EXT3_DELETE_THREAD */
++
+ /* 
+  * On success, We end up with an outstanding reference count against
+  * iloc->bh.  This _must_ be cleaned up later. 
+Index: linux-2.4.29/fs/ext3/file.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/file.c   2005-04-07 19:31:00.000000000 +0300
++++ linux-2.4.29/fs/ext3/file.c        2005-05-03 15:53:56.902907304 +0300
+@@ -123,7 +123,11 @@
+ };
+ struct inode_operations ext3_file_inode_operations = {
++#ifdef EXT3_DELETE_THREAD
++      truncate:       ext3_truncate_thread,   /* BKL held */
++#else
+       truncate:       ext3_truncate,          /* BKL held */
++#endif
+       setattr:        ext3_setattr,           /* BKL held */
+       setxattr:       ext3_setxattr,          /* BKL held */
+       getxattr:       ext3_getxattr,          /* BKL held */
+Index: linux-2.4.29/fs/ext3/namei.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/namei.c  2005-05-03 15:53:33.044534328 +0300
++++ linux-2.4.29/fs/ext3/namei.c       2005-05-03 15:53:56.905906848 +0300
+@@ -838,6 +838,40 @@
+       return retval;
+ }
++#ifdef EXT3_DELETE_THREAD
++static int ext3_try_to_delay_deletion(struct inode *inode)
++{
++      struct ext3_sb_info *sbi = EXT3_SB(inode->i_sb);
++      struct ext3_inode_info *ei = EXT3_I(inode);
++      unsigned long blocks;
++
++      if (!test_opt(inode->i_sb, ASYNCDEL))
++              return 0;
++
++      /* We may want to delete the inode immediately and not defer it */
++      blocks = inode->i_blocks >> (inode->i_blkbits - 9);
++      if (IS_SYNC(inode) || blocks <= EXT3_NDIR_BLOCKS)
++              return 0;
++
++      inode->i_nlink = 1;
++      atomic_inc(&inode->i_count);
++      ei->i_state |= EXT3_STATE_DELETE;
++
++      spin_lock(&sbi->s_delete_lock);
++      J_ASSERT(list_empty(&inode->i_devices));
++      list_add_tail(&inode->i_devices, &sbi->s_delete_list);
++      sbi->s_delete_blocks += blocks;
++      sbi->s_delete_inodes++;
++      spin_unlock(&sbi->s_delete_lock);
++
++      wake_up(&sbi->s_delete_thread_queue);
++
++      return 0;
++}
++#else
++#define ext3_try_to_delay_deletion(inode) do {} while (0)
++#endif
++
+ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
+ {
+       int retval;
+@@ -878,8 +912,10 @@
+       dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+       ext3_mark_inode_dirty(handle, dir);
+       inode->i_nlink--;
+-      if (!inode->i_nlink)
++      if (!inode->i_nlink) {
++              ext3_try_to_delay_deletion(inode);
+               ext3_orphan_add(handle, inode);
++      }
+       inode->i_ctime = dir->i_ctime;
+       ext3_mark_inode_dirty(handle, inode);
+       retval = 0;
+Index: linux-2.4.29/include/linux/ext3_fs.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext3_fs.h  2005-05-03 15:53:37.124914016 +0300
++++ linux-2.4.29/include/linux/ext3_fs.h       2005-05-03 15:53:56.907906544 +0300
+@@ -188,6 +188,7 @@
+  */
+ #define EXT3_STATE_JDATA              0x00000001 /* journaled data exists */
+ #define EXT3_STATE_NEW                        0x00000002 /* inode is newly created */
++#define EXT3_STATE_DELETE             0x00000010 /* deferred delete inode */
+ /*
+  * ioctl commands
+@@ -315,6 +316,7 @@
+ #define EXT3_MOUNT_UPDATE_JOURNAL     0x1000  /* Update the journal format */
+ #define EXT3_MOUNT_NO_UID32           0x2000  /* Disable 32-bit UIDs */
+ #define EXT3_MOUNT_XATTR_USER         0x4000  /* Extended user attributes */
++#define EXT3_MOUNT_ASYNCDEL           0x20000 /* Delayed deletion */
+ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
+ #ifndef _LINUX_EXT2_FS_H
+@@ -639,6 +641,9 @@
+ extern void ext3_dirty_inode(struct inode *);
+ extern int ext3_change_inode_journal_flag(struct inode *, int);
+ extern void ext3_truncate (struct inode *);
++#ifdef EXT3_DELETE_THREAD
++extern void ext3_truncate_thread(struct inode *inode);
++#endif
+ extern void ext3_set_inode_flags(struct inode *);
+ /* ioctl.c */
+Index: linux-2.4.29/include/linux/ext3_fs_sb.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext3_fs_sb.h       2005-05-03 15:53:33.048533720 +0300
++++ linux-2.4.29/include/linux/ext3_fs_sb.h    2005-05-03 15:53:56.909906240 +0300
+@@ -29,6 +29,8 @@
+ #define EXT3_MAX_GROUP_LOADED 8
++#define EXT3_DELETE_THREAD
++
+ /*
+  * third extended-fs super-block data in memory
+  */
+@@ -74,6 +76,14 @@
+       struct timer_list turn_ro_timer;        /* For turning read-only (crash simulation) */
+       wait_queue_head_t ro_wait_queue;        /* For people waiting for the fs to go read-only */
+ #endif
++#ifdef EXT3_DELETE_THREAD
++      spinlock_t s_delete_lock;
++      struct list_head s_delete_list;
++      unsigned long s_delete_blocks;
++      unsigned long s_delete_inodes;
++      wait_queue_head_t s_delete_thread_queue;
++      wait_queue_head_t s_delete_waiter_queue;
++#endif
+ };
+ #endif        /* _LINUX_EXT3_FS_SB */
diff --git a/lustre/kernel_patches/patches/ext3-ea-in-inode-2.4.29.patch b/lustre/kernel_patches/patches/ext3-ea-in-inode-2.4.29.patch
new file mode 100644 (file)
index 0000000..f4832af
--- /dev/null
@@ -0,0 +1,733 @@
+Index: linux-2.4.29/fs/ext3/ialloc.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/ialloc.c 2005-05-03 15:56:43.831530296 +0300
++++ linux-2.4.29/fs/ext3/ialloc.c      2005-05-03 16:07:32.990843080 +0300
+@@ -576,6 +576,12 @@
+       insert_inode_hash(inode);
+       inode->i_generation = sb->u.ext3_sb.s_next_generation++;
++      if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) {
++              inode->u.ext3_i.i_extra_isize = sizeof(__u16)   /* i_extra_isize */
++                              + sizeof(__u16);        /* i_pad1 */
++      } else
++              inode->u.ext3_i.i_extra_isize = 0;
++
+       inode->u.ext3_i.i_state = EXT3_STATE_NEW;
+       err = ext3_get_inode_loc_new(inode, &iloc, 1);
+       if (err) goto fail;
+Index: linux-2.4.29/fs/ext3/inode.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/inode.c  2005-05-03 15:58:30.758274960 +0300
++++ linux-2.4.29/fs/ext3/inode.c       2005-05-03 16:07:32.995842320 +0300
+@@ -2240,6 +2240,12 @@
+               inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block];
+       INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
++      if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
++              inode->u.ext3_i.i_extra_isize =
++                      le16_to_cpu(raw_inode->i_extra_isize);
++      else
++              inode->u.ext3_i.i_extra_isize = 0;
++
+       if (S_ISREG(inode->i_mode)) {
+               inode->i_op = &ext3_file_inode_operations;
+               inode->i_fop = &ext3_file_operations;
+@@ -2367,6 +2373,10 @@
+       else for (block = 0; block < EXT3_N_BLOCKS; block++)
+               raw_inode->i_block[block] = inode->u.ext3_i.i_data[block];
++      if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
++              raw_inode->i_extra_isize =
++                      cpu_to_le16(EXT3_I(inode)->i_extra_isize);
++
+       BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
+       rc = ext3_journal_dirty_metadata(handle, bh);
+       if (!err)
+Index: linux-2.4.29/fs/ext3/xattr.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/xattr.c  2005-04-07 19:31:00.000000000 +0300
++++ linux-2.4.29/fs/ext3/xattr.c       2005-05-03 16:07:33.007840496 +0300
+@@ -100,6 +100,9 @@
+ static int ext3_xattr_set2(handle_t *, struct inode *, struct buffer_head *,
+                          struct ext3_xattr_header *);
++int ext3_xattr_block_set(handle_t *, struct inode *, int, const char *,
++                      const void *, size_t, int);
++
+ #ifdef CONFIG_EXT3_FS_XATTR_SHARING
+ static int ext3_xattr_cache_insert(struct buffer_head *);
+@@ -348,17 +351,12 @@
+ }
+ /*
+- * ext3_xattr_get()
+- *
+- * Copy an extended attribute into the buffer
+- * provided, or compute the buffer size required.
+- * Buffer is NULL to compute the size of the buffer required.
++ * ext3_xattr_block_get()
+  *
+- * Returns a negative error number on failure, or the number of bytes
+- * used / required on success.
++ * routine looks for attribute in EA block and returns it's value and size
+  */
+ int
+-ext3_xattr_get(struct inode *inode, int name_index, const char *name,
++ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
+              void *buffer, size_t buffer_size)
+ {
+       struct buffer_head *bh = NULL;
+@@ -447,6 +445,94 @@
+ }
+ /*
++ * ext3_xattr_ibody_get()
++ *
++ * routine looks for attribute in inode body and returns it's value and size
++ */
++int
++ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
++             void *buffer, size_t buffer_size)
++{
++      int size, name_len = strlen(name), storage_size;
++      struct ext3_xattr_entry *last;
++      struct ext3_inode *raw_inode;
++      struct ext3_iloc iloc;
++      char *start, *end;
++      int ret = -ENOENT;
++      
++      if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
++              return -ENOENT;
++
++      ret = ext3_get_inode_loc(inode, &iloc);
++      if (ret)
++              return ret;
++      raw_inode = iloc.raw_inode;
++
++      storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
++                              EXT3_GOOD_OLD_INODE_SIZE -
++                              EXT3_I(inode)->i_extra_isize -
++                              sizeof(__u32);
++      start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
++                      EXT3_I(inode)->i_extra_isize;
++      if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
++              brelse(iloc.bh);
++              return -ENOENT;
++      }
++      start += sizeof(__u32);
++      end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
++
++      last = (struct ext3_xattr_entry *) start;
++      while (!IS_LAST_ENTRY(last)) {
++              struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
++              if (le32_to_cpu(last->e_value_size) > storage_size ||
++                              (char *) next >= end) {
++                      ext3_error(inode->i_sb, "ext3_xattr_ibody_get",
++                              "inode %ld", inode->i_ino);
++                      brelse(iloc.bh);
++                      return -EIO;
++              }
++              if (name_index == last->e_name_index &&
++                  name_len == last->e_name_len &&
++                  !memcmp(name, last->e_name, name_len))
++                      goto found;
++              last = next;
++      }
++
++      /* can't find EA */
++      brelse(iloc.bh);
++      return -ENOENT;
++      
++found:
++      size = le32_to_cpu(last->e_value_size);
++      if (buffer) {
++              ret = -ERANGE;
++              if (buffer_size >= size) {
++                      memcpy(buffer, start + le16_to_cpu(last->e_value_offs),
++                      size);
++                      ret = size;
++              }
++      } else
++              ret = size;
++      brelse(iloc.bh);
++      return ret;
++}
++
++int ext3_xattr_get(struct inode *inode, int name_index, const char *name,
++                      void *buffer, size_t buffer_size)
++{
++      int err;
++
++      /* try to find attribute in inode body */
++      err = ext3_xattr_ibody_get(inode, name_index, name,
++                                      buffer, buffer_size);
++      if (err < 0)
++              /* search was unsuccessful, try to find EA in dedicated block */
++              err = ext3_xattr_block_get(inode, name_index, name,
++                              buffer, buffer_size);
++      return err;
++}
++
++/*
+  * ext3_xattr_list()
+  *
+  * Copy a list of attribute names into the buffer
+@@ -457,7 +543,7 @@
+  * used / required on success.
+  */
+ int
+-ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
++ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
+ {
+       struct buffer_head *bh = NULL;
+       struct ext3_xattr_entry *entry;
+@@ -530,6 +616,131 @@
+       return error;
+ }
++/* ext3_xattr_ibody_list()
++ *
++ * generate list of attributes stored in inode body
++ */
++int
++ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
++{
++      struct ext3_xattr_entry *last;
++      struct ext3_inode *raw_inode;
++      char *start, *end, *buf;
++      struct ext3_iloc iloc;
++      int storage_size;
++      int ret;
++      int size = 0;
++      
++      if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
++              return 0;
++
++      ret = ext3_get_inode_loc(inode, &iloc);
++      if (ret)
++              return ret;
++      raw_inode = iloc.raw_inode;
++
++      storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
++                              EXT3_GOOD_OLD_INODE_SIZE -
++                              EXT3_I(inode)->i_extra_isize -
++                              sizeof(__u32);
++      start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
++                      EXT3_I(inode)->i_extra_isize;
++      if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
++              brelse(iloc.bh);
++              return 0;
++      }
++      start += sizeof(__u32);
++      end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
++
++      last = (struct ext3_xattr_entry *) start;
++      while (!IS_LAST_ENTRY(last)) {
++              struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
++              struct ext3_xattr_handler *handler;
++              if (le32_to_cpu(last->e_value_size) > storage_size ||
++                              (char *) next >= end) {
++                      ext3_error(inode->i_sb, "ext3_xattr_ibody_list",
++                              "inode %ld", inode->i_ino);
++                      brelse(iloc.bh);
++                      return -EIO;
++              }
++              handler = ext3_xattr_handler(last->e_name_index);
++              if (handler)
++                      size += handler->list(NULL, inode, last->e_name,
++                                            last->e_name_len);
++              last = next;
++      }
++
++      if (!buffer) {
++              ret = size;
++              goto cleanup;
++      } else {
++              ret = -ERANGE;
++              if (size > buffer_size)
++                      goto cleanup;
++      }
++
++      last = (struct ext3_xattr_entry *) start;
++      buf = buffer;
++      while (!IS_LAST_ENTRY(last)) {
++              struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
++              struct ext3_xattr_handler *handler;
++              handler = ext3_xattr_handler(last->e_name_index);
++              if (handler)
++                      buf += handler->list(buf, inode, last->e_name,
++                                            last->e_name_len);
++              last = next;
++      }
++      ret = size;
++cleanup:
++      brelse(iloc.bh);
++      return ret;
++}
++
++/*
++ * ext3_xattr_list()
++ *
++ * Copy a list of attribute names into the buffer
++ * provided, or compute the buffer size required.
++ * Buffer is NULL to compute the size of the buffer required.
++ *
++ * Returns a negative error number on failure, or the number of bytes
++ * used / required on success.
++ */
++int
++ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
++{
++      int error;
++      int size = buffer_size;
++
++      /* get list of attributes stored in inode body */
++      error = ext3_xattr_ibody_list(inode, buffer, buffer_size);
++      if (error < 0) {
++              /* some error occured while collecting
++               * attributes in inode body */
++              size = 0;
++              goto cleanup;
++      }
++      size = error;
++
++      /* get list of attributes stored in dedicated block */
++      if (buffer) {
++              buffer_size -= error;
++              if (buffer_size <= 0) {
++                      buffer = NULL;
++                      buffer_size = 0;
++              } else
++                      buffer += error;
++      }
++
++      error = ext3_xattr_block_list(inode, buffer, buffer_size);
++      if (error < 0)
++              /* listing was successful, so we return len */
++              size = 0;
++
++cleanup:
++      return error + size;
++}
++
+ /*
+  * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is
+  * not set, set it.
+@@ -553,6 +764,279 @@
+ }
+ /*
++ * ext3_xattr_ibody_find()
++ *
++ * search attribute and calculate free space in inode body
++ * NOTE: free space includes space our attribute hold
++ */
++int
++ext3_xattr_ibody_find(struct inode *inode, int name_index,
++              const char *name, struct ext3_xattr_entry *rentry, int *free)
++{
++      struct ext3_xattr_entry *last;
++      struct ext3_inode *raw_inode;
++      int name_len = strlen(name);
++      int err, storage_size;
++      struct ext3_iloc iloc;
++      char *start, *end;
++      int ret = -ENOENT;
++      
++      if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
++              return ret;
++
++      err = ext3_get_inode_loc(inode, &iloc);
++      if (err)
++              return -EIO;
++      raw_inode = iloc.raw_inode;
++
++      storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
++                              EXT3_GOOD_OLD_INODE_SIZE -
++                              EXT3_I(inode)->i_extra_isize -
++                              sizeof(__u32);
++      *free = storage_size - sizeof(__u32);
++      start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
++                      EXT3_I(inode)->i_extra_isize;
++      if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
++              brelse(iloc.bh);
++              return -ENOENT;
++      }
++      start += sizeof(__u32);
++      end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
++
++      last = (struct ext3_xattr_entry *) start;
++      while (!IS_LAST_ENTRY(last)) {
++              struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
++              if (le32_to_cpu(last->e_value_size) > storage_size ||
++                              (char *) next >= end) {
++                      ext3_error(inode->i_sb, "ext3_xattr_ibody_find",
++                              "inode %ld", inode->i_ino);
++                      brelse(iloc.bh);
++                      return -EIO;
++              }
++
++              if (name_index == last->e_name_index &&
++                  name_len == last->e_name_len &&
++                  !memcmp(name, last->e_name, name_len)) {
++                      memcpy(rentry, last, sizeof(struct ext3_xattr_entry));
++                      ret = 0;
++              } else {
++                      *free -= EXT3_XATTR_LEN(last->e_name_len);
++                      *free -= le32_to_cpu(last->e_value_size);
++              }
++              last = next;
++      }
++      
++      brelse(iloc.bh);
++      return ret;
++}
++
++/*
++ * ext3_xattr_block_find()
++ *
++ * search attribute and calculate free space in EA block (if it allocated)
++ * NOTE: free space includes space our attribute hold
++ */
++int
++ext3_xattr_block_find(struct inode *inode, int name_index, const char *name,
++             struct ext3_xattr_entry *rentry, int *free)
++{
++      struct buffer_head *bh = NULL;
++      struct ext3_xattr_entry *entry;
++      char *end;
++      int name_len, error = -ENOENT;
++
++      if (!EXT3_I(inode)->i_file_acl) {
++              *free = inode->i_sb->s_blocksize -
++                      sizeof(struct ext3_xattr_header) -
++                      sizeof(__u32);
++              return -ENOENT;
++      }
++      ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
++      bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
++      if (!bh)
++              return -EIO;
++      ea_bdebug(bh, "b_count=%d, refcount=%d",
++              atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
++      end = bh->b_data + bh->b_size;
++      if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
++          HDR(bh)->h_blocks != cpu_to_le32(1)) {
++bad_block:    ext3_error(inode->i_sb, "ext3_xattr_get",
++                      "inode %ld: bad block %d", inode->i_ino,
++                      EXT3_I(inode)->i_file_acl);
++              brelse(bh);
++              return -EIO;
++      }
++      /* find named attribute */
++      name_len = strlen(name);
++      *free = bh->b_size - sizeof(__u32);
++
++      entry = FIRST_ENTRY(bh);
++      while (!IS_LAST_ENTRY(entry)) {
++              struct ext3_xattr_entry *next =
++                      EXT3_XATTR_NEXT(entry);
++              if ((char *)next >= end)
++                      goto bad_block;
++              if (name_index == entry->e_name_index &&
++                  name_len == entry->e_name_len &&
++                  memcmp(name, entry->e_name, name_len) == 0) {
++                      memcpy(rentry, entry, sizeof(struct ext3_xattr_entry));
++                      error = 0;
++              } else {
++                      *free -= EXT3_XATTR_LEN(entry->e_name_len);
++                      *free -= le32_to_cpu(entry->e_value_size);
++              }
++              entry = next;
++      }
++      brelse(bh);
++
++      return error;
++}
++
++/*
++ * ext3_xattr_inode_set()
++ *
++ * this routine add/remove/replace attribute in inode body
++ */
++int
++ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, int name_index,
++                    const char *name, const void *value, size_t value_len,
++                    int flags)
++{
++      struct ext3_xattr_entry *last, *next, *here = NULL;
++      struct ext3_inode *raw_inode;
++      int name_len = strlen(name);
++      int esize = EXT3_XATTR_LEN(name_len);
++      struct buffer_head *bh;
++      int err, storage_size;
++      struct ext3_iloc iloc;
++      int free, min_offs;
++      char *start, *end;
++      
++      if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
++              return -ENOSPC;
++
++      err = ext3_get_inode_loc(inode, &iloc);
++      if (err)
++              return err;
++      raw_inode = iloc.raw_inode;
++      bh = iloc.bh;
++
++      storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
++                              EXT3_GOOD_OLD_INODE_SIZE -
++                              EXT3_I(inode)->i_extra_isize -
++                              sizeof(__u32);
++      start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
++                      EXT3_I(inode)->i_extra_isize;
++      if ((*(__u32*) start) != EXT3_XATTR_MAGIC) {
++              /* inode had no attributes before */
++              *((__u32*) start) = cpu_to_le32(EXT3_XATTR_MAGIC);
++      }
++      start += sizeof(__u32);
++      end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
++      min_offs = storage_size;
++      free = storage_size - sizeof(__u32);
++
++      last = (struct ext3_xattr_entry *) start;       
++      while (!IS_LAST_ENTRY(last)) {
++              next = EXT3_XATTR_NEXT(last);
++              if (le32_to_cpu(last->e_value_size) > storage_size ||
++                              (char *) next >= end) {
++                      ext3_error(inode->i_sb, "ext3_xattr_ibody_set",
++                              "inode %ld", inode->i_ino);
++                      brelse(bh);
++                      return -EIO;
++              }
++              
++              if (last->e_value_size) {
++                      int offs = le16_to_cpu(last->e_value_offs);
++                      if (offs < min_offs)
++                              min_offs = offs;
++              }
++              if (name_index == last->e_name_index &&
++                      name_len == last->e_name_len &&
++                      !memcmp(name, last->e_name, name_len))
++                      here = last;
++              else {
++                      /* we calculate all but our attribute
++                       * because it will be removed before changing */
++                      free -= EXT3_XATTR_LEN(last->e_name_len);
++                      free -= le32_to_cpu(last->e_value_size);
++              }
++              last = next;
++      }
++
++      if (value && (esize + value_len > free)) {
++              brelse(bh);
++              return -ENOSPC;
++      }
++      
++      err = ext3_reserve_inode_write(handle, inode, &iloc);
++      if (err) {
++              brelse(bh);     
++              return err;
++      }
++
++      if (here) {
++              /* time to remove old value */
++              struct ext3_xattr_entry *e;
++              int size = le32_to_cpu(here->e_value_size);
++              int border = le16_to_cpu(here->e_value_offs);
++              char *src;
++
++              /* move tail */
++              memmove(start + min_offs + size, start + min_offs,
++                              border - min_offs);
++
++              /* recalculate offsets */
++              e = (struct ext3_xattr_entry *) start;
++              while (!IS_LAST_ENTRY(e)) {
++                      struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(e);
++                      int offs = le16_to_cpu(e->e_value_offs);
++                      if (offs < border)
++                              e->e_value_offs =
++                                      cpu_to_le16(offs + size);
++                      e = next;
++              }
++              min_offs += size;
++
++              /* remove entry */
++              border = EXT3_XATTR_LEN(here->e_name_len);
++              src = (char *) here + EXT3_XATTR_LEN(here->e_name_len);
++              size = (char *) last - src;
++              if ((char *) here + size > end)
++                      printk("ALERT at %s:%d: 0x%p + %d > 0x%p\n",
++                                      __FILE__, __LINE__, here, size, end);
++              memmove(here, src, size);
++              last = (struct ext3_xattr_entry *) ((char *) last - border);
++              *((__u32 *) last) = 0;
++      }
++      
++      if (value) {
++              int offs = min_offs - value_len;
++              /* use last to create new entry */
++              last->e_name_len = strlen(name);
++              last->e_name_index = name_index;
++              last->e_value_offs = cpu_to_le16(offs);
++              last->e_value_size = cpu_to_le32(value_len);
++              last->e_hash = last->e_value_block = 0;
++              memset(last->e_name, 0, esize);
++              memcpy(last->e_name, name, last->e_name_len);
++              if (start + offs + value_len > end)
++                      printk("ALERT at %s:%d: 0x%p + %d + %d > 0x%p\n",
++                                      __FILE__, __LINE__, start, offs,
++                                      value_len, end);
++              memcpy(start + offs, value, value_len);
++              last = EXT3_XATTR_NEXT(last);
++              *((__u32 *) last) = 0;
++      }
++      
++      ext3_mark_iloc_dirty(handle, inode, &iloc);
++      brelse(bh);
++
++      return 0;
++}
++
++/*
+  * ext3_xattr_set()
+  *
+  * Create, replace or remove an extended attribute for this inode. Buffer
+@@ -566,6 +1050,101 @@
+  */
+ int
+ ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index,
++              const char *name, const void *value, size_t value_len, int flags)
++{
++      struct ext3_xattr_entry entry;
++      int err, where = 0, found = 0, total;
++      int free1 = -1, free2 = -1;
++      int name_len;
++      
++      ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
++                name_index, name, value, (long)value_len);
++
++      if (IS_RDONLY(inode))
++              return -EROFS;
++      if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
++              return -EPERM;
++      if (value == NULL)
++              value_len = 0;
++      if (name == NULL)
++              return -EINVAL;
++      name_len = strlen(name);
++      if (name_len > 255 || value_len > inode->i_sb->s_blocksize)
++              return -ERANGE;
++
++      /* try to find attribute in inode body */
++      err = ext3_xattr_ibody_find(inode, name_index, name, &entry, &free1);
++      if (err == 0) {
++              /* found EA in inode */
++              found = 1;
++              where = 0;
++      } else if (err == -ENOENT) {
++              /* there is no such attribute in inode body */
++              /* try to find attribute in dedicated block */
++              err = ext3_xattr_block_find(inode, name_index, name,
++                                              &entry, &free2);
++              if (err != 0 && err != -ENOENT) {
++                      /* not found EA in block */
++                      goto finish;    
++              } else if (err == 0) {
++                      /* found EA in block */
++                      where = 1;
++                      found = 1;
++              }
++      } else
++              goto finish;
++
++      /* check flags: may replace? may create ? */
++      if (found && (flags & XATTR_CREATE)) {
++              err = -EEXIST;
++              goto finish;
++      } else if (!found && (flags & XATTR_REPLACE)) {
++              err = -ENODATA;
++              goto finish;
++      }
++
++      /* check if we have enough space to store attribute */
++      total = EXT3_XATTR_LEN(strlen(name)) + value_len;
++      if (free1 >= 0 && total > free1 && free2 >= 0 && total > free2) {
++              /* have no enough space */
++              err = -ENOSPC;
++              goto finish;
++      }
++      
++      /* time to remove attribute */
++      if (found) {
++              if (where == 0) {
++                      /* EA is stored in inode body */
++                      ext3_xattr_ibody_set(handle, inode, name_index, name,
++                                      NULL, 0, flags);
++              } else {
++                      /* EA is stored in separated block */
++                      ext3_xattr_block_set(handle, inode, name_index, name,
++                                      NULL, 0, flags);
++              }
++      }
++
++      /* try to store EA in inode body */
++      err = ext3_xattr_ibody_set(handle, inode, name_index, name,
++                              value, value_len, flags);
++      if (err) {
++              /* can't store EA in inode body */
++              /* try to store in block */
++              err = ext3_xattr_block_set(handle, inode, name_index,
++                                      name, value, value_len, flags); 
++      }
++
++finish:       
++      return err;
++}
++
++/*
++ * ext3_xattr_block_set()
++ *
++ * this routine add/remove/replace attribute in EA block
++ */
++int
++ext3_xattr_block_set(handle_t *handle, struct inode *inode, int name_index,
+              const char *name, const void *value, size_t value_len, int flags)
+ {
+       struct super_block *sb = inode->i_sb;
+@@ -603,6 +1182,7 @@
+       name_len = strlen(name);
+       if (name_len > 255 || value_len > sb->s_blocksize)
+               return -ERANGE;
++
+       down(&ext3_xattr_sem);
+       if (block) {
+Index: linux-2.4.29/include/linux/ext3_fs.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext3_fs.h  2005-05-03 15:58:30.767273592 +0300
++++ linux-2.4.29/include/linux/ext3_fs.h       2005-05-03 16:07:33.009840192 +0300
+@@ -259,6 +259,8 @@
+                       __u32   m_i_reserved2[2];
+               } masix2;
+       } osd2;                         /* OS dependent 2 */
++      __u16   i_extra_isize;
++      __u16   i_pad1;
+ };
+ #define i_size_high   i_dir_acl
+Index: linux-2.4.29/include/linux/ext3_fs_i.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext3_fs_i.h        2005-04-07 18:52:18.000000000 +0300
++++ linux-2.4.29/include/linux/ext3_fs_i.h     2005-05-03 16:07:33.010840040 +0300
+@@ -62,6 +62,9 @@
+        */
+       loff_t  i_disksize;
++      /* on-disk additional length */
++      __u16 i_extra_isize;
++
+       /*
+        * truncate_sem is for serialising ext3_truncate() against
+        * ext3_getblock().  In the 2.4 ext2 design, great chunks of inode's
diff --git a/lustre/kernel_patches/patches/ext3-extents-2.4.29.patch b/lustre/kernel_patches/patches/ext3-extents-2.4.29.patch
new file mode 100644 (file)
index 0000000..2b9f2ec
--- /dev/null
@@ -0,0 +1,2852 @@
+Index: linux-2.4.29/fs/ext3/extents.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/extents.c        2005-05-03 16:52:08.723069952 +0300
++++ linux-2.4.29/fs/ext3/extents.c     2005-05-03 16:52:08.802057944 +0300
+@@ -0,0 +1,2302 @@
++/*
++ * Copyright(c) 2003, 2004, 2005, Cluster File Systems, Inc, info@clusterfs.com
++ * Written by Alex Tomas <alex@clusterfs.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program 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 General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public Licens
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
++ */
++
++/*
++ * Extents support for EXT3
++ *
++ * TODO:
++ *   - ext3_ext_walk_space() sould not use ext3_ext_find_extent()
++ *   - ext3_ext_calc_credits() could take 'mergable' into account
++ *   - ext3*_error() should be used in some situations
++ *   - find_goal() [to be tested and improved]
++ *   - smart tree reduction
++ *   - arch-independence
++ *     common on-disk format for big/little-endian arch
++ */
++
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/time.h>
++#include <linux/ext3_jbd.h>
++#include <linux/jbd.h>
++#include <linux/locks.h>
++#include <linux/smp_lock.h>
++#include <linux/highuid.h>
++#include <linux/pagemap.h>
++#include <linux/quotaops.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/ext3_extents.h>
++#include <asm/uaccess.h>
++
++
++static inline int ext3_ext_check_header(struct ext3_extent_header *eh)
++{
++      if (eh->eh_magic != EXT3_EXT_MAGIC) {
++              printk(KERN_ERR "EXT3-fs: invalid magic = 0x%x\n",
++                     (unsigned)eh->eh_magic);
++              return -EIO;
++      }
++      if (eh->eh_max == 0) {
++              printk(KERN_ERR "EXT3-fs: invalid eh_max = %u\n",
++                     (unsigned)eh->eh_max);
++              return -EIO;
++      }
++      if (eh->eh_entries > eh->eh_max) {
++              printk(KERN_ERR "EXT3-fs: invalid eh_entries = %u\n",
++                     (unsigned)eh->eh_entries);
++              return -EIO;
++      }
++      return 0;
++}
++
++static handle_t *ext3_ext_journal_restart(handle_t *handle, int needed)
++{
++      int err;
++
++      if (handle->h_buffer_credits > needed)
++              return handle;
++      if (!ext3_journal_extend(handle, needed))
++              return handle;
++      err = ext3_journal_restart(handle, needed);
++      
++      return handle;
++}
++
++static int inline
++ext3_ext_get_access_for_root(handle_t *h, struct ext3_extents_tree *tree)
++{
++      if (tree->ops->get_write_access)
++              return tree->ops->get_write_access(h,tree->buffer);
++      else
++              return 0;
++}
++
++static int inline
++ext3_ext_mark_root_dirty(handle_t *h, struct ext3_extents_tree *tree)
++{
++      if (tree->ops->mark_buffer_dirty)
++              return tree->ops->mark_buffer_dirty(h,tree->buffer);
++      else
++              return 0;
++}
++
++/*
++ * could return:
++ *  - EROFS
++ *  - ENOMEM
++ */
++static int ext3_ext_get_access(handle_t *handle,
++                             struct ext3_extents_tree *tree,
++                             struct ext3_ext_path *path)
++{
++      int err;
++
++      if (path->p_bh) {
++              /* path points to block */
++              err = ext3_journal_get_write_access(handle, path->p_bh);
++      } else {
++              /* path points to leaf/index in inode body */
++              err = ext3_ext_get_access_for_root(handle, tree);
++      }
++      return err;
++}
++
++/*
++ * could return:
++ *  - EROFS
++ *  - ENOMEM
++ *  - EIO
++ */
++static int ext3_ext_dirty(handle_t *handle, struct ext3_extents_tree *tree,
++                        struct ext3_ext_path *path)
++{
++      int err;
++      if (path->p_bh) {
++              /* path points to block */
++              err =ext3_journal_dirty_metadata(handle, path->p_bh);
++      } else {
++              /* path points to leaf/index in inode body */
++              err = ext3_ext_mark_root_dirty(handle, tree);
++      }
++      return err;
++}
++
++static int inline
++ext3_ext_new_block(handle_t *handle, struct ext3_extents_tree *tree,
++                 struct ext3_ext_path *path, struct ext3_extent *ex,
++                 int *err)
++{
++      int goal, depth, newblock;
++      struct inode *inode;
++
++      EXT_ASSERT(tree);
++      if (tree->ops->new_block)
++              return tree->ops->new_block(handle, tree, path, ex, err);
++
++      inode = tree->inode;
++      depth = EXT_DEPTH(tree);
++      if (path && depth > 0) {
++              goal = path[depth-1].p_block;
++      } else {
++              struct ext3_inode_info *ei = EXT3_I(inode);
++              unsigned long bg_start;
++              unsigned long colour;
++
++              bg_start = (ei->i_block_group *
++                          EXT3_BLOCKS_PER_GROUP(inode->i_sb)) +
++                      le32_to_cpu(EXT3_SB(inode->i_sb)->s_es->s_first_data_block);
++              colour = (current->pid % 16) *
++                      (EXT3_BLOCKS_PER_GROUP(inode->i_sb) / 16);
++              goal = bg_start + colour;
++      }
++
++      newblock = ext3_new_block(handle, inode, goal, 0, 0, err);
++      return newblock;
++}
++
++static inline void ext3_ext_tree_changed(struct ext3_extents_tree *tree)
++{
++      struct ext3_extent_header *neh;
++      neh = EXT_ROOT_HDR(tree);
++      neh->eh_generation++;
++}
++
++static inline int ext3_ext_space_block(struct ext3_extents_tree *tree)
++{
++      int size;
++
++      size = (tree->inode->i_sb->s_blocksize -
++              sizeof(struct ext3_extent_header)) /
++                              sizeof(struct ext3_extent);
++#ifdef AGRESSIVE_TEST
++      size = 6;
++#endif
++      return size;
++}
++
++static inline int ext3_ext_space_block_idx(struct ext3_extents_tree *tree)
++{
++      int size;
++
++      size = (tree->inode->i_sb->s_blocksize -
++              sizeof(struct ext3_extent_header)) /
++                              sizeof(struct ext3_extent_idx);
++#ifdef AGRESSIVE_TEST
++      size = 5;
++#endif
++      return size;
++}
++
++static inline int ext3_ext_space_root(struct ext3_extents_tree *tree)
++{
++      int size;
++
++      size = (tree->buffer_len - sizeof(struct ext3_extent_header)) /
++                      sizeof(struct ext3_extent);
++#ifdef AGRESSIVE_TEST
++      size = 3;
++#endif
++      return size;
++}
++
++static inline int ext3_ext_space_root_idx(struct ext3_extents_tree *tree)
++{
++      int size;
++
++      size = (tree->buffer_len - sizeof(struct ext3_extent_header)) /
++                      sizeof(struct ext3_extent_idx);
++#ifdef AGRESSIVE_TEST
++      size = 4;
++#endif
++      return size;
++}
++
++static void ext3_ext_show_path(struct ext3_extents_tree *tree,
++                             struct ext3_ext_path *path)
++{
++#ifdef EXT_DEBUG
++      int k, l = path->p_depth;
++
++      ext_debug(tree, "path:");
++      for (k = 0; k <= l; k++, path++) {
++              if (path->p_idx) {
++                      ext_debug(tree, "  %d->%d", path->p_idx->ei_block,
++                                path->p_idx->ei_leaf);
++              } else if (path->p_ext) {
++                      ext_debug(tree, "  %d:%d:%d",
++                                path->p_ext->ee_block,
++                                path->p_ext->ee_len,
++                                path->p_ext->ee_start);
++              } else
++                      ext_debug(tree, "  []");
++      }
++      ext_debug(tree, "\n");
++#endif
++}
++
++static void ext3_ext_show_leaf(struct ext3_extents_tree *tree,
++                             struct ext3_ext_path *path)
++{
++#ifdef EXT_DEBUG
++      int depth = EXT_DEPTH(tree);
++      struct ext3_extent_header *eh;
++      struct ext3_extent *ex;
++      int i;
++
++      if (!path)
++              return;
++
++      eh = path[depth].p_hdr;
++      ex = EXT_FIRST_EXTENT(eh);
++
++      for (i = 0; i < eh->eh_entries; i++, ex++) {
++              ext_debug(tree, "%d:%d:%d ",
++                        ex->ee_block, ex->ee_len, ex->ee_start);
++      }
++      ext_debug(tree, "\n");
++#endif
++}
++
++static void ext3_ext_drop_refs(struct ext3_ext_path *path)
++{
++      int depth = path->p_depth;
++      int i;
++
++      for (i = 0; i <= depth; i++, path++) {
++              if (path->p_bh) {
++                      brelse(path->p_bh);
++                      path->p_bh = NULL;
++              }
++      }
++}
++
++/*
++ * binary search for closest index by given block
++ */
++static inline void
++ext3_ext_binsearch_idx(struct ext3_extents_tree *tree,
++                     struct ext3_ext_path *path, int block)
++{
++      struct ext3_extent_header *eh = path->p_hdr;
++      struct ext3_extent_idx *ix;
++      int l = 0, k, r;
++
++      EXT_ASSERT(eh->eh_magic == EXT3_EXT_MAGIC);
++      EXT_ASSERT(eh->eh_entries <= eh->eh_max);
++      EXT_ASSERT(eh->eh_entries > 0);
++
++      ext_debug(tree, "binsearch for %d(idx):  ", block);
++
++      path->p_idx = ix = EXT_FIRST_INDEX(eh);
++
++      r = k = eh->eh_entries;
++      while (k > 1) {
++              k = (r - l) / 2;
++              if (block < ix[l + k].ei_block)
++                      r -= k;
++              else
++                      l += k;
++              ext_debug(tree, "%d:%d:%d ", k, l, r);
++      }
++
++      ix += l;
++      path->p_idx = ix;
++      ext_debug(tree," -> %d->%d ",path->p_idx->ei_block,path->p_idx->ei_leaf);
++
++      while (l++ < r) {
++              if (block < ix->ei_block) 
++                      break;
++              path->p_idx = ix++;
++      }
++      ext_debug(tree, "  -> %d->%d\n", path->p_idx->ei_block,
++                path->p_idx->ei_leaf);
++
++#ifdef CHECK_BINSEARCH 
++      {
++              struct ext3_extent_idx *chix;
++
++              chix = ix = EXT_FIRST_INDEX(eh);
++              for (k = 0; k < eh->eh_entries; k++, ix++) {
++                      if (k != 0 && ix->ei_block <= ix[-1].ei_block) {
++                              printk("k=%d, ix=0x%p, first=0x%p\n", k,
++                                     ix, EXT_FIRST_INDEX(eh));
++                              printk("%u <= %u\n",
++                                     ix->ei_block,ix[-1].ei_block);
++                      }
++                      EXT_ASSERT(k == 0 || ix->ei_block > ix[-1].ei_block);
++                      if (block < ix->ei_block) 
++                              break;
++                      chix = ix;
++              }
++              EXT_ASSERT(chix == path->p_idx);
++      }
++#endif
++}
++
++/*
++ * binary search for closest extent by given block
++ */
++static inline void
++ext3_ext_binsearch(struct ext3_extents_tree *tree,
++                 struct ext3_ext_path *path, int block)
++{
++      struct ext3_extent_header *eh = path->p_hdr;
++      struct ext3_extent *ex;
++      int l = 0, k, r;
++
++      EXT_ASSERT(eh->eh_magic == EXT3_EXT_MAGIC);
++      EXT_ASSERT(eh->eh_entries <= eh->eh_max);
++
++      if (eh->eh_entries == 0) {
++              /*
++               * this leaf is empty yet:
++               *  we get such a leaf in split/add case
++               */
++              return;
++      }
++      
++      ext_debug(tree, "binsearch for %d:  ", block);
++
++      path->p_ext = ex = EXT_FIRST_EXTENT(eh);
++
++      r = k = eh->eh_entries;
++      while (k > 1) {
++              k = (r - l) / 2;
++              if (block < ex[l + k].ee_block)
++                      r -= k;
++              else
++                      l += k;
++              ext_debug(tree, "%d:%d:%d ", k, l, r);
++      }
++
++      ex += l;
++      path->p_ext = ex;
++      ext_debug(tree, "  -> %d:%d:%d ", path->p_ext->ee_block,
++                path->p_ext->ee_start, path->p_ext->ee_len);
++
++      while (l++ < r) {
++              if (block < ex->ee_block) 
++                      break;
++              path->p_ext = ex++;
++      }
++      ext_debug(tree, "  -> %d:%d:%d\n", path->p_ext->ee_block,
++                path->p_ext->ee_start, path->p_ext->ee_len);
++
++#ifdef CHECK_BINSEARCH 
++      {
++              struct ext3_extent *chex;
++
++              chex = ex = EXT_FIRST_EXTENT(eh);
++              for (k = 0; k < eh->eh_entries; k++, ex++) {
++                      EXT_ASSERT(k == 0 || ex->ee_block > ex[-1].ee_block);
++                      if (block < ex->ee_block) 
++                              break;
++                      chex = ex;
++              }
++              EXT_ASSERT(chex == path->p_ext);
++      }
++#endif
++}
++
++int ext3_extent_tree_init(handle_t *handle, struct ext3_extents_tree *tree)
++{
++      struct ext3_extent_header *eh;
++
++      BUG_ON(tree->buffer_len == 0);
++      ext3_ext_get_access_for_root(handle, tree);
++      eh = EXT_ROOT_HDR(tree);
++      eh->eh_depth = 0;
++      eh->eh_entries = 0;
++      eh->eh_magic = EXT3_EXT_MAGIC;
++      eh->eh_max = ext3_ext_space_root(tree);
++      ext3_ext_mark_root_dirty(handle, tree);
++      ext3_ext_invalidate_cache(tree);
++      return 0;
++}
++
++struct ext3_ext_path *
++ext3_ext_find_extent(struct ext3_extents_tree *tree, int block,
++                   struct ext3_ext_path *path)
++{
++      struct ext3_extent_header *eh;
++      struct buffer_head *bh;
++      int depth, i, ppos = 0;
++
++      EXT_ASSERT(tree);
++      EXT_ASSERT(tree->inode);
++      EXT_ASSERT(tree->root);
++
++      eh = EXT_ROOT_HDR(tree);
++      EXT_ASSERT(eh);
++      if (ext3_ext_check_header(eh))
++              goto err;
++
++      i = depth = EXT_DEPTH(tree);
++      EXT_ASSERT(eh->eh_max);
++      EXT_ASSERT(eh->eh_magic == EXT3_EXT_MAGIC);
++      
++      /* account possible depth increase */
++      if (!path) {
++              path = kmalloc(sizeof(struct ext3_ext_path) * (depth + 2),
++                             GFP_NOFS);
++              if (!path)
++                      return ERR_PTR(-ENOMEM);
++      }
++      memset(path, 0, sizeof(struct ext3_ext_path) * (depth + 1));
++      path[0].p_hdr = eh;
++
++      /* walk through the tree */
++      while (i) {
++              ext_debug(tree, "depth %d: num %d, max %d\n",
++                        ppos, eh->eh_entries, eh->eh_max);
++              ext3_ext_binsearch_idx(tree, path + ppos, block);
++              path[ppos].p_block = path[ppos].p_idx->ei_leaf;
++              path[ppos].p_depth = i;
++              path[ppos].p_ext = NULL;
++
++              bh = sb_bread(tree->inode->i_sb, path[ppos].p_block);
++              if (!bh)
++                      goto err;
++              eh = EXT_BLOCK_HDR(bh);
++              ppos++;
++              EXT_ASSERT(ppos <= depth);
++              path[ppos].p_bh = bh;
++              path[ppos].p_hdr = eh;
++              i--;
++
++              if (ext3_ext_check_header(eh))
++                      goto err;
++      }
++
++      path[ppos].p_depth = i;
++      path[ppos].p_hdr = eh;
++      path[ppos].p_ext = NULL;
++      path[ppos].p_idx = NULL;
++
++      if (ext3_ext_check_header(eh))
++              goto err;
++
++      /* find extent */
++      ext3_ext_binsearch(tree, path + ppos, block);
++
++      ext3_ext_show_path(tree, path);
++
++      return path;
++
++err:
++      printk(KERN_ERR "EXT3-fs: header is corrupted!\n");
++      ext3_ext_drop_refs(path);
++      kfree(path);
++      return ERR_PTR(-EIO);
++}
++
++/*
++ * insert new index [logical;ptr] into the block at cupr
++ * it check where to insert: before curp or after curp
++ */
++static int ext3_ext_insert_index(handle_t *handle,
++                               struct ext3_extents_tree *tree,
++                               struct ext3_ext_path *curp,
++                               int logical, int ptr)
++{
++      struct ext3_extent_idx *ix;
++      int len, err;
++
++      if ((err = ext3_ext_get_access(handle, tree, curp)))
++              return err;
++
++      EXT_ASSERT(logical != curp->p_idx->ei_block);
++      len = EXT_MAX_INDEX(curp->p_hdr) - curp->p_idx;
++      if (logical > curp->p_idx->ei_block) {
++              /* insert after */
++              if (curp->p_idx != EXT_LAST_INDEX(curp->p_hdr)) {
++                      len = (len - 1) * sizeof(struct ext3_extent_idx);
++                      len = len < 0 ? 0 : len;
++                      ext_debug(tree, "insert new index %d after: %d. "
++                                "move %d from 0x%p to 0x%p\n",
++                                logical, ptr, len,
++                                (curp->p_idx + 1), (curp->p_idx + 2));
++                      memmove(curp->p_idx + 2, curp->p_idx + 1, len);
++              }
++              ix = curp->p_idx + 1;
++      } else {
++              /* insert before */
++              len = len * sizeof(struct ext3_extent_idx);
++              len = len < 0 ? 0 : len;
++              ext_debug(tree, "insert new index %d before: %d. "
++                        "move %d from 0x%p to 0x%p\n",
++                        logical, ptr, len,
++                        curp->p_idx, (curp->p_idx + 1));
++              memmove(curp->p_idx + 1, curp->p_idx, len);
++              ix = curp->p_idx;
++      }
++
++      ix->ei_block = logical;
++      ix->ei_leaf = ptr;
++      curp->p_hdr->eh_entries++;
++
++      EXT_ASSERT(curp->p_hdr->eh_entries <= curp->p_hdr->eh_max);
++      EXT_ASSERT(ix <= EXT_LAST_INDEX(curp->p_hdr));
++
++      err = ext3_ext_dirty(handle, tree, curp);
++      ext3_std_error(tree->inode->i_sb, err);
++
++      return err;
++}
++
++/*
++ * routine inserts new subtree into the path, using free index entry
++ * at depth 'at:
++ *  - allocates all needed blocks (new leaf and all intermediate index blocks)
++ *  - makes decision where to split
++ *  - moves remaining extens and index entries (right to the split point)
++ *    into the newly allocated blocks
++ *  - initialize subtree
++ */
++static int ext3_ext_split(handle_t *handle, struct ext3_extents_tree *tree,
++                        struct ext3_ext_path *path,
++                        struct ext3_extent *newext, int at)
++{
++      struct buffer_head *bh = NULL;
++      int depth = EXT_DEPTH(tree);
++      struct ext3_extent_header *neh;
++      struct ext3_extent_idx *fidx;
++      struct ext3_extent *ex;
++      int i = at, k, m, a;
++      unsigned long newblock, oldblock, border;
++      int *ablocks = NULL; /* array of allocated blocks */
++      int err = 0;
++
++      /* make decision: where to split? */
++      /* FIXME: now desicion is simplest: at current extent */
++
++      /* if current leaf will be splitted, then we should use 
++       * border from split point */
++      EXT_ASSERT(path[depth].p_ext <= EXT_MAX_EXTENT(path[depth].p_hdr));
++      if (path[depth].p_ext != EXT_MAX_EXTENT(path[depth].p_hdr)) {
++              border = path[depth].p_ext[1].ee_block;
++              ext_debug(tree, "leaf will be splitted."
++                        " next leaf starts at %d\n",
++                        (int)border);
++      } else {
++              border = newext->ee_block;
++              ext_debug(tree, "leaf will be added."
++                        " next leaf starts at %d\n",
++                        (int)border);
++      }
++
++      /* 
++       * if error occurs, then we break processing
++       * and turn filesystem read-only. so, index won't
++       * be inserted and tree will be in consistent
++       * state. next mount will repair buffers too
++       */
++
++      /*
++       * get array to track all allocated blocks
++       * we need this to handle errors and free blocks
++       * upon them
++       */
++      ablocks = kmalloc(sizeof(unsigned long) * depth, GFP_NOFS);
++      if (!ablocks)
++              return -ENOMEM;
++      memset(ablocks, 0, sizeof(unsigned long) * depth);
++
++      /* allocate all needed blocks */
++      ext_debug(tree, "allocate %d blocks for indexes/leaf\n", depth - at);
++      for (a = 0; a < depth - at; a++) {
++              newblock = ext3_ext_new_block(handle, tree, path, newext, &err);
++              if (newblock == 0)
++                      goto cleanup;
++              ablocks[a] = newblock;
++      }
++
++      /* initialize new leaf */
++      newblock = ablocks[--a];
++      EXT_ASSERT(newblock);
++      bh = sb_getblk(tree->inode->i_sb, newblock);
++      if (!bh) {
++              err = -EIO;
++              goto cleanup;
++      }
++      lock_buffer(bh);
++
++      if ((err = ext3_journal_get_create_access(handle, bh)))
++              goto cleanup;
++
++      neh = EXT_BLOCK_HDR(bh);
++      neh->eh_entries = 0;
++      neh->eh_max = ext3_ext_space_block(tree);
++      neh->eh_magic = EXT3_EXT_MAGIC;
++      neh->eh_depth = 0;
++      ex = EXT_FIRST_EXTENT(neh);
++
++      /* move remain of path[depth] to the new leaf */
++      EXT_ASSERT(path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max);
++      /* start copy from next extent */
++      /* TODO: we could do it by single memmove */
++      m = 0;
++      path[depth].p_ext++;
++      while (path[depth].p_ext <=
++                      EXT_MAX_EXTENT(path[depth].p_hdr)) {
++              ext_debug(tree, "move %d:%d:%d in new leaf %lu\n",
++                        path[depth].p_ext->ee_block,
++                        path[depth].p_ext->ee_start,
++                        path[depth].p_ext->ee_len,
++                        newblock);
++              memmove(ex++, path[depth].p_ext++, sizeof(struct ext3_extent));
++              neh->eh_entries++;
++              m++;
++      }
++      mark_buffer_uptodate(bh, 1);
++      unlock_buffer(bh);
++
++      if ((err = ext3_journal_dirty_metadata(handle, bh)))
++              goto cleanup;   
++      brelse(bh);
++      bh = NULL;
++
++      /* correct old leaf */
++      if (m) {
++              if ((err = ext3_ext_get_access(handle, tree, path + depth)))
++                      goto cleanup;
++              path[depth].p_hdr->eh_entries -= m;
++              if ((err = ext3_ext_dirty(handle, tree, path + depth)))
++                      goto cleanup;
++              
++      }
++
++      /* create intermediate indexes */
++      k = depth - at - 1;
++      EXT_ASSERT(k >= 0);
++      if (k)
++              ext_debug(tree, "create %d intermediate indices\n", k);
++      /* insert new index into current index block */
++      /* current depth stored in i var */
++      i = depth - 1;
++      while (k--) {
++              oldblock = newblock;
++              newblock = ablocks[--a];
++              bh = sb_getblk(tree->inode->i_sb, newblock);
++              if (!bh) {
++                      err = -EIO;
++                      goto cleanup;
++              }
++              lock_buffer(bh);
++
++              if ((err = ext3_journal_get_create_access(handle, bh)))
++                      goto cleanup;
++
++              neh = EXT_BLOCK_HDR(bh);
++              neh->eh_entries = 1;
++              neh->eh_magic = EXT3_EXT_MAGIC;
++              neh->eh_max = ext3_ext_space_block_idx(tree);
++              neh->eh_depth = depth - i; 
++              fidx = EXT_FIRST_INDEX(neh);
++              fidx->ei_block = border;
++              fidx->ei_leaf = oldblock;
++
++              ext_debug(tree, "int.index at %d (block %lu): %lu -> %lu\n",
++                        i, newblock, border, oldblock);
++              /* copy indexes */
++              m = 0;
++              path[i].p_idx++;
++
++              ext_debug(tree, "cur 0x%p, last 0x%p\n", path[i].p_idx,
++                        EXT_MAX_INDEX(path[i].p_hdr));
++              EXT_ASSERT(EXT_MAX_INDEX(path[i].p_hdr) ==
++                         EXT_LAST_INDEX(path[i].p_hdr));
++              while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {
++                      ext_debug(tree, "%d: move %d:%d in new index %lu\n",
++                                i, path[i].p_idx->ei_block,
++                                path[i].p_idx->ei_leaf, newblock);
++                      memmove(++fidx, path[i].p_idx++,
++                              sizeof(struct ext3_extent_idx));
++                      neh->eh_entries++;
++                      EXT_ASSERT(neh->eh_entries <= neh->eh_max);
++                      m++;
++              }
++              mark_buffer_uptodate(bh, 1);
++              unlock_buffer(bh);
++
++              if ((err = ext3_journal_dirty_metadata(handle, bh)))
++                      goto cleanup;
++              brelse(bh);
++              bh = NULL;
++
++              /* correct old index */
++              if (m) {
++                      err = ext3_ext_get_access(handle, tree, path + i);
++                      if (err)
++                              goto cleanup;
++                      path[i].p_hdr->eh_entries -= m;
++                      err = ext3_ext_dirty(handle, tree, path + i);
++                      if (err)
++                              goto cleanup;
++              }
++
++              i--;
++      }
++
++      /* insert new index */
++      if (!err)
++              err = ext3_ext_insert_index(handle, tree, path + at,
++                                          border, newblock);
++
++cleanup:
++      if (bh) {
++              if (buffer_locked(bh))
++                      unlock_buffer(bh);
++              brelse(bh);
++      }
++
++      if (err) {
++              /* free all allocated blocks in error case */
++              for (i = 0; i < depth; i++) {
++                      if (!ablocks[i])
++                              continue;
++                      ext3_free_blocks(handle, tree->inode, ablocks[i], 1);
++              }
++      }
++      kfree(ablocks);
++
++      return err;
++}
++
++/*
++ * routine implements tree growing procedure:
++ *  - allocates new block
++ *  - moves top-level data (index block or leaf) into the new block
++ *  - initialize new top-level, creating index that points to the
++ *    just created block
++ */
++static int ext3_ext_grow_indepth(handle_t *handle,
++                               struct ext3_extents_tree *tree,
++                               struct ext3_ext_path *path,
++                               struct ext3_extent *newext)
++{
++      struct ext3_ext_path *curp = path;
++      struct ext3_extent_header *neh;
++      struct ext3_extent_idx *fidx;
++      struct buffer_head *bh;
++      unsigned long newblock;
++      int err = 0;
++
++      newblock = ext3_ext_new_block(handle, tree, path, newext, &err);
++      if (newblock == 0)
++              return err;
++
++      bh = sb_getblk(tree->inode->i_sb, newblock);
++      if (!bh) {
++              err = -EIO;
++              ext3_std_error(tree->inode->i_sb, err);
++              return err;
++      }
++      lock_buffer(bh);
++
++      if ((err = ext3_journal_get_create_access(handle, bh))) {
++              unlock_buffer(bh);
++              goto out;       
++      }
++
++      /* move top-level index/leaf into new block */
++      memmove(bh->b_data, curp->p_hdr, tree->buffer_len);
++
++      /* set size of new block */
++      neh = EXT_BLOCK_HDR(bh);
++      /* old root could have indexes or leaves
++       * so calculate eh_max right way */
++      if (EXT_DEPTH(tree))
++              neh->eh_max = ext3_ext_space_block_idx(tree);
++      else
++              neh->eh_max = ext3_ext_space_block(tree);
++      neh->eh_magic = EXT3_EXT_MAGIC;
++      mark_buffer_uptodate(bh, 1);
++      unlock_buffer(bh);
++
++      if ((err = ext3_journal_dirty_metadata(handle, bh)))
++              goto out;
++
++      /* create index in new top-level index: num,max,pointer */
++      if ((err = ext3_ext_get_access(handle, tree, curp)))
++              goto out;
++
++      curp->p_hdr->eh_magic = EXT3_EXT_MAGIC;
++      curp->p_hdr->eh_max = ext3_ext_space_root_idx(tree);
++      curp->p_hdr->eh_entries = 1;
++      curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr);
++      /* FIXME: it works, but actually path[0] can be index */
++      curp->p_idx->ei_block = EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block;
++      curp->p_idx->ei_leaf = newblock;
++
++      neh = EXT_ROOT_HDR(tree);
++      fidx = EXT_FIRST_INDEX(neh);
++      ext_debug(tree, "new root: num %d(%d), lblock %d, ptr %d\n",
++                neh->eh_entries, neh->eh_max, fidx->ei_block, fidx->ei_leaf); 
++
++      neh->eh_depth = path->p_depth + 1;
++      err = ext3_ext_dirty(handle, tree, curp);
++out:
++      brelse(bh);
++
++      return err;
++}
++
++/*
++ * routine finds empty index and adds new leaf. if no free index found
++ * then it requests in-depth growing
++ */
++static int ext3_ext_create_new_leaf(handle_t *handle,
++                                  struct ext3_extents_tree *tree,
++                                  struct ext3_ext_path *path,
++                                  struct ext3_extent *newext)
++{
++      struct ext3_ext_path *curp;
++      int depth, i, err = 0;
++
++repeat:
++      i = depth = EXT_DEPTH(tree);
++      
++      /* walk up to the tree and look for free index entry */
++      curp = path + depth;
++      while (i > 0 && !EXT_HAS_FREE_INDEX(curp)) {
++              i--;
++              curp--;
++      }
++
++      /* we use already allocated block for index block
++       * so, subsequent data blocks should be contigoues */
++      if (EXT_HAS_FREE_INDEX(curp)) {
++              /* if we found index with free entry, then use that
++               * entry: create all needed subtree and add new leaf */
++              err = ext3_ext_split(handle, tree, path, newext, i);
++
++              /* refill path */
++              ext3_ext_drop_refs(path);
++              path = ext3_ext_find_extent(tree, newext->ee_block, path);
++              if (IS_ERR(path))
++                      err = PTR_ERR(path);
++      } else {
++              /* tree is full, time to grow in depth */
++              err = ext3_ext_grow_indepth(handle, tree, path, newext);
++
++              /* refill path */
++              ext3_ext_drop_refs(path);
++              path = ext3_ext_find_extent(tree, newext->ee_block, path);
++              if (IS_ERR(path))
++                      err = PTR_ERR(path);
++
++              /*
++               * only first (depth 0 -> 1) produces free space
++               * in all other cases we have to split growed tree
++               */
++              depth = EXT_DEPTH(tree);
++              if (path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max) {
++                      /* now we need split */
++                      goto repeat;
++              }
++      }
++
++      if (err)
++              return err;
++
++      return 0;
++}
++
++/*
++ * returns allocated block in subsequent extent or EXT_MAX_BLOCK
++ * NOTE: it consider block number from index entry as
++ * allocated block. thus, index entries have to be consistent
++ * with leafs
++ */
++static unsigned long
++ext3_ext_next_allocated_block(struct ext3_ext_path *path)
++{
++      int depth;
++
++      EXT_ASSERT(path != NULL);
++      depth = path->p_depth;
++
++      if (depth == 0 && path->p_ext == NULL)
++              return EXT_MAX_BLOCK;
++
++      /* FIXME: what if index isn't full ?! */
++      while (depth >= 0) {
++              if (depth == path->p_depth) {
++                      /* leaf */
++                      if (path[depth].p_ext !=
++                          EXT_LAST_EXTENT(path[depth].p_hdr))
++                              return path[depth].p_ext[1].ee_block;
++              } else {
++                      /* index */
++                      if (path[depth].p_idx !=
++                          EXT_LAST_INDEX(path[depth].p_hdr))
++                              return path[depth].p_idx[1].ei_block;
++              }
++              depth--;        
++      }
++
++      return EXT_MAX_BLOCK;
++}
++
++/*
++ * returns first allocated block from next leaf or EXT_MAX_BLOCK
++ */
++static unsigned ext3_ext_next_leaf_block(struct ext3_extents_tree *tree,
++                                       struct ext3_ext_path *path)
++{
++      int depth;
++
++      EXT_ASSERT(path != NULL);
++      depth = path->p_depth;
++
++      /* zero-tree has no leaf blocks at all */
++      if (depth == 0)
++              return EXT_MAX_BLOCK;
++
++      /* go to index block */
++      depth--;
++      
++      while (depth >= 0) {
++              if (path[depth].p_idx !=
++                  EXT_LAST_INDEX(path[depth].p_hdr))
++                      return path[depth].p_idx[1].ei_block;
++              depth--;        
++      }
++
++      return EXT_MAX_BLOCK;
++}
++
++/*
++ * if leaf gets modified and modified extent is first in the leaf
++ * then we have to correct all indexes above
++ * TODO: do we need to correct tree in all cases?
++ */
++int ext3_ext_correct_indexes(handle_t *handle, struct ext3_extents_tree *tree,
++                           struct ext3_ext_path *path)
++{
++      struct ext3_extent_header *eh;
++      int depth = EXT_DEPTH(tree);    
++      struct ext3_extent *ex;
++      unsigned long border;
++      int k, err = 0;
++      
++      eh = path[depth].p_hdr;
++      ex = path[depth].p_ext;
++      EXT_ASSERT(ex);
++      EXT_ASSERT(eh);
++      
++      if (depth == 0) {
++              /* there is no tree at all */
++              return 0;
++      }
++      
++      if (ex != EXT_FIRST_EXTENT(eh)) {
++              /* we correct tree if first leaf got modified only */
++              return 0;
++      }
++      
++      /*
++       * TODO: we need correction if border is smaller then current one
++       */
++      k = depth - 1;
++      border = path[depth].p_ext->ee_block;
++      if ((err = ext3_ext_get_access(handle, tree, path + k)))
++              return err;
++      path[k].p_idx->ei_block = border;
++      if ((err = ext3_ext_dirty(handle, tree, path + k)))
++              return err;
++
++      while (k--) {
++              /* change all left-side indexes */
++              if (path[k+1].p_idx != EXT_FIRST_INDEX(path[k+1].p_hdr))
++                      break;
++              if ((err = ext3_ext_get_access(handle, tree, path + k)))
++                      break;
++              path[k].p_idx->ei_block = border;
++              if ((err = ext3_ext_dirty(handle, tree, path + k)))
++                      break;
++      }
++
++      return err;
++}
++
++static int inline
++ext3_can_extents_be_merged(struct ext3_extents_tree *tree,
++                         struct ext3_extent *ex1,
++                         struct ext3_extent *ex2)
++{
++      if (ex1->ee_block + ex1->ee_len != ex2->ee_block)
++              return 0;
++
++#ifdef AGRESSIVE_TEST
++      if (ex1->ee_len >= 4)
++              return 0;
++#endif
++
++      if (!tree->ops->mergable)
++              return 1;
++
++      return tree->ops->mergable(ex1, ex2);
++}
++
++/*
++ * this routine tries to merge requsted extent into the existing
++ * extent or inserts requested extent as new one into the tree,
++ * creating new leaf in no-space case
++ */
++int ext3_ext_insert_extent(handle_t *handle, struct ext3_extents_tree *tree,
++                         struct ext3_ext_path *path,
++                         struct ext3_extent *newext)
++{
++      struct ext3_extent_header * eh;
++      struct ext3_extent *ex, *fex;
++      struct ext3_extent *nearex; /* nearest extent */
++      struct ext3_ext_path *npath = NULL;
++      int depth, len, err, next;
++
++      EXT_ASSERT(newext->ee_len > 0);
++      depth = EXT_DEPTH(tree);
++      ex = path[depth].p_ext;
++      EXT_ASSERT(path[depth].p_hdr);
++
++      /* try to insert block into found extent and return */
++      if (ex && ext3_can_extents_be_merged(tree, ex, newext)) {
++              ext_debug(tree, "append %d block to %d:%d (from %d)\n",
++                        newext->ee_len, ex->ee_block, ex->ee_len,
++                        ex->ee_start);
++              if ((err = ext3_ext_get_access(handle, tree, path + depth)))
++                      return err;
++              ex->ee_len += newext->ee_len;
++              eh = path[depth].p_hdr;
++              nearex = ex;
++              goto merge;
++      }
++
++repeat:
++      depth = EXT_DEPTH(tree);
++      eh = path[depth].p_hdr;
++      if (eh->eh_entries < eh->eh_max)
++              goto has_space;
++
++      /* probably next leaf has space for us? */
++      fex = EXT_LAST_EXTENT(eh);
++      next = ext3_ext_next_leaf_block(tree, path);
++      if (newext->ee_block > fex->ee_block && next != EXT_MAX_BLOCK) {
++              ext_debug(tree, "next leaf block - %d\n", next);
++              EXT_ASSERT(!npath);
++              npath = ext3_ext_find_extent(tree, next, NULL);
++              if (IS_ERR(npath))
++                      return PTR_ERR(npath);
++              EXT_ASSERT(npath->p_depth == path->p_depth);
++              eh = npath[depth].p_hdr;
++              if (eh->eh_entries < eh->eh_max) {
++                      ext_debug(tree, "next leaf isnt full(%d)\n",
++                                eh->eh_entries);
++                      path = npath;
++                      goto repeat;
++              }
++              ext_debug(tree, "next leaf hasno free space(%d,%d)\n",
++                        eh->eh_entries, eh->eh_max);
++      }
++
++      /*
++       * there is no free space in found leaf
++       * we're gonna add new leaf in the tree
++       */
++      err = ext3_ext_create_new_leaf(handle, tree, path, newext);
++      if (err)
++              goto cleanup;
++      depth = EXT_DEPTH(tree);
++      eh = path[depth].p_hdr;
++
++has_space:
++      nearex = path[depth].p_ext;
++
++      if ((err = ext3_ext_get_access(handle, tree, path + depth)))
++              goto cleanup;
++
++      if (!nearex) {
++              /* there is no extent in this leaf, create first one */
++              ext_debug(tree, "first extent in the leaf: %d:%d:%d\n",
++                        newext->ee_block, newext->ee_start,
++                        newext->ee_len);
++              path[depth].p_ext = EXT_FIRST_EXTENT(eh);
++      } else if (newext->ee_block > nearex->ee_block) {
++              EXT_ASSERT(newext->ee_block != nearex->ee_block);
++              if (nearex != EXT_LAST_EXTENT(eh)) {
++                      len = EXT_MAX_EXTENT(eh) - nearex;
++                      len = (len - 1) * sizeof(struct ext3_extent);
++                      len = len < 0 ? 0 : len;
++                      ext_debug(tree, "insert %d:%d:%d after: nearest 0x%p, "
++                                "move %d from 0x%p to 0x%p\n",
++                                newext->ee_block, newext->ee_start,
++                                newext->ee_len,
++                                nearex, len, nearex + 1, nearex + 2);
++                      memmove(nearex + 2, nearex + 1, len);
++              }
++              path[depth].p_ext = nearex + 1;
++      } else {
++              EXT_ASSERT(newext->ee_block != nearex->ee_block);
++              len = (EXT_MAX_EXTENT(eh) - nearex) * sizeof(struct ext3_extent);
++              len = len < 0 ? 0 : len;
++              ext_debug(tree, "insert %d:%d:%d before: nearest 0x%p, "
++                        "move %d from 0x%p to 0x%p\n",
++                        newext->ee_block, newext->ee_start, newext->ee_len,
++                        nearex, len, nearex + 1, nearex + 2);
++              memmove(nearex + 1, nearex, len);
++              path[depth].p_ext = nearex;
++      }
++
++      eh->eh_entries++;
++      nearex = path[depth].p_ext;
++      nearex->ee_block = newext->ee_block;
++      nearex->ee_start = newext->ee_start;
++      nearex->ee_len = newext->ee_len;
++      /* FIXME: support for large fs */
++      nearex->ee_start_hi = 0;
++
++merge:
++      /* try to merge extents to the right */
++      while (nearex < EXT_LAST_EXTENT(eh)) {
++              if (!ext3_can_extents_be_merged(tree, nearex, nearex + 1))
++                      break;
++              /* merge with next extent! */
++              nearex->ee_len += nearex[1].ee_len;
++              if (nearex + 1 < EXT_LAST_EXTENT(eh)) {
++                      len = (EXT_LAST_EXTENT(eh) - nearex - 1) *
++                              sizeof(struct ext3_extent);
++                      memmove(nearex + 1, nearex + 2, len);
++              }
++              eh->eh_entries--;
++              EXT_ASSERT(eh->eh_entries > 0);
++      }
++
++      /* try to merge extents to the left */
++
++      /* time to correct all indexes above */
++      err = ext3_ext_correct_indexes(handle, tree, path);
++      if (err)
++              goto cleanup;
++
++      err = ext3_ext_dirty(handle, tree, path + depth);
++
++cleanup:
++      if (npath) {
++              ext3_ext_drop_refs(npath);
++              kfree(npath);
++      }
++      ext3_ext_tree_changed(tree);
++      ext3_ext_invalidate_cache(tree);
++      return err;
++}
++
++int ext3_ext_walk_space(struct ext3_extents_tree *tree, unsigned long block,
++                      unsigned long num, ext_prepare_callback func)
++{
++      struct ext3_ext_path *path = NULL;
++      struct ext3_ext_cache cbex;
++      struct ext3_extent *ex;
++      unsigned long next, start = 0, end = 0;
++      unsigned long last = block + num;
++      int depth, exists, err = 0;
++
++      EXT_ASSERT(tree);
++      EXT_ASSERT(func);
++      EXT_ASSERT(tree->inode);
++      EXT_ASSERT(tree->root);
++
++      while (block < last && block != EXT_MAX_BLOCK) {
++              num = last - block;
++              /* find extent for this block */
++              path = ext3_ext_find_extent(tree, block, path);
++              if (IS_ERR(path)) {
++                      err = PTR_ERR(path);
++                      path = NULL;
++                      break;
++              }
++
++              depth = EXT_DEPTH(tree);
++              EXT_ASSERT(path[depth].p_hdr);
++              ex = path[depth].p_ext;
++              next = ext3_ext_next_allocated_block(path);
++
++              exists = 0;
++              if (!ex) {
++                      /* there is no extent yet, so try to allocate
++                       * all requested space */
++                      start = block;
++                      end = block + num;
++              } else if (ex->ee_block > block) {
++                      /* need to allocate space before found extent */
++                      start = block;
++                      end = ex->ee_block;
++                      if (block + num < end)
++                              end = block + num;
++              } else if (block >= ex->ee_block + ex->ee_len) {
++                      /* need to allocate space after found extent */
++                      start = block;
++                      end = block + num;
++                      if (end >= next)
++                              end = next;
++              } else if (block >= ex->ee_block) {
++                      /* 
++                       * some part of requested space is covered
++                       * by found extent
++                       */
++                      start = block;
++                      end = ex->ee_block + ex->ee_len;
++                      if (block + num < end)
++                              end = block + num;
++                      exists = 1;
++              } else {
++                      BUG();
++              }
++              EXT_ASSERT(end > start);
++
++              if (!exists) {
++                      cbex.ec_block = start;
++                      cbex.ec_len = end - start;
++                      cbex.ec_start = 0;
++                      cbex.ec_type = EXT3_EXT_CACHE_GAP;
++              } else {
++                      cbex.ec_block = ex->ee_block;
++                      cbex.ec_len = ex->ee_len;
++                      cbex.ec_start = ex->ee_start;
++                      cbex.ec_type = EXT3_EXT_CACHE_EXTENT;
++              }
++
++              EXT_ASSERT(cbex.ec_len > 0);
++              EXT_ASSERT(path[depth].p_hdr);
++              err = func(tree, path, &cbex);
++              ext3_ext_drop_refs(path);
++
++              if (err < 0)
++                      break;
++              if (err == EXT_REPEAT)
++                      continue;
++              else if (err == EXT_BREAK) {
++                      err = 0;
++                      break;
++              }
++
++              if (EXT_DEPTH(tree) != depth) {
++                      /* depth was changed. we have to realloc path */
++                      kfree(path);
++                      path = NULL;
++              }
++
++              block = cbex.ec_block + cbex.ec_len;
++      }
++
++      if (path) {
++              ext3_ext_drop_refs(path);
++              kfree(path);
++      }
++
++      return err;
++}
++
++static inline void
++ext3_ext_put_in_cache(struct ext3_extents_tree *tree, __u32 block,
++                    __u32 len, __u32 start, int type)
++{
++      EXT_ASSERT(len > 0);
++      if (tree->cex) {
++              tree->cex->ec_type = type;
++              tree->cex->ec_block = block;
++              tree->cex->ec_len = len;
++              tree->cex->ec_start = start;
++      }
++}
++
++/*
++ * this routine calculate boundaries of the gap requested block fits into
++ * and cache this gap
++ */
++static inline void
++ext3_ext_put_gap_in_cache(struct ext3_extents_tree *tree,
++                        struct ext3_ext_path *path,
++                        unsigned long block)
++{
++      int depth = EXT_DEPTH(tree);
++      unsigned long lblock, len;
++      struct ext3_extent *ex;
++
++      if (!tree->cex)
++              return;
++
++      ex = path[depth].p_ext;
++      if (ex == NULL) {
++              /* there is no extent yet, so gap is [0;-] */
++              lblock = 0;
++              len = EXT_MAX_BLOCK;
++              ext_debug(tree, "cache gap(whole file):");
++      } else if (block < ex->ee_block) {
++              lblock = block;
++              len = ex->ee_block - block;
++              ext_debug(tree, "cache gap(before): %lu [%lu:%lu]",
++                        (unsigned long) block,
++                        (unsigned long) ex->ee_block,
++                        (unsigned long) ex->ee_len);
++      } else if (block >= ex->ee_block + ex->ee_len) {
++              lblock = ex->ee_block + ex->ee_len;
++              len = ext3_ext_next_allocated_block(path);
++              ext_debug(tree, "cache gap(after): [%lu:%lu] %lu",
++                        (unsigned long) ex->ee_block,
++                        (unsigned long) ex->ee_len,
++                        (unsigned long) block);
++              EXT_ASSERT(len > lblock);
++              len = len - lblock;
++      } else {
++              lblock = len = 0;
++              BUG();
++      }
++
++      ext_debug(tree, " -> %lu:%lu\n", (unsigned long) lblock, len);
++      ext3_ext_put_in_cache(tree, lblock, len, 0, EXT3_EXT_CACHE_GAP);
++}
++
++static inline int
++ext3_ext_in_cache(struct ext3_extents_tree *tree, unsigned long block,
++                struct ext3_extent *ex)
++{
++      struct ext3_ext_cache *cex = tree->cex;
++
++      /* is there cache storage at all? */
++      if (!cex)
++              return EXT3_EXT_CACHE_NO;
++
++      /* has cache valid data? */
++      if (cex->ec_type == EXT3_EXT_CACHE_NO)
++              return EXT3_EXT_CACHE_NO;
++
++      EXT_ASSERT(cex->ec_type == EXT3_EXT_CACHE_GAP ||
++                 cex->ec_type == EXT3_EXT_CACHE_EXTENT);
++      if (block >= cex->ec_block && block < cex->ec_block + cex->ec_len) {
++              ex->ee_block = cex->ec_block;
++              ex->ee_start = cex->ec_start;
++              ex->ee_len = cex->ec_len;
++              ext_debug(tree, "%lu cached by %lu:%lu:%lu\n",
++                        (unsigned long) block,
++                        (unsigned long) ex->ee_block,
++                        (unsigned long) ex->ee_len,
++                        (unsigned long) ex->ee_start);
++              return cex->ec_type;
++      }
++
++      /* not in cache */
++      return EXT3_EXT_CACHE_NO;
++}
++
++/*
++ * routine removes index from the index block
++ * it's used in truncate case only. thus all requests are for
++ * last index in the block only
++ */
++int ext3_ext_rm_idx(handle_t *handle, struct ext3_extents_tree *tree,
++                  struct ext3_ext_path *path)
++{
++      struct buffer_head *bh;
++      int err;
++      
++      /* free index block */
++      path--;
++      EXT_ASSERT(path->p_hdr->eh_entries);
++      if ((err = ext3_ext_get_access(handle, tree, path)))
++              return err;
++      path->p_hdr->eh_entries--;
++      if ((err = ext3_ext_dirty(handle, tree, path)))
++              return err;
++      ext_debug(tree, "index is empty, remove it, free block %d\n",
++                path->p_idx->ei_leaf);
++      bh = sb_get_hash_table(tree->inode->i_sb, path->p_idx->ei_leaf);
++      ext3_forget(handle, 1, tree->inode, bh, path->p_idx->ei_leaf);
++      ext3_free_blocks(handle, tree->inode, path->p_idx->ei_leaf, 1);
++      return err;
++}
++
++int ext3_ext_calc_credits_for_insert(struct ext3_extents_tree *tree,
++                                   struct ext3_ext_path *path)
++{
++      int depth = EXT_DEPTH(tree);
++      int needed;
++
++      if (path) {
++              /* probably there is space in leaf? */
++              if (path[depth].p_hdr->eh_entries < path[depth].p_hdr->eh_max)
++                      return 1;
++      }
++      
++      /*
++       * the worste case we're expecting is creation of the
++       * new root (growing in depth) with index splitting
++       * for splitting we have to consider depth + 1 because
++       * previous growing could increase it
++       */
++      depth = depth + 1;
++
++      /* 
++       * growing in depth:
++       * block allocation + new root + old root
++       */
++      needed = EXT3_ALLOC_NEEDED + 2;
++
++      /* index split. we may need:
++       *   allocate intermediate indexes and new leaf
++       *   change two blocks at each level, but root
++       *   modify root block (inode)
++       */
++      needed += (depth * EXT3_ALLOC_NEEDED) + (2 * depth) + 1;
++
++      return needed;
++}
++
++static int
++ext3_ext_split_for_rm(handle_t *handle, struct ext3_extents_tree *tree,
++                    struct ext3_ext_path *path, unsigned long start,
++                    unsigned long end)
++{
++      struct ext3_extent *ex, tex;
++      struct ext3_ext_path *npath;
++      int depth, creds, err;
++
++      depth = EXT_DEPTH(tree);
++      ex = path[depth].p_ext;
++      EXT_ASSERT(ex);
++      EXT_ASSERT(end < ex->ee_block + ex->ee_len - 1);
++      EXT_ASSERT(ex->ee_block < start);
++
++      /* calculate tail extent */
++      tex.ee_block = end + 1;
++      EXT_ASSERT(tex.ee_block < ex->ee_block + ex->ee_len);
++      tex.ee_len = ex->ee_block + ex->ee_len - tex.ee_block;
++
++      creds = ext3_ext_calc_credits_for_insert(tree, path);
++      handle = ext3_ext_journal_restart(handle, creds);
++      if (IS_ERR(handle))
++              return PTR_ERR(handle);
++      
++      /* calculate head extent. use primary extent */
++      err = ext3_ext_get_access(handle, tree, path + depth);
++      if (err)
++              return err;
++      ex->ee_len = start - ex->ee_block;
++      err = ext3_ext_dirty(handle, tree, path + depth);
++      if (err)
++              return err;
++
++      /* FIXME: some callback to free underlying resource
++       * and correct ee_start? */
++      ext_debug(tree, "split extent: head %u:%u, tail %u:%u\n",
++                ex->ee_block, ex->ee_len, tex.ee_block, tex.ee_len);
++
++      npath = ext3_ext_find_extent(tree, ex->ee_block, NULL);
++      if (IS_ERR(npath))
++              return PTR_ERR(npath);
++      depth = EXT_DEPTH(tree);
++      EXT_ASSERT(npath[depth].p_ext->ee_block == ex->ee_block);
++      EXT_ASSERT(npath[depth].p_ext->ee_len == ex->ee_len);
++
++      err = ext3_ext_insert_extent(handle, tree, npath, &tex);
++      ext3_ext_drop_refs(npath);
++      kfree(npath);
++
++      return err;
++}
++
++static int
++ext3_ext_rm_leaf(handle_t *handle, struct ext3_extents_tree *tree,
++               struct ext3_ext_path *path, unsigned long start,
++               unsigned long end)
++{
++      struct ext3_extent *ex, *fu = NULL, *lu, *le;
++      int err = 0, correct_index = 0;
++      int depth = EXT_DEPTH(tree), credits;
++      struct ext3_extent_header *eh;
++      unsigned a, b, block, num;
++
++      ext_debug(tree, "remove [%lu:%lu] in leaf\n", start, end);
++      if (!path[depth].p_hdr)
++              path[depth].p_hdr = EXT_BLOCK_HDR(path[depth].p_bh);
++      eh = path[depth].p_hdr;
++      EXT_ASSERT(eh);
++      EXT_ASSERT(eh->eh_entries <= eh->eh_max);
++      EXT_ASSERT(eh->eh_magic == EXT3_EXT_MAGIC);
++      
++      /* find where to start removing */
++      le = ex = EXT_LAST_EXTENT(eh);
++      while (ex != EXT_FIRST_EXTENT(eh)) {
++              if (ex->ee_block <= end)
++                      break;
++              ex--;
++      }
++
++      if (start > ex->ee_block && end < ex->ee_block + ex->ee_len - 1) {
++              /* removal of internal part of the extent requested
++               * tail and head must be placed in different extent
++               * so, we have to insert one more extent */
++              path[depth].p_ext = ex;
++              return ext3_ext_split_for_rm(handle, tree, path, start, end);
++      }
++      
++      lu = ex;
++      while (ex >= EXT_FIRST_EXTENT(eh) && ex->ee_block + ex->ee_len > start) {
++              ext_debug(tree, "remove ext %u:%u\n", ex->ee_block, ex->ee_len);
++              path[depth].p_ext = ex;
++      
++              a = ex->ee_block > start ? ex->ee_block : start;
++              b = ex->ee_block + ex->ee_len - 1 < end ?
++                      ex->ee_block + ex->ee_len - 1 : end;
++              
++              ext_debug(tree, "  border %u:%u\n", a, b);
++
++              if (a != ex->ee_block && b != ex->ee_block + ex->ee_len - 1) {
++                      block = 0;
++                      num = 0;
++                      BUG();
++              } else if (a != ex->ee_block) {
++                      /* remove tail of the extent */
++                      block = ex->ee_block;
++                      num = a - block;
++              } else if (b != ex->ee_block + ex->ee_len - 1) {
++                      /* remove head of the extent */
++                      block = a;
++                      num = b - a;
++              } else {
++                      /* remove whole extent: excelent! */
++                      block = ex->ee_block; 
++                      num = 0;
++                      EXT_ASSERT(a == ex->ee_block &&
++                                 b == ex->ee_block + ex->ee_len - 1);
++              }
++
++              if (ex == EXT_FIRST_EXTENT(eh))
++                      correct_index = 1;
++
++              credits = 1;
++              if (correct_index)
++                      credits += (EXT_DEPTH(tree) * EXT3_ALLOC_NEEDED) + 1;
++              if (tree->ops->remove_extent_credits)
++                      credits+=tree->ops->remove_extent_credits(tree,ex,a,b);
++              
++              handle = ext3_ext_journal_restart(handle, credits);
++              if (IS_ERR(handle)) {
++                      err = PTR_ERR(handle);
++                      goto out;
++              }
++
++              err = ext3_ext_get_access(handle, tree, path + depth);
++              if (err)
++                      goto out;
++
++              if (tree->ops->remove_extent)
++                      err = tree->ops->remove_extent(tree, ex, a, b);
++              if (err)
++                      goto out;
++
++              if (num == 0) {
++                      /* this extent is removed entirely mark slot unused */
++                      ex->ee_start = 0;
++                      eh->eh_entries--;
++                      fu = ex;
++              }
++
++              ex->ee_block = block;
++              ex->ee_len = num;
++
++              err = ext3_ext_dirty(handle, tree, path + depth);
++              if (err)
++                      goto out;
++
++              ext_debug(tree, "new extent: %u:%u:%u\n",
++                        ex->ee_block, ex->ee_len, ex->ee_start);
++              ex--;
++      }
++
++      if (fu) {
++              /* reuse unused slots */
++              while (lu < le) {
++                      if (lu->ee_start) {
++                              *fu = *lu;
++                              lu->ee_start = 0;
++                              fu++;
++                      }
++                      lu++;
++              }
++      }
++
++      if (correct_index && eh->eh_entries)
++              err = ext3_ext_correct_indexes(handle, tree, path);
++
++      /* if this leaf is free, then we should
++       * remove it from index block above */
++      if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL)
++              err = ext3_ext_rm_idx(handle, tree, path + depth);
++
++out:
++      return err;
++}
++
++
++static struct ext3_extent_idx *
++ext3_ext_last_covered(struct ext3_extent_header *hdr, unsigned long block)
++{
++      struct ext3_extent_idx *ix;
++      
++      ix = EXT_LAST_INDEX(hdr);
++      while (ix != EXT_FIRST_INDEX(hdr)) {
++              if (ix->ei_block <= block)
++                      break;
++              ix--;
++      }
++      return ix;
++}
++
++/*
++ * returns 1 if current index have to be freed (even partial)
++ */
++static int inline
++ext3_ext_more_to_rm(struct ext3_ext_path *path)
++{
++      EXT_ASSERT(path->p_idx);
++
++      if (path->p_idx < EXT_FIRST_INDEX(path->p_hdr))
++              return 0;
++
++      /*
++       * if truncate on deeper level happened it it wasn't partial
++       * so we have to consider current index for truncation
++       */
++      if (path->p_hdr->eh_entries == path->p_block)
++              return 0;
++      return 1;
++}
++
++int ext3_ext_remove_space(struct ext3_extents_tree *tree,
++                        unsigned long start, unsigned long end)
++{
++      struct inode *inode = tree->inode;
++      struct super_block *sb = inode->i_sb;
++      int depth = EXT_DEPTH(tree);
++      struct ext3_ext_path *path;
++      handle_t *handle;
++      int i = 0, err = 0;
++
++      ext_debug(tree, "space to be removed: %lu:%lu\n", start, end);
++
++      /* probably first extent we're gonna free will be last in block */
++      handle = ext3_journal_start(inode, depth + 1);
++      if (IS_ERR(handle))
++              return PTR_ERR(handle);
++
++      ext3_ext_invalidate_cache(tree);
++
++      /*
++       * we start scanning from right side freeing all the blocks
++       * after i_size and walking into the deep
++       */
++      path = kmalloc(sizeof(struct ext3_ext_path) * (depth + 1), GFP_KERNEL);
++      if (IS_ERR(path)) {
++              ext3_error(sb, __FUNCTION__, "Can't allocate path array");
++              ext3_journal_stop(handle, inode);
++              return -ENOMEM;
++      }
++      memset(path, 0, sizeof(struct ext3_ext_path) * (depth + 1));
++      path[i].p_hdr = EXT_ROOT_HDR(tree);
++      
++      while (i >= 0 && err == 0) {
++              if (i == depth) {
++                      /* this is leaf block */
++                      err = ext3_ext_rm_leaf(handle, tree, path, start, end);
++                      /* root level have p_bh == NULL, brelse() eats this */
++                      brelse(path[i].p_bh);
++                      i--;
++                      continue;
++              }
++              
++              /* this is index block */
++              if (!path[i].p_hdr) {
++                      ext_debug(tree, "initialize header\n");
++                      path[i].p_hdr = EXT_BLOCK_HDR(path[i].p_bh);
++              }
++
++              EXT_ASSERT(path[i].p_hdr->eh_entries <= path[i].p_hdr->eh_max);
++              EXT_ASSERT(path[i].p_hdr->eh_magic == EXT3_EXT_MAGIC);
++              
++              if (!path[i].p_idx) {
++                      /* this level hasn't touched yet */
++                      path[i].p_idx =
++                              ext3_ext_last_covered(path[i].p_hdr, end);
++                      path[i].p_block = path[i].p_hdr->eh_entries + 1;
++                      ext_debug(tree, "init index ptr: hdr 0x%p, num %d\n",
++                                path[i].p_hdr, path[i].p_hdr->eh_entries);
++              } else {
++                      /* we've already was here, see at next index */
++                      path[i].p_idx--;
++              }
++
++              ext_debug(tree, "level %d - index, first 0x%p, cur 0x%p\n",
++                        i, EXT_FIRST_INDEX(path[i].p_hdr),
++                        path[i].p_idx);
++              if (ext3_ext_more_to_rm(path + i)) {
++                      /* go to the next level */
++                      ext_debug(tree, "move to level %d (block %d)\n",
++                                i + 1, path[i].p_idx->ei_leaf);
++                      memset(path + i + 1, 0, sizeof(*path));
++                      path[i+1].p_bh = sb_bread(sb, path[i].p_idx->ei_leaf);
++                      if (!path[i+1].p_bh) {
++                              /* should we reset i_size? */
++                              err = -EIO;
++                              break;
++                      }
++                      /* put actual number of indexes to know is this
++                       * number got changed at the next iteration */
++                      path[i].p_block = path[i].p_hdr->eh_entries;
++                      i++;
++              } else {
++                      /* we finish processing this index, go up */
++                      if (path[i].p_hdr->eh_entries == 0 && i > 0) {
++                              /* index is empty, remove it
++                               * handle must be already prepared by the
++                               * truncatei_leaf() */
++                              err = ext3_ext_rm_idx(handle, tree, path + i);
++                      }
++                      /* root level have p_bh == NULL, brelse() eats this */
++                      brelse(path[i].p_bh);
++                      i--;
++                      ext_debug(tree, "return to level %d\n", i);
++              }
++      }
++
++      /* TODO: flexible tree reduction should be here */
++      if (path->p_hdr->eh_entries == 0) {
++              /*
++               * truncate to zero freed all the tree
++               * so, we need to correct eh_depth
++               */
++              err = ext3_ext_get_access(handle, tree, path);
++              if (err == 0) {
++                      EXT_ROOT_HDR(tree)->eh_depth = 0;
++                      EXT_ROOT_HDR(tree)->eh_max = ext3_ext_space_root(tree);
++                      err = ext3_ext_dirty(handle, tree, path);
++              }
++      }
++      ext3_ext_tree_changed(tree);
++
++      kfree(path);
++      ext3_journal_stop(handle, inode);
++
++      return err;
++}
++
++/*
++ * called at mount time
++ */
++void ext3_ext_init(struct super_block *sb)
++{
++      /*
++       * possible initialization would be here
++       */
++
++      if (test_opt(sb, EXTENTS)) {
++              printk("EXT3-fs: file extents enabled");
++#ifdef AGRESSIVE_TEST
++              printk(", agressive tests");
++#endif
++#ifdef CHECK_BINSEARCH
++              printk(", check binsearch");
++#endif
++              printk("\n");
++      }
++}
++
++/*
++ * called at umount time
++ */
++void ext3_ext_release(struct super_block *sb)
++{
++}
++
++/************************************************************************
++ * VFS related routines
++ ************************************************************************/
++
++static int ext3_get_inode_write_access(handle_t *handle, void *buffer)
++{
++      /* we use in-core data, not bh */
++      return 0;
++}
++
++static int ext3_mark_buffer_dirty(handle_t *handle, void *buffer)
++{
++      struct inode *inode = buffer;
++      return ext3_mark_inode_dirty(handle, inode);
++}
++
++static int ext3_ext_mergable(struct ext3_extent *ex1,
++                           struct ext3_extent *ex2)
++{
++      /* FIXME: support for large fs */
++      if (ex1->ee_start + ex1->ee_len == ex2->ee_start)
++              return 1;
++      return 0;
++}
++
++static int
++ext3_remove_blocks_credits(struct ext3_extents_tree *tree,
++                         struct ext3_extent *ex,
++                         unsigned long from, unsigned long to)
++{
++      int needed;
++      
++      /* at present, extent can't cross block group */;
++      needed = 4; /* bitmap + group desc + sb + inode */
++
++#ifdef CONFIG_QUOTA
++      needed += 2 * EXT3_SINGLEDATA_TRANS_BLOCKS;
++#endif
++      return needed;
++}
++
++static int
++ext3_remove_blocks(struct ext3_extents_tree *tree,
++                 struct ext3_extent *ex,
++                 unsigned long from, unsigned long to)
++{
++      int needed = ext3_remove_blocks_credits(tree, ex, from, to);
++      handle_t *handle = ext3_journal_start(tree->inode, needed);
++      struct buffer_head *bh;
++      int i;
++
++      if (IS_ERR(handle))
++              return PTR_ERR(handle);
++      if (from >= ex->ee_block && to == ex->ee_block + ex->ee_len - 1) {
++              /* tail removal */
++              unsigned long num, start;
++              num = ex->ee_block + ex->ee_len - from;
++              start = ex->ee_start + ex->ee_len - num;
++              ext_debug(tree, "free last %lu blocks starting %lu\n",
++                        num, start);
++              for (i = 0; i < num; i++) {
++                      bh = sb_get_hash_table(tree->inode->i_sb, start + i);
++                      ext3_forget(handle, 0, tree->inode, bh, start + i);
++              }
++              ext3_free_blocks(handle, tree->inode, start, num);
++      } else if (from == ex->ee_block && to <= ex->ee_block + ex->ee_len - 1) {
++              printk("strange request: removal %lu-%lu from %u:%u\n",
++                     from, to, ex->ee_block, ex->ee_len);
++      } else {
++              printk("strange request: removal(2) %lu-%lu from %u:%u\n",
++                     from, to, ex->ee_block, ex->ee_len);
++      }
++      ext3_journal_stop(handle, tree->inode);
++      return 0;
++}
++
++int ext3_ext_find_goal(struct inode *inode, struct ext3_ext_path *path,
++                     unsigned long block)
++{
++      struct ext3_inode_info *ei = EXT3_I(inode);
++      unsigned long bg_start;
++      unsigned long colour;
++      int depth;
++      
++      if (path) {
++              struct ext3_extent *ex;
++              depth = path->p_depth;
++              
++              /* try to predict block placement */
++              if ((ex = path[depth].p_ext))
++                      return ex->ee_start + (block - ex->ee_block);
++
++              /* it looks index is empty
++               * try to find starting from index itself */
++              if (path[depth].p_bh)
++                      return path[depth].p_bh->b_blocknr;
++      }
++
++      /* OK. use inode's group */
++      bg_start = (ei->i_block_group * EXT3_BLOCKS_PER_GROUP(inode->i_sb)) +
++              le32_to_cpu(EXT3_SB(inode->i_sb)->s_es->s_first_data_block);
++      colour = (current->pid % 16) *
++                      (EXT3_BLOCKS_PER_GROUP(inode->i_sb) / 16);
++      return bg_start + colour + block;
++}
++
++static int ext3_new_block_cb(handle_t *handle, struct ext3_extents_tree *tree,
++                           struct ext3_ext_path *path,
++                           struct ext3_extent *ex, int *err)
++{
++      struct inode *inode = tree->inode;
++      int newblock, goal;
++      
++      EXT_ASSERT(path);
++      EXT_ASSERT(ex);
++      EXT_ASSERT(ex->ee_start);
++      EXT_ASSERT(ex->ee_len);
++      
++      /* reuse block from the extent to order data/metadata */
++      newblock = ex->ee_start++;
++      ex->ee_len--;
++      if (ex->ee_len == 0) {
++              ex->ee_len = 1;
++              /* allocate new block for the extent */
++              goal = ext3_ext_find_goal(inode, path, ex->ee_block);
++              ex->ee_start = ext3_new_block(handle, inode, goal, 0, 0, err);
++              if (ex->ee_start == 0) {
++                      /* error occured: restore old extent */
++                      ex->ee_start = newblock;
++                      return 0;
++              }
++      }
++      return newblock;
++}
++
++static struct ext3_extents_helpers ext3_blockmap_helpers = {
++      .get_write_access       = ext3_get_inode_write_access,
++      .mark_buffer_dirty      = ext3_mark_buffer_dirty,
++      .mergable               = ext3_ext_mergable,
++      .new_block              = ext3_new_block_cb,
++      .remove_extent          = ext3_remove_blocks,
++      .remove_extent_credits  = ext3_remove_blocks_credits,
++};
++
++void ext3_init_tree_desc(struct ext3_extents_tree *tree,
++                       struct inode *inode)
++{
++      tree->inode = inode;
++      tree->root = (void *) EXT3_I(inode)->i_data;
++      tree->buffer = (void *) inode;
++      tree->buffer_len = sizeof(EXT3_I(inode)->i_data);
++      tree->cex = (struct ext3_ext_cache *) &EXT3_I(inode)->i_cached_extent;
++      tree->ops = &ext3_blockmap_helpers;
++}
++
++int ext3_ext_get_block(handle_t *handle, struct inode *inode,
++                     long iblock, struct buffer_head *bh_result, int create)
++{
++      struct ext3_ext_path *path = NULL;
++      struct ext3_extent newex;
++      struct ext3_extent *ex;
++      int goal, newblock, err = 0, depth;
++      struct ext3_extents_tree tree;
++
++      clear_bit(BH_New, &bh_result->b_state);
++      ext3_init_tree_desc(&tree, inode);
++      ext_debug(&tree, "block %d requested for inode %u\n",
++                (int) iblock, (unsigned) inode->i_ino);
++      down_write(&EXT3_I(inode)->truncate_sem);
++
++      /* check in cache */
++      if ((goal = ext3_ext_in_cache(&tree, iblock, &newex))) {
++              if (goal == EXT3_EXT_CACHE_GAP) {
++                      if (!create) {
++                              /* block isn't allocated yet and
++                               * user don't want to allocate it */
++                              goto out2;
++                      }
++                      /* we should allocate requested block */
++              } else if (goal == EXT3_EXT_CACHE_EXTENT) {
++                      /* block is already allocated */
++                      newblock = iblock - newex.ee_block + newex.ee_start;
++                      goto out;
++              } else {
++                      EXT_ASSERT(0);
++              }
++      }
++
++      /* find extent for this block */
++      path = ext3_ext_find_extent(&tree, iblock, NULL);
++      if (IS_ERR(path)) {
++              err = PTR_ERR(path);
++              path = NULL;
++              goto out2;
++      }
++
++      depth = EXT_DEPTH(&tree);
++
++      /*
++       * consistent leaf must not be empty
++       * this situations is possible, though, _during_ tree modification
++       * this is why assert can't be put in ext3_ext_find_extent()
++       */
++      EXT_ASSERT(path[depth].p_ext != NULL || depth == 0);
++
++      if ((ex = path[depth].p_ext)) {
++              /* if found exent covers block, simple return it */
++              if (iblock >= ex->ee_block && iblock < ex->ee_block + ex->ee_len) {
++                      newblock = iblock - ex->ee_block + ex->ee_start;
++                      ext_debug(&tree, "%d fit into %d:%d -> %d\n",
++                                (int) iblock, ex->ee_block, ex->ee_len,
++                                newblock);
++                      ext3_ext_put_in_cache(&tree, ex->ee_block,
++                                            ex->ee_len, ex->ee_start,
++                                            EXT3_EXT_CACHE_EXTENT);
++                      goto out;
++              }
++      }
++
++      /*
++       * requested block isn't allocated yet
++       * we couldn't try to create block if create flag is zero 
++       */
++      if (!create) {
++              /* put just found gap into cache to speedup subsequest reqs */
++              ext3_ext_put_gap_in_cache(&tree, path, iblock);
++              goto out2;
++      }
++
++      /* allocate new block */
++      goal = ext3_ext_find_goal(inode, path, iblock);
++      newblock = ext3_new_block(handle, inode, goal, 0, 0, &err);
++      if (!newblock)
++              goto out2;
++      ext_debug(&tree, "allocate new block: goal %d, found %d\n",
++                goal, newblock);
++
++      /* try to insert new extent into found leaf and return */
++      newex.ee_block = iblock;
++      newex.ee_start = newblock;
++      newex.ee_len = 1;
++      err = ext3_ext_insert_extent(handle, &tree, path, &newex);
++      if (err)
++              goto out2;
++      
++      if (inode->i_size > EXT3_I(inode)->i_disksize)
++              EXT3_I(inode)->i_disksize = inode->i_size;
++
++      /* previous routine could use block we allocated */
++      newblock = newex.ee_start;
++      set_bit(BH_New, &bh_result->b_state);
++
++      ext3_ext_put_in_cache(&tree, newex.ee_block, newex.ee_len,
++                            newex.ee_start, EXT3_EXT_CACHE_EXTENT);
++out:
++      ext3_ext_show_leaf(&tree, path);
++      set_bit(BH_Mapped, &bh_result->b_state);
++      bh_result->b_dev = inode->i_sb->s_dev;
++      bh_result->b_blocknr = newblock;
++out2:
++      if (path) {
++              ext3_ext_drop_refs(path);
++              kfree(path);
++      }
++      up_write(&EXT3_I(inode)->truncate_sem);
++
++      return err;     
++}
++
++void ext3_ext_truncate(struct inode * inode)
++{
++      struct address_space *mapping = inode->i_mapping;
++      struct super_block *sb = inode->i_sb;
++      struct ext3_extents_tree tree;
++      unsigned long last_block;
++      handle_t *handle;
++      int err = 0;
++
++      ext3_init_tree_desc(&tree, inode);
++
++      /*
++       * probably first extent we're gonna free will be last in block
++       */
++      err = ext3_writepage_trans_blocks(inode) + 3;
++      handle = ext3_journal_start(inode, err);
++      if (IS_ERR(handle))
++              return;
++
++      ext3_block_truncate_page(handle, mapping, inode->i_size);
++
++      down_write(&EXT3_I(inode)->truncate_sem);
++      ext3_ext_invalidate_cache(&tree);
++
++      /* 
++       * TODO: optimization is possible here
++       * probably we need not scaning at all,
++       * because page truncation is enough
++       */
++      if (ext3_orphan_add(handle, inode))
++              goto out_stop;
++
++      /* we have to know where to truncate from in crash case */
++      EXT3_I(inode)->i_disksize = inode->i_size;
++      ext3_mark_inode_dirty(handle, inode);
++
++      last_block = (inode->i_size + sb->s_blocksize - 1) >>
++                      EXT3_BLOCK_SIZE_BITS(sb);
++      err = ext3_ext_remove_space(&tree, last_block, EXT_MAX_BLOCK);
++      
++      /* In a multi-transaction truncate, we only make the final
++       * transaction synchronous */
++      if (IS_SYNC(inode))
++              handle->h_sync = 1;
++
++out_stop:
++      /*
++       * If this was a simple ftruncate(), and the file will remain alive
++       * then we need to clear up the orphan record which we created above.
++       * However, if this was a real unlink then we were called by
++       * ext3_delete_inode(), and we allow that function to clean up the
++       * orphan info for us.
++       */
++      if (inode->i_nlink)
++              ext3_orphan_del(handle, inode);
++
++      up_write(&EXT3_I(inode)->truncate_sem);
++      ext3_journal_stop(handle, inode);
++}
++
++/*
++ * this routine calculate max number of blocks we could modify
++ * in order to allocate new block for an inode
++ */
++int ext3_ext_writepage_trans_blocks(struct inode *inode, int num)
++{
++      struct ext3_extents_tree tree;
++      int needed;
++      
++      ext3_init_tree_desc(&tree, inode);
++      
++      needed = ext3_ext_calc_credits_for_insert(&tree, NULL);
++
++      /* caller want to allocate num blocks */
++      needed *= num;
++      
++#ifdef CONFIG_QUOTA
++      /* 
++       * FIXME: real calculation should be here
++       * it depends on blockmap format of qouta file
++       */
++      needed += 2 * EXT3_SINGLEDATA_TRANS_BLOCKS;
++#endif
++
++      return needed;
++}
++
++void ext3_extents_initialize_blockmap(handle_t *handle, struct inode *inode)
++{
++      struct ext3_extents_tree tree;
++
++      ext3_init_tree_desc(&tree, inode);
++      ext3_extent_tree_init(handle, &tree);
++}
++
++static int
++ext3_ext_store_extent_cb(struct ext3_extents_tree *tree,
++                       struct ext3_ext_path *path,
++                       struct ext3_ext_cache *newex)
++{
++      struct ext3_extent_buf *buf = (struct ext3_extent_buf *) tree->private;
++
++      if (newex->ec_type != EXT3_EXT_CACHE_EXTENT)
++              return EXT_CONTINUE;
++
++      if (buf->err < 0)
++              return EXT_BREAK;
++      if (buf->cur - buf->buffer + sizeof(*newex) > buf->buflen)
++              return EXT_BREAK;
++
++      if (!copy_to_user(buf->cur, newex, sizeof(*newex))) {
++              buf->err++;
++              buf->cur += sizeof(*newex);
++      } else {
++              buf->err = -EFAULT;
++              return EXT_BREAK;
++      }
++      return EXT_CONTINUE;
++}
++
++static int
++ext3_ext_collect_stats_cb(struct ext3_extents_tree *tree,
++                        struct ext3_ext_path *path,
++                        struct ext3_ext_cache *ex)
++{
++      struct ext3_extent_tree_stats *buf =
++              (struct ext3_extent_tree_stats *) tree->private;
++      int depth;
++
++      if (ex->ec_type != EXT3_EXT_CACHE_EXTENT)
++              return EXT_CONTINUE;
++
++      depth = EXT_DEPTH(tree);
++      buf->extents_num++;
++      if (path[depth].p_ext == EXT_FIRST_EXTENT(path[depth].p_hdr))
++              buf->leaf_num++;
++      return EXT_CONTINUE;
++}
++
++int ext3_ext_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
++                 unsigned long arg)
++{
++      int err = 0;
++
++      if (!(EXT3_I(inode)->i_flags & EXT3_EXTENTS_FL))
++              return -EINVAL;
++
++      if (cmd == EXT3_IOC_GET_EXTENTS) {
++              struct ext3_extent_buf buf;
++              struct ext3_extents_tree tree;
++
++              if (copy_from_user(&buf, (void *) arg, sizeof(buf)))
++                      return -EFAULT;
++
++              ext3_init_tree_desc(&tree, inode);
++              buf.cur = buf.buffer;
++              buf.err = 0;
++              tree.private = &buf;
++              down_write(&EXT3_I(inode)->truncate_sem);
++              err = ext3_ext_walk_space(&tree, buf.start, EXT_MAX_BLOCK,
++                                        ext3_ext_store_extent_cb);
++              up_write(&EXT3_I(inode)->truncate_sem);
++              if (err == 0)
++                      err = buf.err;
++      } else if (cmd == EXT3_IOC_GET_TREE_STATS) {
++              struct ext3_extent_tree_stats buf;
++              struct ext3_extents_tree tree;
++
++              ext3_init_tree_desc(&tree, inode);
++              down_write(&EXT3_I(inode)->truncate_sem);
++              buf.depth = EXT_DEPTH(&tree);
++              buf.extents_num = 0;
++              buf.leaf_num = 0;
++              tree.private = &buf;
++              err = ext3_ext_walk_space(&tree, 0, EXT_MAX_BLOCK,
++                                        ext3_ext_collect_stats_cb);
++              up_write(&EXT3_I(inode)->truncate_sem);
++              if (!err)
++                      err = copy_to_user((void *) arg, &buf, sizeof(buf));
++      } else if (cmd == EXT3_IOC_GET_TREE_DEPTH) {
++              struct ext3_extents_tree tree;
++              ext3_init_tree_desc(&tree, inode);
++              down_write(&EXT3_I(inode)->truncate_sem);
++              err = EXT_DEPTH(&tree);
++              up_write(&EXT3_I(inode)->truncate_sem);
++      }
++
++      return err;
++}
++
++EXPORT_SYMBOL(ext3_init_tree_desc);
++EXPORT_SYMBOL(ext3_mark_inode_dirty);
++EXPORT_SYMBOL(ext3_ext_invalidate_cache);
++EXPORT_SYMBOL(ext3_ext_insert_extent);
++EXPORT_SYMBOL(ext3_ext_walk_space);
++EXPORT_SYMBOL(ext3_ext_find_goal);
++EXPORT_SYMBOL(ext3_ext_calc_credits_for_insert);
+Index: linux-2.4.29/fs/ext3/ialloc.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/ialloc.c 2005-05-03 16:50:30.216045296 +0300
++++ linux-2.4.29/fs/ext3/ialloc.c      2005-05-03 16:52:08.804057640 +0300
+@@ -553,7 +553,8 @@
+       inode->i_blksize = PAGE_SIZE;
+       inode->i_blocks = 0;
+       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+-      inode->u.ext3_i.i_flags = dir->u.ext3_i.i_flags & ~EXT3_INDEX_FL;
++      inode->u.ext3_i.i_flags = dir->u.ext3_i.i_flags &
++              ~(EXT3_INDEX_FL | EXT3_EXTENTS_FL);
+       if (S_ISLNK(mode))
+               inode->u.ext3_i.i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL);
+ #ifdef EXT3_FRAGMENTS
+@@ -592,6 +593,19 @@
+               iloc.bh = NULL;
+               goto fail;
+       }
++      if (test_opt(sb, EXTENTS) && S_ISREG(inode->i_mode)) {
++              EXT3_I(inode)->i_flags |= EXT3_EXTENTS_FL;
++              memset(&EXT3_I(inode)->i_cached_extent, 0, sizeof(__u32) * 4);
++              ext3_extents_initialize_blockmap(handle, inode);
++              if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_EXTENTS)) {
++                      err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh);
++                      if (err) goto fail;
++                      EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_EXTENTS);
++                      BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "call ext3_journal_dirty_metadata");
++                      err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
++              }
++      }
++
+       err = ext3_mark_iloc_dirty(handle, inode, &iloc);
+       if (err) goto fail;
+Index: linux-2.4.29/fs/ext3/inode.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/inode.c  2005-05-03 16:51:50.331865840 +0300
++++ linux-2.4.29/fs/ext3/inode.c       2005-05-03 16:52:08.808057032 +0300
+@@ -861,6 +861,15 @@
+       goto reread;
+ }
++static inline int
++ext3_get_block_wrap(handle_t *handle, struct inode *inode, long block,
++                  struct buffer_head *bh, int create)
++{
++      if (EXT3_I(inode)->i_flags & EXT3_EXTENTS_FL)
++              return ext3_ext_get_block(handle, inode, block, bh, create);
++      return ext3_get_block_handle(handle, inode, block, bh, create);
++}
++
+ /*
+  * The BKL is not held on entry here.
+  */
+@@ -874,7 +883,7 @@
+               handle = ext3_journal_current_handle();
+               J_ASSERT(handle != 0);
+       }
+-      ret = ext3_get_block_handle(handle, inode, iblock, bh_result, create);
++      ret = ext3_get_block_wrap(handle, inode, iblock, bh_result, create);
+       return ret;
+ }
+@@ -892,7 +901,7 @@
+       dummy.b_state = 0;
+       dummy.b_blocknr = -1000;
+       buffer_trace_init(&dummy.b_history);
+-      *errp = ext3_get_block_handle(handle, inode, block, &dummy, create);
++      *errp = ext3_get_block_wrap(handle, inode, block, &dummy, create);
+       if (!*errp && buffer_mapped(&dummy)) {
+               struct buffer_head *bh;
+               bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
+@@ -1416,7 +1425,7 @@
+  * This required during truncate. We need to physically zero the tail end
+  * of that block so it doesn't yield old data if the file is later grown.
+  */
+-static int ext3_block_truncate_page(handle_t *handle,
++int ext3_block_truncate_page(handle_t *handle,
+               struct address_space *mapping, loff_t from)
+ {
+       unsigned long index = from >> PAGE_CACHE_SHIFT;
+@@ -1904,6 +1913,9 @@
+       ext3_discard_prealloc(inode);
++      if (EXT3_I(inode)->i_flags & EXT3_EXTENTS_FL)
++              return ext3_ext_truncate(inode);
++
+       handle = start_transaction(inode);
+       if (IS_ERR(handle))
+               return;         /* AKPM: return what? */
+@@ -2240,6 +2252,7 @@
+       for (block = 0; block < EXT3_N_BLOCKS; block++)
+               inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block];
+       INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
++      memset(&EXT3_I(inode)->i_cached_extent, 0, sizeof(__u32) * 4);
+       if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
+               inode->u.ext3_i.i_extra_isize =
+@@ -2546,6 +2559,9 @@
+       int indirects = (EXT3_NDIR_BLOCKS % bpp) ? 5 : 3;
+       int ret;
+       
++      if (EXT3_I(inode)->i_flags & EXT3_EXTENTS_FL)
++              return ext3_ext_writepage_trans_blocks(inode, bpp);
++
+       if (ext3_should_journal_data(inode))
+               ret = 3 * (bpp + indirects) + 2;
+       else
+@@ -2982,7 +2998,7 @@
+       /* alloc blocks one by one */
+       for (i = 0; i < nblocks; i++) {
+-              ret = ext3_get_block_handle(handle, inode, blocks[i],
++              ret = ext3_get_block_wrap(handle, inode, blocks[i],
+                                               &bh_tmp, 1);
+               if (ret)
+                       break;
+@@ -3058,7 +3074,7 @@
+                 if (blocks[i] != 0)
+                         continue;
+-                rc = ext3_get_block_handle(handle, inode, iblock, &bh, 1);
++                rc = ext3_get_block_wrap(handle, inode, iblock, &bh, 1);
+                 if (rc) {
+                         printk(KERN_INFO "ext3_map_inode_page: error %d "
+                                "allocating block %ld\n", rc, iblock);
+Index: linux-2.4.29/fs/ext3/Makefile
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/Makefile 2005-05-03 16:51:32.127633304 +0300
++++ linux-2.4.29/fs/ext3/Makefile      2005-05-03 16:53:38.634401352 +0300
+@@ -13,7 +13,9 @@
+ obj-y    := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o iopen.o \
+               ioctl.o namei.o super.o symlink.o hash.o ext3-exports.o \
+-              xattr_trusted.o
++              xattr_trusted.o extents.o
++export-objs += extents.o
++
+ obj-m    := $(O_TARGET)
+ export-objs += xattr.o
+Index: linux-2.4.29/fs/ext3/super.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/super.c  2005-05-03 16:50:14.750396432 +0300
++++ linux-2.4.29/fs/ext3/super.c       2005-05-03 16:52:08.813056272 +0300
+@@ -531,6 +531,7 @@
+ #ifdef EXT3_DELETE_THREAD
+       J_ASSERT(sbi->s_delete_inodes == 0);
+ #endif
++      ext3_ext_release(sb);
+       ext3_xattr_put_super(sb);
+       journal_destroy(sbi->s_journal);
+       if (!(sb->s_flags & MS_RDONLY)) {
+@@ -702,6 +703,10 @@
+                               return 0;
+                       }
+               }
++              else if (!strcmp (this_char, "extents"))
++                      set_opt (*mount_options, EXTENTS);
++              else if (!strcmp (this_char, "extdebug"))
++                      set_opt (*mount_options, EXTDEBUG);
+               else if (!strcmp (this_char, "grpid") ||
+                        !strcmp (this_char, "bsdgroups"))
+                       set_opt (*mount_options, GRPID);
+@@ -1405,6 +1410,8 @@
+               test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered":
+               "writeback");
++      ext3_ext_init(sb);
++
+       return sb;
+ failed_mount3:
+Index: linux-2.4.29/fs/ext3/ioctl.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/ioctl.c  2005-05-03 16:49:36.825161944 +0300
++++ linux-2.4.29/fs/ext3/ioctl.c       2005-05-03 16:52:08.814056120 +0300
+@@ -174,6 +174,10 @@
+                       return ret;
+               }
+ #endif
++      case EXT3_IOC_GET_EXTENTS:
++      case EXT3_IOC_GET_TREE_STATS:
++      case EXT3_IOC_GET_TREE_DEPTH:
++              return ext3_ext_ioctl(inode, filp, cmd, arg);
+       default:
+               return -ENOTTY;
+       }
+Index: linux-2.4.29/include/linux/ext3_fs.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext3_fs.h  2005-05-03 16:50:30.228043472 +0300
++++ linux-2.4.29/include/linux/ext3_fs.h       2005-05-03 16:52:08.817055664 +0300
+@@ -184,8 +184,9 @@
+ #define EXT3_IMAGIC_FL                        0x00002000 /* AFS directory */
+ #define EXT3_JOURNAL_DATA_FL          0x00004000 /* file data should be journaled */
+ #define EXT3_RESERVED_FL              0x80000000 /* reserved for ext3 lib */
++#define EXT3_EXTENTS_FL                       0x00080000 /* Inode uses extents */
+-#define EXT3_FL_USER_VISIBLE          0x00005FFF /* User visible flags */
++#define EXT3_FL_USER_VISIBLE          0x00085FFF /* User visible flags */
+ #define EXT3_FL_USER_MODIFIABLE               0x000000FF /* User modifiable flags */
+ /*
+@@ -208,6 +209,9 @@
+ #ifdef CONFIG_JBD_DEBUG
+ #define EXT3_IOC_WAIT_FOR_READONLY    _IOR('f', 99, long)
+ #endif
++#define EXT3_IOC_GET_EXTENTS          _IOR('f', 5, long)
++#define EXT3_IOC_GET_TREE_DEPTH               _IOR('f', 6, long)
++#define EXT3_IOC_GET_TREE_STATS               _IOR('f', 7, long)
+ /*
+  * Structure of an inode on the disk
+@@ -327,6 +331,8 @@
+ #define EXT3_MOUNT_ASYNCDEL           0x20000 /* Delayed deletion */
+ #define EXT3_MOUNT_IOPEN              0x40000 /* Allow access via iopen */
+ #define EXT3_MOUNT_IOPEN_NOPRIV               0x80000 /* Make iopen world-readable */
++#define EXT3_MOUNT_EXTENTS            0x100000/* Extents support */
++#define EXT3_MOUNT_EXTDEBUG           0x200000/* Extents debug */
+ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
+ #ifndef _LINUX_EXT2_FS_H
+@@ -506,11 +512,14 @@
+ #define EXT3_FEATURE_INCOMPAT_RECOVER         0x0004 /* Needs recovery */
+ #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV     0x0008 /* Journal device */
+ #define EXT3_FEATURE_INCOMPAT_META_BG         0x0010
++#define EXT3_FEATURE_INCOMPAT_EXTENTS         0x0040 /* extents support */
+ #define EXT3_FEATURE_COMPAT_SUPP      EXT2_FEATURE_COMPAT_EXT_ATTR
+ #define EXT3_FEATURE_INCOMPAT_SUPP    (EXT3_FEATURE_INCOMPAT_FILETYPE| \
+                                        EXT3_FEATURE_INCOMPAT_RECOVER| \
+-                                       EXT3_FEATURE_INCOMPAT_META_BG)
++                                       EXT3_FEATURE_INCOMPAT_META_BG| \
++                                       EXT3_FEATURE_INCOMPAT_RECOVER| \
++                                       EXT3_FEATURE_INCOMPAT_EXTENTS)
+ #define EXT3_FEATURE_RO_COMPAT_SUPP   (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+                                        EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
+                                        EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
+@@ -702,6 +711,7 @@
+ extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
+ /* inode.c */
++extern int ext3_block_truncate_page(handle_t *, struct address_space *, loff_t);
+ extern int ext3_forget(handle_t *, int, struct inode *, struct buffer_head *, int);
+ extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
+ extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
+@@ -783,6 +793,16 @@
+ extern struct inode_operations ext3_symlink_inode_operations;
+ extern struct inode_operations ext3_fast_symlink_inode_operations;
++/* extents.c */
++extern int ext3_ext_writepage_trans_blocks(struct inode *, int);
++extern int ext3_ext_get_block(handle_t *, struct inode *, long,
++                            struct buffer_head *, int);
++extern void ext3_ext_truncate(struct inode *);
++extern void ext3_ext_init(struct super_block *);
++extern void ext3_ext_release(struct super_block *);
++extern void ext3_extents_initialize_blockmap(handle_t *, struct inode *);
++extern int ext3_ext_ioctl(struct inode *inode, struct file *filp,
++                        unsigned int cmd, unsigned long arg);
+ #endif        /* __KERNEL__ */
+Index: linux-2.4.29/include/linux/ext3_extents.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext3_extents.h     2005-05-03 16:52:08.724069800 +0300
++++ linux-2.4.29/include/linux/ext3_extents.h  2005-05-03 16:52:08.819055360 +0300
+@@ -0,0 +1,263 @@
++/*
++ * Copyright (c) 2003, Cluster File Systems, Inc, info@clusterfs.com
++ * Written by Alex Tomas <alex@clusterfs.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program 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 General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public Licens
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
++ */
++
++#ifndef _LINUX_EXT3_EXTENTS
++#define _LINUX_EXT3_EXTENTS
++
++/*
++ * with AGRESSIVE_TEST defined capacity of index/leaf blocks
++ * become very little, so index split, in-depth growing and
++ * other hard changes happens much more often
++ * this is for debug purposes only
++ */
++#define AGRESSIVE_TEST_
++
++/*
++ * if CHECK_BINSEARCH defined, then results of binary search
++ * will be checked by linear search
++ */
++#define CHECK_BINSEARCH_
++
++/*
++ * if EXT_DEBUG is defined you can use 'extdebug' mount option
++ * to get lots of info what's going on
++ */
++#define EXT_DEBUG_
++#ifdef EXT_DEBUG
++#define ext_debug(tree,fmt,a...)                      \
++do {                                                  \
++      if (test_opt((tree)->inode->i_sb, EXTDEBUG))    \
++              printk(fmt, ##a);                       \
++} while (0);
++#else
++#define ext_debug(tree,fmt,a...)
++#endif
++
++/*
++ * if EXT_STATS is defined then stats numbers are collected
++ * these number will be displayed at umount time
++ */
++#define EXT_STATS_
++
++
++#define EXT3_ALLOC_NEEDED     3       /* block bitmap + group desc. + sb */
++
++/*
++ * ext3_inode has i_block array (total 60 bytes)
++ * first 4 bytes are used to store:
++ *  - tree depth (0 mean there is no tree yet. all extents in the inode)
++ *  - number of alive extents in the inode
++ */
++
++/*
++ * this is extent on-disk structure
++ * it's used at the bottom of the tree
++ */
++struct ext3_extent {
++      __u32   ee_block;       /* first logical block extent covers */
++      __u16   ee_len;         /* number of blocks covered by extent */
++      __u16   ee_start_hi;    /* high 16 bits of physical block */
++      __u32   ee_start;       /* low 32 bigs of physical block */
++};
++
++/*
++ * this is index on-disk structure
++ * it's used at all the levels, but the bottom
++ */
++struct ext3_extent_idx {
++      __u32   ei_block;       /* index covers logical blocks from 'block' */
++      __u32   ei_leaf;        /* pointer to the physical block of the next *
++                               * level. leaf or next index could bet here */
++      __u16   ei_leaf_hi;     /* high 16 bits of physical block */
++      __u16   ei_unused;
++};
++
++/*
++ * each block (leaves and indexes), even inode-stored has header
++ */
++struct ext3_extent_header {   
++      __u16   eh_magic;       /* probably will support different formats */   
++      __u16   eh_entries;     /* number of valid entries */
++      __u16   eh_max;         /* capacity of store in entries */
++      __u16   eh_depth;       /* has tree real underlaying blocks? */
++      __u32   eh_generation;  /* generation of the tree */
++};
++
++#define EXT3_EXT_MAGIC                0xf30a
++
++/*
++ * array of ext3_ext_path contains path to some extent
++ * creation/lookup routines use it for traversal/splitting/etc
++ * truncate uses it to simulate recursive walking
++ */
++struct ext3_ext_path {
++      __u32                           p_block;
++      __u16                           p_depth;
++      struct ext3_extent              *p_ext;
++      struct ext3_extent_idx          *p_idx;
++      struct ext3_extent_header       *p_hdr;
++      struct buffer_head              *p_bh;
++};
++
++/*
++ * structure for external API
++ */
++
++/*
++ * storage for cached extent
++ */
++struct ext3_ext_cache {
++      __u32   ec_start;
++      __u32   ec_block;
++      __u32   ec_len;
++      __u32   ec_type;
++};
++
++#define EXT3_EXT_CACHE_NO     0
++#define EXT3_EXT_CACHE_GAP    1
++#define EXT3_EXT_CACHE_EXTENT 2
++
++/*
++ * ext3_extents_tree is used to pass initial information
++ * to top-level extents API
++ */
++struct ext3_extents_helpers;
++struct ext3_extents_tree {
++      struct inode *inode;    /* inode which tree belongs to */
++      void *root;             /* ptr to data top of tree resides at */
++      void *buffer;           /* will be passed as arg to ^^ routines */
++      int buffer_len;
++      void *private;
++      struct ext3_ext_cache *cex;/* last found extent */
++      struct ext3_extents_helpers *ops;
++};
++
++struct ext3_extents_helpers {
++      int (*get_write_access)(handle_t *h, void *buffer);
++      int (*mark_buffer_dirty)(handle_t *h, void *buffer);
++      int (*mergable)(struct ext3_extent *ex1, struct ext3_extent *ex2);
++      int (*remove_extent_credits)(struct ext3_extents_tree *,
++                                   struct ext3_extent *, unsigned long,
++                                   unsigned long);
++      int (*remove_extent)(struct ext3_extents_tree *,
++                           struct ext3_extent *, unsigned long,
++                           unsigned long);
++      int (*new_block)(handle_t *, struct ext3_extents_tree *,
++                       struct ext3_ext_path *, struct ext3_extent *,
++                       int *);
++};
++
++/*
++ * to be called by ext3_ext_walk_space()
++ * negative retcode - error
++ * positive retcode - signal for ext3_ext_walk_space(), see below
++ * callback must return valid extent (passed or newly created)
++ */
++typedef int (*ext_prepare_callback)(struct ext3_extents_tree *,
++                                  struct ext3_ext_path *,
++                                  struct ext3_ext_cache *);
++
++#define EXT_CONTINUE  0
++#define EXT_BREAK     1
++#define EXT_REPEAT    2
++
++
++#define EXT_MAX_BLOCK 0xffffffff
++
++
++#define EXT_FIRST_EXTENT(__hdr__) \
++      ((struct ext3_extent *) (((char *) (__hdr__)) +         \
++                               sizeof(struct ext3_extent_header)))
++#define EXT_FIRST_INDEX(__hdr__) \
++      ((struct ext3_extent_idx *) (((char *) (__hdr__)) +     \
++                                   sizeof(struct ext3_extent_header)))
++#define EXT_HAS_FREE_INDEX(__path__) \
++      ((__path__)->p_hdr->eh_entries < (__path__)->p_hdr->eh_max)
++#define EXT_LAST_EXTENT(__hdr__) \
++      (EXT_FIRST_EXTENT((__hdr__)) + (__hdr__)->eh_entries - 1)
++#define EXT_LAST_INDEX(__hdr__) \
++      (EXT_FIRST_INDEX((__hdr__)) + (__hdr__)->eh_entries - 1)
++#define EXT_MAX_EXTENT(__hdr__) \
++      (EXT_FIRST_EXTENT((__hdr__)) + (__hdr__)->eh_max - 1)
++#define EXT_MAX_INDEX(__hdr__) \
++      (EXT_FIRST_INDEX((__hdr__)) + (__hdr__)->eh_max - 1)
++
++#define EXT_ROOT_HDR(tree) \
++      ((struct ext3_extent_header *) (tree)->root)
++#define EXT_BLOCK_HDR(bh) \
++      ((struct ext3_extent_header *) (bh)->b_data)
++#define EXT_DEPTH(_t_)        \
++      (((struct ext3_extent_header *)((_t_)->root))->eh_depth)
++#define EXT_GENERATION(_t_)   \
++      (((struct ext3_extent_header *)((_t_)->root))->eh_generation)
++
++
++#define EXT_ASSERT(__x__) if (!(__x__)) BUG();
++
++#define EXT_CHECK_PATH(tree,path)                                     \
++{                                                                     \
++      int depth = EXT_DEPTH(tree);                                    \
++      BUG_ON((unsigned long) (path) < __PAGE_OFFSET);                 \
++      BUG_ON((unsigned long) (path)[depth].p_idx <                    \
++                      __PAGE_OFFSET && (path)[depth].p_idx != NULL);  \
++      BUG_ON((unsigned long) (path)[depth].p_ext <                    \
++                      __PAGE_OFFSET && (path)[depth].p_ext != NULL);  \
++      BUG_ON((unsigned long) (path)[depth].p_hdr < __PAGE_OFFSET);    \
++      BUG_ON((unsigned long) (path)[depth].p_bh < __PAGE_OFFSET       \
++                      && depth != 0);                                 \
++      BUG_ON((path)[0].p_depth != depth);                             \
++}
++
++
++/*
++ * this structure is used to gather extents from the tree via ioctl
++ */
++struct ext3_extent_buf {
++      unsigned long start;
++      int buflen;
++      void *buffer;
++      void *cur;
++      int err;
++};
++
++/*
++ * this structure is used to collect stats info about the tree
++ */
++struct ext3_extent_tree_stats {
++      int depth;
++      int extents_num;
++      int leaf_num;
++};
++
++extern void ext3_init_tree_desc(struct ext3_extents_tree *, struct inode *);
++extern int ext3_extent_tree_init(handle_t *, struct ext3_extents_tree *);
++extern int ext3_ext_calc_credits_for_insert(struct ext3_extents_tree *, struct ext3_ext_path *);
++extern int ext3_ext_insert_extent(handle_t *, struct ext3_extents_tree *, struct ext3_ext_path *, struct ext3_extent *);
++extern int ext3_ext_walk_space(struct ext3_extents_tree *, unsigned long, unsigned long, ext_prepare_callback);
++extern int ext3_ext_remove_space(struct ext3_extents_tree *, unsigned long, unsigned long);
++extern struct ext3_ext_path * ext3_ext_find_extent(struct ext3_extents_tree *, int, struct ext3_ext_path *);
++
++static inline void
++ext3_ext_invalidate_cache(struct ext3_extents_tree *tree)
++{
++      if (tree->cex)
++              tree->cex->ec_type = EXT3_EXT_CACHE_NO;
++}
++
++
++#endif /* _LINUX_EXT3_EXTENTS */
+Index: linux-2.4.29/include/linux/ext3_fs_i.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext3_fs_i.h        2005-05-03 16:50:30.229043320 +0300
++++ linux-2.4.29/include/linux/ext3_fs_i.h     2005-05-03 16:52:08.823054752 +0300
+@@ -76,6 +76,8 @@
+        * by other means, so we have truncate_sem.
+        */
+       struct rw_semaphore truncate_sem;
++
++      __u32 i_cached_extent[4];
+ };
+ #endif        /* _LINUX_EXT3_FS_I */
diff --git a/lustre/kernel_patches/patches/ext3-htree-2.4.29.patch b/lustre/kernel_patches/patches/ext3-htree-2.4.29.patch
new file mode 100644 (file)
index 0000000..259c7b7
--- /dev/null
@@ -0,0 +1,2496 @@
+Index: linux-2.4.29/fs/ext3/dir.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/dir.c    2005-04-07 18:53:53.000000000 +0300
++++ linux-2.4.29/fs/ext3/dir.c 2005-05-03 16:34:05.481747664 +0300
+@@ -21,12 +21,16 @@
+ #include <linux/fs.h>
+ #include <linux/jbd.h>
+ #include <linux/ext3_fs.h>
++#include <linux/slab.h>
++#include <linux/rbtree.h>
+ static unsigned char ext3_filetype_table[] = {
+       DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
+ };
+ static int ext3_readdir(struct file *, void *, filldir_t);
++static int ext3_dx_readdir(struct file * filp,
++                         void * dirent, filldir_t filldir);
+ struct file_operations ext3_dir_operations = {
+       read:           generic_read_dir,
+@@ -35,6 +39,17 @@
+       fsync:          ext3_sync_file,         /* BKL held */
+ };
++
++static unsigned char get_dtype(struct super_block *sb, int filetype)
++{
++      if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_FILETYPE) ||
++          (filetype >= EXT3_FT_MAX))
++              return DT_UNKNOWN;
++
++      return (ext3_filetype_table[filetype]);
++}
++                             
++
+ int ext3_check_dir_entry (const char * function, struct inode * dir,
+                         struct ext3_dir_entry_2 * de,
+                         struct buffer_head * bh,
+@@ -79,6 +94,16 @@
+       sb = inode->i_sb;
++      if (is_dx(inode)) {
++              err = ext3_dx_readdir(filp, dirent, filldir);
++              if (err != ERR_BAD_DX_DIR)
++                      return err;
++              /*
++               * We don't set the inode dirty flag since it's not
++               * critical that it get flushed back to the disk.
++               */
++              EXT3_I(filp->f_dentry->d_inode)->i_flags &= ~EXT3_INDEX_FL;
++      }
+       stored = 0;
+       bh = NULL;
+       offset = filp->f_pos & (sb->s_blocksize - 1);
+@@ -162,18 +187,12 @@
+                                * during the copy operation.
+                                */
+                               unsigned long version = filp->f_version;
+-                              unsigned char d_type = DT_UNKNOWN;
+-                              if (EXT3_HAS_INCOMPAT_FEATURE(sb,
+-                                              EXT3_FEATURE_INCOMPAT_FILETYPE)
+-                                              && de->file_type < EXT3_FT_MAX)
+-                                      d_type =
+-                                        ext3_filetype_table[de->file_type];
+                               error = filldir(dirent, de->name,
+                                               de->name_len,
+                                               filp->f_pos,
+                                               le32_to_cpu(de->inode),
+-                                              d_type);
++                                              get_dtype(sb, de->file_type));
+                               if (error)
+                                       break;
+                               if (version != filp->f_version)
+@@ -188,3 +207,272 @@
+       UPDATE_ATIME(inode);
+       return 0;
+ }
++
++#ifdef CONFIG_EXT3_INDEX
++/*
++ * These functions convert from the major/minor hash to an f_pos
++ * value.
++ * 
++ * Currently we only use major hash numer.  This is unfortunate, but
++ * on 32-bit machines, the same VFS interface is used for lseek and
++ * llseek, so if we use the 64 bit offset, then the 32-bit versions of
++ * lseek/telldir/seekdir will blow out spectacularly, and from within
++ * the ext2 low-level routine, we don't know if we're being called by
++ * a 64-bit version of the system call or the 32-bit version of the
++ * system call.  Worse yet, NFSv2 only allows for a 32-bit readdir
++ * cookie.  Sigh.
++ */
++#define hash2pos(major, minor)        (major >> 1)
++#define pos2maj_hash(pos)     ((pos << 1) & 0xffffffff)
++#define pos2min_hash(pos)     (0)
++
++/*
++ * This structure holds the nodes of the red-black tree used to store
++ * the directory entry in hash order.
++ */
++struct fname {
++      __u32           hash;
++      __u32           minor_hash;
++      rb_node_t       rb_hash; 
++      struct fname    *next;
++      __u32           inode;
++      __u8            name_len;
++      __u8            file_type;
++      char            name[0];
++};
++
++/*
++ * This functoin implements a non-recursive way of freeing all of the
++ * nodes in the red-black tree.
++ */
++static void free_rb_tree_fname(rb_root_t *root)
++{
++      rb_node_t       *n = root->rb_node;
++      rb_node_t       *parent;
++      struct fname    *fname;
++
++      while (n) {
++              /* Do the node's children first */
++              if ((n)->rb_left) {
++                      n = n->rb_left;
++                      continue;
++              }
++              if (n->rb_right) {
++                      n = n->rb_right;
++                      continue;
++              }
++              /*
++               * The node has no children; free it, and then zero
++               * out parent's link to it.  Finally go to the
++               * beginning of the loop and try to free the parent
++               * node.
++               */
++              parent = n->rb_parent;
++              fname = rb_entry(n, struct fname, rb_hash);
++              kfree(fname);
++              if (!parent)
++                      root->rb_node = 0;
++              else if (parent->rb_left == n)
++                      parent->rb_left = 0;
++              else if (parent->rb_right == n)
++                      parent->rb_right = 0;
++              n = parent;
++      }
++      root->rb_node = 0;
++}
++
++
++struct dir_private_info *create_dir_info(loff_t pos)
++{
++      struct dir_private_info *p;
++
++      p = kmalloc(sizeof(struct dir_private_info), GFP_KERNEL);
++      if (!p)
++              return NULL;
++      p->root.rb_node = 0;
++      p->curr_node = 0;
++      p->extra_fname = 0;
++      p->last_pos = 0;
++      p->curr_hash = pos2maj_hash(pos);
++      p->curr_minor_hash = pos2min_hash(pos);
++      p->next_hash = 0;
++      return p;
++}
++
++void ext3_htree_free_dir_info(struct dir_private_info *p)
++{
++      free_rb_tree_fname(&p->root);
++      kfree(p);
++}
++              
++/*
++ * Given a directory entry, enter it into the fname rb tree.
++ */
++int ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
++                           __u32 minor_hash,
++                           struct ext3_dir_entry_2 *dirent)
++{
++      rb_node_t **p, *parent = NULL;
++      struct fname * fname, *new_fn;
++      struct dir_private_info *info;
++      int len;
++
++      info = (struct dir_private_info *) dir_file->private_data;
++      p = &info->root.rb_node;
++
++      /* Create and allocate the fname structure */
++      len = sizeof(struct fname) + dirent->name_len + 1;
++      new_fn = kmalloc(len, GFP_KERNEL);
++      if (!new_fn)
++              return -ENOMEM;
++      memset(new_fn, 0, len);
++      new_fn->hash = hash;
++      new_fn->minor_hash = minor_hash;
++      new_fn->inode = le32_to_cpu(dirent->inode);
++      new_fn->name_len = dirent->name_len;
++      new_fn->file_type = dirent->file_type;
++      memcpy(new_fn->name, dirent->name, dirent->name_len);
++      new_fn->name[dirent->name_len] = 0;
++      
++      while (*p) {
++              parent = *p;
++              fname = rb_entry(parent, struct fname, rb_hash);
++
++              /*
++               * If the hash and minor hash match up, then we put
++               * them on a linked list.  This rarely happens...
++               */
++              if ((new_fn->hash == fname->hash) &&
++                  (new_fn->minor_hash == fname->minor_hash)) {
++                      new_fn->next = fname->next;
++                      fname->next = new_fn;
++                      return 0;
++              }
++                      
++              if (new_fn->hash < fname->hash)
++                      p = &(*p)->rb_left;
++              else if (new_fn->hash > fname->hash)
++                      p = &(*p)->rb_right;
++              else if (new_fn->minor_hash < fname->minor_hash)
++                      p = &(*p)->rb_left;
++              else /* if (new_fn->minor_hash > fname->minor_hash) */
++                      p = &(*p)->rb_right;
++      }
++
++      rb_link_node(&new_fn->rb_hash, parent, p);
++      rb_insert_color(&new_fn->rb_hash, &info->root);
++      return 0;
++}
++
++
++
++/*
++ * This is a helper function for ext3_dx_readdir.  It calls filldir
++ * for all entres on the fname linked list.  (Normally there is only
++ * one entry on the linked list, unless there are 62 bit hash collisions.)
++ */
++static int call_filldir(struct file * filp, void * dirent,
++                      filldir_t filldir, struct fname *fname)
++{
++      struct dir_private_info *info = filp->private_data;
++      loff_t  curr_pos;
++      struct inode *inode = filp->f_dentry->d_inode;
++      struct super_block * sb;
++      int error;
++
++      sb = inode->i_sb;
++      
++      if (!fname) {
++              printk("call_filldir: called with null fname?!?\n");
++              return 0;
++      }
++      curr_pos = hash2pos(fname->hash, fname->minor_hash);
++      while (fname) {
++              error = filldir(dirent, fname->name,
++                              fname->name_len, curr_pos, 
++                              fname->inode,
++                              get_dtype(sb, fname->file_type));
++              if (error) {
++                      filp->f_pos = curr_pos;
++                      info->extra_fname = fname->next;
++                      return error;
++              }
++              fname = fname->next;
++      }
++      return 0;
++}
++
++static int ext3_dx_readdir(struct file * filp,
++                       void * dirent, filldir_t filldir)
++{
++      struct dir_private_info *info = filp->private_data;
++      struct inode *inode = filp->f_dentry->d_inode;
++      struct fname *fname;
++      int     ret;
++
++      if (!info) {
++              info = create_dir_info(filp->f_pos);
++              if (!info)
++                      return -ENOMEM;
++              filp->private_data = info;
++      }
++
++      /* Some one has messed with f_pos; reset the world */
++      if (info->last_pos != filp->f_pos) {
++              free_rb_tree_fname(&info->root);
++              info->curr_node = 0;
++              info->extra_fname = 0;
++              info->curr_hash = pos2maj_hash(filp->f_pos);
++              info->curr_minor_hash = pos2min_hash(filp->f_pos);
++      }
++
++      /*
++       * If there are any leftover names on the hash collision
++       * chain, return them first.
++       */
++      if (info->extra_fname &&
++          call_filldir(filp, dirent, filldir, info->extra_fname))
++              goto finished;
++
++      if (!info->curr_node)
++              info->curr_node = rb_first(&info->root);
++
++      while (1) {
++              /*
++               * Fill the rbtree if we have no more entries,
++               * or the inode has changed since we last read in the
++               * cached entries. 
++               */
++              if ((!info->curr_node) ||
++                  (filp->f_version != inode->i_version)) {
++                      info->curr_node = 0;
++                      free_rb_tree_fname(&info->root);
++                      filp->f_version = inode->i_version;
++                      ret = ext3_htree_fill_tree(filp, info->curr_hash,
++                                                 info->curr_minor_hash,
++                                                 &info->next_hash);
++                      if (ret < 0)
++                              return ret;
++                      if (ret == 0)
++                              break;
++                      info->curr_node = rb_first(&info->root);
++              }
++
++              fname = rb_entry(info->curr_node, struct fname, rb_hash);
++              info->curr_hash = fname->hash;
++              info->curr_minor_hash = fname->minor_hash;
++              if (call_filldir(filp, dirent, filldir, fname))
++                      break;
++
++              info->curr_node = rb_next(info->curr_node);
++              if (!info->curr_node) {
++                      info->curr_hash = info->next_hash;
++                      info->curr_minor_hash = 0;
++              }
++      }
++finished:
++      info->last_pos = filp->f_pos;
++      UPDATE_ATIME(inode);
++      return 0;
++}
++#endif
+Index: linux-2.4.29/fs/ext3/file.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/file.c   2005-04-07 18:55:11.000000000 +0300
++++ linux-2.4.29/fs/ext3/file.c        2005-05-03 16:29:50.563501128 +0300
+@@ -35,6 +35,9 @@
+ {
+       if (filp->f_mode & FMODE_WRITE)
+               ext3_discard_prealloc (inode);
++      if (is_dx(inode) && filp->private_data)
++              ext3_htree_free_dir_info(filp->private_data);
++
+       return 0;
+ }
+Index: linux-2.4.29/fs/ext3/hash.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/hash.c   2005-05-03 16:29:50.539504776 +0300
++++ linux-2.4.29/fs/ext3/hash.c        2005-05-03 16:29:50.565500824 +0300
+@@ -0,0 +1,215 @@
++/*
++ *  linux/fs/ext3/hash.c
++ *
++ * Copyright (C) 2002 by Theodore Ts'o
++ *
++ * This file is released under the GPL v2.
++ * 
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ */
++
++#include <linux/fs.h>
++#include <linux/jbd.h>
++#include <linux/sched.h>
++#include <linux/ext3_fs.h>
++
++#define DELTA 0x9E3779B9
++
++static void TEA_transform(__u32 buf[4], __u32 const in[])
++{
++      __u32   sum = 0;
++      __u32   b0 = buf[0], b1 = buf[1];
++      __u32   a = in[0], b = in[1], c = in[2], d = in[3];
++      int     n = 16;
++
++      do {                                                    
++              sum += DELTA;                                   
++              b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); 
++              b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); 
++      } while(--n);
++
++      buf[0] += b0;
++      buf[1] += b1;
++}
++
++/* F, G and H are basic MD4 functions: selection, majority, parity */
++#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
++#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
++#define H(x, y, z) ((x) ^ (y) ^ (z))
++
++/*
++ * The generic round function.  The application is so specific that
++ * we don't bother protecting all the arguments with parens, as is generally
++ * good macro practice, in favor of extra legibility.
++ * Rotation is separate from addition to prevent recomputation
++ */
++#define ROUND(f, a, b, c, d, x, s)    \
++      (a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
++#define K1 0
++#define K2 013240474631UL
++#define K3 015666365641UL
++
++/*
++ * Basic cut-down MD4 transform.  Returns only 32 bits of result.
++ */
++static void halfMD4Transform (__u32 buf[4], __u32 const in[])
++{
++      __u32   a = buf[0], b = buf[1], c = buf[2], d = buf[3];
++
++      /* Round 1 */
++      ROUND(F, a, b, c, d, in[0] + K1,  3);
++      ROUND(F, d, a, b, c, in[1] + K1,  7);
++      ROUND(F, c, d, a, b, in[2] + K1, 11);
++      ROUND(F, b, c, d, a, in[3] + K1, 19);
++      ROUND(F, a, b, c, d, in[4] + K1,  3);
++      ROUND(F, d, a, b, c, in[5] + K1,  7);
++      ROUND(F, c, d, a, b, in[6] + K1, 11);
++      ROUND(F, b, c, d, a, in[7] + K1, 19);
++
++      /* Round 2 */
++      ROUND(G, a, b, c, d, in[1] + K2,  3);
++      ROUND(G, d, a, b, c, in[3] + K2,  5);
++      ROUND(G, c, d, a, b, in[5] + K2,  9);
++      ROUND(G, b, c, d, a, in[7] + K2, 13);
++      ROUND(G, a, b, c, d, in[0] + K2,  3);
++      ROUND(G, d, a, b, c, in[2] + K2,  5);
++      ROUND(G, c, d, a, b, in[4] + K2,  9);
++      ROUND(G, b, c, d, a, in[6] + K2, 13);
++
++      /* Round 3 */
++      ROUND(H, a, b, c, d, in[3] + K3,  3);
++      ROUND(H, d, a, b, c, in[7] + K3,  9);
++      ROUND(H, c, d, a, b, in[2] + K3, 11);
++      ROUND(H, b, c, d, a, in[6] + K3, 15);
++      ROUND(H, a, b, c, d, in[1] + K3,  3);
++      ROUND(H, d, a, b, c, in[5] + K3,  9);
++      ROUND(H, c, d, a, b, in[0] + K3, 11);
++      ROUND(H, b, c, d, a, in[4] + K3, 15);
++
++      buf[0] += a;
++      buf[1] += b;
++      buf[2] += c;
++      buf[3] += d;
++}
++
++#undef ROUND
++#undef F
++#undef G
++#undef H
++#undef K1
++#undef K2
++#undef K3
++
++/* The old legacy hash */
++static __u32 dx_hack_hash (const char *name, int len)
++{
++      __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
++      while (len--) {
++              __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
++              
++              if (hash & 0x80000000) hash -= 0x7fffffff;
++              hash1 = hash0;
++              hash0 = hash;
++      }
++      return (hash0 << 1);
++}
++
++static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
++{
++      __u32   pad, val;
++      int     i;
++
++      pad = (__u32)len | ((__u32)len << 8);
++      pad |= pad << 16;
++
++      val = pad;
++      if (len > num*4)
++              len = num * 4;
++      for (i=0; i < len; i++) {
++              if ((i % 4) == 0)
++                      val = pad;
++              val = msg[i] + (val << 8);
++              if ((i % 4) == 3) {
++                      *buf++ = val;
++                      val = pad;
++                      num--;
++              }
++      }
++      if (--num >= 0)
++              *buf++ = val;
++      while (--num >= 0)
++              *buf++ = pad;
++}
++
++/*
++ * Returns the hash of a filename.  If len is 0 and name is NULL, then
++ * this function can be used to test whether or not a hash version is
++ * supported.
++ * 
++ * The seed is an 4 longword (32 bits) "secret" which can be used to
++ * uniquify a hash.  If the seed is all zero's, then some default seed
++ * may be used.
++ * 
++ * A particular hash version specifies whether or not the seed is
++ * represented, and whether or not the returned hash is 32 bits or 64
++ * bits.  32 bit hashes will return 0 for the minor hash.
++ */
++int ext3fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo)
++{
++      __u32   hash;
++      __u32   minor_hash = 0;
++      const char      *p;
++      int             i;
++      __u32           in[8], buf[4];
++
++      /* Initialize the default seed for the hash checksum functions */
++      buf[0] = 0x67452301;
++      buf[1] = 0xefcdab89;
++      buf[2] = 0x98badcfe;
++      buf[3] = 0x10325476;
++
++      /* Check to see if the seed is all zero's */
++      if (hinfo->seed) {
++              for (i=0; i < 4; i++) {
++                      if (hinfo->seed[i])
++                              break;
++              }
++              if (i < 4)
++                      memcpy(buf, hinfo->seed, sizeof(buf));
++      }
++              
++      switch (hinfo->hash_version) {
++      case DX_HASH_LEGACY:
++              hash = dx_hack_hash(name, len);
++              break;
++      case DX_HASH_HALF_MD4:
++              p = name;
++              while (len > 0) {
++                      str2hashbuf(p, len, in, 8);
++                      halfMD4Transform(buf, in);
++                      len -= 32;
++                      p += 32;
++              }
++              minor_hash = buf[2];
++              hash = buf[1];
++              break;
++      case DX_HASH_TEA:
++              p = name;
++              while (len > 0) {
++                      str2hashbuf(p, len, in, 4);
++                      TEA_transform(buf, in);
++                      len -= 16;
++                      p += 16;
++              }
++              hash = buf[0];
++              minor_hash = buf[1];
++              break;
++      default:
++              hinfo->hash = 0;
++              return -1;
++      }
++      hinfo->hash = hash & ~1;
++      hinfo->minor_hash = minor_hash;
++      return 0;
++}
+Index: linux-2.4.29/fs/ext3/Makefile
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/Makefile 2005-04-07 18:59:19.000000000 +0300
++++ linux-2.4.29/fs/ext3/Makefile      2005-05-03 16:29:50.565500824 +0300
+@@ -12,7 +12,7 @@
+ export-objs :=        super.o inode.o
+ obj-y    := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+-              ioctl.o namei.o super.o symlink.o
++              ioctl.o namei.o super.o symlink.o hash.o
+ obj-m    := $(O_TARGET)
+ include $(TOPDIR)/Rules.make
+Index: linux-2.4.29/fs/ext3/namei.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/namei.c  2005-04-07 18:53:59.000000000 +0300
++++ linux-2.4.29/fs/ext3/namei.c       2005-05-03 16:29:50.576499152 +0300
+@@ -16,6 +16,12 @@
+  *        David S. Miller (davem@caip.rutgers.edu), 1995
+  *  Directory entry file type support and forward compatibility hooks
+  *    for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
++ *  Hash Tree Directory indexing (c)
++ *    Daniel Phillips, 2001
++ *  Hash Tree Directory indexing porting
++ *    Christopher Li, 2002
++ *  Hash Tree Directory indexing cleanup
++ *    Theodore Ts'o, 2002
+  */
+ #include <linux/fs.h>
+@@ -38,6 +44,642 @@
+ #define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+ #define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
++static struct buffer_head *ext3_append(handle_t *handle,
++                                      struct inode *inode,
++                                      u32 *block, int *err)
++{
++      struct buffer_head *bh;
++
++      *block = inode->i_size >> inode->i_sb->s_blocksize_bits;
++
++      if ((bh = ext3_bread(handle, inode, *block, 1, err))) {
++              inode->i_size += inode->i_sb->s_blocksize;
++              EXT3_I(inode)->i_disksize = inode->i_size;
++              ext3_journal_get_write_access(handle,bh);
++      }
++      return bh;
++}
++
++#ifndef assert
++#define assert(test) J_ASSERT(test)
++#endif
++
++#ifndef swap
++#define swap(x, y) do { typeof(x) z = x; x = y; y = z; } while (0)
++#endif
++
++typedef struct { u32 v; } le_u32;
++typedef struct { u16 v; } le_u16;
++
++#ifdef DX_DEBUG
++#define dxtrace(command) command
++#else
++#define dxtrace(command) 
++#endif
++
++struct fake_dirent
++{
++      /*le*/u32 inode;
++      /*le*/u16 rec_len;
++      u8 name_len;
++      u8 file_type;
++};
++
++struct dx_countlimit
++{
++      le_u16 limit;
++      le_u16 count;
++};
++
++struct dx_entry
++{
++      le_u32 hash;
++      le_u32 block;
++};
++
++/*
++ * dx_root_info is laid out so that if it should somehow get overlaid by a
++ * dirent the two low bits of the hash version will be zero.  Therefore, the
++ * hash version mod 4 should never be 0.  Sincerely, the paranoia department.
++ */
++
++struct dx_root
++{
++      struct fake_dirent dot;
++      char dot_name[4];
++      struct fake_dirent dotdot;
++      char dotdot_name[4];
++      struct dx_root_info
++      {
++              le_u32 reserved_zero;
++              u8 hash_version;
++              u8 info_length; /* 8 */
++              u8 indirect_levels;
++              u8 unused_flags;
++      }
++      info;
++      struct dx_entry entries[0];
++};
++
++struct dx_node
++{
++      struct fake_dirent fake;
++      struct dx_entry entries[0];
++};
++
++
++struct dx_frame
++{
++      struct buffer_head *bh;
++      struct dx_entry *entries;
++      struct dx_entry *at;
++};
++
++struct dx_map_entry
++{
++      u32 hash;
++      u32 offs;
++};
++
++#ifdef CONFIG_EXT3_INDEX
++static inline unsigned dx_get_block (struct dx_entry *entry);
++static void dx_set_block (struct dx_entry *entry, unsigned value);
++static inline unsigned dx_get_hash (struct dx_entry *entry);
++static void dx_set_hash (struct dx_entry *entry, unsigned value);
++static unsigned dx_get_count (struct dx_entry *entries);
++static unsigned dx_get_limit (struct dx_entry *entries);
++static void dx_set_count (struct dx_entry *entries, unsigned value);
++static void dx_set_limit (struct dx_entry *entries, unsigned value);
++static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
++static unsigned dx_node_limit (struct inode *dir);
++static struct dx_frame *dx_probe(struct dentry *dentry,
++                               struct inode *dir,
++                               struct dx_hash_info *hinfo,
++                               struct dx_frame *frame,
++                               int *err);
++static void dx_release (struct dx_frame *frames);
++static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
++                      struct dx_hash_info *hinfo, struct dx_map_entry map[]);
++static void dx_sort_map(struct dx_map_entry *map, unsigned count);
++static struct ext3_dir_entry_2 *dx_move_dirents (char *from, char *to,
++              struct dx_map_entry *offsets, int count);
++static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size);
++static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
++static int ext3_htree_next_block(struct inode *dir, __u32 hash,
++                               struct dx_frame *frame,
++                               struct dx_frame *frames, int *err,
++                               __u32 *start_hash);
++static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
++                     struct ext3_dir_entry_2 **res_dir, int *err);
++static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
++                           struct inode *inode);
++
++/*
++ * Future: use high four bits of block for coalesce-on-delete flags
++ * Mask them off for now.
++ */
++
++static inline unsigned dx_get_block (struct dx_entry *entry)
++{
++      return le32_to_cpu(entry->block.v) & 0x00ffffff;
++}
++
++static inline void dx_set_block (struct dx_entry *entry, unsigned value)
++{
++      entry->block.v = cpu_to_le32(value);
++}
++
++static inline unsigned dx_get_hash (struct dx_entry *entry)
++{
++      return le32_to_cpu(entry->hash.v);
++}
++
++static inline void dx_set_hash (struct dx_entry *entry, unsigned value)
++{
++      entry->hash.v = cpu_to_le32(value);
++}
++
++static inline unsigned dx_get_count (struct dx_entry *entries)
++{
++      return le16_to_cpu(((struct dx_countlimit *) entries)->count.v);
++}
++
++static inline unsigned dx_get_limit (struct dx_entry *entries)
++{
++      return le16_to_cpu(((struct dx_countlimit *) entries)->limit.v);
++}
++
++static inline void dx_set_count (struct dx_entry *entries, unsigned value)
++{
++      ((struct dx_countlimit *) entries)->count.v = cpu_to_le16(value);
++}
++
++static inline void dx_set_limit (struct dx_entry *entries, unsigned value)
++{
++      ((struct dx_countlimit *) entries)->limit.v = cpu_to_le16(value);
++}
++
++static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize)
++{
++      unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(1) -
++              EXT3_DIR_REC_LEN(2) - infosize;
++      return 0? 20: entry_space / sizeof(struct dx_entry);
++}
++
++static inline unsigned dx_node_limit (struct inode *dir)
++{
++      unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(0);
++      return 0? 22: entry_space / sizeof(struct dx_entry);
++}
++
++/*
++ * Debug
++ */
++#ifdef DX_DEBUG
++struct stats
++{ 
++      unsigned names;
++      unsigned space;
++      unsigned bcount;
++};
++
++static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_entry_2 *de,
++                               int size, int show_names)
++{
++      unsigned names = 0, space = 0;
++      char *base = (char *) de;
++      struct dx_hash_info h = *hinfo;
++      
++      printk("names: ");
++      while ((char *) de < base + size)
++      {
++              if (de->inode)
++              {
++                      if (show_names)
++                      {
++                              int len = de->name_len;
++                              char *name = de->name;
++                              while (len--) printk("%c", *name++);
++                              ext3fs_dirhash(de->name, de->name_len, &h);
++                              printk(":%x.%u ", h.hash,
++                                     ((char *) de - base));
++                      }
++                      space += EXT3_DIR_REC_LEN(de->name_len);
++                      names++;
++              }
++              de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
++      }
++      printk("(%i)\n", names);
++      return (struct stats) { names, space, 1 };
++}
++
++struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
++                           struct dx_entry *entries, int levels)
++{
++      unsigned blocksize = dir->i_sb->s_blocksize;
++      unsigned count = dx_get_count (entries), names = 0, space = 0, i;
++      unsigned bcount = 0;
++      struct buffer_head *bh;
++      int err;
++      printk("%i indexed blocks...\n", count);
++      for (i = 0; i < count; i++, entries++)
++      {
++              u32 block = dx_get_block(entries), hash = i? dx_get_hash(entries): 0;
++              u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash;
++              struct stats stats;
++              printk("%s%3u:%03u hash %8x/%8x ",levels?"":"   ", i, block, hash, range);
++              if (!(bh = ext3_bread (NULL,dir, block, 0,&err))) continue;
++              stats = levels?
++                 dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1):
++                 dx_show_leaf(hinfo, (struct ext3_dir_entry_2 *) bh->b_data, blocksize, 0);
++              names += stats.names;
++              space += stats.space;
++              bcount += stats.bcount;
++              brelse (bh);
++      }
++      if (bcount)
++              printk("%snames %u, fullness %u (%u%%)\n", levels?"":"   ",
++                      names, space/bcount,(space/bcount)*100/blocksize);
++      return (struct stats) { names, space, bcount};
++}
++#endif /* DX_DEBUG */
++
++/*
++ * Probe for a directory leaf block to search.
++ *
++ * dx_probe can return ERR_BAD_DX_DIR, which means there was a format
++ * error in the directory index, and the caller should fall back to
++ * searching the directory normally.  The callers of dx_probe **MUST**
++ * check for this error code, and make sure it never gets reflected
++ * back to userspace.
++ */
++static struct dx_frame *
++dx_probe(struct dentry *dentry, struct inode *dir,
++       struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err)
++{
++      unsigned count, indirect;
++      struct dx_entry *at, *entries, *p, *q, *m;
++      struct dx_root *root;
++      struct buffer_head *bh;
++      struct dx_frame *frame = frame_in;
++      u32 hash;
++
++      frame->bh = NULL;
++      if (dentry)
++              dir = dentry->d_parent->d_inode;
++      if (!(bh = ext3_bread (NULL,dir, 0, 0, err)))
++              goto fail;
++      root = (struct dx_root *) bh->b_data;
++      if (root->info.hash_version != DX_HASH_TEA &&
++          root->info.hash_version != DX_HASH_HALF_MD4 &&
++          root->info.hash_version != DX_HASH_LEGACY) {
++              ext3_warning(dir->i_sb, __FUNCTION__,
++                           "Unrecognised inode hash code %d",
++                           root->info.hash_version);
++              brelse(bh);
++              *err = ERR_BAD_DX_DIR;
++              goto fail;
++      }
++      hinfo->hash_version = root->info.hash_version;
++      hinfo->seed = dir->i_sb->u.ext3_sb.s_hash_seed;
++      if (dentry)
++              ext3fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);
++      hash = hinfo->hash;
++
++      if (root->info.unused_flags & 1) {
++              ext3_warning(dir->i_sb, __FUNCTION__,
++                           "Unimplemented inode hash flags: %#06x",
++                           root->info.unused_flags);
++              brelse(bh);
++              *err = ERR_BAD_DX_DIR;
++              goto fail;
++      }
++
++      if ((indirect = root->info.indirect_levels) > 1) {
++              ext3_warning(dir->i_sb, __FUNCTION__,
++                           "Unimplemented inode hash depth: %#06x",
++                           root->info.indirect_levels);
++              brelse(bh);
++              *err = ERR_BAD_DX_DIR;
++              goto fail;
++      }
++
++      entries = (struct dx_entry *) (((char *)&root->info) +
++                                     root->info.info_length);
++      assert(dx_get_limit(entries) == dx_root_limit(dir,
++                                                    root->info.info_length));
++      dxtrace (printk("Look up %x", hash));
++      while (1)
++      {
++              count = dx_get_count(entries);
++              assert (count && count <= dx_get_limit(entries));
++              p = entries + 1;
++              q = entries + count - 1;
++              while (p <= q)
++              {
++                      m = p + (q - p)/2;
++                      dxtrace(printk("."));
++                      if (dx_get_hash(m) > hash)
++                              q = m - 1;
++                      else
++                              p = m + 1;
++              }
++
++              if (0) // linear search cross check
++              {
++                      unsigned n = count - 1;
++                      at = entries;
++                      while (n--)
++                      {
++                              dxtrace(printk(","));
++                              if (dx_get_hash(++at) > hash)
++                              {
++                                      at--;
++                                      break;
++                              }
++                      }
++                      assert (at == p - 1);
++              }
++
++              at = p - 1;
++              dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at)));
++              frame->bh = bh;
++              frame->entries = entries;
++              frame->at = at;
++              if (!indirect--) return frame;
++              if (!(bh = ext3_bread (NULL,dir, dx_get_block(at), 0, err)))
++                      goto fail2;
++              at = entries = ((struct dx_node *) bh->b_data)->entries;
++              assert (dx_get_limit(entries) == dx_node_limit (dir));
++              frame++;
++      }
++fail2:
++      while (frame >= frame_in) {
++              brelse(frame->bh);
++              frame--;
++      }
++fail:
++      return NULL;
++}
++
++static void dx_release (struct dx_frame *frames)
++{
++      if (frames[0].bh == NULL)
++              return;
++
++      if (((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels)
++              brelse(frames[1].bh);
++      brelse(frames[0].bh);
++}
++
++/*
++ * This function increments the frame pointer to search the next leaf
++ * block, and reads in the necessary intervening nodes if the search
++ * should be necessary.  Whether or not the search is necessary is
++ * controlled by the hash parameter.  If the hash value is even, then
++ * the search is only continued if the next block starts with that
++ * hash value.  This is used if we are searching for a specific file.
++ *
++ * If the hash value is HASH_NB_ALWAYS, then always go to the next block.
++ *
++ * This function returns 1 if the caller should continue to search,
++ * or 0 if it should not.  If there is an error reading one of the
++ * index blocks, it will return -1.
++ *
++ * If start_hash is non-null, it will be filled in with the starting
++ * hash of the next page.
++ */
++static int ext3_htree_next_block(struct inode *dir, __u32 hash,
++                               struct dx_frame *frame,
++                               struct dx_frame *frames, int *err,
++                               __u32 *start_hash)
++{
++      struct dx_frame *p;
++      struct buffer_head *bh;
++      int num_frames = 0;
++      __u32 bhash;
++
++      *err = ENOENT;
++      p = frame;
++      /*
++       * Find the next leaf page by incrementing the frame pointer.
++       * If we run out of entries in the interior node, loop around and
++       * increment pointer in the parent node.  When we break out of
++       * this loop, num_frames indicates the number of interior
++       * nodes need to be read.
++       */
++      while (1) {
++              if (++(p->at) < p->entries + dx_get_count(p->entries))
++                      break;
++              if (p == frames)
++                      return 0;
++              num_frames++;
++              p--;
++      }
++
++      /*
++       * If the hash is 1, then continue only if the next page has a
++       * continuation hash of any value.  This is used for readdir
++       * handling.  Otherwise, check to see if the hash matches the
++       * desired contiuation hash.  If it doesn't, return since
++       * there's no point to read in the successive index pages.
++       */
++      bhash = dx_get_hash(p->at);
++      if (start_hash)
++              *start_hash = bhash;
++      if ((hash & 1) == 0) {
++              if ((bhash & ~1) != hash)
++                      return 0;
++      }
++      /*
++       * If the hash is HASH_NB_ALWAYS, we always go to the next
++       * block so no check is necessary
++       */
++      while (num_frames--) {
++              if (!(bh = ext3_bread(NULL, dir, dx_get_block(p->at),
++                                    0, err)))
++                      return -1; /* Failure */
++              p++;
++              brelse (p->bh);
++              p->bh = bh;
++              p->at = p->entries = ((struct dx_node *) bh->b_data)->entries;
++      }
++      return 1;
++}
++
++
++/*
++ * p is at least 6 bytes before the end of page
++ */
++static inline struct ext3_dir_entry_2 *ext3_next_entry(struct ext3_dir_entry_2 *p)
++{
++      return (struct ext3_dir_entry_2 *)((char*)p + le16_to_cpu(p->rec_len));
++}
++
++/*
++ * This function fills a red-black tree with information from a
++ * directory.  We start scanning the directory in hash order, starting
++ * at start_hash and start_minor_hash.
++ *
++ * This function returns the number of entries inserted into the tree,
++ * or a negative error code.
++ */
++int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash,
++                       __u32 start_minor_hash, __u32 *next_hash)
++{
++      struct dx_hash_info hinfo;
++      struct buffer_head *bh;
++      struct ext3_dir_entry_2 *de, *top;
++      static struct dx_frame frames[2], *frame;
++      struct inode *dir;
++      int block, err;
++      int count = 0;
++      int ret;
++      __u32 hashval;
++      
++      dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash,
++                     start_minor_hash));
++      dir = dir_file->f_dentry->d_inode;
++      hinfo.hash = start_hash;
++      hinfo.minor_hash = 0;
++      frame = dx_probe(0, dir_file->f_dentry->d_inode, &hinfo, frames, &err);
++      if (!frame)
++              return err;
++
++      /* Add '.' and '..' from the htree header */
++      if (!start_hash && !start_minor_hash) {
++              de = (struct ext3_dir_entry_2 *) frames[0].bh->b_data;
++              if ((err = ext3_htree_store_dirent(dir_file, 0, 0, de)) != 0)
++                      goto errout;
++              de = ext3_next_entry(de);
++              if ((err = ext3_htree_store_dirent(dir_file, 0, 0, de)) != 0)
++                      goto errout;
++              count += 2;
++      }
++
++      while (1) {
++              block = dx_get_block(frame->at);
++              dxtrace(printk("Reading block %d\n", block));
++              if (!(bh = ext3_bread (NULL, dir, block, 0, &err)))
++                      goto errout;
++      
++              de = (struct ext3_dir_entry_2 *) bh->b_data;
++              top = (struct ext3_dir_entry_2 *) ((char *) de + dir->i_sb->s_blocksize -
++                                     EXT3_DIR_REC_LEN(0));
++              for (; de < top; de = ext3_next_entry(de)) {
++                      ext3fs_dirhash(de->name, de->name_len, &hinfo);
++                      if ((hinfo.hash < start_hash) ||
++                          ((hinfo.hash == start_hash) &&
++                           (hinfo.minor_hash < start_minor_hash)))
++                              continue;
++                      if ((err = ext3_htree_store_dirent(dir_file,
++                                 hinfo.hash, hinfo.minor_hash, de)) != 0)
++                              goto errout;
++                      count++;
++              }
++              brelse (bh);
++              hashval = ~1;
++              ret = ext3_htree_next_block(dir, HASH_NB_ALWAYS, 
++                                          frame, frames, &err, &hashval);
++              if (next_hash)
++                      *next_hash = hashval;
++              if (ret == -1)
++                      goto errout;
++              /*
++               * Stop if:  (a) there are no more entries, or
++               * (b) we have inserted at least one entry and the
++               * next hash value is not a continuation
++               */
++              if ((ret == 0) ||
++                  (count && ((hashval & 1) == 0)))
++                      break;
++      }
++      dx_release(frames);
++      dxtrace(printk("Fill tree: returned %d entries\n", count));
++      return count;
++errout:
++      dx_release(frames);
++      return (err);
++}
++
++
++/*
++ * Directory block splitting, compacting
++ */
++
++static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
++                      struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
++{
++      int count = 0;
++      char *base = (char *) de;
++      struct dx_hash_info h = *hinfo;
++      
++      while ((char *) de < base + size)
++      {
++              if (de->name_len && de->inode) {
++                      ext3fs_dirhash(de->name, de->name_len, &h);
++                      map_tail--;
++                      map_tail->hash = h.hash;
++                      map_tail->offs = (u32) ((char *) de - base);
++                      count++;
++              }
++              /* XXX: do we need to check rec_len == 0 case? -Chris */
++              de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
++      }
++      return count;
++}
++
++static void dx_sort_map (struct dx_map_entry *map, unsigned count)
++{
++      struct dx_map_entry *p, *q, *top = map + count - 1;
++      int more;
++      /* Combsort until bubble sort doesn't suck */
++      while (count > 2)
++      {
++              count = count*10/13;
++              if (count - 9 < 2) /* 9, 10 -> 11 */
++                      count = 11;
++              for (p = top, q = p - count; q >= map; p--, q--)
++                      if (p->hash < q->hash)
++                              swap(*p, *q);
++      }
++      /* Garden variety bubble sort */
++      do {
++              more = 0;
++              q = top;
++              while (q-- > map)
++              {
++                      if (q[1].hash >= q[0].hash)
++                              continue;
++                      swap(*(q+1), *q);
++                      more = 1;
++              }
++      } while(more);
++}
++
++static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block)
++{
++      struct dx_entry *entries = frame->entries;
++      struct dx_entry *old = frame->at, *new = old + 1;
++      int count = dx_get_count(entries);
++
++      assert(count < dx_get_limit(entries));
++      assert(old < entries + count);
++      memmove(new + 1, new, (char *)(entries + count) - (char *)(new));
++      dx_set_hash(new, hash);
++      dx_set_block(new, block);
++      dx_set_count(entries, count + 1);
++}
++#endif
++
++
++static void ext3_update_dx_flag(struct inode *inode)
++{
++      if (!EXT3_HAS_COMPAT_FEATURE(inode->i_sb,
++                                   EXT3_FEATURE_COMPAT_DIR_INDEX))
++              EXT3_I(inode)->i_flags &= ~EXT3_INDEX_FL;
++}
++
+ /*
+  * NOTE! unlike strncmp, ext3_match returns 1 for success, 0 for failure.
+  *
+@@ -94,6 +736,7 @@
+       return 0;
+ }
++
+ /*
+  *    ext3_find_entry()
+  *
+@@ -105,6 +748,8 @@
+  * The returned buffer_head has ->b_count elevated.  The caller is expected
+  * to brelse() it when appropriate.
+  */
++
++      
+ static struct buffer_head * ext3_find_entry (struct dentry *dentry,
+                                       struct ext3_dir_entry_2 ** res_dir)
+ {
+@@ -119,12 +764,32 @@
+       int num = 0;
+       int nblocks, i, err;
+       struct inode *dir = dentry->d_parent->d_inode;
++      int namelen;
++      const u8 *name;
++      unsigned blocksize;
+       *res_dir = NULL;
+       sb = dir->i_sb;
+-
++      blocksize = sb->s_blocksize;
++      namelen = dentry->d_name.len;
++      name = dentry->d_name.name;
++      if (namelen > EXT3_NAME_LEN)
++              return NULL;
++#ifdef CONFIG_EXT3_INDEX
++      if (is_dx(dir)) {
++              bh = ext3_dx_find_entry(dentry, res_dir, &err);
++              /*
++               * On success, or if the error was file not found,
++               * return.  Otherwise, fall back to doing a search the
++               * old fashioned way.
++               */
++              if (bh || (err != ERR_BAD_DX_DIR))
++                      return bh;
++              dxtrace(printk("ext3_find_entry: dx failed, falling back\n"));
++      }
++#endif
+       nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb);
+-      start = dir->u.ext3_i.i_dir_start_lookup;
++      start = EXT3_I(dir)->i_dir_start_lookup;
+       if (start >= nblocks)
+               start = 0;
+       block = start;
+@@ -165,7 +830,7 @@
+               i = search_dirblock(bh, dir, dentry,
+                           block << EXT3_BLOCK_SIZE_BITS(sb), res_dir);
+               if (i == 1) {
+-                      dir->u.ext3_i.i_dir_start_lookup = block;
++                      EXT3_I(dir)->i_dir_start_lookup = block;
+                       ret = bh;
+                       goto cleanup_and_exit;
+               } else {
+@@ -196,6 +861,66 @@
+       return ret;
+ }
++#ifdef CONFIG_EXT3_INDEX
++static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
++                     struct ext3_dir_entry_2 **res_dir, int *err)
++{
++      struct super_block * sb;
++      struct dx_hash_info     hinfo;
++      u32 hash;
++      struct dx_frame frames[2], *frame;
++      struct ext3_dir_entry_2 *de, *top;
++      struct buffer_head *bh;
++      unsigned long block;
++      int retval;
++      int namelen = dentry->d_name.len;
++      const u8 *name = dentry->d_name.name;
++      struct inode *dir = dentry->d_parent->d_inode;
++      
++      sb = dir->i_sb;
++      if (!(frame = dx_probe (dentry, 0, &hinfo, frames, err)))
++              return NULL;
++      hash = hinfo.hash;
++      do {
++              block = dx_get_block(frame->at);
++              if (!(bh = ext3_bread (NULL,dir, block, 0, err)))
++                      goto errout;
++              de = (struct ext3_dir_entry_2 *) bh->b_data;
++              top = (struct ext3_dir_entry_2 *) ((char *) de + sb->s_blocksize -
++                                     EXT3_DIR_REC_LEN(0));
++              for (; de < top; de = ext3_next_entry(de))
++              if (ext3_match (namelen, name, de)) {
++                      if (!ext3_check_dir_entry("ext3_find_entry",
++                                                dir, de, bh,
++                                (block<<EXT3_BLOCK_SIZE_BITS(sb))
++                                        +((char *)de - bh->b_data))) {
++                              brelse (bh);
++                              goto errout;
++                      }
++                      *res_dir = de;
++                      dx_release (frames);
++                      return bh;
++              }
++              brelse (bh);
++              /* Check to see if we should continue to search */
++              retval = ext3_htree_next_block(dir, hash, frame,
++                                             frames, err, 0);
++              if (retval == -1) {
++                      ext3_warning(sb, __FUNCTION__,
++                           "error reading index page in directory #%lu",
++                           dir->i_ino);
++                      goto errout;
++              }
++      } while (retval == 1);
++      
++      *err = -ENOENT;
++errout:
++      dxtrace(printk("%s not found\n", name));
++      dx_release (frames);
++      return NULL;
++}
++#endif
++
+ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry)
+ {
+       struct inode * inode;
+@@ -212,8 +937,9 @@
+               brelse (bh);
+               inode = iget(dir->i_sb, ino);
+-              if (!inode)
++              if (!inode) {
+                       return ERR_PTR(-EACCES);
++              }
+       }
+       d_add(dentry, inode);
+       return NULL;
+@@ -237,6 +963,301 @@
+               de->file_type = ext3_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
+ }
++#ifdef CONFIG_EXT3_INDEX
++static struct ext3_dir_entry_2 *
++dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
++{
++      unsigned rec_len = 0;
++
++      while (count--) {
++              struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *) (from + map->offs);
++              rec_len = EXT3_DIR_REC_LEN(de->name_len);
++              memcpy (to, de, rec_len);
++              ((struct ext3_dir_entry_2 *)to)->rec_len = cpu_to_le16(rec_len);
++              de->inode = 0;
++              map++;
++              to += rec_len;
++      }
++      return (struct ext3_dir_entry_2 *) (to - rec_len);
++}
++
++static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size)
++{
++      struct ext3_dir_entry_2 *next, *to, *prev, *de = (struct ext3_dir_entry_2 *) base;
++      unsigned rec_len = 0;
++
++      prev = to = de;
++      while ((char*)de < base + size) {
++              next = (struct ext3_dir_entry_2 *) ((char *) de +
++                                                  le16_to_cpu(de->rec_len));
++              if (de->inode && de->name_len) {
++                      rec_len = EXT3_DIR_REC_LEN(de->name_len);
++                      if (de > to)
++                              memmove(to, de, rec_len);
++                      to->rec_len = cpu_to_le16(rec_len);
++                      prev = to;
++                      to = (struct ext3_dir_entry_2 *)((char *)to + rec_len);
++              }
++              de = next;
++      }
++      return prev;
++}
++
++static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
++                      struct buffer_head **bh,struct dx_frame *frame,
++                      struct dx_hash_info *hinfo, int *error)
++{
++      unsigned blocksize = dir->i_sb->s_blocksize;
++      unsigned count, continued;
++      struct buffer_head *bh2;
++      u32 newblock;
++      u32 hash2;
++      struct dx_map_entry *map;
++      char *data1 = (*bh)->b_data, *data2;
++      unsigned split;
++      struct ext3_dir_entry_2 *de = NULL, *de2;
++      int     err;
++
++      bh2 = ext3_append (handle, dir, &newblock, error);
++      if (!(bh2)) {
++              brelse(*bh);
++              *bh = NULL;
++              goto errout;
++      }
++
++      BUFFER_TRACE(*bh, "get_write_access");
++      err = ext3_journal_get_write_access(handle, *bh);
++      if (err) {
++      journal_error:
++              brelse(*bh);
++              brelse(bh2);
++              *bh = NULL;
++              ext3_std_error(dir->i_sb, err);
++              goto errout;
++      }
++      BUFFER_TRACE(frame->bh, "get_write_access");
++      err = ext3_journal_get_write_access(handle, frame->bh);
++      if (err)
++              goto journal_error;
++
++      data2 = bh2->b_data;
++
++      /* create map in the end of data2 block */
++      map = (struct dx_map_entry *) (data2 + blocksize);
++      count = dx_make_map ((struct ext3_dir_entry_2 *) data1,
++                           blocksize, hinfo, map);
++      map -= count;
++      split = count/2; // need to adjust to actual middle
++      dx_sort_map (map, count);
++      hash2 = map[split].hash;
++      continued = hash2 == map[split - 1].hash;
++      dxtrace(printk("Split block %i at %x, %i/%i\n",
++              dx_get_block(frame->at), hash2, split, count-split));
++
++      /* Fancy dance to stay within two buffers */
++      de2 = dx_move_dirents(data1, data2, map + split, count - split);
++      de = dx_pack_dirents(data1,blocksize);
++      de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
++      de2->rec_len = cpu_to_le16(data2 + blocksize - (char *) de2);
++      dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data1, blocksize, 1));
++      dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data2, blocksize, 1));
++
++      /* Which block gets the new entry? */
++      if (hinfo->hash >= hash2)
++      {
++              swap(*bh, bh2);
++              de = de2;
++      }
++      dx_insert_block (frame, hash2 + continued, newblock);
++      err = ext3_journal_dirty_metadata (handle, bh2);
++      if (err)
++              goto journal_error;
++      err = ext3_journal_dirty_metadata (handle, frame->bh);
++      if (err)
++              goto journal_error;
++      brelse (bh2);
++      dxtrace(dx_show_index ("frame", frame->entries));
++errout:
++      return de;
++}
++#endif
++
++
++/*
++ * Add a new entry into a directory (leaf) block.  If de is non-NULL,
++ * it points to a directory entry which is guaranteed to be large
++ * enough for new directory entry.  If de is NULL, then
++ * add_dirent_to_buf will attempt search the directory block for
++ * space.  It will return -ENOSPC if no space is available, and -EIO
++ * and -EEXIST if directory entry already exists.
++ * 
++ * NOTE!  bh is NOT released in the case where ENOSPC is returned.  In
++ * all other cases bh is released.
++ */
++static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
++                           struct inode *inode, struct ext3_dir_entry_2 *de,
++                           struct buffer_head * bh)
++{
++      struct inode    *dir = dentry->d_parent->d_inode;
++      const char      *name = dentry->d_name.name;
++      int             namelen = dentry->d_name.len;
++      unsigned long   offset = 0;
++      unsigned short  reclen;
++      int             nlen, rlen, err;
++      char            *top;
++      
++      reclen = EXT3_DIR_REC_LEN(namelen);
++      if (!de) {
++              de = (struct ext3_dir_entry_2 *)bh->b_data;
++              top = bh->b_data + dir->i_sb->s_blocksize - reclen;
++              while ((char *) de <= top) {
++                      if (!ext3_check_dir_entry("ext3_add_entry", dir, de,
++                                                bh, offset)) {
++                              brelse (bh);
++                              return -EIO;
++                      }
++                      if (ext3_match (namelen, name, de)) {
++                              brelse (bh);
++                              return -EEXIST;
++                      }
++                      nlen = EXT3_DIR_REC_LEN(de->name_len);
++                      rlen = le16_to_cpu(de->rec_len);
++                      if ((de->inode? rlen - nlen: rlen) >= reclen)
++                              break;
++                      de = (struct ext3_dir_entry_2 *)((char *)de + rlen);
++                      offset += rlen;
++              }
++              if ((char *) de > top)
++                      return -ENOSPC;
++      }
++      BUFFER_TRACE(bh, "get_write_access");
++      err = ext3_journal_get_write_access(handle, bh);
++      if (err) {
++              ext3_std_error(dir->i_sb, err);
++              brelse(bh);
++              return err;
++      }
++      
++      /* By now the buffer is marked for journaling */
++      nlen = EXT3_DIR_REC_LEN(de->name_len);
++      rlen = le16_to_cpu(de->rec_len);
++      if (de->inode) {
++              struct ext3_dir_entry_2 *de1 = (struct ext3_dir_entry_2 *)((char *)de + nlen);
++              de1->rec_len = cpu_to_le16(rlen - nlen);
++              de->rec_len = cpu_to_le16(nlen);
++              de = de1;
++      }
++      de->file_type = EXT3_FT_UNKNOWN;
++      if (inode) {
++              de->inode = cpu_to_le32(inode->i_ino);
++              ext3_set_de_type(dir->i_sb, de, inode->i_mode);
++      } else
++              de->inode = 0;
++      de->name_len = namelen;
++      memcpy (de->name, name, namelen);
++      /*
++       * XXX shouldn't update any times until successful
++       * completion of syscall, but too many callers depend
++       * on this.
++       *
++       * XXX similarly, too many callers depend on
++       * ext3_new_inode() setting the times, but error
++       * recovery deletes the inode, so the worst that can
++       * happen is that the times are slightly out of date
++       * and/or different from the directory change time.
++       */
++      dir->i_mtime = dir->i_ctime = CURRENT_TIME;
++      ext3_update_dx_flag(dir);
++      dir->i_version = ++event;
++      ext3_mark_inode_dirty(handle, dir);
++      BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
++      err = ext3_journal_dirty_metadata(handle, bh);
++      if (err)
++              ext3_std_error(dir->i_sb, err);
++      brelse(bh);
++      return 0;
++}
++
++#ifdef CONFIG_EXT3_INDEX
++/*
++ * This converts a one block unindexed directory to a 3 block indexed
++ * directory, and adds the dentry to the indexed directory.
++ */
++static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
++                          struct inode *inode, struct buffer_head *bh)
++{
++      struct inode    *dir = dentry->d_parent->d_inode;
++      const char      *name = dentry->d_name.name;
++      int             namelen = dentry->d_name.len;
++      struct buffer_head *bh2;
++      struct dx_root  *root;
++      struct dx_frame frames[2], *frame;
++      struct dx_entry *entries;
++      struct ext3_dir_entry_2 *de, *de2;
++      char            *data1, *top;
++      unsigned        len;
++      int             retval;
++      unsigned        blocksize;
++      struct dx_hash_info hinfo;
++      u32             block;
++              
++      blocksize =  dir->i_sb->s_blocksize;
++      dxtrace(printk("Creating index\n"));
++      retval = ext3_journal_get_write_access(handle, bh);
++      if (retval) {
++              ext3_std_error(dir->i_sb, retval);
++              brelse(bh);
++              return retval;
++      }
++      root = (struct dx_root *) bh->b_data;
++              
++      EXT3_I(dir)->i_flags |= EXT3_INDEX_FL;
++      bh2 = ext3_append (handle, dir, &block, &retval);
++      if (!(bh2)) {
++              brelse(bh);
++              return retval;
++      }
++      data1 = bh2->b_data;
++
++      /* The 0th block becomes the root, move the dirents out */
++      de = (struct ext3_dir_entry_2 *)&root->dotdot;
++      de = (struct ext3_dir_entry_2 *)((char *)de + le16_to_cpu(de->rec_len));
++      len = ((char *) root) + blocksize - (char *) de;
++      memcpy (data1, de, len);
++      de = (struct ext3_dir_entry_2 *) data1;
++      top = data1 + len;
++      while (((char *) de2=(char*)de+le16_to_cpu(de->rec_len)) < top)
++              de = de2;
++      de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
++      /* Initialize the root; the dot dirents already exist */
++      de = (struct ext3_dir_entry_2 *) (&root->dotdot);
++      de->rec_len = cpu_to_le16(blocksize - EXT3_DIR_REC_LEN(2));
++      memset (&root->info, 0, sizeof(root->info));
++      root->info.info_length = sizeof(root->info);
++      root->info.hash_version = dir->i_sb->u.ext3_sb.s_def_hash_version;
++      entries = root->entries;
++      dx_set_block (entries, 1);
++      dx_set_count (entries, 1);
++      dx_set_limit (entries, dx_root_limit(dir, sizeof(root->info)));
++
++      /* Initialize as for dx_probe */
++      hinfo.hash_version = root->info.hash_version;
++      hinfo.seed = dir->i_sb->u.ext3_sb.s_hash_seed;
++      ext3fs_dirhash(name, namelen, &hinfo);
++      frame = frames;
++      frame->entries = entries;
++      frame->at = entries;
++      frame->bh = bh;
++      bh = bh2;
++      de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
++      dx_release (frames);
++      if (!(de))
++              return retval;
++
++      return add_dirent_to_buf(handle, dentry, inode, de, bh);
++}
++#endif
++
+ /*
+  *    ext3_add_entry()
+  *
+@@ -247,127 +1268,198 @@
+  * may not sleep between calling this and putting something into
+  * the entry, as someone else might have used it while you slept.
+  */
+-
+-/*
+- * AKPM: the journalling code here looks wrong on the error paths
+- */
+ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
+       struct inode *inode)
+ {
+       struct inode *dir = dentry->d_parent->d_inode;
+-      const char *name = dentry->d_name.name;
+-      int namelen = dentry->d_name.len;
+       unsigned long offset;
+-      unsigned short rec_len;
+       struct buffer_head * bh;
+-      struct ext3_dir_entry_2 * de, * de1;
++      struct ext3_dir_entry_2 *de;
+       struct super_block * sb;
+       int     retval;
++#ifdef CONFIG_EXT3_INDEX
++      int     dx_fallback=0;
++#endif
++      unsigned blocksize;
++      unsigned nlen, rlen;
++      u32 block, blocks;
+       sb = dir->i_sb;
+-
+-      if (!namelen)
++      blocksize = sb->s_blocksize;
++      if (!dentry->d_name.len)
+               return -EINVAL;
+-      bh = ext3_bread (handle, dir, 0, 0, &retval);
++#ifdef CONFIG_EXT3_INDEX
++      if (is_dx(dir)) {
++              retval = ext3_dx_add_entry(handle, dentry, inode);
++              if (!retval || (retval != ERR_BAD_DX_DIR))
++                      return retval;
++              EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
++              dx_fallback++;
++              ext3_mark_inode_dirty(handle, dir);
++      }
++#endif
++      blocks = dir->i_size >> sb->s_blocksize_bits;
++      for (block = 0, offset = 0; block < blocks; block++) {
++              bh = ext3_bread(handle, dir, block, 0, &retval);
++              if(!bh)
++                      return retval;
++              retval = add_dirent_to_buf(handle, dentry, inode, 0, bh);
++              if (retval != -ENOSPC)
++                      return retval;
++
++#ifdef CONFIG_EXT3_INDEX
++              if (blocks == 1 && !dx_fallback &&
++                  EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX))
++                      return make_indexed_dir(handle, dentry, inode, bh);
++#endif
++              brelse(bh);
++      }
++      bh = ext3_append(handle, dir, &block, &retval);
+       if (!bh)
+               return retval;
+-      rec_len = EXT3_DIR_REC_LEN(namelen);
+-      offset = 0;
+       de = (struct ext3_dir_entry_2 *) bh->b_data;
+-      while (1) {
+-              if ((char *)de >= sb->s_blocksize + bh->b_data) {
+-                      brelse (bh);
+-                      bh = NULL;
+-                      bh = ext3_bread (handle, dir,
+-                              offset >> EXT3_BLOCK_SIZE_BITS(sb), 1, &retval);
+-                      if (!bh)
+-                              return retval;
+-                      if (dir->i_size <= offset) {
+-                              if (dir->i_size == 0) {
+-                                      brelse(bh);
+-                                      return -ENOENT;
+-                              }
++      de->inode = 0;
++      de->rec_len = cpu_to_le16(rlen = blocksize);
++      nlen = 0;
++      return add_dirent_to_buf(handle, dentry, inode, de, bh);
++}
+-                              ext3_debug ("creating next block\n");
++#ifdef CONFIG_EXT3_INDEX
++/*
++ * Returns 0 for success, or a negative error value
++ */
++static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
++                           struct inode *inode)
++{
++      struct dx_frame frames[2], *frame;
++      struct dx_entry *entries, *at;
++      struct dx_hash_info hinfo;
++      struct buffer_head * bh;
++      struct inode *dir = dentry->d_parent->d_inode;
++      struct super_block * sb = dir->i_sb;
++      struct ext3_dir_entry_2 *de;
++      int err;
+-                              BUFFER_TRACE(bh, "get_write_access");
+-                              ext3_journal_get_write_access(handle, bh);
+-                              de = (struct ext3_dir_entry_2 *) bh->b_data;
+-                              de->inode = 0;
+-                              de->rec_len = le16_to_cpu(sb->s_blocksize);
+-                              dir->u.ext3_i.i_disksize =
+-                                      dir->i_size = offset + sb->s_blocksize;
+-                              dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+-                              ext3_mark_inode_dirty(handle, dir);
+-                      } else {
++      frame = dx_probe(dentry, 0, &hinfo, frames, &err);
++      if (!frame)
++              return err;
++      entries = frame->entries;
++      at = frame->at;
+-                              ext3_debug ("skipping to next block\n");
++      if (!(bh = ext3_bread(handle,dir, dx_get_block(frame->at), 0, &err)))
++              goto cleanup;
+-                              de = (struct ext3_dir_entry_2 *) bh->b_data;
+-                      }
+-              }
+-              if (!ext3_check_dir_entry ("ext3_add_entry", dir, de, bh,
+-                                         offset)) {
+-                      brelse (bh);
+-                      return -ENOENT;
+-              }
+-              if (ext3_match (namelen, name, de)) {
+-                              brelse (bh);
+-                              return -EEXIST;
++      BUFFER_TRACE(bh, "get_write_access");
++      err = ext3_journal_get_write_access(handle, bh);
++      if (err)
++              goto journal_error;
++
++      err = add_dirent_to_buf(handle, dentry, inode, 0, bh);
++      if (err != -ENOSPC) {
++              bh = 0;
++              goto cleanup;
++      }
++
++      /* Block full, should compress but for now just split */
++      dxtrace(printk("using %u of %u node entries\n",
++                     dx_get_count(entries), dx_get_limit(entries)));
++      /* Need to split index? */
++      if (dx_get_count(entries) == dx_get_limit(entries)) {
++              u32 newblock;
++              unsigned icount = dx_get_count(entries);
++              int levels = frame - frames;
++              struct dx_entry *entries2;
++              struct dx_node *node2;
++              struct buffer_head *bh2;
++
++              if (levels && (dx_get_count(frames->entries) ==
++                             dx_get_limit(frames->entries))) {
++                      ext3_warning(sb, __FUNCTION__,
++                                   "Directory index full!\n");
++                      err = -ENOSPC;
++                      goto cleanup;
+               }
+-              if ((le32_to_cpu(de->inode) == 0 &&
+-                              le16_to_cpu(de->rec_len) >= rec_len) ||
+-                  (le16_to_cpu(de->rec_len) >=
+-                              EXT3_DIR_REC_LEN(de->name_len) + rec_len)) {
+-                      BUFFER_TRACE(bh, "get_write_access");
+-                      ext3_journal_get_write_access(handle, bh);
+-                      /* By now the buffer is marked for journaling */
+-                      offset += le16_to_cpu(de->rec_len);
+-                      if (le32_to_cpu(de->inode)) {
+-                              de1 = (struct ext3_dir_entry_2 *) ((char *) de +
+-                                      EXT3_DIR_REC_LEN(de->name_len));
+-                              de1->rec_len =
+-                                      cpu_to_le16(le16_to_cpu(de->rec_len) -
+-                                      EXT3_DIR_REC_LEN(de->name_len));
+-                              de->rec_len = cpu_to_le16(
+-                                              EXT3_DIR_REC_LEN(de->name_len));
+-                              de = de1;
++              bh2 = ext3_append (handle, dir, &newblock, &err);
++              if (!(bh2))
++                      goto cleanup;
++              node2 = (struct dx_node *)(bh2->b_data);
++              entries2 = node2->entries;
++              node2->fake.rec_len = cpu_to_le16(sb->s_blocksize);
++              node2->fake.inode = 0;
++              BUFFER_TRACE(frame->bh, "get_write_access");
++              err = ext3_journal_get_write_access(handle, frame->bh);
++              if (err)
++                      goto journal_error;
++              if (levels) {
++                      unsigned icount1 = icount/2, icount2 = icount - icount1;
++                      unsigned hash2 = dx_get_hash(entries + icount1);
++                      dxtrace(printk("Split index %i/%i\n", icount1, icount2));
++                              
++                      BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */
++                      err = ext3_journal_get_write_access(handle,
++                                                           frames[0].bh);
++                      if (err)
++                              goto journal_error;
++                              
++                      memcpy ((char *) entries2, (char *) (entries + icount1),
++                              icount2 * sizeof(struct dx_entry));
++                      dx_set_count (entries, icount1);
++                      dx_set_count (entries2, icount2);
++                      dx_set_limit (entries2, dx_node_limit(dir));
++
++                      /* Which index block gets the new entry? */
++                      if (at - entries >= icount1) {
++                              frame->at = at = at - entries - icount1 + entries2;
++                              frame->entries = entries = entries2;
++                              swap(frame->bh, bh2);
+                       }
+-                      de->file_type = EXT3_FT_UNKNOWN;
+-                      if (inode) {
+-                              de->inode = cpu_to_le32(inode->i_ino);
+-                              ext3_set_de_type(dir->i_sb, de, inode->i_mode);
+-                      } else
+-                              de->inode = 0;
+-                      de->name_len = namelen;
+-                      memcpy (de->name, name, namelen);
+-                      /*
+-                       * XXX shouldn't update any times until successful
+-                       * completion of syscall, but too many callers depend
+-                       * on this.
+-                       *
+-                       * XXX similarly, too many callers depend on
+-                       * ext3_new_inode() setting the times, but error
+-                       * recovery deletes the inode, so the worst that can
+-                       * happen is that the times are slightly out of date
+-                       * and/or different from the directory change time.
+-                       */
+-                      dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+-                      dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
+-                      dir->i_version = ++event;
+-                      ext3_mark_inode_dirty(handle, dir);
+-                      BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
+-                      ext3_journal_dirty_metadata(handle, bh);
+-                      brelse(bh);
+-                      return 0;
++                      dx_insert_block (frames + 0, hash2, newblock);
++                      dxtrace(dx_show_index ("node", frames[1].entries));
++                      dxtrace(dx_show_index ("node",
++                             ((struct dx_node *) bh2->b_data)->entries));
++                      err = ext3_journal_dirty_metadata(handle, bh2);
++                      if (err)
++                              goto journal_error;
++                      brelse (bh2);
++              } else {
++                      dxtrace(printk("Creating second level index...\n"));
++                      memcpy((char *) entries2, (char *) entries,
++                             icount * sizeof(struct dx_entry));
++                      dx_set_limit(entries2, dx_node_limit(dir));
++
++                      /* Set up root */
++                      dx_set_count(entries, 1);
++                      dx_set_block(entries + 0, newblock);
++                      ((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1;
++
++                      /* Add new access path frame */
++                      frame = frames + 1;
++                      frame->at = at = at - entries + entries2;
++                      frame->entries = entries = entries2;
++                      frame->bh = bh2;
++                      err = ext3_journal_get_write_access(handle,
++                                                           frame->bh);
++                      if (err)
++                              goto journal_error;
+               }
+-              offset += le16_to_cpu(de->rec_len);
+-              de = (struct ext3_dir_entry_2 *)
+-                      ((char *) de + le16_to_cpu(de->rec_len));
++              ext3_journal_dirty_metadata(handle, frames[0].bh);
+       }
+-      brelse (bh);
+-      return -ENOSPC;
++      de = do_split(handle, dir, &bh, frame, &hinfo, &err);
++      if (!de)
++              goto cleanup;
++      err = add_dirent_to_buf(handle, dentry, inode, de, bh);
++      bh = 0;
++      goto cleanup;
++      
++journal_error:
++      ext3_std_error(dir->i_sb, err);
++cleanup:
++      if (bh)
++              brelse(bh);
++      dx_release(frames);
++      return err;
+ }
++#endif
+ /*
+  * ext3_delete_entry deletes a directory entry by merging it with the
+@@ -454,9 +1546,11 @@
+       struct inode * inode;
+       int err;
+-      handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 3);
+-      if (IS_ERR(handle))
++      handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
++                                      EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3);
++      if (IS_ERR(handle)) {
+               return PTR_ERR(handle);
++      }
+       if (IS_SYNC(dir))
+               handle->h_sync = 1;
+@@ -480,9 +1574,11 @@
+       struct inode *inode;
+       int err;
+-      handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 3);
+-      if (IS_ERR(handle))
++      handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
++                                      EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3);
++      if (IS_ERR(handle)) {
+               return PTR_ERR(handle);
++      }
+       if (IS_SYNC(dir))
+               handle->h_sync = 1;
+@@ -508,9 +1604,11 @@
+       if (dir->i_nlink >= EXT3_LINK_MAX)
+               return -EMLINK;
+-      handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 3);
+-      if (IS_ERR(handle))
++      handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
++                                      EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3);
++      if (IS_ERR(handle)) {
+               return PTR_ERR(handle);
++      }
+       if (IS_SYNC(dir))
+               handle->h_sync = 1;
+@@ -522,7 +1620,7 @@
+       inode->i_op = &ext3_dir_inode_operations;
+       inode->i_fop = &ext3_dir_operations;
+-      inode->i_size = inode->u.ext3_i.i_disksize = inode->i_sb->s_blocksize;
++      inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
+       inode->i_blocks = 0;    
+       dir_block = ext3_bread (handle, inode, 0, 1, &err);
+       if (!dir_block) {
+@@ -555,21 +1653,19 @@
+               inode->i_mode |= S_ISGID;
+       ext3_mark_inode_dirty(handle, inode);
+       err = ext3_add_entry (handle, dentry, inode);
+-      if (err)
+-              goto out_no_entry;
++      if (err) {
++              inode->i_nlink = 0;
++              ext3_mark_inode_dirty(handle, inode);
++              iput (inode);
++              goto out_stop;
++      }
+       dir->i_nlink++;
+-      dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
++      ext3_update_dx_flag(dir);
+       ext3_mark_inode_dirty(handle, dir);
+       d_instantiate(dentry, inode);
+ out_stop:
+       ext3_journal_stop(handle, dir);
+       return err;
+-
+-out_no_entry:
+-      inode->i_nlink = 0;
+-      ext3_mark_inode_dirty(handle, inode);
+-      iput (inode);
+-      goto out_stop;
+ }
+ /*
+@@ -656,7 +1752,7 @@
+       int err = 0, rc;
+       
+       lock_super(sb);
+-      if (!list_empty(&inode->u.ext3_i.i_orphan))
++      if (!list_empty(&EXT3_I(inode)->i_orphan))
+               goto out_unlock;
+       /* Orphan handling is only valid for files with data blocks
+@@ -697,7 +1793,7 @@
+        * This is safe: on error we're going to ignore the orphan list
+        * anyway on the next recovery. */
+       if (!err)
+-              list_add(&inode->u.ext3_i.i_orphan, &EXT3_SB(sb)->s_orphan);
++              list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan);
+       jbd_debug(4, "superblock will point to %ld\n", inode->i_ino);
+       jbd_debug(4, "orphan inode %ld will point to %d\n",
+@@ -715,25 +1811,26 @@
+ int ext3_orphan_del(handle_t *handle, struct inode *inode)
+ {
+       struct list_head *prev;
++      struct ext3_inode_info *ei = EXT3_I(inode);
+       struct ext3_sb_info *sbi;
+       unsigned long ino_next;
+       struct ext3_iloc iloc;
+       int err = 0;
+       lock_super(inode->i_sb);
+-      if (list_empty(&inode->u.ext3_i.i_orphan)) {
++      if (list_empty(&ei->i_orphan)) {
+               unlock_super(inode->i_sb);
+               return 0;
+       }
+       ino_next = NEXT_ORPHAN(inode);
+-      prev = inode->u.ext3_i.i_orphan.prev;
++      prev = ei->i_orphan.prev;
+       sbi = EXT3_SB(inode->i_sb);
+       jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino);
+-      list_del(&inode->u.ext3_i.i_orphan);
+-      INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
++      list_del(&ei->i_orphan);
++      INIT_LIST_HEAD(&ei->i_orphan);
+       /* If we're on an error path, we may not have a valid
+        * transaction handle with which to update the orphan list on
+@@ -794,8 +1891,9 @@
+       handle_t *handle;
+       handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
+-      if (IS_ERR(handle))
++      if (IS_ERR(handle)) {
+               return PTR_ERR(handle);
++      }
+       retval = -ENOENT;
+       bh = ext3_find_entry (dentry, &de);
+@@ -833,7 +1931,7 @@
+       dir->i_nlink--;
+       inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+       ext3_mark_inode_dirty(handle, inode);
+-      dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
++      ext3_update_dx_flag(dir);
+       ext3_mark_inode_dirty(handle, dir);
+ end_rmdir:
+@@ -851,8 +1949,9 @@
+       handle_t *handle;
+       handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
+-      if (IS_ERR(handle))
++      if (IS_ERR(handle)) {
+               return PTR_ERR(handle);
++      }
+       if (IS_SYNC(dir))
+               handle->h_sync = 1;
+@@ -879,7 +1978,7 @@
+       if (retval)
+               goto end_unlink;
+       dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+-      dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
++      ext3_update_dx_flag(dir);
+       ext3_mark_inode_dirty(handle, dir);
+       inode->i_nlink--;
+       if (!inode->i_nlink)
+@@ -905,9 +2004,11 @@
+       if (l > dir->i_sb->s_blocksize)
+               return -ENAMETOOLONG;
+-      handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 5);
+-      if (IS_ERR(handle))
++      handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
++                                      EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5);
++      if (IS_ERR(handle)) {
+               return PTR_ERR(handle);
++      }
+       if (IS_SYNC(dir))
+               handle->h_sync = 1;
+@@ -917,7 +2018,7 @@
+       if (IS_ERR(inode))
+               goto out_stop;
+-      if (l > sizeof (inode->u.ext3_i.i_data)) {
++      if (l > sizeof (EXT3_I(inode)->i_data)) {
+               inode->i_op = &page_symlink_inode_operations;
+               inode->i_mapping->a_ops = &ext3_aops;
+               /*
+@@ -926,24 +2027,22 @@
+                * i_size in generic_commit_write().
+                */
+               err = block_symlink(inode, symname, l);
+-              if (err)
+-                      goto out_no_entry;
++              if (err) {
++                      ext3_dec_count(handle, inode);
++                      ext3_mark_inode_dirty(handle, inode);
++                      iput (inode);
++                      goto out_stop;
++              }
+       } else {
+               inode->i_op = &ext3_fast_symlink_inode_operations;
+-              memcpy((char*)&inode->u.ext3_i.i_data,symname,l);
++              memcpy((char*)&EXT3_I(inode)->i_data,symname,l);
+               inode->i_size = l-1;
+       }
+-      inode->u.ext3_i.i_disksize = inode->i_size;
++      EXT3_I(inode)->i_disksize = inode->i_size;
+       err = ext3_add_nondir(handle, dentry, inode);
+ out_stop:
+       ext3_journal_stop(handle, dir);
+       return err;
+-
+-out_no_entry:
+-      ext3_dec_count(handle, inode);
+-      ext3_mark_inode_dirty(handle, inode);
+-      iput (inode);
+-      goto out_stop;
+ }
+ static int ext3_link (struct dentry * old_dentry,
+@@ -956,12 +2055,15 @@
+       if (S_ISDIR(inode->i_mode))
+               return -EPERM;
+-      if (inode->i_nlink >= EXT3_LINK_MAX)
++      if (inode->i_nlink >= EXT3_LINK_MAX) {
+               return -EMLINK;
++      }
+-      handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS);
+-      if (IS_ERR(handle))
++      handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
++                                      EXT3_INDEX_EXTRA_TRANS_BLOCKS);
++      if (IS_ERR(handle)) {
+               return PTR_ERR(handle);
++      }
+       if (IS_SYNC(dir))
+               handle->h_sync = 1;
+@@ -994,9 +2096,11 @@
+       old_bh = new_bh = dir_bh = NULL;
+-      handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS + 2);
+-      if (IS_ERR(handle))
++      handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS +
++                                      EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2);
++      if (IS_ERR(handle)) {
+               return PTR_ERR(handle);
++      }
+       if (IS_SYNC(old_dir) || IS_SYNC(new_dir))
+               handle->h_sync = 1;
+@@ -1069,14 +2173,37 @@
+       /*
+        * ok, that's it
+        */
+-      ext3_delete_entry(handle, old_dir, old_de, old_bh);
++      if (le32_to_cpu(old_de->inode) != old_inode->i_ino ||
++          old_de->name_len != old_dentry->d_name.len ||
++          strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) ||
++          (retval = ext3_delete_entry(handle, old_dir,
++                                      old_de, old_bh)) == -ENOENT) {
++              /* old_de could have moved from under us during htree split, so
++               * make sure that we are deleting the right entry.  We might
++               * also be pointing to a stale entry in the unused part of
++               * old_bh so just checking inum and the name isn't enough. */
++              struct buffer_head *old_bh2;
++              struct ext3_dir_entry_2 *old_de2;
++
++              old_bh2 = ext3_find_entry(old_dentry, &old_de2);
++              if (old_bh2) {
++                      retval = ext3_delete_entry(handle, old_dir,
++                                                 old_de2, old_bh2);
++                      brelse(old_bh2);
++              }
++      }
++      if (retval) {
++              ext3_warning(old_dir->i_sb, "ext3_rename",
++                              "Deleting old file (%lu), %d, error=%d",
++                              old_dir->i_ino, old_dir->i_nlink, retval);
++      }
+       if (new_inode) {
+               new_inode->i_nlink--;
+               new_inode->i_ctime = CURRENT_TIME;
+       }
+       old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+-      old_dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
++      ext3_update_dx_flag(old_dir);
+       if (dir_bh) {
+               BUFFER_TRACE(dir_bh, "get_write_access");
+               ext3_journal_get_write_access(handle, dir_bh);
+@@ -1088,7 +2215,7 @@
+                       new_inode->i_nlink--;
+               } else {
+                       new_dir->i_nlink++;
+-                      new_dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
++                      ext3_update_dx_flag(new_dir);
+                       ext3_mark_inode_dirty(handle, new_dir);
+               }
+       }
+Index: linux-2.4.29/fs/ext3/super.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/super.c  2005-04-07 18:59:19.000000000 +0300
++++ linux-2.4.29/fs/ext3/super.c       2005-05-03 16:29:50.580498544 +0300
+@@ -712,6 +712,7 @@
+       es->s_mtime = cpu_to_le32(CURRENT_TIME);
+       ext3_update_dynamic_rev(sb);
+       EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
++
+       ext3_commit_super (sb, es, 1);
+       if (test_opt (sb, DEBUG))
+               printk (KERN_INFO
+@@ -722,6 +723,7 @@
+                       EXT3_BLOCKS_PER_GROUP(sb),
+                       EXT3_INODES_PER_GROUP(sb),
+                       sbi->s_mount_opt);
++
+       printk(KERN_INFO "EXT3 FS " EXT3FS_VERSION ", " EXT3FS_DATE " on %s, ",
+                               bdevname(sb->s_dev));
+       if (EXT3_SB(sb)->s_journal->j_inode == NULL) {
+@@ -915,6 +917,7 @@
+       return res;
+ }
++
+ struct super_block * ext3_read_super (struct super_block * sb, void * data,
+                                     int silent)
+ {
+@@ -1094,6 +1097,9 @@
+       sbi->s_mount_state = le16_to_cpu(es->s_state);
+       sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb));
+       sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb));
++      for (i=0; i < 4; i++)
++              sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
++      sbi->s_def_hash_version = es->s_def_hash_version;
+       if (sbi->s_blocks_per_group > blocksize * 8) {
+               printk (KERN_ERR
+@@ -1845,6 +1851,7 @@
+       unregister_filesystem(&ext3_fs_type);
+ }
++EXPORT_SYMBOL(ext3_force_commit);
+ EXPORT_SYMBOL(ext3_bread);
+ MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
+Index: linux-2.4.29/include/linux/ext3_fs.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext3_fs.h  2005-04-07 18:52:26.000000000 +0300
++++ linux-2.4.29/include/linux/ext3_fs.h       2005-05-03 16:29:50.584497936 +0300
+@@ -40,6 +40,11 @@
+ #define EXT3FS_VERSION                "2.4-0.9.19"
+ /*
++ * Always enable hashed directories
++ */
++#define CONFIG_EXT3_INDEX
++
++/*
+  * Debug code
+  */
+ #ifdef EXT3FS_DEBUG
+@@ -593,9 +598,46 @@
+ #define EXT3_DIR_ROUND                        (EXT3_DIR_PAD - 1)
+ #define EXT3_DIR_REC_LEN(name_len)    (((name_len) + 8 + EXT3_DIR_ROUND) & \
+                                        ~EXT3_DIR_ROUND)
++/*
++ * Hash Tree Directory indexing
++ * (c) Daniel Phillips, 2001
++ */
++
++#ifdef CONFIG_EXT3_INDEX
++  #define is_dx(dir) (EXT3_HAS_COMPAT_FEATURE(dir->i_sb, \
++                                            EXT3_FEATURE_COMPAT_DIR_INDEX) && \
++                    (EXT3_I(dir)->i_flags & EXT3_INDEX_FL))
++#define EXT3_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT3_LINK_MAX)
++#define EXT3_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
++#else
++  #define is_dx(dir) 0
++#define EXT3_DIR_LINK_MAX(dir) ((dir)->i_nlink >= EXT3_LINK_MAX)
++#define EXT3_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2)
++#endif
++
++/* Legal values for the dx_root hash_version field: */
++
++#define DX_HASH_LEGACY                0
++#define DX_HASH_HALF_MD4      1
++#define DX_HASH_TEA           2
++
++/* hash info structure used by the directory hash */
++struct dx_hash_info
++{
++      u32             hash;
++      u32             minor_hash;
++      int             hash_version;
++      u32             *seed;
++};
+ #ifdef __KERNEL__
+ /*
++ * Control parameters used by ext3_htree_next_block
++ */
++#define HASH_NB_ALWAYS                1
++
++
++/*
+  * Describe an inode's exact location on disk and in memory
+  */
+ struct ext3_iloc
+@@ -605,6 +647,27 @@
+       unsigned long block_group;
+ };
++
++/*
++ * This structure is stuffed into the struct file's private_data field
++ * for directories.  It is where we put information so that we can do
++ * readdir operations in hash tree order.
++ */
++struct dir_private_info {
++      rb_root_t       root;
++      rb_node_t       *curr_node;
++      struct fname    *extra_fname;
++      loff_t          last_pos;
++      __u32           curr_hash;
++      __u32           curr_minor_hash;
++      __u32           next_hash;
++};
++
++/*
++ * Special error return code only used by dx_probe() and its callers.
++ */
++#define ERR_BAD_DX_DIR        -75000
++
+ /*
+  * Function prototypes
+  */
+@@ -632,11 +695,20 @@
+ /* dir.c */
+ extern int ext3_check_dir_entry(const char *, struct inode *,
+-                              struct ext3_dir_entry_2 *, struct buffer_head *,
+-                              unsigned long);
++                              struct ext3_dir_entry_2 *,
++                              struct buffer_head *, unsigned long);
++extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
++                                  __u32 minor_hash,
++                                  struct ext3_dir_entry_2 *dirent);
++extern void ext3_htree_free_dir_info(struct dir_private_info *p);
++
+ /* fsync.c */
+ extern int ext3_sync_file (struct file *, struct dentry *, int);
++/* hash.c */
++extern int ext3fs_dirhash(const char *name, int len, struct
++                        dx_hash_info *hinfo);
++
+ /* ialloc.c */
+ extern struct inode * ext3_new_inode (handle_t *, const struct inode *, int);
+ extern void ext3_free_inode (handle_t *, struct inode *);
+@@ -669,6 +741,8 @@
+ /* namei.c */
+ extern int ext3_orphan_add(handle_t *, struct inode *);
+ extern int ext3_orphan_del(handle_t *, struct inode *);
++extern int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash,
++                              __u32 start_minor_hash, __u32 *next_hash);
+ /* super.c */
+ extern void ext3_error (struct super_block *, const char *, const char *, ...)
+Index: linux-2.4.29/include/linux/ext3_fs_sb.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext3_fs_sb.h       2005-04-07 18:54:55.000000000 +0300
++++ linux-2.4.29/include/linux/ext3_fs_sb.h    2005-05-03 16:29:50.586497632 +0300
+@@ -62,6 +62,8 @@
+       int s_inode_size;
+       int s_first_ino;
+       u32 s_next_generation;
++      u32 s_hash_seed[4];
++      int s_def_hash_version;
+       /* Journaling */
+       struct inode * s_journal_inode;
+Index: linux-2.4.29/include/linux/ext3_jbd.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext3_jbd.h 2005-04-07 18:52:32.000000000 +0300
++++ linux-2.4.29/include/linux/ext3_jbd.h      2005-05-03 16:29:50.587497480 +0300
+@@ -63,6 +63,8 @@
+ #define EXT3_RESERVE_TRANS_BLOCKS     12U
++#define EXT3_INDEX_EXTRA_TRANS_BLOCKS 8
++
+ int
+ ext3_mark_iloc_dirty(handle_t *handle, 
+                    struct inode *inode,
diff --git a/lustre/kernel_patches/patches/invalidate_show-2.4.29.patch b/lustre/kernel_patches/patches/invalidate_show-2.4.29.patch
new file mode 100644 (file)
index 0000000..dedc90b
--- /dev/null
@@ -0,0 +1,107 @@
+Index: linux-2.4.29/fs/inode.c
+===================================================================
+--- linux-2.4.29.orig/fs/inode.c       2005-04-07 18:55:16.732416736 +0300
++++ linux-2.4.29/fs/inode.c    2005-04-07 19:16:46.772300864 +0300
+@@ -670,7 +670,8 @@
+ /*
+  * 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;
+@@ -695,6 +696,11 @@
+                       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 */
+@@ -719,17 +725,17 @@
+  *    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);
+-      busy = invalidate_list(&inode_in_use, sb, &throw_away);
+-      busy |= invalidate_list(&inode_unused, sb, &throw_away);
+-      busy |= invalidate_list(&inode_unused_pagecache, 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(&inode_unused_pagecache, 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);
+@@ -755,7 +761,7 @@
+                * hold).
+                */
+               shrink_dcache_sb(sb);
+-              res = invalidate_inodes(sb);
++              res = invalidate_inodes(sb, 0);
+               drop_super(sb);
+       }
+       invalidate_buffers(dev);
+Index: linux-2.4.29/fs/super.c
+===================================================================
+--- linux-2.4.29.orig/fs/super.c       2005-04-07 18:53:30.978493776 +0300
++++ linux-2.4.29/fs/super.c    2005-04-07 19:14:26.187672976 +0300
+@@ -844,7 +844,7 @@
+       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);
+@@ -853,7 +853,7 @@
+       }
+       /* 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");
+       }
+Index: linux-2.4.29/include/linux/fs.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/fs.h       2005-04-07 19:14:06.319693368 +0300
++++ linux-2.4.29/include/linux/fs.h    2005-04-07 19:14:26.190672520 +0300
+@@ -1286,7 +1286,7 @@
+ extern int get_buffer_flushtime(void);
+ 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 *);
+Index: linux-2.4.29/fs/smbfs/inode.c
+===================================================================
+--- linux-2.4.29.orig/fs/smbfs/inode.c 2005-04-07 18:52:37.889564520 +0300
++++ linux-2.4.29/fs/smbfs/inode.c      2005-04-07 19:14:26.192672216 +0300
+@@ -175,7 +175,7 @@
+ {
+       VERBOSE("\n");
+       shrink_dcache_sb(SB_of(server));
+-      invalidate_inodes(SB_of(server));
++      invalidate_inodes(SB_of(server), 0);
+ }
+ /*
diff --git a/lustre/kernel_patches/patches/linux-2.4.29-xattr-0.8.54.patch b/lustre/kernel_patches/patches/linux-2.4.29-xattr-0.8.54.patch
new file mode 100644 (file)
index 0000000..8225ea3
--- /dev/null
@@ -0,0 +1,5362 @@
+Index: linux-2.4.29/Documentation/Configure.help
+===================================================================
+--- linux-2.4.29.orig/Documentation/Configure.help     2005-04-07 18:55:00.000000000 +0300
++++ linux-2.4.29/Documentation/Configure.help  2005-05-03 17:59:40.363127040 +0300
+@@ -16679,6 +16679,39 @@
+   be compiled as a module, and so this could be dangerous.  Most
+   everyone wants to say Y here.
++Ext2 extended attributes
++CONFIG_EXT2_FS_XATTR
++  Extended attributes are name:value pairs associated with inodes by
++  the kernel or by users (see the attr(5) manual page, or visit
++  <http://acl.bestbits.at/> for details).
++
++  If unsure, say N.
++
++Ext2 extended attribute block sharing
++CONFIG_EXT2_FS_XATTR_SHARING
++  This options enables code for sharing identical extended attribute
++  blocks among multiple inodes.
++
++  Usually, say Y.
++
++Ext2 extended user attributes
++CONFIG_EXT2_FS_XATTR_USER
++  This option enables extended user attributes on ext2. Processes can
++  associate extended user attributes with inodes to store additional
++  information such as the character encoding of files, etc. (see the
++  attr(5) manual page, or visit <http://acl.bestbits.at/> for details).
++
++  If unsure, say N.
++
++Ext2 trusted extended attributes
++CONFIG_EXT2_FS_XATTR_TRUSTED
++  This option enables extended attributes on ext2 that are accessible
++  (and visible) only to users capable of CAP_SYS_ADMIN. Usually this
++  is only the super user. Trusted extended attributes are meant for
++  implementing system/security services.
++
++  If unsure, say N.
++
+ Ext3 journalling file system support (EXPERIMENTAL)
+ CONFIG_EXT3_FS
+   This is the journalling version of the Second extended file system
+@@ -16711,6 +16744,39 @@
+   of your root partition (the one containing the directory /) cannot
+   be compiled as a module, and so this may be dangerous.
++Ext3 extended attributes
++CONFIG_EXT3_FS_XATTR
++  Extended attributes are name:value pairs associated with inodes by
++  the kernel or by users (see the attr(5) manual page, or visit
++  <http://acl.bestbits.at/> for details).
++
++  If unsure, say N.
++
++Ext3 extended attribute block sharing
++CONFIG_EXT3_FS_XATTR_SHARING
++  This options enables code for sharing identical extended attribute
++  blocks among multiple inodes.
++
++  Usually, say Y.
++
++Ext3 extended user attributes
++CONFIG_EXT3_FS_XATTR_USER
++  This option enables extended user attributes on ext3. Processes can
++  associate extended user attributes with inodes to store additional
++  information such as the character encoding of files, etc. (see the
++  attr(5) manual page, or visit <http://acl.bestbits.at/> for details).
++
++  If unsure, say N.
++
++Ext3 trusted extended attributes
++CONFIG_EXT3_FS_XATTR_TRUSTED
++  This option enables extended attributes on ext3 that are accessible
++  (and visible) only to users capable of CAP_SYS_ADMIN. Usually this
++  is only the super user. Trusted extended attributes are meant for
++  implementing system/security services.
++
++  If unsure, say N.
++
+ Journal Block Device support (JBD for ext3) (EXPERIMENTAL)
+ CONFIG_JBD
+   This is a generic journalling layer for block devices.  It is
+Index: linux-2.4.29/arch/alpha/defconfig
+===================================================================
+--- linux-2.4.29.orig/arch/alpha/defconfig     2005-04-07 18:53:42.000000000 +0300
++++ linux-2.4.29/arch/alpha/defconfig  2005-05-03 17:59:40.365126736 +0300
+@@ -1,6 +1,13 @@
+ #
+ # Automatically generated make config: don't edit
+ #
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_XATTR_SHARING is not set
++# CONFIG_EXT3_FS_XATTR_USER is not set
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XATTR_SHARING is not set
++# CONFIG_EXT2_FS_XATTR_USER is not set
++# CONFIG_FS_MBCACHE is not set
+ CONFIG_ALPHA=y
+ # CONFIG_UID16 is not set
+ # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+Index: linux-2.4.29/arch/alpha/kernel/entry.S
+===================================================================
+--- linux-2.4.29.orig/arch/alpha/kernel/entry.S        2005-04-07 18:52:17.000000000 +0300
++++ linux-2.4.29/arch/alpha/kernel/entry.S     2005-05-03 17:59:40.367126432 +0300
+@@ -1154,6 +1154,18 @@
+       .quad sys_readahead
+       .quad sys_ni_syscall                    /* 380, sys_security */
+       .quad sys_tkill
++      .quad sys_setxattr
++      .quad sys_lsetxattr
++      .quad sys_fsetxattr
++      .quad sys_getxattr                      /* 385 */
++      .quad sys_lgetxattr
++      .quad sys_fgetxattr
++      .quad sys_listxattr
++      .quad sys_llistxattr
++      .quad sys_flistxattr                    /* 390 */
++      .quad sys_removexattr
++      .quad sys_lremovexattr
++      .quad sys_fremovexattr
+ /* Remember to update everything, kids.  */
+ .ifne (. - sys_call_table) - (NR_SYSCALLS * 8)
+Index: linux-2.4.29/arch/arm/defconfig
+===================================================================
+--- linux-2.4.29.orig/arch/arm/defconfig       2005-04-07 18:53:03.000000000 +0300
++++ linux-2.4.29/arch/arm/defconfig    2005-05-03 17:59:40.369126128 +0300
+@@ -1,6 +1,13 @@
+ #
+ # Automatically generated make config: don't edit
+ #
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_XATTR_SHARING is not set
++# CONFIG_EXT3_FS_XATTR_USER is not set
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XATTR_SHARING is not set
++# CONFIG_EXT2_FS_XATTR_USER is not set
++# CONFIG_FS_MBCACHE is not set
+ CONFIG_ARM=y
+ # CONFIG_EISA is not set
+ # CONFIG_SBUS is not set
+Index: linux-2.4.29/arch/arm/kernel/calls.S
+===================================================================
+--- linux-2.4.29.orig/arch/arm/kernel/calls.S  2005-04-07 18:55:23.000000000 +0300
++++ linux-2.4.29/arch/arm/kernel/calls.S       2005-05-03 17:59:40.371125824 +0300
+@@ -240,18 +240,18 @@
+               .long   SYMBOL_NAME(sys_ni_syscall) /* Security */
+               .long   SYMBOL_NAME(sys_gettid)
+ /* 225 */     .long   SYMBOL_NAME(sys_readahead)
+-              .long   SYMBOL_NAME(sys_ni_syscall) /* setxattr */
+-              .long   SYMBOL_NAME(sys_ni_syscall) /* lsetxattr */
+-              .long   SYMBOL_NAME(sys_ni_syscall) /* fsetxattr */
+-              .long   SYMBOL_NAME(sys_ni_syscall) /* getxattr */
+-/* 230 */     .long   SYMBOL_NAME(sys_ni_syscall) /* lgetxattr */
+-              .long   SYMBOL_NAME(sys_ni_syscall) /* fgetxattr */
+-              .long   SYMBOL_NAME(sys_ni_syscall) /* listxattr */
+-              .long   SYMBOL_NAME(sys_ni_syscall) /* llistxattr */
+-              .long   SYMBOL_NAME(sys_ni_syscall) /* flistxattr */
+-/* 235 */     .long   SYMBOL_NAME(sys_ni_syscall) /* removexattr */
+-              .long   SYMBOL_NAME(sys_ni_syscall) /* lremovexattr */
+-              .long   SYMBOL_NAME(sys_ni_syscall) /* fremovexattr */
++              .long   SYMBOL_NAME(sys_setxattr)
++              .long   SYMBOL_NAME(sys_lsetxattr)
++              .long   SYMBOL_NAME(sys_fsetxattr)
++              .long   SYMBOL_NAME(sys_getxattr)
++/* 230 */     .long   SYMBOL_NAME(sys_lgetxattr)
++              .long   SYMBOL_NAME(sys_fgetxattr)
++              .long   SYMBOL_NAME(sys_listxattr)
++              .long   SYMBOL_NAME(sys_llistxattr)
++              .long   SYMBOL_NAME(sys_flistxattr)
++/* 235 */     .long   SYMBOL_NAME(sys_removexattr)
++              .long   SYMBOL_NAME(sys_lremovexattr)
++              .long   SYMBOL_NAME(sys_fremovexattr)
+               .long   SYMBOL_NAME(sys_tkill)
+               .long   SYMBOL_NAME(sys_ni_syscall) /* sendfile64 */
+ /* 240 */     .long   SYMBOL_NAME(sys_ni_syscall) /* futex */
+Index: linux-2.4.29/arch/i386/defconfig
+===================================================================
+--- linux-2.4.29.orig/arch/i386/defconfig      2005-04-07 18:52:37.000000000 +0300
++++ linux-2.4.29/arch/i386/defconfig   2005-05-03 17:59:40.372125672 +0300
+@@ -1,6 +1,13 @@
+ #
+ # Automatically generated make config: don't edit
+ #
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_XATTR_SHARING is not set
++# CONFIG_EXT3_FS_XATTR_USER is not set
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XATTR_SHARING is not set
++# CONFIG_EXT2_FS_XATTR_USER is not set
++# CONFIG_FS_MBCACHE is not set
+ CONFIG_X86=y
+ # CONFIG_SBUS is not set
+ CONFIG_UID16=y
+Index: linux-2.4.29/arch/ia64/defconfig
+===================================================================
+--- linux-2.4.29.orig/arch/ia64/defconfig      2005-04-07 18:52:32.000000000 +0300
++++ linux-2.4.29/arch/ia64/defconfig   2005-05-03 17:59:40.374125368 +0300
+@@ -1,6 +1,13 @@
+ #
+ # Automatically generated make config: don't edit
+ #
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_XATTR_SHARING is not set
++# CONFIG_EXT3_FS_XATTR_USER is not set
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XATTR_SHARING is not set
++# CONFIG_EXT2_FS_XATTR_USER is not set
++# CONFIG_FS_MBCACHE is not set
+ #
+ # Code maturity level options
+Index: linux-2.4.29/arch/m68k/defconfig
+===================================================================
+--- linux-2.4.29.orig/arch/m68k/defconfig      2005-04-07 18:52:26.000000000 +0300
++++ linux-2.4.29/arch/m68k/defconfig   2005-05-03 17:59:40.375125216 +0300
+@@ -1,6 +1,13 @@
+ #
+ # Automatically generated make config: don't edit
+ #
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_XATTR_SHARING is not set
++# CONFIG_EXT3_FS_XATTR_USER is not set
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XATTR_SHARING is not set
++# CONFIG_EXT2_FS_XATTR_USER is not set
++# CONFIG_FS_MBCACHE is not set
+ CONFIG_UID16=y
+ #
+Index: linux-2.4.29/arch/mips/defconfig
+===================================================================
+--- linux-2.4.29.orig/arch/mips/defconfig      2005-04-07 18:52:42.000000000 +0300
++++ linux-2.4.29/arch/mips/defconfig   2005-05-03 17:59:40.376125064 +0300
+@@ -1,6 +1,13 @@
+ #
+ # Automatically generated make config: don't edit
+ #
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_XATTR_SHARING is not set
++# CONFIG_EXT3_FS_XATTR_USER is not set
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XATTR_SHARING is not set
++# CONFIG_EXT2_FS_XATTR_USER is not set
++# CONFIG_FS_MBCACHE is not set
+ CONFIG_MIPS=y
+ CONFIG_MIPS32=y
+ # CONFIG_MIPS64 is not set
+Index: linux-2.4.29/arch/mips64/defconfig
+===================================================================
+--- linux-2.4.29.orig/arch/mips64/defconfig    2005-04-07 18:52:47.000000000 +0300
++++ linux-2.4.29/arch/mips64/defconfig 2005-05-03 17:59:40.378124760 +0300
+@@ -1,6 +1,13 @@
+ #
+ # Automatically generated make config: don't edit
+ #
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_XATTR_SHARING is not set
++# CONFIG_EXT3_FS_XATTR_USER is not set
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XATTR_SHARING is not set
++# CONFIG_EXT2_FS_XATTR_USER is not set
++# CONFIG_FS_MBCACHE is not set
+ CONFIG_MIPS=y
+ # CONFIG_MIPS32 is not set
+ CONFIG_MIPS64=y
+Index: linux-2.4.29/arch/s390/defconfig
+===================================================================
+--- linux-2.4.29.orig/arch/s390/defconfig      2005-04-07 18:54:49.000000000 +0300
++++ linux-2.4.29/arch/s390/defconfig   2005-05-03 17:59:40.379124608 +0300
+@@ -1,6 +1,13 @@
+ #
+ # Automatically generated make config: don't edit
+ #
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_XATTR_SHARING is not set
++# CONFIG_EXT3_FS_XATTR_USER is not set
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XATTR_SHARING is not set
++# CONFIG_EXT2_FS_XATTR_USER is not set
++# CONFIG_FS_MBCACHE is not set
+ # CONFIG_ISA is not set
+ # CONFIG_EISA is not set
+ # CONFIG_MCA is not set
+Index: linux-2.4.29/arch/s390/kernel/entry.S
+===================================================================
+--- linux-2.4.29.orig/arch/s390/kernel/entry.S 2005-04-07 18:52:47.000000000 +0300
++++ linux-2.4.29/arch/s390/kernel/entry.S      2005-05-03 17:59:40.381124304 +0300
+@@ -558,18 +558,18 @@
+         .long  sys_fcntl64 
+       .long  sys_readahead
+       .long  sys_ni_syscall
+-      .long  sys_ni_syscall            /* 224 - reserved for setxattr  */
+-      .long  sys_ni_syscall            /* 225 - reserved for lsetxattr */
+-      .long  sys_ni_syscall            /* 226 - reserved for fsetxattr */
+-      .long  sys_ni_syscall            /* 227 - reserved for getxattr  */
+-      .long  sys_ni_syscall            /* 228 - reserved for lgetxattr */
+-      .long  sys_ni_syscall            /* 229 - reserved for fgetxattr */
+-      .long  sys_ni_syscall            /* 230 - reserved for listxattr */
+-      .long  sys_ni_syscall            /* 231 - reserved for llistxattr */
+-      .long  sys_ni_syscall            /* 232 - reserved for flistxattr */
+-      .long  sys_ni_syscall            /* 233 - reserved for removexattr */
+-      .long  sys_ni_syscall            /* 234 - reserved for lremovexattr */
+-      .long  sys_ni_syscall            /* 235 - reserved for fremovexattr */
++      .long  sys_setxattr
++      .long  sys_lsetxattr            /* 225 */
++      .long  sys_fsetxattr
++      .long  sys_getxattr
++      .long  sys_lgetxattr
++      .long  sys_fgetxattr
++      .long  sys_listxattr            /* 230 */
++      .long  sys_llistxattr
++      .long  sys_flistxattr
++      .long  sys_removexattr
++      .long  sys_lremovexattr
++      .long  sys_fremovexattr         /* 235 */
+       .long  sys_gettid
+       .long  sys_tkill
+       .rept  255-237
+Index: linux-2.4.29/arch/s390x/defconfig
+===================================================================
+--- linux-2.4.29.orig/arch/s390x/defconfig     2005-04-07 18:52:17.000000000 +0300
++++ linux-2.4.29/arch/s390x/defconfig  2005-05-03 17:59:40.382124152 +0300
+@@ -1,6 +1,13 @@
+ #
+ # Automatically generated make config: don't edit
+ #
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_XATTR_SHARING is not set
++# CONFIG_EXT3_FS_XATTR_USER is not set
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XATTR_SHARING is not set
++# CONFIG_EXT2_FS_XATTR_USER is not set
++# CONFIG_FS_MBCACHE is not set
+ # CONFIG_ISA is not set
+ # CONFIG_EISA is not set
+ # CONFIG_MCA is not set
+Index: linux-2.4.29/arch/s390x/kernel/entry.S
+===================================================================
+--- linux-2.4.29.orig/arch/s390x/kernel/entry.S        2005-04-07 18:52:58.000000000 +0300
++++ linux-2.4.29/arch/s390x/kernel/entry.S     2005-05-03 17:59:40.384123848 +0300
+@@ -591,18 +591,18 @@
+       .long  SYSCALL(sys_ni_syscall,sys32_fcntl64_wrapper)
+       .long  SYSCALL(sys_readahead,sys32_readahead)
+       .long  SYSCALL(sys_ni_syscall,sys_ni_syscall)
+-      .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 224 - reserved for setxattr  */
+-      .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 225 - reserved for lsetxattr */
+-      .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 226 - reserved for fsetxattr */
+-      .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 227 - reserved for getxattr  */
+-      .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 228 - reserved for lgetxattr */
+-      .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 229 - reserved for fgetxattr */
+-      .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 230 - reserved for listxattr */
+-      .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 231 - reserved for llistxattr */
+-      .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 232 - reserved for flistxattr */
+-      .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 233 - reserved for removexattr */
+-      .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 234 - reserved for lremovexattr */
+-      .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 235 - reserved for fremovexattr */
++      .long  SYSCALL(sys_setxattr,sys32_setxattr_wrapper)
++      .long  SYSCALL(sys_lsetxattr,sys32_lsetxattr_wrapper)   /* 225 */
++      .long  SYSCALL(sys_fsetxattr,sys32_fsetxattr_wrapper)
++      .long  SYSCALL(sys_getxattr,sys32_getxattr_wrapper)
++      .long  SYSCALL(sys_lgetxattr,sys32_lgetxattr_wrapper)
++      .long  SYSCALL(sys_fgetxattr,sys32_fgetxattr_wrapper)
++      .long  SYSCALL(sys_listxattr,sys32_listxattr_wrapper)   /* 230 */
++      .long  SYSCALL(sys_llistxattr,sys32_llistxattr_wrapper)
++      .long  SYSCALL(sys_flistxattr,sys32_flistxattr_wrapper)
++      .long  SYSCALL(sys_removexattr,sys32_removexattr_wrapper)
++      .long  SYSCALL(sys_lremovexattr,sys32_lremovexattr_wrapper)
++      .long  SYSCALL(sys_fremovexattr,sys32_fremovexattr_wrapper)/* 235 */
+       .long  SYSCALL(sys_gettid,sys_gettid)
+       .long  SYSCALL(sys_tkill,sys_tkill)
+       .rept  255-237
+Index: linux-2.4.29/arch/s390x/kernel/wrapper32.S
+===================================================================
+--- linux-2.4.29.orig/arch/s390x/kernel/wrapper32.S    2005-04-07 18:55:12.000000000 +0300
++++ linux-2.4.29/arch/s390x/kernel/wrapper32.S 2005-05-03 17:59:40.386123544 +0300
+@@ -1098,6 +1098,98 @@
+       llgfr   %r4,%r4                 # long
+       jg      sys32_fstat64           # branch to system call
++      .globl  sys32_setxattr_wrapper
++sys32_setxattr_wrapper:
++      llgtr   %r2,%r2                 # char *
++      llgtr   %r3,%r3                 # char *
++      llgtr   %r4,%r4                 # void *
++      llgfr   %r5,%r5                 # size_t
++      lgfr    %r6,%r6                 # int
++      jg      sys_setxattr
++
++      .globl  sys32_lsetxattr_wrapper
++sys32_lsetxattr_wrapper:
++      llgtr   %r2,%r2                 # char *
++      llgtr   %r3,%r3                 # char *
++      llgtr   %r4,%r4                 # void *
++      llgfr   %r5,%r5                 # size_t
++      lgfr    %r6,%r6                 # int
++      jg      sys_lsetxattr
++
++      .globl  sys32_fsetxattr_wrapper
++sys32_fsetxattr_wrapper:
++      lgfr    %r2,%r2                 # int
++      llgtr   %r3,%r3                 # char *
++      llgtr   %r4,%r4                 # void *
++      llgfr   %r5,%r5                 # size_t
++      lgfr    %r6,%r6                 # int
++      jg      sys_fsetxattr
++
++      .globl  sys32_getxattr_wrapper
++sys32_getxattr_wrapper:
++      llgtr   %r2,%r2                 # char *
++      llgtr   %r3,%r3                 # char *
++      llgtr   %r4,%r4                 # void *
++      llgfr   %r5,%r5                 # size_t
++      jg      sys_getxattr
++
++      .globl  sys32_lgetxattr_wrapper
++sys32_lgetxattr_wrapper:
++      llgtr   %r2,%r2                 # char *
++      llgtr   %r3,%r3                 # char *
++      llgtr   %r4,%r4                 # void *
++      llgfr   %r5,%r5                 # size_t
++      jg      sys_lgetxattr
++
++      .globl  sys32_fgetxattr_wrapper
++sys32_fgetxattr_wrapper:
++      lgfr    %r2,%r2                 # int
++      llgtr   %r3,%r3                 # char *
++      llgtr   %r4,%r4                 # void *
++      llgfr   %r5,%r5                 # size_t
++      jg      sys_fgetxattr
++
++      .globl  sys32_listxattr_wrapper
++sys32_listxattr_wrapper:
++      llgtr   %r2,%r2                 # char *
++      llgtr   %r3,%r3                 # char *
++      llgfr   %r4,%r4                 # size_t
++      jg      sys_listxattr
++
++      .globl  sys32_llistxattr_wrapper
++sys32_llistxattr_wrapper:
++      llgtr   %r2,%r2                 # char *
++      llgtr   %r3,%r3                 # char *
++      llgfr   %r4,%r4                 # size_t
++      jg      sys_llistxattr
++
++      .globl  sys32_flistxattr_wrapper
++sys32_flistxattr_wrapper:
++      lgfr    %r2,%r2                 # int
++      llgtr   %r3,%r3                 # char *
++      llgfr   %r4,%r4                 # size_t
++      jg      sys_flistxattr
++
++      .globl  sys32_removexattr_wrapper
++sys32_removexattr_wrapper:
++      llgtr   %r2,%r2                 # char *
++      llgtr   %r3,%r3                 # char *
++      jg      sys_removexattr
++
++      .globl  sys32_lremovexattr_wrapper
++sys32_lremovexattr_wrapper:
++      llgtr   %r2,%r2                 # char *
++      llgtr   %r3,%r3                 # char *
++      jg      sys_lremovexattr
++
++      .globl  sys32_fremovexattr_wrapper
++sys32_fremovexattr_wrapper:
++      lgfr    %r2,%r2                 # int
++      llgtr   %r3,%r3                 # char *
++      jg      sys_fremovexattr
++
++
++
+       .globl  sys32_stime_wrapper
+ sys32_stime_wrapper:
+       llgtr   %r2,%r2                 # int *
+Index: linux-2.4.29/arch/sparc64/defconfig
+===================================================================
+--- linux-2.4.29.orig/arch/sparc64/defconfig   2005-04-07 18:53:09.000000000 +0300
++++ linux-2.4.29/arch/sparc64/defconfig        2005-05-03 17:59:40.388123240 +0300
+@@ -1,6 +1,13 @@
+ #
+ # Automatically generated make config: don't edit
+ #
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_XATTR_SHARING is not set
++# CONFIG_EXT3_FS_XATTR_USER is not set
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XATTR_SHARING is not set
++# CONFIG_EXT2_FS_XATTR_USER is not set
++# CONFIG_FS_MBCACHE is not set
+ #
+ # Code maturity level options
+Index: linux-2.4.29/fs/Config.in
+===================================================================
+--- linux-2.4.29.orig/fs/Config.in     2005-04-07 18:54:16.000000000 +0300
++++ linux-2.4.29/fs/Config.in  2005-05-03 17:59:40.389123088 +0300
+@@ -29,6 +29,11 @@
+ dep_tristate 'BFS file system support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL
+ tristate 'Ext3 journalling file system support' CONFIG_EXT3_FS
++dep_mbool '  Ext3 extended attributes' CONFIG_EXT3_FS_XATTR $CONFIG_EXT3_FS
++dep_bool '    Ext3 extended attribute block sharing' \
++    CONFIG_EXT3_FS_XATTR_SHARING $CONFIG_EXT3_FS_XATTR
++dep_bool '    Ext3 extended user attributes' \
++    CONFIG_EXT3_FS_XATTR_USER $CONFIG_EXT3_FS_XATTR
+ # CONFIG_JBD could be its own option (even modular), but until there are
+ # other users than ext3, we will simply make it be the same as CONFIG_EXT3_FS
+ # dep_tristate '  Journal Block Device support (JBD for ext3)' CONFIG_JBD $CONFIG_EXT3_FS
+@@ -92,6 +97,11 @@
+ tristate 'ROM file system support' CONFIG_ROMFS_FS
+ tristate 'Second extended fs support' CONFIG_EXT2_FS
++dep_mbool '  Ext2 extended attributes' CONFIG_EXT2_FS_XATTR $CONFIG_EXT2_FS
++dep_bool '    Ext2 extended attribute block sharing' \
++    CONFIG_EXT2_FS_XATTR_SHARING $CONFIG_EXT2_FS_XATTR
++dep_bool '    Ext2 extended user attributes' \
++    CONFIG_EXT2_FS_XATTR_USER $CONFIG_EXT2_FS_XATTR
+ tristate 'System V/Xenix/V7/Coherent file system support' CONFIG_SYSV_FS
+@@ -171,6 +181,10 @@
+    define_tristate CONFIG_ZISOFS_FS n
+ fi
++# Meta block cache for Extended Attributes (ext2/ext3)
++#tristate 'Meta block cache' CONFIG_FS_MBCACHE
++define_tristate CONFIG_FS_MBCACHE y 
++
+ mainmenu_option next_comment
+ comment 'Partition Types'
+ source fs/partitions/Config.in
+Index: linux-2.4.29/fs/Makefile
+===================================================================
+--- linux-2.4.29.orig/fs/Makefile      2005-05-03 17:23:53.969428480 +0300
++++ linux-2.4.29/fs/Makefile   2005-05-03 17:59:40.390122936 +0300
+@@ -77,6 +77,9 @@
+ obj-$(CONFIG_BINFMT_ELF)      += binfmt_elf.o
++export-objs += mbcache.o
++obj-$(CONFIG_FS_MBCACHE)      += mbcache.o
++
+ # persistent filesystems
+ obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+Index: linux-2.4.29/fs/ext2/Makefile
+===================================================================
+--- linux-2.4.29.orig/fs/ext2/Makefile 2005-04-07 18:54:32.000000000 +0300
++++ linux-2.4.29/fs/ext2/Makefile      2005-05-03 17:59:40.391122784 +0300
+@@ -13,4 +13,8 @@
+               ioctl.o namei.o super.o symlink.o
+ obj-m    := $(O_TARGET)
++export-objs += xattr.o
++obj-$(CONFIG_EXT2_FS_XATTR) += xattr.o
++obj-$(CONFIG_EXT2_FS_XATTR_USER) += xattr_user.o
++
+ include $(TOPDIR)/Rules.make
+Index: linux-2.4.29/fs/ext2/file.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext2/file.c   2005-04-07 18:53:14.000000000 +0300
++++ linux-2.4.29/fs/ext2/file.c        2005-05-03 17:59:40.392122632 +0300
+@@ -20,6 +20,7 @@
+ #include <linux/fs.h>
+ #include <linux/ext2_fs.h>
++#include <linux/ext2_xattr.h>
+ #include <linux/sched.h>
+ /*
+@@ -51,4 +52,8 @@
+ struct inode_operations ext2_file_inode_operations = {
+       truncate:       ext2_truncate,
++      setxattr:       ext2_setxattr,
++      getxattr:       ext2_getxattr,
++      listxattr:      ext2_listxattr,
++      removexattr:    ext2_removexattr,
+ };
+Index: linux-2.4.29/fs/ext2/ialloc.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext2/ialloc.c 2005-04-07 18:53:47.000000000 +0300
++++ linux-2.4.29/fs/ext2/ialloc.c      2005-05-03 17:59:40.393122480 +0300
+@@ -15,6 +15,7 @@
+ #include <linux/config.h>
+ #include <linux/fs.h>
+ #include <linux/ext2_fs.h>
++#include <linux/ext2_xattr.h>
+ #include <linux/locks.h>
+ #include <linux/quotaops.h>
+@@ -167,6 +168,7 @@
+        */
+       if (!is_bad_inode(inode)) {
+               /* Quota is already initialized in iput() */
++              ext2_xattr_delete_inode(inode);
+               DQUOT_FREE_INODE(inode);
+               DQUOT_DROP(inode);
+       }
+Index: linux-2.4.29/fs/ext2/inode.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext2/inode.c  2005-04-07 18:52:32.000000000 +0300
++++ linux-2.4.29/fs/ext2/inode.c       2005-05-03 17:59:40.396122024 +0300
+@@ -64,9 +64,7 @@
+ {
+       lock_kernel();
+-      if (is_bad_inode(inode) ||
+-          inode->i_ino == EXT2_ACL_IDX_INO ||
+-          inode->i_ino == EXT2_ACL_DATA_INO)
++      if (is_bad_inode(inode))
+               goto no_delete;
+       inode->u.ext2_i.i_dtime = CURRENT_TIME;
+       mark_inode_dirty(inode);
+@@ -815,6 +813,8 @@
+               return;
+       if (ext2_inode_is_fast_symlink(inode))
+               return;
++      if (ext2_inode_is_fast_symlink(inode))
++              return;
+       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+               return;
+@@ -917,8 +917,7 @@
+       unsigned long offset;
+       struct ext2_group_desc * gdp;
+-      if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO &&
+-           inode->i_ino != EXT2_ACL_DATA_INO &&
++      if ((inode->i_ino != EXT2_ROOT_INO &&
+            inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) ||
+           inode->i_ino > le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_inodes_count)) {
+               ext2_error (inode->i_sb, "ext2_read_inode",
+@@ -1004,10 +1003,7 @@
+       for (block = 0; block < EXT2_N_BLOCKS; block++)
+               inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
+-      if (inode->i_ino == EXT2_ACL_IDX_INO ||
+-          inode->i_ino == EXT2_ACL_DATA_INO)
+-              /* Nothing to do */ ;
+-      else if (S_ISREG(inode->i_mode)) {
++      if (S_ISREG(inode->i_mode)) {
+               inode->i_op = &ext2_file_inode_operations;
+               inode->i_fop = &ext2_file_operations;
+               inode->i_mapping->a_ops = &ext2_aops;
+@@ -1019,12 +1015,14 @@
+               if (ext2_inode_is_fast_symlink(inode))
+                       inode->i_op = &ext2_fast_symlink_inode_operations;
+               else {
+-                      inode->i_op = &page_symlink_inode_operations;
++                      inode->i_op = &ext2_symlink_inode_operations;
+                       inode->i_mapping->a_ops = &ext2_aops;
+               }
+-      } else 
++      } else {
++              inode->i_op = &ext2_special_inode_operations;
+               init_special_inode(inode, inode->i_mode,
+                                  le32_to_cpu(raw_inode->i_block[0]));
++      }
+       brelse (bh);
+       inode->i_attr_flags = 0;
+       ext2_set_inode_flags(inode);
+Index: linux-2.4.29/fs/ext2/namei.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext2/namei.c  2005-04-07 18:54:50.000000000 +0300
++++ linux-2.4.29/fs/ext2/namei.c       2005-05-03 17:59:40.397121872 +0300
+@@ -31,6 +31,7 @@
+ #include <linux/fs.h>
+ #include <linux/ext2_fs.h>
++#include <linux/ext2_xattr.h>
+ #include <linux/pagemap.h>
+ /*
+@@ -136,7 +137,7 @@
+       if (l > sizeof (inode->u.ext2_i.i_data)) {
+               /* slow symlink */
+-              inode->i_op = &page_symlink_inode_operations;
++              inode->i_op = &ext2_symlink_inode_operations;
+               inode->i_mapping->a_ops = &ext2_aops;
+               err = block_symlink(inode, symname, l);
+               if (err)
+@@ -345,4 +346,15 @@
+       rmdir:          ext2_rmdir,
+       mknod:          ext2_mknod,
+       rename:         ext2_rename,
++      setxattr:       ext2_setxattr,
++      getxattr:       ext2_getxattr,
++      listxattr:      ext2_listxattr,
++      removexattr:    ext2_removexattr,
++};
++
++struct inode_operations ext2_special_inode_operations = {
++      setxattr:       ext2_setxattr,
++      getxattr:       ext2_getxattr,
++      listxattr:      ext2_listxattr,
++      removexattr:    ext2_removexattr,
+ };
+Index: linux-2.4.29/fs/ext2/super.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext2/super.c  2005-04-07 18:54:16.000000000 +0300
++++ linux-2.4.29/fs/ext2/super.c       2005-05-03 17:59:40.400121416 +0300
+@@ -21,6 +21,7 @@
+ #include <linux/string.h>
+ #include <linux/fs.h>
+ #include <linux/ext2_fs.h>
++#include <linux/ext2_xattr.h>
+ #include <linux/slab.h>
+ #include <linux/init.h>
+ #include <linux/locks.h>
+@@ -125,6 +126,7 @@
+       int db_count;
+       int i;
++      ext2_xattr_put_super(sb);
+       if (!(sb->s_flags & MS_RDONLY)) {
+               struct ext2_super_block *es = EXT2_SB(sb)->s_es;
+@@ -175,6 +177,13 @@
+            this_char = strtok (NULL, ",")) {
+               if ((value = strchr (this_char, '=')) != NULL)
+                       *value++ = 0;
++#ifdef CONFIG_EXT2_FS_XATTR_USER
++              if (!strcmp (this_char, "user_xattr"))
++                      set_opt (*mount_options, XATTR_USER);
++              else if (!strcmp (this_char, "nouser_xattr"))
++                      clear_opt (*mount_options, XATTR_USER);
++              else
++#endif
+               if (!strcmp (this_char, "bsddf"))
+                       clear_opt (*mount_options, MINIX_DF);
+               else if (!strcmp (this_char, "nouid32")) {
+@@ -446,6 +455,9 @@
+           blocksize = BLOCK_SIZE;
+       sb->u.ext2_sb.s_mount_opt = 0;
++#ifdef CONFIG_EXT2_FS_XATTR_USER
++      /* set_opt (sb->u.ext2_sb.s_mount_opt, XATTR_USER); */
++#endif
+       if (!parse_options ((char *) data, &sb_block, &resuid, &resgid,
+           &sb->u.ext2_sb.s_mount_opt)) {
+               return NULL;
+@@ -840,12 +852,27 @@
+ static int __init init_ext2_fs(void)
+ {
+-        return register_filesystem(&ext2_fs_type);
++      int error = init_ext2_xattr();
++      if (error)
++              return error;
++      error = init_ext2_xattr_user();
++      if (error)
++              goto fail;
++      error = register_filesystem(&ext2_fs_type);
++      if (!error)
++              return 0;
++
++      exit_ext2_xattr_user();
++fail:
++      exit_ext2_xattr();
++      return error;
+ }
+ static void __exit exit_ext2_fs(void)
+ {
+       unregister_filesystem(&ext2_fs_type);
++      exit_ext2_xattr_user();
++      exit_ext2_xattr();
+ }
+ EXPORT_NO_SYMBOLS;
+Index: linux-2.4.29/fs/ext2/symlink.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext2/symlink.c        2005-04-07 18:52:53.000000000 +0300
++++ linux-2.4.29/fs/ext2/symlink.c     2005-05-03 17:59:40.400121416 +0300
+@@ -19,6 +19,7 @@
+ #include <linux/fs.h>
+ #include <linux/ext2_fs.h>
++#include <linux/ext2_xattr.h>
+ static int ext2_readlink(struct dentry *dentry, char *buffer, int buflen)
+ {
+@@ -32,7 +33,20 @@
+       return vfs_follow_link(nd, s);
+ }
++struct inode_operations ext2_symlink_inode_operations = {
++      readlink:       page_readlink,
++      follow_link:    page_follow_link,
++      setxattr:       ext2_setxattr,
++      getxattr:       ext2_getxattr,
++      listxattr:      ext2_listxattr,
++      removexattr:    ext2_removexattr,
++};
++
+ struct inode_operations ext2_fast_symlink_inode_operations = {
+       readlink:       ext2_readlink,
+       follow_link:    ext2_follow_link,
++      setxattr:       ext2_setxattr,
++      getxattr:       ext2_getxattr,
++      listxattr:      ext2_listxattr,
++      removexattr:    ext2_removexattr,
+ };
+Index: linux-2.4.29/fs/ext2/xattr.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext2/xattr.c  2005-05-03 17:59:40.233146800 +0300
++++ linux-2.4.29/fs/ext2/xattr.c       2005-05-03 17:59:40.405120656 +0300
+@@ -0,0 +1,1212 @@
++/*
++ * linux/fs/ext2/xattr.c
++ *
++ * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
++ *
++ * Fix by Harrison Xing <harrison@mountainviewdata.com>.
++ * Extended attributes for symlinks and special files added per
++ *  suggestion of Luka Renko <luka.renko@hermes.si>.
++ */
++
++/*
++ * Extended attributes are stored on disk blocks allocated outside of
++ * any inode. The i_file_acl field is then made to point to this allocated
++ * block. If all extended attributes of an inode are identical, these
++ * inodes may share the same extended attribute block. Such situations
++ * are automatically detected by keeping a cache of recent attribute block
++ * numbers and hashes over the block's contents in memory.
++ *
++ *
++ * Extended attribute block layout:
++ *
++ *   +------------------+
++ *   | header           |
++ *   | entry 1          | |
++ *   | entry 2          | | growing downwards
++ *   | entry 3          | v
++ *   | four null bytes  |
++ *   | . . .            |
++ *   | value 1          | ^
++ *   | value 3          | | growing upwards
++ *   | value 2          | |
++ *   +------------------+
++ *
++ * The block header is followed by multiple entry descriptors. These entry
++ * descriptors are variable in size, and alligned to EXT2_XATTR_PAD
++ * byte boundaries. The entry descriptors are sorted by attribute name,
++ * so that two extended attribute blocks can be compared efficiently.
++ *
++ * Attribute values are aligned to the end of the block, stored in
++ * no specific order. They are also padded to EXT2_XATTR_PAD byte
++ * boundaries. No additional gaps are left between them.
++ *
++ * Locking strategy
++ * ----------------
++ * The VFS already holds the BKL and the inode->i_sem semaphore when any of
++ * the xattr inode operations are called, so we are guaranteed that only one
++ * processes accesses extended attributes of an inode at any time.
++ *
++ * For writing we also grab the ext2_xattr_sem semaphore. This ensures that
++ * only a single process is modifying an extended attribute block, even
++ * if the block is shared among inodes.
++ *
++ * Note for porting to 2.5
++ * -----------------------
++ * The BKL will no longer be held in the xattr inode operations.
++ */
++
++#include <linux/module.h>
++#include <linux/locks.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/ext2_fs.h>
++#include <linux/ext2_xattr.h>
++#include <linux/mbcache.h>
++#include <linux/quotaops.h>
++#include <asm/semaphore.h>
++#include <linux/compatmac.h>
++
++/* These symbols may be needed by a module. */
++EXPORT_SYMBOL(ext2_xattr_register);
++EXPORT_SYMBOL(ext2_xattr_unregister);
++EXPORT_SYMBOL(ext2_xattr_get);
++EXPORT_SYMBOL(ext2_xattr_list);
++EXPORT_SYMBOL(ext2_xattr_set);
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
++# define mark_buffer_dirty(bh) mark_buffer_dirty(bh, 1)
++#endif
++
++#define HDR(bh) ((struct ext2_xattr_header *)((bh)->b_data))
++#define ENTRY(ptr) ((struct ext2_xattr_entry *)(ptr))
++#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1)
++#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
++
++#ifdef EXT2_XATTR_DEBUG
++# define ea_idebug(inode, f...) do { \
++              printk(KERN_DEBUG "inode %s:%ld: ", \
++                      kdevname(inode->i_dev), inode->i_ino); \
++              printk(f); \
++              printk("\n"); \
++      } while (0)
++# define ea_bdebug(bh, f...) do { \
++              printk(KERN_DEBUG "block %s:%ld: ", \
++                      kdevname(bh->b_dev), bh->b_blocknr); \
++              printk(f); \
++              printk("\n"); \
++      } while (0)
++#else
++# define ea_idebug(f...)
++# define ea_bdebug(f...)
++#endif
++
++static int ext2_xattr_set2(struct inode *, struct buffer_head *,
++                         struct ext2_xattr_header *);
++
++#ifdef CONFIG_EXT2_FS_XATTR_SHARING
++
++static int ext2_xattr_cache_insert(struct buffer_head *);
++static struct buffer_head *ext2_xattr_cache_find(struct inode *,
++                                               struct ext2_xattr_header *);
++static void ext2_xattr_cache_remove(struct buffer_head *);
++static void ext2_xattr_rehash(struct ext2_xattr_header *,
++                            struct ext2_xattr_entry *);
++
++static struct mb_cache *ext2_xattr_cache;
++
++#else
++# define ext2_xattr_cache_insert(bh) 0
++# define ext2_xattr_cache_find(inode, header) NULL
++# define ext2_xattr_cache_remove(bh) while(0) {}
++# define ext2_xattr_rehash(header, entry) while(0) {}
++#endif
++
++/*
++ * If a file system does not share extended attributes among inodes,
++ * we should not need the ext2_xattr_sem semaphore. However, the
++ * filesystem may still contain shared blocks, so we always take
++ * the lock.
++ */
++
++DECLARE_MUTEX(ext2_xattr_sem);
++
++static inline int
++ext2_xattr_new_block(struct inode *inode, int * errp, int force)
++{
++      struct super_block *sb = inode->i_sb;
++      int goal = le32_to_cpu(EXT2_SB(sb)->s_es->s_first_data_block) +
++              EXT2_I(inode)->i_block_group * EXT2_BLOCKS_PER_GROUP(sb);
++
++      /* How can we enforce the allocation? */
++      int block = ext2_new_block(inode, goal, 0, 0, errp);
++#ifdef OLD_QUOTAS
++      if (!*errp)
++              inode->i_blocks += inode->i_sb->s_blocksize >> 9;
++#endif
++      return block;
++}
++
++static inline int
++ext2_xattr_quota_alloc(struct inode *inode, int force)
++{
++      /* How can we enforce the allocation? */
++#ifdef OLD_QUOTAS
++      int error = DQUOT_ALLOC_BLOCK(inode->i_sb, inode, 1);
++      if (!error)
++              inode->i_blocks += inode->i_sb->s_blocksize >> 9;
++#else
++      int error = DQUOT_ALLOC_BLOCK(inode, 1);
++#endif
++      return error;
++}
++
++#ifdef OLD_QUOTAS
++
++static inline void
++ext2_xattr_quota_free(struct inode *inode)
++{
++      DQUOT_FREE_BLOCK(inode->i_sb, inode, 1);
++      inode->i_blocks -= inode->i_sb->s_blocksize >> 9;
++}
++
++static inline void
++ext2_xattr_free_block(struct inode * inode, unsigned long block)
++{
++      ext2_free_blocks(inode, block, 1);
++      inode->i_blocks -= inode->i_sb->s_blocksize >> 9;
++}
++
++#else
++# define ext2_xattr_quota_free(inode) \
++      DQUOT_FREE_BLOCK(inode, 1)
++# define ext2_xattr_free_block(inode, block) \
++      ext2_free_blocks(inode, block, 1)
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
++
++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);
++}
++
++#endif
++
++struct ext2_xattr_handler *ext2_xattr_handlers[EXT2_XATTR_INDEX_MAX];
++rwlock_t ext2_handler_lock = RW_LOCK_UNLOCKED;
++
++int
++ext2_xattr_register(int name_index, struct ext2_xattr_handler *handler)
++{
++      int error = -EINVAL;
++
++      if (name_index > 0 && name_index <= EXT2_XATTR_INDEX_MAX) {
++              write_lock(&ext2_handler_lock);
++              if (!ext2_xattr_handlers[name_index-1]) {
++                      ext2_xattr_handlers[name_index-1] = handler;
++                      error = 0;
++              }
++              write_unlock(&ext2_handler_lock);
++      }
++      return error;
++}
++
++void
++ext2_xattr_unregister(int name_index, struct ext2_xattr_handler *handler)
++{
++      if (name_index > 0 && name_index <= EXT2_XATTR_INDEX_MAX) {
++              write_lock(&ext2_handler_lock);
++              ext2_xattr_handlers[name_index-1] = NULL;
++              write_unlock(&ext2_handler_lock);
++      }
++}
++
++static inline const char *
++strcmp_prefix(const char *a, const char *a_prefix)
++{
++      while (*a_prefix && *a == *a_prefix) {
++              a++;
++              a_prefix++;
++      }
++      return *a_prefix ? NULL : a;
++}
++
++/*
++ * Decode the extended attribute name, and translate it into
++ * the name_index and name suffix.
++ */
++static struct ext2_xattr_handler *
++ext2_xattr_resolve_name(const char **name)
++{
++      struct ext2_xattr_handler *handler = NULL;
++      int i;
++
++      if (!*name)
++              return NULL;
++      read_lock(&ext2_handler_lock);
++      for (i=0; i<EXT2_XATTR_INDEX_MAX; i++) {
++              if (ext2_xattr_handlers[i]) {
++                      const char *n = strcmp_prefix(*name,
++                              ext2_xattr_handlers[i]->prefix);
++                      if (n) {
++                              handler = ext2_xattr_handlers[i];
++                              *name = n;
++                              break;
++                      }
++              }
++      }
++      read_unlock(&ext2_handler_lock);
++      return handler;
++}
++
++static inline struct ext2_xattr_handler *
++ext2_xattr_handler(int name_index)
++{
++      struct ext2_xattr_handler *handler = NULL;
++      if (name_index > 0 && name_index <= EXT2_XATTR_INDEX_MAX) {
++              read_lock(&ext2_handler_lock);
++              handler = ext2_xattr_handlers[name_index-1];
++              read_unlock(&ext2_handler_lock);
++      }
++      return handler;
++}
++
++/*
++ * Inode operation getxattr()
++ *
++ * dentry->d_inode->i_sem down
++ * BKL held [before 2.5.x]
++ */
++ssize_t
++ext2_getxattr(struct dentry *dentry, const char *name,
++            void *buffer, size_t size)
++{
++      struct ext2_xattr_handler *handler;
++      struct inode *inode = dentry->d_inode;
++
++      handler = ext2_xattr_resolve_name(&name);
++      if (!handler)
++              return -ENOTSUP;
++      return handler->get(inode, name, buffer, size);
++}
++
++/*
++ * Inode operation listxattr()
++ *
++ * dentry->d_inode->i_sem down
++ * BKL held [before 2.5.x]
++ */
++ssize_t
++ext2_listxattr(struct dentry *dentry, char *buffer, size_t size)
++{
++      return ext2_xattr_list(dentry->d_inode, buffer, size);
++}
++
++/*
++ * Inode operation setxattr()
++ *
++ * dentry->d_inode->i_sem down
++ * BKL held [before 2.5.x]
++ */
++int
++ext2_setxattr(struct dentry *dentry, const char *name,
++            const void *value, size_t size, int flags)
++{
++      struct ext2_xattr_handler *handler;
++      struct inode *inode = dentry->d_inode;
++
++      if (size == 0)
++              value = "";  /* empty EA, do not remove */
++      handler = ext2_xattr_resolve_name(&name);
++      if (!handler)
++              return -ENOTSUP;
++      return handler->set(inode, name, value, size, flags);
++}
++
++/*
++ * Inode operation removexattr()
++ *
++ * dentry->d_inode->i_sem down
++ * BKL held [before 2.5.x]
++ */
++int
++ext2_removexattr(struct dentry *dentry, const char *name)
++{
++      struct ext2_xattr_handler *handler;
++      struct inode *inode = dentry->d_inode;
++
++      handler = ext2_xattr_resolve_name(&name);
++      if (!handler)
++              return -ENOTSUP;
++      return handler->set(inode, name, NULL, 0, XATTR_REPLACE);
++}
++
++/*
++ * ext2_xattr_get()
++ *
++ * Copy an extended attribute into the buffer
++ * provided, or compute the buffer size required.
++ * Buffer is NULL to compute the size of the buffer required.
++ *
++ * Returns a negative error number on failure, or the number of bytes
++ * used / required on success.
++ */
++int
++ext2_xattr_get(struct inode *inode, int name_index, const char *name,
++             void *buffer, size_t buffer_size)
++{
++      struct buffer_head *bh = NULL;
++      struct ext2_xattr_entry *entry;
++      unsigned int block, size;
++      char *end;
++      int name_len, error;
++
++      ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
++                name_index, name, buffer, (long)buffer_size);
++
++      if (name == NULL)
++              return -EINVAL;
++      if (!EXT2_I(inode)->i_file_acl)
++              return -ENOATTR;
++      block = EXT2_I(inode)->i_file_acl;
++      ea_idebug(inode, "reading block %d", block);
++      bh = sb_bread(inode->i_sb, block);
++      if (!bh)
++              return -EIO;
++      ea_bdebug(bh, "b_count=%d, refcount=%d",
++              atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
++      end = bh->b_data + bh->b_size;
++      if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) ||
++          HDR(bh)->h_blocks != cpu_to_le32(1)) {
++bad_block:    ext2_error(inode->i_sb, "ext2_xattr_get",
++                      "inode %ld: bad block %d", inode->i_ino, block);
++              error = -EIO;
++              goto cleanup;
++      }
++      /* find named attribute */
++      name_len = strlen(name);
++
++      error = -ERANGE;
++      if (name_len > 255)
++              goto cleanup;
++      entry = FIRST_ENTRY(bh);
++      while (!IS_LAST_ENTRY(entry)) {
++              struct ext2_xattr_entry *next =
++                      EXT2_XATTR_NEXT(entry);
++              if ((char *)next >= end)
++                      goto bad_block;
++              if (name_index == entry->e_name_index &&
++                  name_len == entry->e_name_len &&
++                  memcmp(name, entry->e_name, name_len) == 0)
++                      goto found;
++              entry = next;
++      }
++      /* Check the remaining name entries */
++      while (!IS_LAST_ENTRY(entry)) {
++              struct ext2_xattr_entry *next =
++                      EXT2_XATTR_NEXT(entry);
++              if ((char *)next >= end)
++                      goto bad_block;
++              entry = next;
++      }
++      if (ext2_xattr_cache_insert(bh))
++              ea_idebug(inode, "cache insert failed");
++      error = -ENOATTR;
++      goto cleanup;
++found:
++      /* check the buffer size */
++      if (entry->e_value_block != 0)
++              goto bad_block;
++      size = le32_to_cpu(entry->e_value_size);
++      if (size > inode->i_sb->s_blocksize ||
++          le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize)
++              goto bad_block;
++
++      if (ext2_xattr_cache_insert(bh))
++              ea_idebug(inode, "cache insert failed");
++      if (buffer) {
++              error = -ERANGE;
++              if (size > buffer_size)
++                      goto cleanup;
++              /* return value of attribute */
++              memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs),
++                      size);
++      }
++      error = size;
++
++cleanup:
++      brelse(bh);
++
++      return error;
++}
++
++/*
++ * ext2_xattr_list()
++ *
++ * Copy a list of attribute names into the buffer
++ * provided, or compute the buffer size required.
++ * Buffer is NULL to compute the size of the buffer required.
++ *
++ * Returns a negative error number on failure, or the number of bytes
++ * used / required on success.
++ */
++int
++ext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
++{
++      struct buffer_head *bh = NULL;
++      struct ext2_xattr_entry *entry;
++      unsigned int block, size = 0;
++      char *buf, *end;
++      int error;
++
++      ea_idebug(inode, "buffer=%p, buffer_size=%ld",
++                buffer, (long)buffer_size);
++
++      if (!EXT2_I(inode)->i_file_acl)
++              return 0;
++      block = EXT2_I(inode)->i_file_acl;
++      ea_idebug(inode, "reading block %d", block);
++      bh = sb_bread(inode->i_sb, block);
++      if (!bh)
++              return -EIO;
++      ea_bdebug(bh, "b_count=%d, refcount=%d",
++              atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
++      end = bh->b_data + bh->b_size;
++      if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) ||
++          HDR(bh)->h_blocks != cpu_to_le32(1)) {
++bad_block:    ext2_error(inode->i_sb, "ext2_xattr_list",
++                      "inode %ld: bad block %d", inode->i_ino, block);
++              error = -EIO;
++              goto cleanup;
++      }
++      /* compute the size required for the list of attribute names */
++      for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
++           entry = EXT2_XATTR_NEXT(entry)) {
++              struct ext2_xattr_handler *handler;
++              struct ext2_xattr_entry *next =
++                      EXT2_XATTR_NEXT(entry);
++              if ((char *)next >= end)
++                      goto bad_block;
++
++              handler = ext2_xattr_handler(entry->e_name_index);
++              if (handler)
++                      size += handler->list(NULL, inode, entry->e_name,
++                                            entry->e_name_len);
++      }
++
++      if (ext2_xattr_cache_insert(bh))
++              ea_idebug(inode, "cache insert failed");
++      if (!buffer) {
++              error = size;
++              goto cleanup;
++      } else {
++              error = -ERANGE;
++              if (size > buffer_size)
++                      goto cleanup;
++      }
++
++      /* list the attribute names */
++      buf = buffer;
++      for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
++           entry = EXT2_XATTR_NEXT(entry)) {
++              struct ext2_xattr_handler *handler;
++              
++              handler = ext2_xattr_handler(entry->e_name_index);
++              if (handler)
++                      buf += handler->list(buf, inode, entry->e_name,
++                                           entry->e_name_len);
++      }
++      error = size;
++
++cleanup:
++      brelse(bh);
++
++      return error;
++}
++
++/*
++ * If the EXT2_FEATURE_COMPAT_EXT_ATTR feature of this file system is
++ * not set, set it.
++ */
++static void ext2_xattr_update_super_block(struct super_block *sb)
++{
++      if (EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR))
++              return;
++
++      lock_super(sb);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
++      EXT2_SB(sb)->s_feature_compat |= EXT2_FEATURE_COMPAT_EXT_ATTR;
++#endif
++      EXT2_SB(sb)->s_es->s_feature_compat |=
++              cpu_to_le32(EXT2_FEATURE_COMPAT_EXT_ATTR);
++      sb->s_dirt = 1;
++      mark_buffer_dirty(EXT2_SB(sb)->s_sbh);
++      unlock_super(sb);
++}
++
++/*
++ * ext2_xattr_set()
++ *
++ * Create, replace or remove an extended attribute for this inode. Buffer
++ * is NULL to remove an existing extended attribute, and non-NULL to
++ * either replace an existing extended attribute, or create a new extended
++ * attribute. The flags XATTR_REPLACE and XATTR_CREATE
++ * specify that an extended attribute must exist and must not exist
++ * previous to the call, respectively.
++ *
++ * Returns 0, or a negative error number on failure.
++ */
++int
++ext2_xattr_set(struct inode *inode, int name_index, const char *name,
++             const void *value, size_t value_len, int flags)
++{
++      struct super_block *sb = inode->i_sb;
++      struct buffer_head *bh = NULL;
++      struct ext2_xattr_header *header = NULL;
++      struct ext2_xattr_entry *here, *last;
++      unsigned int name_len;
++      int block = EXT2_I(inode)->i_file_acl;
++      int min_offs = sb->s_blocksize, not_found = 1, free, error;
++      char *end;
++      
++      /*
++       * header -- Points either into bh, or to a temporarily
++       *           allocated buffer.
++       * here -- The named entry found, or the place for inserting, within
++       *         the block pointed to by header.
++       * last -- Points right after the last named entry within the block
++       *         pointed to by header.
++       * min_offs -- The offset of the first value (values are aligned
++       *             towards the end of the block).
++       * end -- Points right after the block pointed to by header.
++       */
++      
++      ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
++                name_index, name, value, (long)value_len);
++
++      if (IS_RDONLY(inode))
++              return -EROFS;
++      if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
++              return -EPERM;
++      if (value == NULL)
++              value_len = 0;
++      if (name == NULL)
++              return -EINVAL;
++      name_len = strlen(name);
++      if (name_len > 255 || value_len > sb->s_blocksize)
++              return -ERANGE;
++      down(&ext2_xattr_sem);
++
++      if (block) {
++              /* The inode already has an extended attribute block. */
++
++              bh = sb_bread(sb, block);
++              error = -EIO;
++              if (!bh)
++                      goto cleanup;
++              ea_bdebug(bh, "b_count=%d, refcount=%d",
++                      atomic_read(&(bh->b_count)),
++                      le32_to_cpu(HDR(bh)->h_refcount));
++              header = HDR(bh);
++              end = bh->b_data + bh->b_size;
++              if (header->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) ||
++                  header->h_blocks != cpu_to_le32(1)) {
++bad_block:            ext2_error(sb, "ext2_xattr_set",
++                              "inode %ld: bad block %d", inode->i_ino, block);
++                      error = -EIO;
++                      goto cleanup;
++              }
++              /* Find the named attribute. */
++              here = FIRST_ENTRY(bh);
++              while (!IS_LAST_ENTRY(here)) {
++                      struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(here);
++                      if ((char *)next >= end)
++                              goto bad_block;
++                      if (!here->e_value_block && here->e_value_size) {
++                              int offs = le16_to_cpu(here->e_value_offs);
++                              if (offs < min_offs)
++                                      min_offs = offs;
++                      }
++                      not_found = name_index - here->e_name_index;
++                      if (!not_found)
++                              not_found = name_len - here->e_name_len;
++                      if (!not_found)
++                              not_found = memcmp(name, here->e_name,name_len);
++                      if (not_found <= 0)
++                              break;
++                      here = next;
++              }
++              last = here;
++              /* We still need to compute min_offs and last. */
++              while (!IS_LAST_ENTRY(last)) {
++                      struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(last);
++                      if ((char *)next >= end)
++                              goto bad_block;
++                      if (!last->e_value_block && last->e_value_size) {
++                              int offs = le16_to_cpu(last->e_value_offs);
++                              if (offs < min_offs)
++                                      min_offs = offs;
++                      }
++                      last = next;
++              }
++
++              /* Check whether we have enough space left. */
++              free = min_offs - ((char*)last - (char*)header) - sizeof(__u32);
++      } else {
++              /* We will use a new extended attribute block. */
++              free = sb->s_blocksize -
++                      sizeof(struct ext2_xattr_header) - sizeof(__u32);
++              here = last = NULL;  /* avoid gcc uninitialized warning. */
++      }
++
++      if (not_found) {
++              /* Request to remove a nonexistent attribute? */
++              error = -ENOATTR;
++              if (flags & XATTR_REPLACE)
++                      goto cleanup;
++              error = 0;
++              if (value == NULL)
++                      goto cleanup;
++              else
++                      free -= EXT2_XATTR_LEN(name_len);
++      } else {
++              /* Request to create an existing attribute? */
++              error = -EEXIST;
++              if (flags & XATTR_CREATE)
++                      goto cleanup;
++              if (!here->e_value_block && here->e_value_size) {
++                      unsigned int size = le32_to_cpu(here->e_value_size);
++
++                      if (le16_to_cpu(here->e_value_offs) + size > 
++                          sb->s_blocksize || size > sb->s_blocksize)
++                              goto bad_block;
++                      free += EXT2_XATTR_SIZE(size);
++              }
++      }
++      free -= EXT2_XATTR_SIZE(value_len);
++      error = -ENOSPC;
++      if (free < 0)
++              goto cleanup;
++
++      /* Here we know that we can set the new attribute. */
++
++      if (header) {
++              if (header->h_refcount == cpu_to_le32(1)) {
++                      ea_bdebug(bh, "modifying in-place");
++                      ext2_xattr_cache_remove(bh);
++              } else {
++                      int offset;
++
++                      ea_bdebug(bh, "cloning");
++                      header = kmalloc(bh->b_size, GFP_KERNEL);
++                      error = -ENOMEM;
++                      if (header == NULL)
++                              goto cleanup;
++                      memcpy(header, HDR(bh), bh->b_size);
++                      header->h_refcount = cpu_to_le32(1);
++                      offset = (char *)header - bh->b_data;
++                      here = ENTRY((char *)here + offset);
++                      last = ENTRY((char *)last + offset);
++              }
++      } else {
++              /* Allocate a buffer where we construct the new block. */
++              header = kmalloc(sb->s_blocksize, GFP_KERNEL);
++              error = -ENOMEM;
++              if (header == NULL)
++                      goto cleanup;
++              memset(header, 0, sb->s_blocksize);
++              end = (char *)header + sb->s_blocksize;
++              header->h_magic = cpu_to_le32(EXT2_XATTR_MAGIC);
++              header->h_blocks = header->h_refcount = cpu_to_le32(1);
++              last = here = ENTRY(header+1);
++      }
++
++      if (not_found) {
++              /* Insert the new name. */
++              int size = EXT2_XATTR_LEN(name_len);
++              int rest = (char *)last - (char *)here;
++              memmove((char *)here + size, here, rest);
++              memset(here, 0, size);
++              here->e_name_index = name_index;
++              here->e_name_len = name_len;
++              memcpy(here->e_name, name, name_len);
++      } else {
++              /* Remove the old value. */
++              if (!here->e_value_block && here->e_value_size) {
++                      char *first_val = (char *)header + min_offs;
++                      int offs = le16_to_cpu(here->e_value_offs);
++                      char *val = (char *)header + offs;
++                      size_t size = EXT2_XATTR_SIZE(
++                              le32_to_cpu(here->e_value_size));
++                      memmove(first_val + size, first_val, val - first_val);
++                      memset(first_val, 0, size);
++                      here->e_value_offs = 0;
++                      min_offs += size;
++
++                      /* Adjust all value offsets. */
++                      last = ENTRY(header+1);
++                      while (!IS_LAST_ENTRY(last)) {
++                              int o = le16_to_cpu(last->e_value_offs);
++                              if (!last->e_value_block && o < offs)
++                                      last->e_value_offs =
++                                              cpu_to_le16(o + size);
++                              last = EXT2_XATTR_NEXT(last);
++                      }
++              }
++              if (value == NULL) {
++                      /* Remove this attribute. */
++                      if (EXT2_XATTR_NEXT(ENTRY(header+1)) == last) {
++                              /* This block is now empty. */
++                              error = ext2_xattr_set2(inode, bh, NULL);
++                              goto cleanup;
++                      } else {
++                              /* Remove the old name. */
++                              int size = EXT2_XATTR_LEN(name_len);
++                              last = ENTRY((char *)last - size);
++                              memmove(here, (char*)here + size,
++                                      (char*)last - (char*)here);
++                              memset(last, 0, size);
++                      }
++              }
++      }
++
++      if (value != NULL) {
++              /* Insert the new value. */
++              here->e_value_size = cpu_to_le32(value_len);
++              if (value_len) {
++                      size_t size = EXT2_XATTR_SIZE(value_len);
++                      char *val = (char *)header + min_offs - size;
++                      here->e_value_offs =
++                              cpu_to_le16((char *)val - (char *)header);
++                      memset(val + size - EXT2_XATTR_PAD, 0,
++                             EXT2_XATTR_PAD); /* Clear the pad bytes. */
++                      memcpy(val, value, value_len);
++              }
++      }
++      ext2_xattr_rehash(header, here);
++
++      error = ext2_xattr_set2(inode, bh, header);
++
++cleanup:
++      brelse(bh);
++      if (!(bh && header == HDR(bh)))
++              kfree(header);
++      up(&ext2_xattr_sem);
++
++      return error;
++}
++
++/*
++ * Second half of ext2_xattr_set(): Update the file system.
++ */
++static int
++ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
++              struct ext2_xattr_header *header)
++{
++      struct super_block *sb = inode->i_sb;
++      struct buffer_head *new_bh = NULL;
++      int error;
++
++      if (header) {
++              new_bh = ext2_xattr_cache_find(inode, header);
++              if (new_bh) {
++                      /*
++                       * We found an identical block in the cache.
++                       * The old block will be released after updating
++                       * the inode.
++                       */
++                      ea_bdebug(old_bh, "reusing block %ld",
++                              new_bh->b_blocknr);
++                      
++                      error = -EDQUOT;
++                      if (ext2_xattr_quota_alloc(inode, 1))
++                              goto cleanup;
++                      
++                      HDR(new_bh)->h_refcount = cpu_to_le32(
++                              le32_to_cpu(HDR(new_bh)->h_refcount) + 1);
++                      ea_bdebug(new_bh, "refcount now=%d",
++                              le32_to_cpu(HDR(new_bh)->h_refcount));
++              } else if (old_bh && header == HDR(old_bh)) {
++                      /* Keep this block. */
++                      new_bh = old_bh;
++                      (void)ext2_xattr_cache_insert(new_bh);
++              } else {
++                      /* We need to allocate a new block */
++                      int force = EXT2_I(inode)->i_file_acl != 0;
++                      int block = ext2_xattr_new_block(inode, &error, force);
++                      if (error)
++                              goto cleanup;
++                      ea_idebug(inode, "creating block %d", block);
++
++                      new_bh = sb_getblk(sb, block);
++                      if (!new_bh) {
++                              ext2_xattr_free_block(inode, block);
++                              error = -EIO;
++                              goto cleanup;
++                      }
++                      lock_buffer(new_bh);
++                      memcpy(new_bh->b_data, header, new_bh->b_size);
++                      mark_buffer_uptodate(new_bh, 1);
++                      unlock_buffer(new_bh);
++                      (void)ext2_xattr_cache_insert(new_bh);
++                      
++                      ext2_xattr_update_super_block(sb);
++              }
++              mark_buffer_dirty(new_bh);
++              if (IS_SYNC(inode)) {
++                      ll_rw_block(WRITE, 1, &new_bh);
++                      wait_on_buffer(new_bh); 
++                      error = -EIO;
++                      if (buffer_req(new_bh) && !buffer_uptodate(new_bh))
++                              goto cleanup;
++              }
++      }
++
++      /* Update the inode. */
++      EXT2_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0;
++      inode->i_ctime = CURRENT_TIME;
++      if (IS_SYNC(inode)) {
++              error = ext2_sync_inode (inode);
++              if (error)
++                      goto cleanup;
++      } else
++              mark_inode_dirty(inode);
++
++      error = 0;
++      if (old_bh && old_bh != new_bh) {
++              /*
++               * If there was an old block, and we are not still using it,
++               * we now release the old block.
++              */
++              unsigned int refcount = le32_to_cpu(HDR(old_bh)->h_refcount);
++
++              if (refcount == 1) {
++                      /* Free the old block. */
++                      ea_bdebug(old_bh, "freeing");
++                      ext2_xattr_free_block(inode, old_bh->b_blocknr);
++                      mark_buffer_clean(old_bh);
++              } else {
++                      /* Decrement the refcount only. */
++                      refcount--;
++                      HDR(old_bh)->h_refcount = cpu_to_le32(refcount);
++                      ext2_xattr_quota_free(inode);
++                      mark_buffer_dirty(old_bh);
++                      ea_bdebug(old_bh, "refcount now=%d", refcount);
++              }
++      }
++
++cleanup:
++      if (old_bh != new_bh)
++              brelse(new_bh);
++
++      return error;
++}
++
++/*
++ * ext2_xattr_delete_inode()
++ *
++ * Free extended attribute resources associated with this inode. This
++ * is called immediately before an inode is freed.
++ */
++void
++ext2_xattr_delete_inode(struct inode *inode)
++{
++      struct buffer_head *bh;
++      unsigned int block = EXT2_I(inode)->i_file_acl;
++
++      if (!block)
++              return;
++      down(&ext2_xattr_sem);
++
++      bh = sb_bread(inode->i_sb, block);
++      if (!bh) {
++              ext2_error(inode->i_sb, "ext2_xattr_delete_inode",
++                      "inode %ld: block %d read error", inode->i_ino, block);
++              goto cleanup;
++      }
++      ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count)));
++      if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) ||
++          HDR(bh)->h_blocks != cpu_to_le32(1)) {
++              ext2_error(inode->i_sb, "ext2_xattr_delete_inode",
++                      "inode %ld: bad block %d", inode->i_ino, block);
++              goto cleanup;
++      }
++      ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1);
++      if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
++              ext2_xattr_cache_remove(bh);
++              ext2_xattr_free_block(inode, block);
++              bforget(bh);
++              bh = NULL;
++      } else {
++              HDR(bh)->h_refcount = cpu_to_le32(
++                      le32_to_cpu(HDR(bh)->h_refcount) - 1);
++              mark_buffer_dirty(bh);
++              if (IS_SYNC(inode)) {
++                      ll_rw_block(WRITE, 1, &bh);
++                      wait_on_buffer(bh);
++              }
++              ext2_xattr_quota_free(inode);
++      }
++      EXT2_I(inode)->i_file_acl = 0;
++
++cleanup:
++      brelse(bh);
++      up(&ext2_xattr_sem);
++}
++
++/*
++ * ext2_xattr_put_super()
++ *
++ * This is called when a file system is unmounted.
++ */
++void
++ext2_xattr_put_super(struct super_block *sb)
++{
++#ifdef CONFIG_EXT2_FS_XATTR_SHARING
++      mb_cache_shrink(ext2_xattr_cache, sb->s_dev);
++#endif
++}
++
++#ifdef CONFIG_EXT2_FS_XATTR_SHARING
++
++/*
++ * ext2_xattr_cache_insert()
++ *
++ * Create a new entry in the extended attribute cache, and insert
++ * it unless such an entry is already in the cache.
++ *
++ * Returns 0, or a negative error number on failure.
++ */
++static int
++ext2_xattr_cache_insert(struct buffer_head *bh)
++{
++      __u32 hash = le32_to_cpu(HDR(bh)->h_hash);
++      struct mb_cache_entry *ce;
++      int error;
++
++      ce = mb_cache_entry_alloc(ext2_xattr_cache);
++      if (!ce)
++              return -ENOMEM;
++      error = mb_cache_entry_insert(ce, bh->b_dev, bh->b_blocknr, &hash);
++      if (error) {
++              mb_cache_entry_free(ce);
++              if (error == -EBUSY) {
++                      ea_bdebug(bh, "already in cache (%d cache entries)",
++                              atomic_read(&ext2_xattr_cache->c_entry_count));
++                      error = 0;
++              }
++      } else {
++              ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash,
++                        atomic_read(&ext2_xattr_cache->c_entry_count));
++              mb_cache_entry_release(ce);
++      }
++      return error;
++}
++
++/*
++ * ext2_xattr_cmp()
++ *
++ * Compare two extended attribute blocks for equality.
++ *
++ * Returns 0 if the blocks are equal, 1 if they differ, and
++ * a negative error number on errors.
++ */
++static int
++ext2_xattr_cmp(struct ext2_xattr_header *header1,
++             struct ext2_xattr_header *header2)
++{
++      struct ext2_xattr_entry *entry1, *entry2;
++
++      entry1 = ENTRY(header1+1);
++      entry2 = ENTRY(header2+1);
++      while (!IS_LAST_ENTRY(entry1)) {
++              if (IS_LAST_ENTRY(entry2))
++                      return 1;
++              if (entry1->e_hash != entry2->e_hash ||
++                  entry1->e_name_len != entry2->e_name_len ||
++                  entry1->e_value_size != entry2->e_value_size ||
++                  memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len))
++                      return 1;
++              if (entry1->e_value_block != 0 || entry2->e_value_block != 0)
++                      return -EIO;
++              if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs),
++                         (char *)header2 + le16_to_cpu(entry2->e_value_offs),
++                         le32_to_cpu(entry1->e_value_size)))
++                      return 1;
++
++              entry1 = EXT2_XATTR_NEXT(entry1);
++              entry2 = EXT2_XATTR_NEXT(entry2);
++      }
++      if (!IS_LAST_ENTRY(entry2))
++              return 1;
++      return 0;
++}
++
++/*
++ * ext2_xattr_cache_find()
++ *
++ * Find an identical extended attribute block.
++ *
++ * Returns a pointer to the block found, or NULL if such a block was
++ * not found or an error occurred.
++ */
++static struct buffer_head *
++ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header)
++{
++      __u32 hash = le32_to_cpu(header->h_hash);
++      struct mb_cache_entry *ce;
++
++      if (!header->h_hash)
++              return NULL;  /* never share */
++      ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
++      ce = mb_cache_entry_find_first(ext2_xattr_cache, 0, inode->i_dev, hash);
++      while (ce) {
++              struct buffer_head *bh = sb_bread(inode->i_sb, ce->e_block);
++
++              if (!bh) {
++                      ext2_error(inode->i_sb, "ext2_xattr_cache_find",
++                              "inode %ld: block %ld read error",
++                              inode->i_ino, ce->e_block);
++              } else if (le32_to_cpu(HDR(bh)->h_refcount) >
++                         EXT2_XATTR_REFCOUNT_MAX) {
++                      ea_idebug(inode, "block %ld refcount %d>%d",ce->e_block,
++                              le32_to_cpu(HDR(bh)->h_refcount),
++                              EXT2_XATTR_REFCOUNT_MAX);
++              } else if (!ext2_xattr_cmp(header, HDR(bh))) {
++                      ea_bdebug(bh, "b_count=%d",atomic_read(&(bh->b_count)));
++                      mb_cache_entry_release(ce);
++                      return bh;
++              }
++              brelse(bh);
++              ce = mb_cache_entry_find_next(ce, 0, inode->i_dev, hash);
++      }
++      return NULL;
++}
++
++/*
++ * ext2_xattr_cache_remove()
++ *
++ * Remove the cache entry of a block from the cache. Called when a
++ * block becomes invalid.
++ */
++static void
++ext2_xattr_cache_remove(struct buffer_head *bh)
++{
++      struct mb_cache_entry *ce;
++
++      ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_dev, bh->b_blocknr);
++      if (ce) {
++              ea_bdebug(bh, "removing (%d cache entries remaining)",
++                        atomic_read(&ext2_xattr_cache->c_entry_count)-1);
++              mb_cache_entry_free(ce);
++      } else 
++              ea_bdebug(bh, "no cache entry");
++}
++
++#define NAME_HASH_SHIFT 5
++#define VALUE_HASH_SHIFT 16
++
++/*
++ * ext2_xattr_hash_entry()
++ *
++ * Compute the hash of an extended attribute.
++ */
++static inline void ext2_xattr_hash_entry(struct ext2_xattr_header *header,
++                                       struct ext2_xattr_entry *entry)
++{
++      __u32 hash = 0;
++      char *name = entry->e_name;
++      int n;
++
++      for (n=0; n < entry->e_name_len; n++) {
++              hash = (hash << NAME_HASH_SHIFT) ^
++                     (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
++                     *name++;
++      }
++
++      if (entry->e_value_block == 0 && entry->e_value_size != 0) {
++              __u32 *value = (__u32 *)((char *)header +
++                      le16_to_cpu(entry->e_value_offs));
++              for (n = (le32_to_cpu(entry->e_value_size) +
++                   EXT2_XATTR_ROUND) >> EXT2_XATTR_PAD_BITS; n; n--) {
++                      hash = (hash << VALUE_HASH_SHIFT) ^
++                             (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
++                             le32_to_cpu(*value++);
++              }
++      }
++      entry->e_hash = cpu_to_le32(hash);
++}
++
++#undef NAME_HASH_SHIFT
++#undef VALUE_HASH_SHIFT
++
++#define BLOCK_HASH_SHIFT 16
++
++/*
++ * ext2_xattr_rehash()
++ *
++ * Re-compute the extended attribute hash value after an entry has changed.
++ */
++static void ext2_xattr_rehash(struct ext2_xattr_header *header,
++                            struct ext2_xattr_entry *entry)
++{
++      struct ext2_xattr_entry *here;
++      __u32 hash = 0;
++      
++      ext2_xattr_hash_entry(header, entry);
++      here = ENTRY(header+1);
++      while (!IS_LAST_ENTRY(here)) {
++              if (!here->e_hash) {
++                      /* Block is not shared if an entry's hash value == 0 */
++                      hash = 0;
++                      break;
++              }
++              hash = (hash << BLOCK_HASH_SHIFT) ^
++                     (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^
++                     le32_to_cpu(here->e_hash);
++              here = EXT2_XATTR_NEXT(here);
++      }
++      header->h_hash = cpu_to_le32(hash);
++}
++
++#undef BLOCK_HASH_SHIFT
++
++int __init
++init_ext2_xattr(void)
++{
++      ext2_xattr_cache = mb_cache_create("ext2_xattr", NULL,
++              sizeof(struct mb_cache_entry) +
++              sizeof(struct mb_cache_entry_index), 1, 61);
++      if (!ext2_xattr_cache)
++              return -ENOMEM;
++
++      return 0;
++}
++
++void
++exit_ext2_xattr(void)
++{
++      mb_cache_destroy(ext2_xattr_cache);
++}
++
++#else  /* CONFIG_EXT2_FS_XATTR_SHARING */
++
++int __init
++init_ext2_xattr(void)
++{
++      return 0;
++}
++
++void
++exit_ext2_xattr(void)
++{
++}
++
++#endif  /* CONFIG_EXT2_FS_XATTR_SHARING */
+Index: linux-2.4.29/fs/ext2/xattr_user.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext2/xattr_user.c     2005-05-03 17:59:40.233146800 +0300
++++ linux-2.4.29/fs/ext2/xattr_user.c  2005-05-03 17:59:40.407120352 +0300
+@@ -0,0 +1,103 @@
++/*
++ * linux/fs/ext2/xattr_user.c
++ * Handler for extended user attributes.
++ *
++ * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
++ */
++
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/fs.h>
++#include <linux/ext2_fs.h>
++#include <linux/ext2_xattr.h>
++
++#ifdef CONFIG_EXT2_FS_POSIX_ACL
++# include <linux/ext2_acl.h>
++#endif
++
++#define XATTR_USER_PREFIX "user."
++
++static size_t
++ext2_xattr_user_list(char *list, struct inode *inode,
++                   const char *name, int name_len)
++{
++      const int prefix_len = sizeof(XATTR_USER_PREFIX)-1;
++
++      if (!test_opt(inode->i_sb, XATTR_USER))
++              return 0;
++
++      if (list) {
++              memcpy(list, XATTR_USER_PREFIX, prefix_len);
++              memcpy(list+prefix_len, name, name_len);
++              list[prefix_len + name_len] = '\0';
++      }
++      return prefix_len + name_len + 1;
++}
++
++static int
++ext2_xattr_user_get(struct inode *inode, const char *name,
++                  void *buffer, size_t size)
++{
++      int error;
++
++      if (strcmp(name, "") == 0)
++              return -EINVAL;
++      if (!test_opt(inode->i_sb, XATTR_USER))
++              return -ENOTSUP;
++#ifdef CONFIG_EXT2_FS_POSIX_ACL
++      error = ext2_permission_locked(inode, MAY_READ);
++#else
++      error = permission(inode, MAY_READ);
++#endif
++      if (error)
++              return error;
++
++      return ext2_xattr_get(inode, EXT2_XATTR_INDEX_USER, name,
++                            buffer, size);
++}
++
++static int
++ext2_xattr_user_set(struct inode *inode, const char *name,
++                  const void *value, size_t size, int flags)
++{
++      int error;
++
++      if (strcmp(name, "") == 0)
++              return -EINVAL;
++      if (!test_opt(inode->i_sb, XATTR_USER))
++              return -ENOTSUP;
++      if ( !S_ISREG(inode->i_mode) &&
++          (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
++              return -EPERM;
++#ifdef CONFIG_EXT2_FS_POSIX_ACL
++      error = ext2_permission_locked(inode, MAY_WRITE);
++#else
++      error = permission(inode, MAY_WRITE);
++#endif
++      if (error)
++              return error;
++
++      return ext2_xattr_set(inode, EXT2_XATTR_INDEX_USER, name,
++                            value, size, flags);
++}
++
++struct ext2_xattr_handler ext2_xattr_user_handler = {
++      prefix: XATTR_USER_PREFIX,
++      list:   ext2_xattr_user_list,
++      get:    ext2_xattr_user_get,
++      set:    ext2_xattr_user_set,
++};
++
++int __init
++init_ext2_xattr_user(void)
++{
++      return ext2_xattr_register(EXT2_XATTR_INDEX_USER,
++                                 &ext2_xattr_user_handler);
++}
++
++void
++exit_ext2_xattr_user(void)
++{
++      ext2_xattr_unregister(EXT2_XATTR_INDEX_USER,
++                            &ext2_xattr_user_handler);
++}
+Index: linux-2.4.29/fs/ext3/Makefile
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/Makefile 2005-05-03 17:23:54.093409632 +0300
++++ linux-2.4.29/fs/ext3/Makefile      2005-05-03 17:59:40.408120200 +0300
+@@ -1,5 +1,5 @@
+ #
+-# Makefile for the linux ext2-filesystem routines.
++# Makefile for the linux ext3-filesystem routines.
+ #
+ # Note! Dependencies are done automagically by 'make dep', which also
+ # removes any old dependencies. DON'T put your own dependencies here
+@@ -9,10 +9,14 @@
+ O_TARGET := ext3.o
+-export-objs :=        super.o inode.o
++export-objs :=        ext3-exports.o
+ obj-y    := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+-              ioctl.o namei.o super.o symlink.o hash.o
++              ioctl.o namei.o super.o symlink.o hash.o ext3-exports.o
+ obj-m    := $(O_TARGET)
++export-objs += xattr.o
++obj-$(CONFIG_EXT3_FS_XATTR) += xattr.o
++obj-$(CONFIG_EXT3_FS_XATTR_USER) += xattr_user.o
++
+ include $(TOPDIR)/Rules.make
+Index: linux-2.4.29/fs/ext3/file.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/file.c   2005-05-03 17:23:54.091409936 +0300
++++ linux-2.4.29/fs/ext3/file.c        2005-05-03 17:59:40.410119896 +0300
+@@ -23,6 +23,7 @@
+ #include <linux/locks.h>
+ #include <linux/jbd.h>
+ #include <linux/ext3_fs.h>
++#include <linux/ext3_xattr.h>
+ #include <linux/ext3_jbd.h>
+ #include <linux/smp_lock.h>
+@@ -127,5 +128,9 @@
+ struct inode_operations ext3_file_inode_operations = {
+       truncate:       ext3_truncate,          /* BKL held */
+       setattr:        ext3_setattr,           /* BKL held */
++      setxattr:       ext3_setxattr,          /* BKL held */
++      getxattr:       ext3_getxattr,          /* BKL held */
++      listxattr:      ext3_listxattr,         /* BKL held */
++      removexattr:    ext3_removexattr,       /* BKL held */
+ };
+Index: linux-2.4.29/fs/ext3/ialloc.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/ialloc.c 2005-04-07 18:53:42.000000000 +0300
++++ linux-2.4.29/fs/ext3/ialloc.c      2005-05-03 17:59:40.411119744 +0300
+@@ -17,6 +17,7 @@
+ #include <linux/jbd.h>
+ #include <linux/ext3_fs.h>
+ #include <linux/ext3_jbd.h>
++#include <linux/ext3_xattr.h>
+ #include <linux/stat.h>
+ #include <linux/string.h>
+ #include <linux/locks.h>
+@@ -216,6 +217,7 @@
+        * as writing the quota to disk may need the lock as well.
+        */
+       DQUOT_INIT(inode);
++      ext3_xattr_delete_inode(handle, inode);
+       DQUOT_FREE_INODE(inode);
+       DQUOT_DROP(inode);
+Index: linux-2.4.29/fs/ext3/inode.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/inode.c  2005-04-07 18:54:16.000000000 +0300
++++ linux-2.4.29/fs/ext3/inode.c       2005-05-03 17:59:40.415119136 +0300
+@@ -60,7 +60,7 @@
+  * still needs to be revoked.
+  */
+-static int ext3_forget(handle_t *handle, int is_metadata,
++int ext3_forget(handle_t *handle, int is_metadata,
+                      struct inode *inode, struct buffer_head *bh,
+                      int blocknr)
+ {
+@@ -191,9 +191,7 @@
+ {
+       handle_t *handle;
+       
+-      if (is_bad_inode(inode) ||
+-          inode->i_ino == EXT3_ACL_IDX_INO ||
+-          inode->i_ino == EXT3_ACL_DATA_INO)
++      if (is_bad_inode(inode))
+               goto no_delete;
+       lock_kernel();
+@@ -1885,6 +1883,8 @@
+               return;
+       if (ext3_inode_is_fast_symlink(inode))
+               return;
++      if (ext3_inode_is_fast_symlink(inode))
++              return;
+       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+               return;
+@@ -2032,8 +2032,6 @@
+       struct ext3_group_desc * gdp;
+               
+       if ((inode->i_ino != EXT3_ROOT_INO &&
+-              inode->i_ino != EXT3_ACL_IDX_INO &&
+-              inode->i_ino != EXT3_ACL_DATA_INO &&
+               inode->i_ino != EXT3_JOURNAL_INO &&
+               inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) ||
+               inode->i_ino > le32_to_cpu(
+@@ -2174,10 +2172,7 @@
+               inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block];
+       INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
+-      if (inode->i_ino == EXT3_ACL_IDX_INO ||
+-          inode->i_ino == EXT3_ACL_DATA_INO)
+-              /* Nothing to do */ ;
+-      else if (S_ISREG(inode->i_mode)) {
++      if (S_ISREG(inode->i_mode)) {
+               inode->i_op = &ext3_file_inode_operations;
+               inode->i_fop = &ext3_file_operations;
+               inode->i_mapping->a_ops = &ext3_aops;
+@@ -2188,12 +2183,14 @@
+               if (ext3_inode_is_fast_symlink(inode))
+                       inode->i_op = &ext3_fast_symlink_inode_operations;
+               else {
+-                      inode->i_op = &page_symlink_inode_operations;
++                      inode->i_op = &ext3_symlink_inode_operations;
+                       inode->i_mapping->a_ops = &ext3_aops;
+               }
+-      } else 
++      } else {
++              inode->i_op = &ext3_special_inode_operations;
+               init_special_inode(inode, inode->i_mode,
+                                  le32_to_cpu(iloc.raw_inode->i_block[0]));
++      }
+       brelse(iloc.bh);
+       ext3_set_inode_flags(inode);
+       return;
+Index: linux-2.4.29/fs/ext3/namei.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/namei.c  2005-05-03 17:23:54.101408416 +0300
++++ linux-2.4.29/fs/ext3/namei.c       2005-05-03 17:59:40.419118528 +0300
+@@ -29,6 +29,7 @@
+ #include <linux/sched.h>
+ #include <linux/ext3_fs.h>
+ #include <linux/ext3_jbd.h>
++#include <linux/ext3_xattr.h>
+ #include <linux/fcntl.h>
+ #include <linux/stat.h>
+ #include <linux/string.h>
+@@ -1613,7 +1614,7 @@
+       if (IS_SYNC(dir))
+               handle->h_sync = 1;
+-      inode = ext3_new_inode (handle, dir, S_IFDIR);
++      inode = ext3_new_inode (handle, dir, S_IFDIR | mode);
+       err = PTR_ERR(inode);
+       if (IS_ERR(inode))
+               goto out_stop;
+@@ -1621,7 +1622,6 @@
+       inode->i_op = &ext3_dir_inode_operations;
+       inode->i_fop = &ext3_dir_operations;
+       inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
+-      inode->i_blocks = 0;    
+       dir_block = ext3_bread (handle, inode, 0, 1, &err);
+       if (!dir_block) {
+               inode->i_nlink--; /* is this nlink == 0? */
+@@ -1648,9 +1648,6 @@
+       BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata");
+       ext3_journal_dirty_metadata(handle, dir_block);
+       brelse (dir_block);
+-      inode->i_mode = S_IFDIR | mode;
+-      if (dir->i_mode & S_ISGID)
+-              inode->i_mode |= S_ISGID;
+       ext3_mark_inode_dirty(handle, inode);
+       err = ext3_add_entry (handle, dentry, inode);
+       if (err) {
+@@ -2019,7 +2016,7 @@
+               goto out_stop;
+       if (l > sizeof (EXT3_I(inode)->i_data)) {
+-              inode->i_op = &page_symlink_inode_operations;
++              inode->i_op = &ext3_symlink_inode_operations;
+               inode->i_mapping->a_ops = &ext3_aops;
+               /*
+                * block_symlink() calls back into ext3_prepare/commit_write.
+@@ -2248,4 +2245,16 @@
+       rmdir:          ext3_rmdir,             /* BKL held */
+       mknod:          ext3_mknod,             /* BKL held */
+       rename:         ext3_rename,            /* BKL held */
++      setxattr:       ext3_setxattr,          /* BKL held */
++      getxattr:       ext3_getxattr,          /* BKL held */
++      listxattr:      ext3_listxattr,         /* BKL held */
++      removexattr:    ext3_removexattr,       /* BKL held */
+ };
++
++struct inode_operations ext3_special_inode_operations = {
++      setxattr:       ext3_setxattr,          /* BKL held */
++      getxattr:       ext3_getxattr,          /* BKL held */
++      listxattr:      ext3_listxattr,         /* BKL held */
++      removexattr:    ext3_removexattr,       /* BKL held */
++};
++
+Index: linux-2.4.29/fs/ext3/super.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/super.c  2005-05-03 17:23:54.104407960 +0300
++++ linux-2.4.29/fs/ext3/super.c       2005-05-03 18:00:16.805586944 +0300
+@@ -24,6 +24,7 @@
+ #include <linux/jbd.h>
+ #include <linux/ext3_fs.h>
+ #include <linux/ext3_jbd.h>
++#include <linux/ext3_xattr.h>
+ #include <linux/slab.h>
+ #include <linux/init.h>
+ #include <linux/locks.h>
+@@ -406,6 +407,7 @@
+       kdev_t j_dev = sbi->s_journal->j_dev;
+       int i;
++      ext3_xattr_put_super(sb);
+       journal_destroy(sbi->s_journal);
+       if (!(sb->s_flags & MS_RDONLY)) {
+               EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
+@@ -504,6 +506,7 @@
+                         int is_remount)
+ {
+       unsigned long *mount_options = &sbi->s_mount_opt;
++      
+       uid_t *resuid = &sbi->s_resuid;
+       gid_t *resgid = &sbi->s_resgid;
+       char * this_char;
+@@ -516,6 +519,13 @@
+            this_char = strtok (NULL, ",")) {
+               if ((value = strchr (this_char, '=')) != NULL)
+                       *value++ = 0;
++#ifdef CONFIG_EXT3_FS_XATTR_USER
++              if (!strcmp (this_char, "user_xattr"))
++                      set_opt (*mount_options, XATTR_USER);
++              else if (!strcmp (this_char, "nouser_xattr"))
++                      clear_opt (*mount_options, XATTR_USER);
++              else
++#endif
+               if (!strcmp (this_char, "bsddf"))
+                       clear_opt (*mount_options, MINIX_DF);
+               else if (!strcmp (this_char, "nouid32")) {
+@@ -954,6 +964,12 @@
+       sbi->s_mount_opt = 0;
+       sbi->s_resuid = EXT3_DEF_RESUID;
+       sbi->s_resgid = EXT3_DEF_RESGID;
++
++      /* Default extended attribute flags */
++#ifdef CONFIG_EXT3_FS_XATTR_USER
++      /* set_opt(sbi->s_mount_opt, XATTR_USER); */
++#endif
++
+       if (!parse_options ((char *) data, &sb_block, sbi, &journal_inum, 0)) {
+               sb->s_dev = 0;
+               goto out_fail;
+@@ -1838,22 +1854,35 @@
+ static int __init init_ext3_fs(void)
+ {
++      int error;
+ #ifdef CONFIG_QUOTA
+       init_dquot_operations(&ext3_qops);
+       old_write_dquot = ext3_qops.write_dquot;
+       ext3_qops.write_dquot = ext3_write_dquot;
+ #endif
+-        return register_filesystem(&ext3_fs_type);
++      error = init_ext3_xattr();
++      if (error)
++              return error;
++      error = init_ext3_xattr_user();
++      if (error)
++              goto fail;
++      error = register_filesystem(&ext3_fs_type);
++      if (!error)
++              return 0;
++
++      exit_ext3_xattr_user();
++fail:
++      exit_ext3_xattr();
++      return error;
+ }
+ static void __exit exit_ext3_fs(void)
+ {
+       unregister_filesystem(&ext3_fs_type);
++      exit_ext3_xattr_user(); 
++      exit_ext3_xattr();
+ }
+-EXPORT_SYMBOL(ext3_force_commit);
+-EXPORT_SYMBOL(ext3_bread);
+-
+ MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
+ MODULE_DESCRIPTION("Second Extended Filesystem with journaling extensions");
+ MODULE_LICENSE("GPL");
+Index: linux-2.4.29/fs/ext3/symlink.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/symlink.c        2005-04-07 18:53:53.000000000 +0300
++++ linux-2.4.29/fs/ext3/symlink.c     2005-05-03 17:59:40.423117920 +0300
+@@ -20,6 +20,7 @@
+ #include <linux/fs.h>
+ #include <linux/jbd.h>
+ #include <linux/ext3_fs.h>
++#include <linux/ext3_xattr.h>
+ static int ext3_readlink(struct dentry *dentry, char *buffer, int buflen)
+ {
+@@ -33,7 +34,20 @@
+       return vfs_follow_link(nd, s);
+ }
++struct inode_operations ext3_symlink_inode_operations = {
++      readlink:       page_readlink,          /* BKL not held.  Don't need */
++      follow_link:    page_follow_link,       /* BKL not held.  Don't need */
++      setxattr:       ext3_setxattr,          /* BKL held */
++      getxattr:       ext3_getxattr,          /* BKL held */
++      listxattr:      ext3_listxattr,         /* BKL held */
++      removexattr:    ext3_removexattr,       /* BKL held */
++};
++
+ struct inode_operations ext3_fast_symlink_inode_operations = {
+       readlink:       ext3_readlink,          /* BKL not held.  Don't need */
+       follow_link:    ext3_follow_link,       /* BKL not held.  Don't need */
++      setxattr:       ext3_setxattr,          /* BKL held */
++      getxattr:       ext3_getxattr,          /* BKL held */
++      listxattr:      ext3_listxattr,         /* BKL held */
++      removexattr:    ext3_removexattr,       /* BKL held */
+ };
+Index: linux-2.4.29/fs/ext3/xattr.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/xattr.c  2005-05-03 17:59:40.234146648 +0300
++++ linux-2.4.29/fs/ext3/xattr.c       2005-05-03 17:59:40.428117160 +0300
+@@ -0,0 +1,1225 @@
++/*
++ * linux/fs/ext3/xattr.c
++ *
++ * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
++ *
++ * Fix by Harrison Xing <harrison@mountainviewdata.com>.
++ * Ext3 code with a lot of help from Eric Jarman <ejarman@acm.org>.
++ * Extended attributes for symlinks and special files added per
++ *  suggestion of Luka Renko <luka.renko@hermes.si>.
++ */
++
++/*
++ * Extended attributes are stored on disk blocks allocated outside of
++ * any inode. The i_file_acl field is then made to point to this allocated
++ * block. If all extended attributes of an inode are identical, these
++ * inodes may share the same extended attribute block. Such situations
++ * are automatically detected by keeping a cache of recent attribute block
++ * numbers and hashes over the block's contents in memory.
++ *
++ *
++ * Extended attribute block layout:
++ *
++ *   +------------------+
++ *   | header           |
++ *   | entry 1          | |
++ *   | entry 2          | | growing downwards
++ *   | entry 3          | v
++ *   | four null bytes  |
++ *   | . . .            |
++ *   | value 1          | ^
++ *   | value 3          | | growing upwards
++ *   | value 2          | |
++ *   +------------------+
++ *
++ * The block header is followed by multiple entry descriptors. These entry
++ * descriptors are variable in size, and alligned to EXT3_XATTR_PAD
++ * byte boundaries. The entry descriptors are sorted by attribute name,
++ * so that two extended attribute blocks can be compared efficiently.
++ *
++ * Attribute values are aligned to the end of the block, stored in
++ * no specific order. They are also padded to EXT3_XATTR_PAD byte
++ * boundaries. No additional gaps are left between them.
++ *
++ * Locking strategy
++ * ----------------
++ * The VFS already holds the BKL and the inode->i_sem semaphore when any of
++ * the xattr inode operations are called, so we are guaranteed that only one
++ * processes accesses extended attributes of an inode at any time.
++ *
++ * For writing we also grab the ext3_xattr_sem semaphore. This ensures that
++ * only a single process is modifying an extended attribute block, even
++ * if the block is shared among inodes.
++ *
++ * Note for porting to 2.5
++ * -----------------------
++ * The BKL will no longer be held in the xattr inode operations.
++ */
++
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/locks.h>
++#include <linux/slab.h>
++#include <linux/ext3_jbd.h>
++#include <linux/ext3_fs.h>
++#include <linux/ext3_xattr.h>
++#include <linux/mbcache.h>
++#include <linux/quotaops.h>
++#include <asm/semaphore.h>
++#include <linux/compatmac.h>
++
++#define EXT3_EA_USER "user."
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
++# define mark_buffer_dirty(bh) mark_buffer_dirty(bh, 1)
++#endif
++
++#define HDR(bh) ((struct ext3_xattr_header *)((bh)->b_data))
++#define ENTRY(ptr) ((struct ext3_xattr_entry *)(ptr))
++#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1)
++#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
++
++#ifdef EXT3_XATTR_DEBUG
++# define ea_idebug(inode, f...) do { \
++              printk(KERN_DEBUG "inode %s:%ld: ", \
++                      kdevname(inode->i_dev), inode->i_ino); \
++              printk(f); \
++              printk("\n"); \
++      } while (0)
++# define ea_bdebug(bh, f...) do { \
++              printk(KERN_DEBUG "block %s:%ld: ", \
++                      kdevname(bh->b_dev), bh->b_blocknr); \
++              printk(f); \
++              printk("\n"); \
++      } while (0)
++#else
++# define ea_idebug(f...)
++# define ea_bdebug(f...)
++#endif
++
++static int ext3_xattr_set2(handle_t *, struct inode *, struct buffer_head *,
++                         struct ext3_xattr_header *);
++
++#ifdef CONFIG_EXT3_FS_XATTR_SHARING
++
++static int ext3_xattr_cache_insert(struct buffer_head *);
++static struct buffer_head *ext3_xattr_cache_find(struct inode *,
++                                               struct ext3_xattr_header *);
++static void ext3_xattr_cache_remove(struct buffer_head *);
++static void ext3_xattr_rehash(struct ext3_xattr_header *,
++                            struct ext3_xattr_entry *);
++
++static struct mb_cache *ext3_xattr_cache;
++
++#else
++# define ext3_xattr_cache_insert(bh) 0
++# define ext3_xattr_cache_find(inode, header) NULL
++# define ext3_xattr_cache_remove(bh) while(0) {}
++# define ext3_xattr_rehash(header, entry) while(0) {}
++#endif
++
++/*
++ * If a file system does not share extended attributes among inodes,
++ * we should not need the ext3_xattr_sem semaphore. However, the
++ * filesystem may still contain shared blocks, so we always take
++ * the lock.
++ */
++
++DECLARE_MUTEX(ext3_xattr_sem);
++
++static inline int
++ext3_xattr_new_block(handle_t *handle, struct inode *inode,
++                   int * errp, int force)
++{
++      struct super_block *sb = inode->i_sb;
++      int goal = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
++              EXT3_I(inode)->i_block_group * EXT3_BLOCKS_PER_GROUP(sb);
++
++      /* How can we enforce the allocation? */
++      int block = ext3_new_block(handle, inode, goal, 0, 0, errp);
++#ifdef OLD_QUOTAS
++      if (!*errp)
++              inode->i_blocks += inode->i_sb->s_blocksize >> 9;
++#endif
++      return block;
++}
++
++static inline int
++ext3_xattr_quota_alloc(struct inode *inode, int force)
++{
++      /* How can we enforce the allocation? */
++#ifdef OLD_QUOTAS
++      int error = DQUOT_ALLOC_BLOCK(inode->i_sb, inode, 1);
++      if (!error)
++              inode->i_blocks += inode->i_sb->s_blocksize >> 9;
++#else
++      int error = DQUOT_ALLOC_BLOCK(inode, 1);
++#endif
++      return error;
++}
++
++#ifdef OLD_QUOTAS
++
++static inline void
++ext3_xattr_quota_free(struct inode *inode)
++{
++      DQUOT_FREE_BLOCK(inode->i_sb, inode, 1);
++      inode->i_blocks -= inode->i_sb->s_blocksize >> 9;
++}
++
++static inline void
++ext3_xattr_free_block(handle_t *handle, struct inode * inode,
++                    unsigned long block)
++{
++      ext3_free_blocks(handle, inode, block, 1);
++      inode->i_blocks -= inode->i_sb->s_blocksize >> 9;
++}
++
++#else
++# define ext3_xattr_quota_free(inode) \
++      DQUOT_FREE_BLOCK(inode, 1)
++# define ext3_xattr_free_block(handle, inode, block) \
++      ext3_free_blocks(handle, inode, block, 1)
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
++
++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);
++}
++
++#endif
++
++struct ext3_xattr_handler *ext3_xattr_handlers[EXT3_XATTR_INDEX_MAX];
++rwlock_t ext3_handler_lock = RW_LOCK_UNLOCKED;
++
++int
++ext3_xattr_register(int name_index, struct ext3_xattr_handler *handler)
++{
++      int error = -EINVAL;
++
++      if (name_index > 0 && name_index <= EXT3_XATTR_INDEX_MAX) {
++              write_lock(&ext3_handler_lock);
++              if (!ext3_xattr_handlers[name_index-1]) {
++                      ext3_xattr_handlers[name_index-1] = handler;
++                      error = 0;
++              }
++              write_unlock(&ext3_handler_lock);
++      }
++      return error;
++}
++
++void
++ext3_xattr_unregister(int name_index, struct ext3_xattr_handler *handler)
++{
++      if (name_index > 0 || name_index <= EXT3_XATTR_INDEX_MAX) {
++              write_lock(&ext3_handler_lock);
++              ext3_xattr_handlers[name_index-1] = NULL;
++              write_unlock(&ext3_handler_lock);
++      }
++}
++
++static inline const char *
++strcmp_prefix(const char *a, const char *a_prefix)
++{
++      while (*a_prefix && *a == *a_prefix) {
++              a++;
++              a_prefix++;
++      }
++      return *a_prefix ? NULL : a;
++}
++
++/*
++ * Decode the extended attribute name, and translate it into
++ * the name_index and name suffix.
++ */
++static inline struct ext3_xattr_handler *
++ext3_xattr_resolve_name(const char **name)
++{
++      struct ext3_xattr_handler *handler = NULL;
++      int i;
++
++      if (!*name)
++              return NULL;
++      read_lock(&ext3_handler_lock);
++      for (i=0; i<EXT3_XATTR_INDEX_MAX; i++) {
++              if (ext3_xattr_handlers[i]) {
++                      const char *n = strcmp_prefix(*name,
++                              ext3_xattr_handlers[i]->prefix);
++                      if (n) {
++                              handler = ext3_xattr_handlers[i];
++                              *name = n;
++                              break;
++                      }
++              }
++      }
++      read_unlock(&ext3_handler_lock);
++      return handler;
++}
++
++static inline struct ext3_xattr_handler *
++ext3_xattr_handler(int name_index)
++{
++      struct ext3_xattr_handler *handler = NULL;
++      if (name_index > 0 && name_index <= EXT3_XATTR_INDEX_MAX) {
++              read_lock(&ext3_handler_lock);
++              handler = ext3_xattr_handlers[name_index-1];
++              read_unlock(&ext3_handler_lock);
++      }
++      return handler;
++}
++
++/*
++ * Inode operation getxattr()
++ *
++ * dentry->d_inode->i_sem down
++ * BKL held [before 2.5.x]
++ */
++ssize_t
++ext3_getxattr(struct dentry *dentry, const char *name,
++            void *buffer, size_t size)
++{
++      struct ext3_xattr_handler *handler;
++      struct inode *inode = dentry->d_inode;
++
++      handler = ext3_xattr_resolve_name(&name);
++      if (!handler)
++              return -ENOTSUP;
++      return handler->get(inode, name, buffer, size);
++}
++
++/*
++ * Inode operation listxattr()
++ *
++ * dentry->d_inode->i_sem down
++ * BKL held [before 2.5.x]
++ */
++ssize_t
++ext3_listxattr(struct dentry *dentry, char *buffer, size_t size)
++{
++      return ext3_xattr_list(dentry->d_inode, buffer, size);
++}
++
++/*
++ * Inode operation setxattr()
++ *
++ * dentry->d_inode->i_sem down
++ * BKL held [before 2.5.x]
++ */
++int
++ext3_setxattr(struct dentry *dentry, const char *name,
++            const void *value, size_t size, int flags)
++{
++      struct ext3_xattr_handler *handler;
++      struct inode *inode = dentry->d_inode;
++
++      if (size == 0)
++              value = "";  /* empty EA, do not remove */
++      handler = ext3_xattr_resolve_name(&name);
++      if (!handler)
++              return -ENOTSUP;
++      return handler->set(inode, name, value, size, flags);
++}
++
++/*
++ * Inode operation removexattr()
++ *
++ * dentry->d_inode->i_sem down
++ * BKL held [before 2.5.x]
++ */
++int
++ext3_removexattr(struct dentry *dentry, const char *name)
++{
++      struct ext3_xattr_handler *handler;
++      struct inode *inode = dentry->d_inode;
++
++      handler = ext3_xattr_resolve_name(&name);
++      if (!handler)
++              return -ENOTSUP;
++      return handler->set(inode, name, NULL, 0, XATTR_REPLACE);
++}
++
++/*
++ * ext3_xattr_get()
++ *
++ * Copy an extended attribute into the buffer
++ * provided, or compute the buffer size required.
++ * Buffer is NULL to compute the size of the buffer required.
++ *
++ * Returns a negative error number on failure, or the number of bytes
++ * used / required on success.
++ */
++int
++ext3_xattr_get(struct inode *inode, int name_index, const char *name,
++             void *buffer, size_t buffer_size)
++{
++      struct buffer_head *bh = NULL;
++      struct ext3_xattr_entry *entry;
++      unsigned int block, size;
++      char *end;
++      int name_len, error;
++
++      ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
++                name_index, name, buffer, (long)buffer_size);
++
++      if (name == NULL)
++              return -EINVAL;
++      if (!EXT3_I(inode)->i_file_acl)
++              return -ENOATTR;
++      block = EXT3_I(inode)->i_file_acl;
++      ea_idebug(inode, "reading block %d", block);
++      bh = sb_bread(inode->i_sb, block);
++      if (!bh)
++              return -EIO;
++      ea_bdebug(bh, "b_count=%d, refcount=%d",
++              atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
++      end = bh->b_data + bh->b_size;
++      if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
++          HDR(bh)->h_blocks != cpu_to_le32(1)) {
++bad_block:    ext3_error(inode->i_sb, "ext3_xattr_get",
++                      "inode %ld: bad block %d", inode->i_ino, block);
++              error = -EIO;
++              goto cleanup;
++      }
++      /* find named attribute */
++      name_len = strlen(name);
++
++      error = -ERANGE;
++      if (name_len > 255)
++              goto cleanup;
++      entry = FIRST_ENTRY(bh);
++      while (!IS_LAST_ENTRY(entry)) {
++              struct ext3_xattr_entry *next =
++                      EXT3_XATTR_NEXT(entry);
++              if ((char *)next >= end)
++                      goto bad_block;
++              if (name_index == entry->e_name_index &&
++                  name_len == entry->e_name_len &&
++                  memcmp(name, entry->e_name, name_len) == 0)
++                      goto found;
++              entry = next;
++      }
++      /* Check the remaining name entries */
++      while (!IS_LAST_ENTRY(entry)) {
++              struct ext3_xattr_entry *next =
++                      EXT3_XATTR_NEXT(entry);
++              if ((char *)next >= end)
++                      goto bad_block;
++              entry = next;
++      }
++      if (ext3_xattr_cache_insert(bh))
++              ea_idebug(inode, "cache insert failed");
++      error = -ENOATTR;
++      goto cleanup;
++found:
++      /* check the buffer size */
++      if (entry->e_value_block != 0)
++              goto bad_block;
++      size = le32_to_cpu(entry->e_value_size);
++      if (size > inode->i_sb->s_blocksize ||
++          le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize)
++              goto bad_block;
++
++      if (ext3_xattr_cache_insert(bh))
++              ea_idebug(inode, "cache insert failed");
++      if (buffer) {
++              error = -ERANGE;
++              if (size > buffer_size)
++                      goto cleanup;
++              /* return value of attribute */
++              memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs),
++                      size);
++      }
++      error = size;
++
++cleanup:
++      brelse(bh);
++
++      return error;
++}
++
++/*
++ * ext3_xattr_list()
++ *
++ * Copy a list of attribute names into the buffer
++ * provided, or compute the buffer size required.
++ * Buffer is NULL to compute the size of the buffer required.
++ *
++ * Returns a negative error number on failure, or the number of bytes
++ * used / required on success.
++ */
++int
++ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
++{
++      struct buffer_head *bh = NULL;
++      struct ext3_xattr_entry *entry;
++      unsigned int block, size = 0;
++      char *buf, *end;
++      int error;
++
++      ea_idebug(inode, "buffer=%p, buffer_size=%ld",
++                buffer, (long)buffer_size);
++
++      if (!EXT3_I(inode)->i_file_acl)
++              return 0;
++      block = EXT3_I(inode)->i_file_acl;
++      ea_idebug(inode, "reading block %d", block);
++      bh = sb_bread(inode->i_sb, block);
++      if (!bh)
++              return -EIO;
++      ea_bdebug(bh, "b_count=%d, refcount=%d",
++              atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
++      end = bh->b_data + bh->b_size;
++      if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
++          HDR(bh)->h_blocks != cpu_to_le32(1)) {
++bad_block:    ext3_error(inode->i_sb, "ext3_xattr_list",
++                      "inode %ld: bad block %d", inode->i_ino, block);
++              error = -EIO;
++              goto cleanup;
++      }
++      /* compute the size required for the list of attribute names */
++      for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
++           entry = EXT3_XATTR_NEXT(entry)) {
++              struct ext3_xattr_handler *handler;
++              struct ext3_xattr_entry *next =
++                      EXT3_XATTR_NEXT(entry);
++              if ((char *)next >= end)
++                      goto bad_block;
++
++              handler = ext3_xattr_handler(entry->e_name_index);
++              if (handler)
++                      size += handler->list(NULL, inode, entry->e_name,
++                                            entry->e_name_len);
++      }
++
++      if (ext3_xattr_cache_insert(bh))
++              ea_idebug(inode, "cache insert failed");
++      if (!buffer) {
++              error = size;
++              goto cleanup;
++      } else {
++              error = -ERANGE;
++              if (size > buffer_size)
++                      goto cleanup;
++      }
++
++      /* list the attribute names */
++      buf = buffer;
++      for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
++           entry = EXT3_XATTR_NEXT(entry)) {
++              struct ext3_xattr_handler *handler;
++
++              handler = ext3_xattr_handler(entry->e_name_index);
++              if (handler)
++                      buf += handler->list(buf, inode, entry->e_name,
++                                           entry->e_name_len);
++      }
++      error = size;
++
++cleanup:
++      brelse(bh);
++
++      return error;
++}
++
++/*
++ * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is
++ * not set, set it.
++ */
++static void ext3_xattr_update_super_block(handle_t *handle,
++                                        struct super_block *sb)
++{
++      if (EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR))
++              return;
++
++      lock_super(sb);
++      ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
++      EXT3_SB(sb)->s_feature_compat |= EXT3_FEATURE_COMPAT_EXT_ATTR;
++#endif
++      EXT3_SB(sb)->s_es->s_feature_compat |=
++              cpu_to_le32(EXT3_FEATURE_COMPAT_EXT_ATTR);
++      sb->s_dirt = 1;
++      ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
++      unlock_super(sb);
++}
++
++/*
++ * ext3_xattr_set()
++ *
++ * Create, replace or remove an extended attribute for this inode. Buffer
++ * is NULL to remove an existing extended attribute, and non-NULL to
++ * either replace an existing extended attribute, or create a new extended
++ * attribute. The flags XATTR_REPLACE and XATTR_CREATE
++ * specify that an extended attribute must exist and must not exist
++ * previous to the call, respectively.
++ *
++ * Returns 0, or a negative error number on failure.
++ */
++int
++ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index,
++             const char *name, const void *value, size_t value_len, int flags)
++{
++      struct super_block *sb = inode->i_sb;
++      struct buffer_head *bh = NULL;
++      struct ext3_xattr_header *header = NULL;
++      struct ext3_xattr_entry *here, *last;
++      unsigned int name_len;
++      int block = EXT3_I(inode)->i_file_acl;
++      int min_offs = sb->s_blocksize, not_found = 1, free, error;
++      char *end;
++      
++      /*
++       * header -- Points either into bh, or to a temporarily
++       *           allocated buffer.
++       * here -- The named entry found, or the place for inserting, within
++       *         the block pointed to by header.
++       * last -- Points right after the last named entry within the block
++       *         pointed to by header.
++       * min_offs -- The offset of the first value (values are aligned
++       *             towards the end of the block).
++       * end -- Points right after the block pointed to by header.
++       */
++      
++      ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
++                name_index, name, value, (long)value_len);
++
++      if (IS_RDONLY(inode))
++              return -EROFS;
++      if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
++              return -EPERM;
++      if (value == NULL)
++              value_len = 0;
++      if (name == NULL)
++              return -EINVAL;
++      name_len = strlen(name);
++      if (name_len > 255 || value_len > sb->s_blocksize)
++              return -ERANGE;
++      down(&ext3_xattr_sem);
++
++      if (block) {
++              /* The inode already has an extended attribute block. */
++              bh = sb_bread(sb, block);
++              error = -EIO;
++              if (!bh)
++                      goto cleanup;
++              ea_bdebug(bh, "b_count=%d, refcount=%d",
++                      atomic_read(&(bh->b_count)),
++                      le32_to_cpu(HDR(bh)->h_refcount));
++              header = HDR(bh);
++              end = bh->b_data + bh->b_size;
++              if (header->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
++                  header->h_blocks != cpu_to_le32(1)) {
++bad_block:            ext3_error(sb, "ext3_xattr_set",
++                              "inode %ld: bad block %d", inode->i_ino, block);
++                      error = -EIO;
++                      goto cleanup;
++              }
++              /* Find the named attribute. */
++              here = FIRST_ENTRY(bh);
++              while (!IS_LAST_ENTRY(here)) {
++                      struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(here);
++                      if ((char *)next >= end)
++                              goto bad_block;
++                      if (!here->e_value_block && here->e_value_size) {
++                              int offs = le16_to_cpu(here->e_value_offs);
++                              if (offs < min_offs)
++                                      min_offs = offs;
++                      }
++                      not_found = name_index - here->e_name_index;
++                      if (!not_found)
++                              not_found = name_len - here->e_name_len;
++                      if (!not_found)
++                              not_found = memcmp(name, here->e_name,name_len);
++                      if (not_found <= 0)
++                              break;
++                      here = next;
++              }
++              last = here;
++              /* We still need to compute min_offs and last. */
++              while (!IS_LAST_ENTRY(last)) {
++                      struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
++                      if ((char *)next >= end)
++                              goto bad_block;
++                      if (!last->e_value_block && last->e_value_size) {
++                              int offs = le16_to_cpu(last->e_value_offs);
++                              if (offs < min_offs)
++                                      min_offs = offs;
++                      }
++                      last = next;
++              }
++
++              /* Check whether we have enough space left. */
++              free = min_offs - ((char*)last - (char*)header) - sizeof(__u32);
++      } else {
++              /* We will use a new extended attribute block. */
++              free = sb->s_blocksize -
++                      sizeof(struct ext3_xattr_header) - sizeof(__u32);
++              here = last = NULL;  /* avoid gcc uninitialized warning. */
++      }
++
++      if (not_found) {
++              /* Request to remove a nonexistent attribute? */
++              error = -ENOATTR;
++              if (flags & XATTR_REPLACE)
++                      goto cleanup;
++              error = 0;
++              if (value == NULL)
++                      goto cleanup;
++              else
++                      free -= EXT3_XATTR_LEN(name_len);
++      } else {
++              /* Request to create an existing attribute? */
++              error = -EEXIST;
++              if (flags & XATTR_CREATE)
++                      goto cleanup;
++              if (!here->e_value_block && here->e_value_size) {
++                      unsigned int size = le32_to_cpu(here->e_value_size);
++
++                      if (le16_to_cpu(here->e_value_offs) + size > 
++                          sb->s_blocksize || size > sb->s_blocksize)
++                              goto bad_block;
++                      free += EXT3_XATTR_SIZE(size);
++              }
++      }
++      free -= EXT3_XATTR_SIZE(value_len);
++      error = -ENOSPC;
++      if (free < 0)
++              goto cleanup;
++
++      /* Here we know that we can set the new attribute. */
++
++      if (header) {
++              if (header->h_refcount == cpu_to_le32(1)) {
++                      ea_bdebug(bh, "modifying in-place");
++                      ext3_xattr_cache_remove(bh);
++                      error = ext3_journal_get_write_access(handle, bh);
++                      if (error)
++                              goto cleanup;
++              } else {
++                      int offset;
++
++                      ea_bdebug(bh, "cloning");
++                      header = kmalloc(bh->b_size, GFP_KERNEL);
++                      error = -ENOMEM;
++                      if (header == NULL)
++                              goto cleanup;
++                      memcpy(header, HDR(bh), bh->b_size);
++                      header->h_refcount = cpu_to_le32(1);
++                      offset = (char *)header - bh->b_data;
++                      here = ENTRY((char *)here + offset);
++                      last = ENTRY((char *)last + offset);
++              }
++      } else {
++              /* Allocate a buffer where we construct the new block. */
++              header = kmalloc(sb->s_blocksize, GFP_KERNEL);
++              error = -ENOMEM;
++              if (header == NULL)
++                      goto cleanup;
++              memset(header, 0, sb->s_blocksize);
++              end = (char *)header + sb->s_blocksize;
++              header->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC);
++              header->h_blocks = header->h_refcount = cpu_to_le32(1);
++              last = here = ENTRY(header+1);
++      }
++
++      if (not_found) {
++              /* Insert the new name. */
++              int size = EXT3_XATTR_LEN(name_len);
++              int rest = (char *)last - (char *)here;
++              memmove((char *)here + size, here, rest);
++              memset(here, 0, size);
++              here->e_name_index = name_index;
++              here->e_name_len = name_len;
++              memcpy(here->e_name, name, name_len);
++      } else {
++              /* Remove the old value. */
++              if (!here->e_value_block && here->e_value_size) {
++                      char *first_val = (char *)header + min_offs;
++                      int offs = le16_to_cpu(here->e_value_offs);
++                      char *val = (char *)header + offs;
++                      size_t size = EXT3_XATTR_SIZE(
++                              le32_to_cpu(here->e_value_size));
++                      memmove(first_val + size, first_val, val - first_val);
++                      memset(first_val, 0, size);
++                      here->e_value_offs = 0;
++                      min_offs += size;
++
++                      /* Adjust all value offsets. */
++                      last = ENTRY(header+1);
++                      while (!IS_LAST_ENTRY(last)) {
++                              int o = le16_to_cpu(last->e_value_offs);
++                              if (!last->e_value_block && o < offs)
++                                      last->e_value_offs =
++                                              cpu_to_le16(o + size);
++                              last = EXT3_XATTR_NEXT(last);
++                      }
++              }
++              if (value == NULL) {
++                      /* Remove this attribute. */
++                      if (EXT3_XATTR_NEXT(ENTRY(header+1)) == last) {
++                              /* This block is now empty. */
++                              error = ext3_xattr_set2(handle, inode, bh,NULL);
++                              goto cleanup;
++                      } else {
++                              /* Remove the old name. */
++                              int size = EXT3_XATTR_LEN(name_len);
++                              last = ENTRY((char *)last - size);
++                              memmove(here, (char*)here + size,
++                                      (char*)last - (char*)here);
++                              memset(last, 0, size);
++                      }
++              }
++      }
++
++      if (value != NULL) {
++              /* Insert the new value. */
++              here->e_value_size = cpu_to_le32(value_len);
++              if (value_len) {
++                      size_t size = EXT3_XATTR_SIZE(value_len);
++                      char *val = (char *)header + min_offs - size;
++                      here->e_value_offs =
++                              cpu_to_le16((char *)val - (char *)header);
++                      memset(val + size - EXT3_XATTR_PAD, 0,
++                             EXT3_XATTR_PAD); /* Clear the pad bytes. */
++                      memcpy(val, value, value_len);
++              }
++      }
++      ext3_xattr_rehash(header, here);
++
++      error = ext3_xattr_set2(handle, inode, bh, header);
++
++cleanup:
++      brelse(bh);
++      if (!(bh && header == HDR(bh)))
++              kfree(header);
++      up(&ext3_xattr_sem);
++
++      return error;
++}
++
++/*
++ * Second half of ext3_xattr_set(): Update the file system.
++ */
++static int
++ext3_xattr_set2(handle_t *handle, struct inode *inode,
++              struct buffer_head *old_bh, struct ext3_xattr_header *header)
++{
++      struct super_block *sb = inode->i_sb;
++      struct buffer_head *new_bh = NULL;
++      int error;
++
++      if (header) {
++              new_bh = ext3_xattr_cache_find(inode, header);
++              if (new_bh) {
++                      /*
++                       * We found an identical block in the cache.
++                       * The old block will be released after updating
++                       * the inode.
++                       */
++                      ea_bdebug(old_bh, "reusing block %ld",
++                              new_bh->b_blocknr);
++                      
++                      error = -EDQUOT;
++                      if (ext3_xattr_quota_alloc(inode, 1))
++                              goto cleanup;
++                      
++                      error = ext3_journal_get_write_access(handle, new_bh);
++                      if (error)
++                              goto cleanup;
++                      HDR(new_bh)->h_refcount = cpu_to_le32(
++                              le32_to_cpu(HDR(new_bh)->h_refcount) + 1);
++                      ea_bdebug(new_bh, "refcount now=%d",
++                              le32_to_cpu(HDR(new_bh)->h_refcount));
++              } else if (old_bh && header == HDR(old_bh)) {
++                      /* Keep this block. */
++                      new_bh = old_bh;
++                      (void)ext3_xattr_cache_insert(new_bh);
++              } else {
++                      /* We need to allocate a new block */
++                      int force = EXT3_I(inode)->i_file_acl != 0;
++                      int block = ext3_xattr_new_block(handle, inode,
++                                                       &error, force);
++                      if (error)
++                              goto cleanup;
++                      ea_idebug(inode, "creating block %d", block);
++
++                      new_bh = sb_getblk(sb, block);
++                      if (!new_bh) {
++getblk_failed:                        ext3_xattr_free_block(handle, inode, block);
++                              error = -EIO;
++                              goto cleanup;
++                      }
++                      lock_buffer(new_bh);
++                      error = ext3_journal_get_create_access(handle, new_bh);
++                      if (error) {
++                              unlock_buffer(new_bh);
++                              goto getblk_failed;
++                      }
++                      memcpy(new_bh->b_data, header, new_bh->b_size);
++                      mark_buffer_uptodate(new_bh, 1);
++                      unlock_buffer(new_bh);
++                      (void)ext3_xattr_cache_insert(new_bh);
++                      
++                      ext3_xattr_update_super_block(handle, sb);
++              }
++              error = ext3_journal_dirty_metadata(handle, new_bh);
++              if (error)
++                      goto cleanup;
++      }
++
++      /* Update the inode. */
++      EXT3_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0;
++      inode->i_ctime = CURRENT_TIME;
++      ext3_mark_inode_dirty(handle, inode);
++      if (IS_SYNC(inode))
++              handle->h_sync = 1;
++
++      error = 0;
++      if (old_bh && old_bh != new_bh) {
++              /*
++               * If there was an old block, and we are not still using it,
++               * we now release the old block.
++              */
++              unsigned int refcount = le32_to_cpu(HDR(old_bh)->h_refcount);
++
++              error = ext3_journal_get_write_access(handle, old_bh);
++              if (error)
++                      goto cleanup;
++              if (refcount == 1) {
++                      /* Free the old block. */
++                      ea_bdebug(old_bh, "freeing");
++                      ext3_xattr_free_block(handle, inode, old_bh->b_blocknr);
++
++                      /* ext3_forget() calls bforget() for us, but we
++                         let our caller release old_bh, so we need to
++                         duplicate the handle before. */
++                      get_bh(old_bh);
++                      ext3_forget(handle, 1, inode, old_bh,old_bh->b_blocknr);
++              } else {
++                      /* Decrement the refcount only. */
++                      refcount--;
++                      HDR(old_bh)->h_refcount = cpu_to_le32(refcount);
++                      ext3_xattr_quota_free(inode);
++                      ext3_journal_dirty_metadata(handle, old_bh);
++                      ea_bdebug(old_bh, "refcount now=%d", refcount);
++              }
++      }
++
++cleanup:
++      if (old_bh != new_bh)
++              brelse(new_bh);
++
++      return error;
++}
++
++/*
++ * ext3_xattr_delete_inode()
++ *
++ * Free extended attribute resources associated with this inode. This
++ * is called immediately before an inode is freed.
++ */
++void
++ext3_xattr_delete_inode(handle_t *handle, struct inode *inode)
++{
++      struct buffer_head *bh;
++      unsigned int block = EXT3_I(inode)->i_file_acl;
++
++      if (!block)
++              return;
++      down(&ext3_xattr_sem);
++
++      bh = sb_bread(inode->i_sb, block);
++      if (!bh) {
++              ext3_error(inode->i_sb, "ext3_xattr_delete_inode",
++                      "inode %ld: block %d read error", inode->i_ino, block);
++              goto cleanup;
++      }
++      ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count)));
++      if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
++          HDR(bh)->h_blocks != cpu_to_le32(1)) {
++              ext3_error(inode->i_sb, "ext3_xattr_delete_inode",
++                      "inode %ld: bad block %d", inode->i_ino, block);
++              goto cleanup;
++      }
++      ext3_journal_get_write_access(handle, bh);
++      ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1);
++      if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
++              ext3_xattr_cache_remove(bh);
++              ext3_xattr_free_block(handle, inode, block);
++              ext3_forget(handle, 1, inode, bh, block);
++              bh = NULL;
++      } else {
++              HDR(bh)->h_refcount = cpu_to_le32(
++                      le32_to_cpu(HDR(bh)->h_refcount) - 1);
++              ext3_journal_dirty_metadata(handle, bh);
++              if (IS_SYNC(inode))
++                      handle->h_sync = 1;
++              ext3_xattr_quota_free(inode);
++      }
++      EXT3_I(inode)->i_file_acl = 0;
++
++cleanup:
++      brelse(bh);
++      up(&ext3_xattr_sem);
++}
++
++/*
++ * ext3_xattr_put_super()
++ *
++ * This is called when a file system is unmounted.
++ */
++void
++ext3_xattr_put_super(struct super_block *sb)
++{
++#ifdef CONFIG_EXT3_FS_XATTR_SHARING
++      mb_cache_shrink(ext3_xattr_cache, sb->s_dev);
++#endif
++}
++
++#ifdef CONFIG_EXT3_FS_XATTR_SHARING
++
++/*
++ * ext3_xattr_cache_insert()
++ *
++ * Create a new entry in the extended attribute cache, and insert
++ * it unless such an entry is already in the cache.
++ *
++ * Returns 0, or a negative error number on failure.
++ */
++static int
++ext3_xattr_cache_insert(struct buffer_head *bh)
++{
++      __u32 hash = le32_to_cpu(HDR(bh)->h_hash);
++      struct mb_cache_entry *ce;
++      int error;
++
++      ce = mb_cache_entry_alloc(ext3_xattr_cache);
++      if (!ce)
++              return -ENOMEM;
++      error = mb_cache_entry_insert(ce, bh->b_dev, bh->b_blocknr, &hash);
++      if (error) {
++              mb_cache_entry_free(ce);
++              if (error == -EBUSY) {
++                      ea_bdebug(bh, "already in cache (%d cache entries)",
++                              atomic_read(&ext3_xattr_cache->c_entry_count));
++                      error = 0;
++              }
++      } else {
++              ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash,
++                        atomic_read(&ext3_xattr_cache->c_entry_count));
++              mb_cache_entry_release(ce);
++      }
++      return error;
++}
++
++/*
++ * ext3_xattr_cmp()
++ *
++ * Compare two extended attribute blocks for equality.
++ *
++ * Returns 0 if the blocks are equal, 1 if they differ, and
++ * a negative error number on errors.
++ */
++static int
++ext3_xattr_cmp(struct ext3_xattr_header *header1,
++             struct ext3_xattr_header *header2)
++{
++      struct ext3_xattr_entry *entry1, *entry2;
++
++      entry1 = ENTRY(header1+1);
++      entry2 = ENTRY(header2+1);
++      while (!IS_LAST_ENTRY(entry1)) {
++              if (IS_LAST_ENTRY(entry2))
++                      return 1;
++              if (entry1->e_hash != entry2->e_hash ||
++                  entry1->e_name_len != entry2->e_name_len ||
++                  entry1->e_value_size != entry2->e_value_size ||
++                  memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len))
++                      return 1;
++              if (entry1->e_value_block != 0 || entry2->e_value_block != 0)
++                      return -EIO;
++              if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs),
++                         (char *)header2 + le16_to_cpu(entry2->e_value_offs),
++                         le32_to_cpu(entry1->e_value_size)))
++                      return 1;
++
++              entry1 = EXT3_XATTR_NEXT(entry1);
++              entry2 = EXT3_XATTR_NEXT(entry2);
++      }
++      if (!IS_LAST_ENTRY(entry2))
++              return 1;
++      return 0;
++}
++
++/*
++ * ext3_xattr_cache_find()
++ *
++ * Find an identical extended attribute block.
++ *
++ * Returns a pointer to the block found, or NULL if such a block was
++ * not found or an error occurred.
++ */
++static struct buffer_head *
++ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header)
++{
++      __u32 hash = le32_to_cpu(header->h_hash);
++      struct mb_cache_entry *ce;
++
++      if (!header->h_hash)
++              return NULL;  /* never share */
++      ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
++      ce = mb_cache_entry_find_first(ext3_xattr_cache, 0, inode->i_dev, hash);
++      while (ce) {
++              struct buffer_head *bh = sb_bread(inode->i_sb, ce->e_block);
++
++              if (!bh) {
++                      ext3_error(inode->i_sb, "ext3_xattr_cache_find",
++                              "inode %ld: block %ld read error",
++                              inode->i_ino, ce->e_block);
++              } else if (le32_to_cpu(HDR(bh)->h_refcount) >
++                         EXT3_XATTR_REFCOUNT_MAX) {
++                      ea_idebug(inode, "block %ld refcount %d>%d",ce->e_block,
++                              le32_to_cpu(HDR(bh)->h_refcount),
++                              EXT3_XATTR_REFCOUNT_MAX);
++              } else if (!ext3_xattr_cmp(header, HDR(bh))) {
++                      ea_bdebug(bh, "b_count=%d",atomic_read(&(bh->b_count)));
++                      mb_cache_entry_release(ce);
++                      return bh;
++              }
++              brelse(bh);
++              ce = mb_cache_entry_find_next(ce, 0, inode->i_dev, hash);
++      }
++      return NULL;
++}
++
++/*
++ * ext3_xattr_cache_remove()
++ *
++ * Remove the cache entry of a block from the cache. Called when a
++ * block becomes invalid.
++ */
++static void
++ext3_xattr_cache_remove(struct buffer_head *bh)
++{
++      struct mb_cache_entry *ce;
++
++      ce = mb_cache_entry_get(ext3_xattr_cache, bh->b_dev, bh->b_blocknr);
++      if (ce) {
++              ea_bdebug(bh, "removing (%d cache entries remaining)",
++                        atomic_read(&ext3_xattr_cache->c_entry_count)-1);
++              mb_cache_entry_free(ce);
++      } else 
++              ea_bdebug(bh, "no cache entry");
++}
++
++#define NAME_HASH_SHIFT 5
++#define VALUE_HASH_SHIFT 16
++
++/*
++ * ext3_xattr_hash_entry()
++ *
++ * Compute the hash of an extended attribute.
++ */
++static inline void ext3_xattr_hash_entry(struct ext3_xattr_header *header,
++                                       struct ext3_xattr_entry *entry)
++{
++      __u32 hash = 0;
++      char *name = entry->e_name;
++      int n;
++
++      for (n=0; n < entry->e_name_len; n++) {
++              hash = (hash << NAME_HASH_SHIFT) ^
++                     (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
++                     *name++;
++      }
++
++      if (entry->e_value_block == 0 && entry->e_value_size != 0) {
++              __u32 *value = (__u32 *)((char *)header +
++                      le16_to_cpu(entry->e_value_offs));
++              for (n = (le32_to_cpu(entry->e_value_size) +
++                   EXT3_XATTR_ROUND) >> EXT3_XATTR_PAD_BITS; n; n--) {
++                      hash = (hash << VALUE_HASH_SHIFT) ^
++                             (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
++                             le32_to_cpu(*value++);
++              }
++      }
++      entry->e_hash = cpu_to_le32(hash);
++}
++
++#undef NAME_HASH_SHIFT
++#undef VALUE_HASH_SHIFT
++
++#define BLOCK_HASH_SHIFT 16
++
++/*
++ * ext3_xattr_rehash()
++ *
++ * Re-compute the extended attribute hash value after an entry has changed.
++ */
++static void ext3_xattr_rehash(struct ext3_xattr_header *header,
++                            struct ext3_xattr_entry *entry)
++{
++      struct ext3_xattr_entry *here;
++      __u32 hash = 0;
++      
++      ext3_xattr_hash_entry(header, entry);
++      here = ENTRY(header+1);
++      while (!IS_LAST_ENTRY(here)) {
++              if (!here->e_hash) {
++                      /* Block is not shared if an entry's hash value == 0 */
++                      hash = 0;
++                      break;
++              }
++              hash = (hash << BLOCK_HASH_SHIFT) ^
++                     (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^
++                     le32_to_cpu(here->e_hash);
++              here = EXT3_XATTR_NEXT(here);
++      }
++      header->h_hash = cpu_to_le32(hash);
++}
++
++#undef BLOCK_HASH_SHIFT
++
++int __init
++init_ext3_xattr(void)
++{
++      ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL,
++              sizeof(struct mb_cache_entry) +
++              sizeof(struct mb_cache_entry_index), 1, 61);
++      if (!ext3_xattr_cache)
++              return -ENOMEM;
++
++      return 0;
++}
++
++void
++exit_ext3_xattr(void)
++{
++      if (ext3_xattr_cache)
++              mb_cache_destroy(ext3_xattr_cache);
++      ext3_xattr_cache = NULL;
++}
++
++#else  /* CONFIG_EXT3_FS_XATTR_SHARING */
++
++int __init
++init_ext3_xattr(void)
++{
++      return 0;
++}
++
++void
++exit_ext3_xattr(void)
++{
++}
++
++#endif  /* CONFIG_EXT3_FS_XATTR_SHARING */
+Index: linux-2.4.29/fs/ext3/xattr_user.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/xattr_user.c     2005-05-03 17:59:40.234146648 +0300
++++ linux-2.4.29/fs/ext3/xattr_user.c  2005-05-03 17:59:40.429117008 +0300
+@@ -0,0 +1,111 @@
++/*
++ * linux/fs/ext3/xattr_user.c
++ * Handler for extended user attributes.
++ *
++ * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
++ */
++
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/fs.h>
++#include <linux/ext3_jbd.h>
++#include <linux/ext3_fs.h>
++#include <linux/ext3_xattr.h>
++
++#ifdef CONFIG_EXT3_FS_POSIX_ACL
++# include <linux/ext3_acl.h>
++#endif
++
++#define XATTR_USER_PREFIX "user."
++
++static size_t
++ext3_xattr_user_list(char *list, struct inode *inode,
++                   const char *name, int name_len)
++{
++      const int prefix_len = sizeof(XATTR_USER_PREFIX)-1;
++
++      if (!test_opt(inode->i_sb, XATTR_USER))
++              return 0;
++
++      if (list) {
++              memcpy(list, XATTR_USER_PREFIX, prefix_len);
++              memcpy(list+prefix_len, name, name_len);
++              list[prefix_len + name_len] = '\0';
++      }
++      return prefix_len + name_len + 1;
++}
++
++static int
++ext3_xattr_user_get(struct inode *inode, const char *name,
++                  void *buffer, size_t size)
++{
++      int error;
++
++      if (strcmp(name, "") == 0)
++              return -EINVAL;
++      if (!test_opt(inode->i_sb, XATTR_USER))
++              return -ENOTSUP;
++#ifdef CONFIG_EXT3_FS_POSIX_ACL
++      error = ext3_permission_locked(inode, MAY_READ);
++#else
++      error = permission(inode, MAY_READ);
++#endif
++      if (error)
++              return error;
++
++      return ext3_xattr_get(inode, EXT3_XATTR_INDEX_USER, name,
++                            buffer, size);
++}
++
++static int
++ext3_xattr_user_set(struct inode *inode, const char *name,
++                  const void *value, size_t size, int flags)
++{
++      handle_t *handle;
++      int error;
++
++      if (strcmp(name, "") == 0)
++              return -EINVAL;
++      if (!test_opt(inode->i_sb, XATTR_USER))
++              return -ENOTSUP;
++      if ( !S_ISREG(inode->i_mode) &&
++          (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
++              return -EPERM;
++#ifdef CONFIG_EXT3_FS_POSIX_ACL
++      error = ext3_permission_locked(inode, MAY_WRITE);
++#else
++      error = permission(inode, MAY_WRITE);
++#endif
++      if (error)
++              return error;
++
++      handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS);
++      if (IS_ERR(handle))
++              return PTR_ERR(handle);
++      error = ext3_xattr_set(handle, inode, EXT3_XATTR_INDEX_USER, name,
++                             value, size, flags);
++      ext3_journal_stop(handle, inode);
++
++      return error;
++}
++
++struct ext3_xattr_handler ext3_xattr_user_handler = {
++      prefix: XATTR_USER_PREFIX,
++      list:   ext3_xattr_user_list,
++      get:    ext3_xattr_user_get,
++      set:    ext3_xattr_user_set,
++};
++
++int __init
++init_ext3_xattr_user(void)
++{
++      return ext3_xattr_register(EXT3_XATTR_INDEX_USER,
++                                 &ext3_xattr_user_handler);
++}
++
++void
++exit_ext3_xattr_user(void)
++{
++      ext3_xattr_unregister(EXT3_XATTR_INDEX_USER,
++                            &ext3_xattr_user_handler);
++}
+Index: linux-2.4.29/fs/ext3/ext3-exports.c
+===================================================================
+--- linux-2.4.29.orig/fs/ext3/ext3-exports.c   2005-05-03 17:59:40.234146648 +0300
++++ linux-2.4.29/fs/ext3/ext3-exports.c        2005-05-03 18:00:08.195895816 +0300
+@@ -0,0 +1,13 @@
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/ext3_fs.h>
++#include <linux/ext3_jbd.h>
++#include <linux/ext3_xattr.h>
++
++EXPORT_SYMBOL(ext3_force_commit);
++EXPORT_SYMBOL(ext3_bread);
++EXPORT_SYMBOL(ext3_xattr_register);
++EXPORT_SYMBOL(ext3_xattr_unregister);
++EXPORT_SYMBOL(ext3_xattr_get);
++EXPORT_SYMBOL(ext3_xattr_list);
++EXPORT_SYMBOL(ext3_xattr_set);
+Index: linux-2.4.29/fs/jfs/jfs_xattr.h
+===================================================================
+--- linux-2.4.29.orig/fs/jfs/jfs_xattr.h       2005-04-07 18:53:29.000000000 +0300
++++ linux-2.4.29/fs/jfs/jfs_xattr.h    2005-05-03 17:59:40.431116704 +0300
+@@ -52,8 +52,10 @@
+ #define       END_EALIST(ealist) \
+       ((struct jfs_ea *) (((char *) (ealist)) + EALIST_SIZE(ealist)))
+-extern int __jfs_setxattr(struct inode *, const char *, void *, size_t, int);
+-extern int jfs_setxattr(struct dentry *, const char *, void *, size_t, int);
++extern int __jfs_setxattr(struct inode *, const char *, const void *, size_t,
++                        int);
++extern int jfs_setxattr(struct dentry *, const char *, const void *, size_t,
++                      int);
+ extern ssize_t __jfs_getxattr(struct inode *, const char *, void *, size_t);
+ extern ssize_t jfs_getxattr(struct dentry *, const char *, void *, size_t);
+ extern ssize_t jfs_listxattr(struct dentry *, char *, size_t);
+Index: linux-2.4.29/fs/jfs/xattr.c
+===================================================================
+--- linux-2.4.29.orig/fs/jfs/xattr.c   2005-04-07 18:52:32.000000000 +0300
++++ linux-2.4.29/fs/jfs/xattr.c        2005-05-03 17:59:40.433116400 +0300
+@@ -649,7 +649,7 @@
+ }
+ static int can_set_xattr(struct inode *inode, const char *name,
+-                       void *value, size_t value_len)
++                       const void *value, size_t value_len)
+ {
+       if (IS_RDONLY(inode))
+               return -EROFS;
+@@ -668,7 +668,7 @@
+       return permission(inode, MAY_WRITE);
+ }
+-int __jfs_setxattr(struct inode *inode, const char *name, void *value,
++int __jfs_setxattr(struct inode *inode, const char *name, const void *value,
+                  size_t value_len, int flags)
+ {
+       struct jfs_ea_list *ealist;
+@@ -807,7 +807,7 @@
+       return rc;
+ }
+-int jfs_setxattr(struct dentry *dentry, const char *name, void *value,
++int jfs_setxattr(struct dentry *dentry, const char *name, const void *value,
+                size_t value_len, int flags)
+ {
+       if (value == NULL) {    /* empty EA, do not remove */
+Index: linux-2.4.29/fs/mbcache.c
+===================================================================
+--- linux-2.4.29.orig/fs/mbcache.c     2005-05-03 17:59:40.235146496 +0300
++++ linux-2.4.29/fs/mbcache.c  2005-05-03 17:59:40.436115944 +0300
+@@ -0,0 +1,648 @@
++/*
++ * linux/fs/mbcache.c
++ * (C) 2001-2002 Andreas Gruenbacher, <a.gruenbacher@computer.org>
++ */
++
++/*
++ * Filesystem Meta Information Block Cache (mbcache)
++ *
++ * The mbcache caches blocks of block devices that need to be located
++ * by their device/block number, as well as by other criteria (such
++ * as the block's contents).
++ *
++ * There can only be one cache entry in a cache per device and block number.
++ * Additional indexes need not be unique in this sense. The number of
++ * additional indexes (=other criteria) can be hardwired at compile time
++ * or specified at cache create time.
++ *
++ * Each cache entry is of fixed size. An entry may be `valid' or `invalid'
++ * in the cache. A valid entry is in the main hash tables of the cache,
++ * and may also be in the lru list. An invalid entry is not in any hashes
++ * or lists.
++ *
++ * A valid cache entry is only in the lru list if no handles refer to it.
++ * Invalid cache entries will be freed when the last handle to the cache
++ * entry is released. Entries that cannot be freed immediately are put
++ * back on the lru list.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/cache_def.h>
++#include <linux/version.h>
++#include <linux/init.h>
++#include <linux/mbcache.h>
++
++
++#ifdef MB_CACHE_DEBUG
++# define mb_debug(f...) do { \
++              printk(KERN_DEBUG f); \
++              printk("\n"); \
++      } while (0)
++#define mb_assert(c) do { if (!(c)) \
++              printk(KERN_ERR "assertion " #c " failed\n"); \
++      } while(0)
++#else
++# define mb_debug(f...) do { } while(0)
++# define mb_assert(c) do { } while(0)
++#endif
++#define mb_error(f...) do { \
++              printk(KERN_ERR f); \
++              printk("\n"); \
++      } while(0)
++              
++MODULE_AUTHOR("Andreas Gruenbacher <a.gruenbacher@computer.org>");
++MODULE_DESCRIPTION("Meta block cache (for extended attributes)");
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
++MODULE_LICENSE("GPL");
++#endif
++
++EXPORT_SYMBOL(mb_cache_create);
++EXPORT_SYMBOL(mb_cache_shrink);
++EXPORT_SYMBOL(mb_cache_destroy);
++EXPORT_SYMBOL(mb_cache_entry_alloc);
++EXPORT_SYMBOL(mb_cache_entry_insert);
++EXPORT_SYMBOL(mb_cache_entry_release);
++EXPORT_SYMBOL(mb_cache_entry_takeout);
++EXPORT_SYMBOL(mb_cache_entry_free);
++EXPORT_SYMBOL(mb_cache_entry_dup);
++EXPORT_SYMBOL(mb_cache_entry_get);
++#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0)
++EXPORT_SYMBOL(mb_cache_entry_find_first);
++EXPORT_SYMBOL(mb_cache_entry_find_next);
++#endif
++
++
++/*
++ * Global data: list of all mbcache's, lru list, and a spinlock for
++ * accessing cache data structures on SMP machines. The lru list is
++ * global across all mbcaches.
++ */
++
++static LIST_HEAD(mb_cache_list);
++static LIST_HEAD(mb_cache_lru_list);
++static spinlock_t mb_cache_spinlock = SPIN_LOCK_UNLOCKED;
++
++static inline int
++mb_cache_indexes(struct mb_cache *cache)
++{
++#ifdef MB_CACHE_INDEXES_COUNT
++      return MB_CACHE_INDEXES_COUNT;
++#else
++      return cache->c_indexes_count;
++#endif
++}
++
++/*
++ * What the mbcache registers as to get shrunk dynamically.
++ */
++
++static void
++mb_cache_memory_pressure(int priority, unsigned int gfp_mask);
++
++static struct cache_definition mb_cache_definition = {
++      "mb_cache",
++      mb_cache_memory_pressure
++};
++
++
++static inline int
++__mb_cache_entry_is_hashed(struct mb_cache_entry *ce)
++{
++      return !list_empty(&ce->e_block_list);
++}
++
++
++static inline void
++__mb_cache_entry_unhash(struct mb_cache_entry *ce)
++{
++      int n;
++
++      if (__mb_cache_entry_is_hashed(ce)) {
++              list_del_init(&ce->e_block_list);
++              for (n=0; n<mb_cache_indexes(ce->e_cache); n++)
++                      list_del(&ce->e_indexes[n].o_list);
++      }
++}
++
++
++static inline void
++__mb_cache_entry_forget(struct mb_cache_entry *ce, int gfp_mask)
++{
++      struct mb_cache *cache = ce->e_cache;
++
++      mb_assert(atomic_read(&ce->e_used) == 0);
++      if (cache->c_op.free && cache->c_op.free(ce, gfp_mask)) {
++              /* free failed -- put back on the lru list
++                 for freeing later. */
++              spin_lock(&mb_cache_spinlock);
++              list_add(&ce->e_lru_list, &mb_cache_lru_list);
++              spin_unlock(&mb_cache_spinlock);
++      } else {
++              kmem_cache_free(cache->c_entry_cache, ce);
++              atomic_dec(&cache->c_entry_count);
++      }
++}
++
++
++static inline void
++__mb_cache_entry_release_unlock(struct mb_cache_entry *ce)
++{
++      if (atomic_dec_and_test(&ce->e_used)) {
++              if (__mb_cache_entry_is_hashed(ce))
++                      list_add_tail(&ce->e_lru_list, &mb_cache_lru_list);
++              else {
++                      spin_unlock(&mb_cache_spinlock);
++                      __mb_cache_entry_forget(ce, GFP_KERNEL);
++                      return;
++              }
++      }
++      spin_unlock(&mb_cache_spinlock);
++}
++
++
++/*
++ * mb_cache_memory_pressure()  memory pressure callback
++ *
++ * This function is called by the kernel memory management when memory
++ * gets low.
++ *
++ * @priority: Amount by which to shrink the cache (0 = highes priority)
++ * @gfp_mask: (ignored)
++ */
++static void
++mb_cache_memory_pressure(int priority, unsigned int gfp_mask)
++{
++      LIST_HEAD(free_list);
++      struct list_head *l, *ltmp;
++      int count = 0;
++
++      spin_lock(&mb_cache_spinlock);
++      list_for_each(l, &mb_cache_list) {
++              struct mb_cache *cache =
++                      list_entry(l, struct mb_cache, c_cache_list);
++              mb_debug("cache %s (%d)", cache->c_name,
++                        atomic_read(&cache->c_entry_count));
++              count += atomic_read(&cache->c_entry_count);
++      }
++      mb_debug("trying to free %d of %d entries",
++                count / (priority ? priority : 1), count);
++      if (priority)
++              count /= priority;
++      while (count-- && !list_empty(&mb_cache_lru_list)) {
++              struct mb_cache_entry *ce =
++                      list_entry(mb_cache_lru_list.next,
++                                 struct mb_cache_entry, e_lru_list);
++              list_del(&ce->e_lru_list);
++              __mb_cache_entry_unhash(ce);
++              list_add_tail(&ce->e_lru_list, &free_list);
++      }
++      spin_unlock(&mb_cache_spinlock);
++      list_for_each_safe(l, ltmp, &free_list) {
++              __mb_cache_entry_forget(list_entry(l, struct mb_cache_entry,
++                                                 e_lru_list), gfp_mask);
++      }
++}
++
++
++/*
++ * mb_cache_create()  create a new cache
++ *
++ * All entries in one cache are equal size. Cache entries may be from
++ * multiple devices. If this is the first mbcache created, registers
++ * the cache with kernel memory management. Returns NULL if no more
++ * memory was available.
++ *
++ * @name: name of the cache (informal)
++ * @cache_op: contains the callback called when freeing a cache entry
++ * @entry_size: The size of a cache entry, including
++ *              struct mb_cache_entry
++ * @indexes_count: number of additional indexes in the cache. Must equal
++ *                 MB_CACHE_INDEXES_COUNT if the number of indexes is
++ *                 hardwired.
++ * @bucket_count: number of hash buckets
++ */
++struct mb_cache *
++mb_cache_create(const char *name, struct mb_cache_op *cache_op,
++              size_t entry_size, int indexes_count, int bucket_count)
++{
++      int m=0, n;
++      struct mb_cache *cache = NULL;
++
++      if(entry_size < sizeof(struct mb_cache_entry) +
++         indexes_count * sizeof(struct mb_cache_entry_index))
++              return NULL;
++
++      MOD_INC_USE_COUNT;
++      cache = kmalloc(sizeof(struct mb_cache) +
++                      indexes_count * sizeof(struct list_head), GFP_KERNEL);
++      if (!cache)
++              goto fail;
++      cache->c_name = name;
++      cache->c_op.free = NULL;
++      if (cache_op)
++              cache->c_op.free = cache_op->free;
++      atomic_set(&cache->c_entry_count, 0);
++      cache->c_bucket_count = bucket_count;
++#ifdef MB_CACHE_INDEXES_COUNT
++      mb_assert(indexes_count == MB_CACHE_INDEXES_COUNT);
++#else
++      cache->c_indexes_count = indexes_count;
++#endif
++      cache->c_block_hash = kmalloc(bucket_count * sizeof(struct list_head),
++                                    GFP_KERNEL);
++      if (!cache->c_block_hash)
++              goto fail;
++      for (n=0; n<bucket_count; n++)
++              INIT_LIST_HEAD(&cache->c_block_hash[n]);
++      for (m=0; m<indexes_count; m++) {
++              cache->c_indexes_hash[m] = kmalloc(bucket_count *
++                                               sizeof(struct list_head),
++                                               GFP_KERNEL);
++              if (!cache->c_indexes_hash[m])
++                      goto fail;
++              for (n=0; n<bucket_count; n++)
++                      INIT_LIST_HEAD(&cache->c_indexes_hash[m][n]);
++      }
++      cache->c_entry_cache = kmem_cache_create(name, entry_size, 0,
++              0 /*SLAB_POISON | SLAB_RED_ZONE*/, NULL, NULL);
++      if (!cache->c_entry_cache)
++              goto fail;
++
++      spin_lock(&mb_cache_spinlock);
++      list_add(&cache->c_cache_list, &mb_cache_list);
++      spin_unlock(&mb_cache_spinlock);
++      return cache;
++
++fail:
++      if (cache) {
++              while (--m >= 0)
++                      kfree(cache->c_indexes_hash[m]);
++              if (cache->c_block_hash)
++                      kfree(cache->c_block_hash);
++              kfree(cache);
++      }
++      MOD_DEC_USE_COUNT;
++      return NULL;
++}
++
++
++/*
++ * mb_cache_shrink()
++ *
++ * Removes all cache entires of a device from the cache. All cache entries
++ * currently in use cannot be freed, and thus remain in the cache.
++ *
++ * @cache: which cache to shrink
++ * @dev: which device's cache entries to shrink
++ */
++void
++mb_cache_shrink(struct mb_cache *cache, kdev_t dev)
++{
++      LIST_HEAD(free_list);
++      struct list_head *l, *ltmp;
++
++      spin_lock(&mb_cache_spinlock);
++      list_for_each_safe(l, ltmp, &mb_cache_lru_list) {
++              struct mb_cache_entry *ce =
++                      list_entry(l, struct mb_cache_entry, e_lru_list);
++              if (ce->e_dev == dev) {
++                      list_del(&ce->e_lru_list);
++                      list_add_tail(&ce->e_lru_list, &free_list);
++                      __mb_cache_entry_unhash(ce);
++              }
++      }
++      spin_unlock(&mb_cache_spinlock);
++      list_for_each_safe(l, ltmp, &free_list) {
++              __mb_cache_entry_forget(list_entry(l, struct mb_cache_entry,
++                                                 e_lru_list), GFP_KERNEL);
++      }
++}
++
++
++/*
++ * mb_cache_destroy()
++ *
++ * Shrinks the cache to its minimum possible size (hopefully 0 entries),
++ * and then destroys it. If this was the last mbcache, un-registers the
++ * mbcache from kernel memory management.
++ */
++void
++mb_cache_destroy(struct mb_cache *cache)
++{
++      LIST_HEAD(free_list);
++      struct list_head *l, *ltmp;
++      int n;
++
++      spin_lock(&mb_cache_spinlock);
++      list_for_each_safe(l, ltmp, &mb_cache_lru_list) {
++              struct mb_cache_entry *ce =
++                      list_entry(l, struct mb_cache_entry, e_lru_list);
++              if (ce->e_cache == cache) {
++                      list_del(&ce->e_lru_list);
++                      list_add_tail(&ce->e_lru_list, &free_list);
++                      __mb_cache_entry_unhash(ce);
++              }
++      }
++      list_del(&cache->c_cache_list);
++      spin_unlock(&mb_cache_spinlock);
++      list_for_each_safe(l, ltmp, &free_list) {
++              __mb_cache_entry_forget(list_entry(l, struct mb_cache_entry,
++                                                 e_lru_list), GFP_KERNEL);
++      }
++
++      if (atomic_read(&cache->c_entry_count) > 0) {
++              mb_error("cache %s: %d orphaned entries",
++                        cache->c_name,
++                        atomic_read(&cache->c_entry_count));
++      }
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
++      /* We don't have kmem_cache_destroy() in 2.2.x */
++      kmem_cache_shrink(cache->c_entry_cache);
++#else
++      kmem_cache_destroy(cache->c_entry_cache);
++#endif
++      for (n=0; n < mb_cache_indexes(cache); n++)
++              kfree(cache->c_indexes_hash[n]);
++      kfree(cache->c_block_hash);
++      kfree(cache);
++
++      MOD_DEC_USE_COUNT;
++}
++
++
++/*
++ * mb_cache_entry_alloc()
++ *
++ * Allocates a new cache entry. The new entry will not be valid initially,
++ * and thus cannot be looked up yet. It should be filled with data, and
++ * then inserted into the cache using mb_cache_entry_insert(). Returns NULL
++ * if no more memory was available.
++ */
++struct mb_cache_entry *
++mb_cache_entry_alloc(struct mb_cache *cache)
++{
++      struct mb_cache_entry *ce;
++
++      atomic_inc(&cache->c_entry_count);
++      ce = kmem_cache_alloc(cache->c_entry_cache, GFP_KERNEL);
++      if (ce) {
++              INIT_LIST_HEAD(&ce->e_lru_list);
++              INIT_LIST_HEAD(&ce->e_block_list);
++              ce->e_cache = cache;
++              atomic_set(&ce->e_used, 1);
++      }
++      return ce;
++}
++
++
++/*
++ * mb_cache_entry_insert()
++ *
++ * Inserts an entry that was allocated using mb_cache_entry_alloc() into
++ * the cache. After this, the cache entry can be looked up, but is not yet
++ * in the lru list as the caller still holds a handle to it. Returns 0 on
++ * success, or -EBUSY if a cache entry for that device + inode exists
++ * already (this may happen after a failed lookup, if another process has
++ * inserted the same cache entry in the meantime).
++ *
++ * @dev: device the cache entry belongs to
++ * @block: block number
++ * @keys: array of additional keys. There must be indexes_count entries
++ *        in the array (as specified when creating the cache).
++ */
++int
++mb_cache_entry_insert(struct mb_cache_entry *ce, kdev_t dev,
++                    unsigned long block, unsigned int keys[])
++{
++      struct mb_cache *cache = ce->e_cache;
++      unsigned int bucket = (HASHDEV(dev) + block) % cache->c_bucket_count;
++      struct list_head *l;
++      int error = -EBUSY, n;
++
++      spin_lock(&mb_cache_spinlock);
++      list_for_each(l, &cache->c_block_hash[bucket]) {
++              struct mb_cache_entry *ce =
++                      list_entry(l, struct mb_cache_entry, e_block_list);
++              if (ce->e_dev == dev && ce->e_block == block)
++                      goto out;
++      }
++      __mb_cache_entry_unhash(ce);
++      ce->e_dev = dev;
++      ce->e_block = block;
++      list_add(&ce->e_block_list, &cache->c_block_hash[bucket]);
++      for (n=0; n<mb_cache_indexes(cache); n++) {
++              ce->e_indexes[n].o_key = keys[n];
++              bucket = keys[n] % cache->c_bucket_count;
++              list_add(&ce->e_indexes[n].o_list,
++                       &cache->c_indexes_hash[n][bucket]);
++      }
++out:
++      spin_unlock(&mb_cache_spinlock);
++      return error;
++}
++
++
++/*
++ * mb_cache_entry_release()
++ *
++ * Release a handle to a cache entry. When the last handle to a cache entry
++ * is released it is either freed (if it is invalid) or otherwise inserted
++ * in to the lru list.
++ */
++void
++mb_cache_entry_release(struct mb_cache_entry *ce)
++{
++      spin_lock(&mb_cache_spinlock);
++      __mb_cache_entry_release_unlock(ce);
++}
++
++
++/*
++ * mb_cache_entry_takeout()
++ *
++ * Take a cache entry out of the cache, making it invalid. The entry can later
++ * be re-inserted using mb_cache_entry_insert(), or released using
++ * mb_cache_entry_release().
++ */
++void
++mb_cache_entry_takeout(struct mb_cache_entry *ce)
++{
++      spin_lock(&mb_cache_spinlock);
++      mb_assert(list_empty(&ce->e_lru_list));
++      __mb_cache_entry_unhash(ce);
++      spin_unlock(&mb_cache_spinlock);
++}
++
++
++/*
++ * mb_cache_entry_free()
++ *
++ * This is equivalent to the sequence mb_cache_entry_takeout() --
++ * mb_cache_entry_release().
++ */
++void
++mb_cache_entry_free(struct mb_cache_entry *ce)
++{
++      spin_lock(&mb_cache_spinlock);
++      mb_assert(list_empty(&ce->e_lru_list));
++      __mb_cache_entry_unhash(ce);
++      __mb_cache_entry_release_unlock(ce);
++}
++
++
++/*
++ * mb_cache_entry_dup()
++ *
++ * Duplicate a handle to a cache entry (does not duplicate the cache entry
++ * itself). After the call, both the old and the new handle must be released.
++ */
++struct mb_cache_entry *
++mb_cache_entry_dup(struct mb_cache_entry *ce)
++{
++      atomic_inc(&ce->e_used);
++      return ce;
++}
++
++
++/*
++ * mb_cache_entry_get()
++ *
++ * Get a cache entry  by device / block number. (There can only be one entry
++ * in the cache per device and block.) Returns NULL if no such cache entry
++ * exists.
++ */
++struct mb_cache_entry *
++mb_cache_entry_get(struct mb_cache *cache, kdev_t dev, unsigned long block)
++{
++      unsigned int bucket = (HASHDEV(dev) + block) % cache->c_bucket_count;
++      struct list_head *l;
++      struct mb_cache_entry *ce;
++
++      spin_lock(&mb_cache_spinlock);
++      list_for_each(l, &cache->c_block_hash[bucket]) {
++              ce = list_entry(l, struct mb_cache_entry, e_block_list);
++              if (ce->e_dev == dev && ce->e_block == block) {
++                      if (!list_empty(&ce->e_lru_list))
++                              list_del_init(&ce->e_lru_list);
++                      atomic_inc(&ce->e_used);
++                      goto cleanup;
++              }
++      }
++      ce = NULL;
++
++cleanup:
++      spin_unlock(&mb_cache_spinlock);
++      return ce;
++}
++
++#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0)
++
++static struct mb_cache_entry *
++__mb_cache_entry_find(struct list_head *l, struct list_head *head,
++                    int index, kdev_t dev, unsigned int key)
++{
++      while (l != head) {
++              struct mb_cache_entry *ce =
++                      list_entry(l, struct mb_cache_entry,
++                                 e_indexes[index].o_list);
++              if (ce->e_dev == dev && ce->e_indexes[index].o_key == key) {
++                      if (!list_empty(&ce->e_lru_list))
++                              list_del_init(&ce->e_lru_list);
++                      atomic_inc(&ce->e_used);
++                      return ce;
++              }
++              l = l->next;
++      }
++      return NULL;
++}
++
++
++/*
++ * mb_cache_entry_find_first()
++ *
++ * Find the first cache entry on a given device with a certain key in
++ * an additional index. Additonal matches can be found with
++ * mb_cache_entry_find_next(). Returns NULL if no match was found.
++ *
++ * @cache: the cache to search
++ * @index: the number of the additonal index to search (0<=index<indexes_count)
++ * @dev: the device the cache entry should belong to
++ * @key: the key in the index
++ */
++struct mb_cache_entry *
++mb_cache_entry_find_first(struct mb_cache *cache, int index, kdev_t dev,
++                        unsigned int key)
++{
++      unsigned int bucket = key % cache->c_bucket_count;
++      struct list_head *l;
++      struct mb_cache_entry *ce;
++
++      mb_assert(index < mb_cache_indexes(cache));
++      spin_lock(&mb_cache_spinlock);
++      l = cache->c_indexes_hash[index][bucket].next;
++      ce = __mb_cache_entry_find(l, &cache->c_indexes_hash[index][bucket],
++                                 index, dev, key);
++      spin_unlock(&mb_cache_spinlock);
++      return ce;
++}
++
++
++/*
++ * mb_cache_entry_find_next()
++ *
++ * Find the next cache entry on a given device with a certain key in an
++ * additional index. Returns NULL if no match could be found. The previous
++ * entry is atomatically released, so that mb_cache_entry_find_next() can
++ * be called like this:
++ *
++ * entry = mb_cache_entry_find_first();
++ * while (entry) {
++ *    ...
++ *    entry = mb_cache_entry_find_next(entry, ...);
++ * }
++ *
++ * @prev: The previous match
++ * @index: the number of the additonal index to search (0<=index<indexes_count)
++ * @dev: the device the cache entry should belong to
++ * @key: the key in the index
++ */
++struct mb_cache_entry *
++mb_cache_entry_find_next(struct mb_cache_entry *prev, int index, kdev_t dev,
++                       unsigned int key)
++{
++      struct mb_cache *cache = prev->e_cache;
++      unsigned int bucket = key % cache->c_bucket_count;
++      struct list_head *l;
++      struct mb_cache_entry *ce;
++
++      mb_assert(index < mb_cache_indexes(cache));
++      spin_lock(&mb_cache_spinlock);
++      l = prev->e_indexes[index].o_list.next;
++      ce = __mb_cache_entry_find(l, &cache->c_indexes_hash[index][bucket],
++                                 index, dev, key);
++      __mb_cache_entry_release_unlock(prev);
++      return ce;
++}
++
++#endif  /* !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) */
++
++static int __init init_mbcache(void)
++{
++      register_cache(&mb_cache_definition);
++      return 0;
++}
++
++static void __exit exit_mbcache(void)
++{
++      unregister_cache(&mb_cache_definition);
++}
++
++module_init(init_mbcache)
++module_exit(exit_mbcache)
++
+Index: linux-2.4.29/include/asm-arm/unistd.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-arm/unistd.h 2005-04-07 18:55:01.000000000 +0300
++++ linux-2.4.29/include/asm-arm/unistd.h      2005-05-03 17:59:40.438115640 +0300
+@@ -250,7 +250,6 @@
+ #define __NR_security                 (__NR_SYSCALL_BASE+223)
+ #define __NR_gettid                   (__NR_SYSCALL_BASE+224)
+ #define __NR_readahead                        (__NR_SYSCALL_BASE+225)
+-#if 0 /* allocated in 2.5 */
+ #define __NR_setxattr                 (__NR_SYSCALL_BASE+226)
+ #define __NR_lsetxattr                        (__NR_SYSCALL_BASE+227)
+ #define __NR_fsetxattr                        (__NR_SYSCALL_BASE+228)
+@@ -263,7 +262,6 @@
+ #define __NR_removexattr              (__NR_SYSCALL_BASE+235)
+ #define __NR_lremovexattr             (__NR_SYSCALL_BASE+236)
+ #define __NR_fremovexattr             (__NR_SYSCALL_BASE+237)
+-#endif
+ #define __NR_tkill                    (__NR_SYSCALL_BASE+238)
+ #if 0 /* allocated in 2.5 */
+ #define __NR_sendfile64                 (__NR_SYSCALL_BASE+239)
+Index: linux-2.4.29/include/asm-ppc64/unistd.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-ppc64/unistd.h       2005-04-07 18:52:47.000000000 +0300
++++ linux-2.4.29/include/asm-ppc64/unistd.h    2005-05-03 17:59:40.439115488 +0300
+@@ -218,6 +218,7 @@
+ #define __NR_mincore          206
+ #define __NR_gettid           207
+ #define __NR_tkill            208
++#endif
+ #define __NR_setxattr         209
+ #define __NR_lsetxattr                210
+ #define __NR_fsetxattr                211
+@@ -230,6 +231,7 @@
+ #define __NR_removexattr      218
+ #define __NR_lremovexattr     219
+ #define __NR_fremovexattr     220
++#if 0 /* Reserved syscalls */
+ #define __NR_futex            221
+ #define __NR_sched_setaffinity        222     
+ #define __NR_sched_getaffinity        223
+Index: linux-2.4.29/include/asm-s390/unistd.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-s390/unistd.h        2005-04-07 18:55:23.000000000 +0300
++++ linux-2.4.29/include/asm-s390/unistd.h     2005-05-03 17:59:40.440115336 +0300
+@@ -213,9 +213,18 @@
+ #define __NR_getdents64               220
+ #define __NR_fcntl64          221
+ #define __NR_readahead                222
+-/*
+- * Numbers 224-235 are reserved for posix acl
+- */
++#define __NR_setxattr         224
++#define __NR_lsetxattr                225
++#define __NR_fsetxattr                226
++#define __NR_getxattr         227
++#define __NR_lgetxattr                228
++#define __NR_fgetxattr                229
++#define __NR_listxattr                230
++#define __NR_llistxattr               231
++#define __NR_flistxattr               232
++#define __NR_removexattr      233
++#define __NR_lremovexattr     234
++#define __NR_fremovexattr     235
+ #define __NR_gettid           236
+ #define __NR_tkill            237
+Index: linux-2.4.29/include/asm-s390x/unistd.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-s390x/unistd.h       2005-04-07 18:54:22.000000000 +0300
++++ linux-2.4.29/include/asm-s390x/unistd.h    2005-05-03 17:59:40.441115184 +0300
+@@ -181,9 +181,18 @@
+ #define __NR_mincore            218
+ #define __NR_madvise            219
+ #define __NR_readahead                222
+-/*
+- * Numbers 224-235 are reserved for posix acl
+- */
++#define __NR_setxattr         224
++#define __NR_lsetxattr                225
++#define __NR_fsetxattr                226
++#define __NR_getxattr         227
++#define __NR_lgetxattr                228
++#define __NR_fgetxattr                229
++#define __NR_listxattr                230
++#define __NR_llistxattr               231
++#define __NR_flistxattr               232
++#define __NR_removexattr      233
++#define __NR_lremovexattr     234
++#define __NR_fremovexattr     235
+ #define __NR_gettid           236
+ #define __NR_tkill            237
+Index: linux-2.4.29/include/linux/cache_def.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/cache_def.h        2005-05-03 17:59:40.235146496 +0300
++++ linux-2.4.29/include/linux/cache_def.h     2005-05-03 17:59:40.442115032 +0300
+@@ -0,0 +1,15 @@
++/*
++ * linux/cache_def.h
++ * Handling of caches defined in drivers, filesystems, ...
++ *
++ * Copyright (C) 2002 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
++ */
++
++struct cache_definition {
++      const char *name;
++      void (*shrink)(int, unsigned int);
++      struct list_head link;
++};
++
++extern void register_cache(struct cache_definition *);
++extern void unregister_cache(struct cache_definition *);
+Index: linux-2.4.29/include/linux/errno.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/errno.h    2005-04-07 18:54:43.000000000 +0300
++++ linux-2.4.29/include/linux/errno.h 2005-05-03 17:59:40.443114880 +0300
+@@ -23,4 +23,8 @@
+ #endif
++/* Defined for extended attributes */
++#define ENOATTR ENODATA               /* No such attribute */
++#define ENOTSUP EOPNOTSUPP    /* Operation not supported */
++
+ #endif
+Index: linux-2.4.29/include/linux/ext2_fs.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext2_fs.h  2005-04-07 18:52:37.000000000 +0300
++++ linux-2.4.29/include/linux/ext2_fs.h       2005-05-03 17:59:40.445114576 +0300
+@@ -57,8 +57,6 @@
+  */
+ #define       EXT2_BAD_INO             1      /* Bad blocks inode */
+ #define EXT2_ROOT_INO          2      /* Root inode */
+-#define EXT2_ACL_IDX_INO       3      /* ACL inode */
+-#define EXT2_ACL_DATA_INO      4      /* ACL inode */
+ #define EXT2_BOOT_LOADER_INO   5      /* Boot loader inode */
+ #define EXT2_UNDEL_DIR_INO     6      /* Undelete directory inode */
+@@ -86,7 +84,6 @@
+ #else
+ # define EXT2_BLOCK_SIZE(s)           (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+ #endif
+-#define EXT2_ACLE_PER_BLOCK(s)                (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
+ #define       EXT2_ADDR_PER_BLOCK(s)          (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
+ #ifdef __KERNEL__
+ # define EXT2_BLOCK_SIZE_BITS(s)      ((s)->s_blocksize_bits)
+@@ -121,28 +118,6 @@
+ #endif
+ /*
+- * ACL structures
+- */
+-struct ext2_acl_header        /* Header of Access Control Lists */
+-{
+-      __u32   aclh_size;
+-      __u32   aclh_file_count;
+-      __u32   aclh_acle_count;
+-      __u32   aclh_first_acle;
+-};
+-
+-struct ext2_acl_entry /* Access Control List Entry */
+-{
+-      __u32   acle_size;
+-      __u16   acle_perms;     /* Access permissions */
+-      __u16   acle_type;      /* Type of entry */
+-      __u16   acle_tag;       /* User or group identity */
+-      __u16   acle_pad1;
+-      __u32   acle_next;      /* Pointer on next entry for the */
+-                                      /* same inode or on next free entry */
+-};
+-
+-/*
+  * Structure of a blocks group descriptor
+  */
+ struct ext2_group_desc
+@@ -314,6 +289,7 @@
+ #define EXT2_MOUNT_ERRORS_PANIC               0x0040  /* Panic on errors */
+ #define EXT2_MOUNT_MINIX_DF           0x0080  /* Mimics the Minix statfs */
+ #define EXT2_MOUNT_NO_UID32           0x0200  /* Disable 32-bit UIDs */
++#define EXT2_MOUNT_XATTR_USER         0x4000  /* Extended user attributes */
+ #define clear_opt(o, opt)             o &= ~EXT2_MOUNT_##opt
+ #define set_opt(o, opt)                       o |= EXT2_MOUNT_##opt
+@@ -410,6 +386,7 @@
+ #ifdef __KERNEL__
+ #define EXT2_SB(sb)   (&((sb)->u.ext2_sb))
++#define EXT2_I(inode) (&((inode)->u.ext2_i))
+ #else
+ /* Assume that user mode programs are passing in an ext2fs superblock, not
+  * a kernel struct super_block.  This will allow us to call the feature-test
+@@ -480,7 +457,7 @@
+ #define EXT2_FEATURE_INCOMPAT_META_BG         0x0010
+ #define EXT2_FEATURE_INCOMPAT_ANY             0xffffffff
+-#define EXT2_FEATURE_COMPAT_SUPP      0
++#define EXT2_FEATURE_COMPAT_SUPP      EXT2_FEATURE_COMPAT_EXT_ATTR
+ #define EXT2_FEATURE_INCOMPAT_SUPP    (EXT2_FEATURE_INCOMPAT_FILETYPE| \
+                                        EXT2_FEATURE_INCOMPAT_META_BG)
+ #define EXT2_FEATURE_RO_COMPAT_SUPP   (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+@@ -650,8 +627,10 @@
+ /* namei.c */
+ extern struct inode_operations ext2_dir_inode_operations;
++extern struct inode_operations ext2_special_inode_operations;
+ /* symlink.c */
++extern struct inode_operations ext2_symlink_inode_operations;
+ extern struct inode_operations ext2_fast_symlink_inode_operations;
+ #endif        /* __KERNEL__ */
+Index: linux-2.4.29/include/linux/ext2_xattr.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext2_xattr.h       2005-05-03 17:59:40.236146344 +0300
++++ linux-2.4.29/include/linux/ext2_xattr.h    2005-05-03 17:59:40.446114424 +0300
+@@ -0,0 +1,157 @@
++/*
++  File: linux/ext2_xattr.h
++
++  On-disk format of extended attributes for the ext2 filesystem.
++
++  (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
++*/
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/xattr.h>
++
++/* Magic value in attribute blocks */
++#define EXT2_XATTR_MAGIC              0xEA020000
++
++/* Maximum number of references to one attribute block */
++#define EXT2_XATTR_REFCOUNT_MAX               1024
++
++/* Name indexes */
++#define EXT2_XATTR_INDEX_MAX                  10
++#define EXT2_XATTR_INDEX_USER                 1
++#define EXT2_XATTR_INDEX_POSIX_ACL_ACCESS     2
++#define EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT    3
++
++struct ext2_xattr_header {
++      __u32   h_magic;        /* magic number for identification */
++      __u32   h_refcount;     /* reference count */
++      __u32   h_blocks;       /* number of disk blocks used */
++      __u32   h_hash;         /* hash value of all attributes */
++      __u32   h_reserved[4];  /* zero right now */
++};
++
++struct ext2_xattr_entry {
++      __u8    e_name_len;     /* length of name */
++      __u8    e_name_index;   /* attribute name index */
++      __u16   e_value_offs;   /* offset in disk block of value */
++      __u32   e_value_block;  /* disk block attribute is stored on (n/i) */
++      __u32   e_value_size;   /* size of attribute value */
++      __u32   e_hash;         /* hash value of name and value */
++      char    e_name[0];      /* attribute name */
++};
++
++#define EXT2_XATTR_PAD_BITS           2
++#define EXT2_XATTR_PAD                (1<<EXT2_XATTR_PAD_BITS)
++#define EXT2_XATTR_ROUND              (EXT2_XATTR_PAD-1)
++#define EXT2_XATTR_LEN(name_len) \
++      (((name_len) + EXT2_XATTR_ROUND + \
++      sizeof(struct ext2_xattr_entry)) & ~EXT2_XATTR_ROUND)
++#define EXT2_XATTR_NEXT(entry) \
++      ( (struct ext2_xattr_entry *)( \
++        (char *)(entry) + EXT2_XATTR_LEN((entry)->e_name_len)) )
++#define EXT2_XATTR_SIZE(size) \
++      (((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND)
++
++#ifdef __KERNEL__
++
++# ifdef CONFIG_EXT2_FS_XATTR
++
++struct ext2_xattr_handler {
++      char *prefix;
++      size_t (*list)(char *list, struct inode *inode, const char *name,
++                     int name_len);
++      int (*get)(struct inode *inode, const char *name, void *buffer,
++                 size_t size);
++      int (*set)(struct inode *inode, const char *name, const void *buffer,
++                 size_t size, int flags);
++};
++
++extern int ext2_xattr_register(int, struct ext2_xattr_handler *);
++extern void ext2_xattr_unregister(int, struct ext2_xattr_handler *);
++
++extern int ext2_setxattr(struct dentry *, const char *, const void *, size_t, int);
++extern ssize_t ext2_getxattr(struct dentry *, const char *, void *, size_t);
++extern ssize_t ext2_listxattr(struct dentry *, char *, size_t);
++extern int ext2_removexattr(struct dentry *, const char *);
++
++extern int ext2_xattr_get(struct inode *, int, const char *, void *, size_t);
++extern int ext2_xattr_list(struct inode *, char *, size_t);
++extern int ext2_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
++
++extern void ext2_xattr_delete_inode(struct inode *);
++extern void ext2_xattr_put_super(struct super_block *);
++
++extern int init_ext2_xattr(void) __init;
++extern void exit_ext2_xattr(void);
++
++# else  /* CONFIG_EXT2_FS_XATTR */
++#  define ext2_setxattr               NULL
++#  define ext2_getxattr               NULL
++#  define ext2_listxattr      NULL
++#  define ext2_removexattr    NULL
++
++static inline int
++ext2_xattr_get(struct inode *inode, int name_index,
++             const char *name, void *buffer, size_t size)
++{
++      return -ENOTSUP;
++}
++
++static inline int
++ext2_xattr_list(struct inode *inode, char *buffer, size_t size)
++{
++      return -ENOTSUP;
++}
++
++static inline int
++ext2_xattr_set(struct inode *inode, int name_index, const char *name,
++             const void *value, size_t size, int flags)
++{
++      return -ENOTSUP;
++}
++
++static inline void
++ext2_xattr_delete_inode(struct inode *inode)
++{
++}
++
++static inline void
++ext2_xattr_put_super(struct super_block *sb)
++{
++}
++
++static inline int
++init_ext2_xattr(void)
++{
++      return 0;
++}
++
++static inline void
++exit_ext2_xattr(void)
++{
++}
++
++# endif  /* CONFIG_EXT2_FS_XATTR */
++
++# ifdef CONFIG_EXT2_FS_XATTR_USER
++
++extern int init_ext2_xattr_user(void) __init;
++extern void exit_ext2_xattr_user(void);
++
++# else  /* CONFIG_EXT2_FS_XATTR_USER */
++
++static inline int
++init_ext2_xattr_user(void)
++{
++      return 0;
++}
++
++static inline void
++exit_ext2_xattr_user(void)
++{
++}
++
++# endif  /* CONFIG_EXT2_FS_XATTR_USER */
++
++#endif  /* __KERNEL__ */
++
+Index: linux-2.4.29/include/linux/ext3_fs.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext3_fs.h  2005-05-03 17:23:54.107407504 +0300
++++ linux-2.4.29/include/linux/ext3_fs.h       2005-05-03 17:59:40.448114120 +0300
+@@ -63,8 +63,6 @@
+  */
+ #define       EXT3_BAD_INO             1      /* Bad blocks inode */
+ #define EXT3_ROOT_INO          2      /* Root inode */
+-#define EXT3_ACL_IDX_INO       3      /* ACL inode */
+-#define EXT3_ACL_DATA_INO      4      /* ACL inode */
+ #define EXT3_BOOT_LOADER_INO   5      /* Boot loader inode */
+ #define EXT3_UNDEL_DIR_INO     6      /* Undelete directory inode */
+ #define EXT3_RESIZE_INO                7      /* Reserved group descriptors inode */
+@@ -94,7 +92,6 @@
+ #else
+ # define EXT3_BLOCK_SIZE(s)           (EXT3_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+ #endif
+-#define EXT3_ACLE_PER_BLOCK(s)                (EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_acl_entry))
+ #define       EXT3_ADDR_PER_BLOCK(s)          (EXT3_BLOCK_SIZE(s) / sizeof (__u32))
+ #ifdef __KERNEL__
+ # define EXT3_BLOCK_SIZE_BITS(s)      ((s)->s_blocksize_bits)
+@@ -129,28 +126,6 @@
+ #endif
+ /*
+- * ACL structures
+- */
+-struct ext3_acl_header        /* Header of Access Control Lists */
+-{
+-      __u32   aclh_size;
+-      __u32   aclh_file_count;
+-      __u32   aclh_acle_count;
+-      __u32   aclh_first_acle;
+-};
+-
+-struct ext3_acl_entry /* Access Control List Entry */
+-{
+-      __u32   acle_size;
+-      __u16   acle_perms;     /* Access permissions */
+-      __u16   acle_type;      /* Type of entry */
+-      __u16   acle_tag;       /* User or group identity */
+-      __u16   acle_pad1;
+-      __u32   acle_next;      /* Pointer on next entry for the */
+-                                      /* same inode or on next free entry */
+-};
+-
+-/*
+  * Structure of a blocks group descriptor
+  */
+ struct ext3_group_desc
+@@ -344,6 +319,7 @@
+   #define EXT3_MOUNT_WRITEBACK_DATA   0x0C00  /* No data ordering */
+ #define EXT3_MOUNT_UPDATE_JOURNAL     0x1000  /* Update the journal format */
+ #define EXT3_MOUNT_NO_UID32           0x2000  /* Disable 32-bit UIDs */
++#define EXT3_MOUNT_XATTR_USER         0x4000  /* Extended user attributes */
+ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
+ #ifndef _LINUX_EXT2_FS_H
+@@ -524,7 +500,7 @@
+ #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV     0x0008 /* Journal device */
+ #define EXT3_FEATURE_INCOMPAT_META_BG         0x0010
+-#define EXT3_FEATURE_COMPAT_SUPP      0
++#define EXT3_FEATURE_COMPAT_SUPP      EXT2_FEATURE_COMPAT_EXT_ATTR
+ #define EXT3_FEATURE_INCOMPAT_SUPP    (EXT3_FEATURE_INCOMPAT_FILETYPE| \
+                                        EXT3_FEATURE_INCOMPAT_RECOVER| \
+                                        EXT3_FEATURE_INCOMPAT_META_BG)
+@@ -718,6 +694,7 @@
+ extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
+ /* inode.c */
++extern int ext3_forget(handle_t *, int, struct inode *, struct buffer_head *, int);
+ extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
+ extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
+@@ -787,8 +764,10 @@
+ /* namei.c */
+ extern struct inode_operations ext3_dir_inode_operations;
++extern struct inode_operations ext3_special_inode_operations;
+ /* symlink.c */
++extern struct inode_operations ext3_symlink_inode_operations;
+ extern struct inode_operations ext3_fast_symlink_inode_operations;
+Index: linux-2.4.29/include/linux/ext3_jbd.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext3_jbd.h 2005-05-03 17:23:54.109407200 +0300
++++ linux-2.4.29/include/linux/ext3_jbd.h      2005-05-03 17:59:40.449113968 +0300
+@@ -30,13 +30,19 @@
+ #define EXT3_SINGLEDATA_TRANS_BLOCKS  8U
++/* Extended attributes may touch two data buffers, two bitmap buffers,
++ * and two group and summaries. */
++
++#define EXT3_XATTR_TRANS_BLOCKS               8
++
+ /* Define the minimum size for a transaction which modifies data.  This
+  * needs to take into account the fact that we may end up modifying two
+  * quota files too (one for the group, one for the user quota).  The
+  * superblock only gets updated once, of course, so don't bother
+  * counting that again for the quota updates. */
+-#define EXT3_DATA_TRANS_BLOCKS                (3 * EXT3_SINGLEDATA_TRANS_BLOCKS - 2)
++#define EXT3_DATA_TRANS_BLOCKS                (3 * EXT3_SINGLEDATA_TRANS_BLOCKS + \
++                                       EXT3_XATTR_TRANS_BLOCKS - 2)
+ extern int ext3_writepage_trans_blocks(struct inode *inode);
+Index: linux-2.4.29/include/linux/ext3_xattr.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ext3_xattr.h       2005-05-03 17:59:40.236146344 +0300
++++ linux-2.4.29/include/linux/ext3_xattr.h    2005-05-03 17:59:40.451113664 +0300
+@@ -0,0 +1,157 @@
++/*
++  File: linux/ext3_xattr.h
++
++  On-disk format of extended attributes for the ext3 filesystem.
++
++  (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
++*/
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/xattr.h>
++
++/* Magic value in attribute blocks */
++#define EXT3_XATTR_MAGIC              0xEA020000
++
++/* Maximum number of references to one attribute block */
++#define EXT3_XATTR_REFCOUNT_MAX               1024
++
++/* Name indexes */
++#define EXT3_XATTR_INDEX_MAX                  10
++#define EXT3_XATTR_INDEX_USER                 1
++#define EXT3_XATTR_INDEX_POSIX_ACL_ACCESS     2
++#define EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT    3
++
++struct ext3_xattr_header {
++      __u32   h_magic;        /* magic number for identification */
++      __u32   h_refcount;     /* reference count */
++      __u32   h_blocks;       /* number of disk blocks used */
++      __u32   h_hash;         /* hash value of all attributes */
++      __u32   h_reserved[4];  /* zero right now */
++};
++
++struct ext3_xattr_entry {
++      __u8    e_name_len;     /* length of name */
++      __u8    e_name_index;   /* attribute name index */
++      __u16   e_value_offs;   /* offset in disk block of value */
++      __u32   e_value_block;  /* disk block attribute is stored on (n/i) */
++      __u32   e_value_size;   /* size of attribute value */
++      __u32   e_hash;         /* hash value of name and value */
++      char    e_name[0];      /* attribute name */
++};
++
++#define EXT3_XATTR_PAD_BITS           2
++#define EXT3_XATTR_PAD                (1<<EXT3_XATTR_PAD_BITS)
++#define EXT3_XATTR_ROUND              (EXT3_XATTR_PAD-1)
++#define EXT3_XATTR_LEN(name_len) \
++      (((name_len) + EXT3_XATTR_ROUND + \
++      sizeof(struct ext3_xattr_entry)) & ~EXT3_XATTR_ROUND)
++#define EXT3_XATTR_NEXT(entry) \
++      ( (struct ext3_xattr_entry *)( \
++        (char *)(entry) + EXT3_XATTR_LEN((entry)->e_name_len)) )
++#define EXT3_XATTR_SIZE(size) \
++      (((size) + EXT3_XATTR_ROUND) & ~EXT3_XATTR_ROUND)
++
++#ifdef __KERNEL__
++
++# ifdef CONFIG_EXT3_FS_XATTR
++
++struct ext3_xattr_handler {
++      char *prefix;
++      size_t (*list)(char *list, struct inode *inode, const char *name,
++                     int name_len);
++      int (*get)(struct inode *inode, const char *name, void *buffer,
++                 size_t size);
++      int (*set)(struct inode *inode, const char *name, const void *buffer,
++                 size_t size, int flags);
++};
++
++extern int ext3_xattr_register(int, struct ext3_xattr_handler *);
++extern void ext3_xattr_unregister(int, struct ext3_xattr_handler *);
++
++extern int ext3_setxattr(struct dentry *, const char *, const void *, size_t, int);
++extern ssize_t ext3_getxattr(struct dentry *, const char *, void *, size_t);
++extern ssize_t ext3_listxattr(struct dentry *, char *, size_t);
++extern int ext3_removexattr(struct dentry *, const char *);
++
++extern int ext3_xattr_get(struct inode *, int, const char *, void *, size_t);
++extern int ext3_xattr_list(struct inode *, char *, size_t);
++extern int ext3_xattr_set(handle_t *handle, struct inode *, int, const char *, const void *, size_t, int);
++
++extern void ext3_xattr_delete_inode(handle_t *, struct inode *);
++extern void ext3_xattr_put_super(struct super_block *);
++
++extern int init_ext3_xattr(void) __init;
++extern void exit_ext3_xattr(void);
++
++# else  /* CONFIG_EXT3_FS_XATTR */
++#  define ext3_setxattr               NULL
++#  define ext3_getxattr               NULL
++#  define ext3_listxattr      NULL
++#  define ext3_removexattr    NULL
++
++static inline int
++ext3_xattr_get(struct inode *inode, int name_index, const char *name,
++             void *buffer, size_t size)
++{
++      return -ENOTSUP;
++}
++
++static inline int
++ext3_xattr_list(struct inode *inode, void *buffer, size_t size)
++{
++      return -ENOTSUP;
++}
++
++static inline int
++ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index,
++             const char *name, const void *value, size_t size, int flags)
++{
++      return -ENOTSUP;
++}
++
++static inline void
++ext3_xattr_delete_inode(handle_t *handle, struct inode *inode)
++{
++}
++
++static inline void
++ext3_xattr_put_super(struct super_block *sb)
++{
++}
++
++static inline int
++init_ext3_xattr(void)
++{
++      return 0;
++}
++
++static inline void
++exit_ext3_xattr(void)
++{
++}
++
++# endif  /* CONFIG_EXT3_FS_XATTR */
++
++# ifdef CONFIG_EXT3_FS_XATTR_USER
++
++extern int init_ext3_xattr_user(void) __init;
++extern void exit_ext3_xattr_user(void);
++
++# else  /* CONFIG_EXT3_FS_XATTR_USER */
++
++static inline int
++init_ext3_xattr_user(void)
++{
++      return 0;
++}
++
++static inline void
++exit_ext3_xattr_user(void)
++{
++}
++
++#endif  /* CONFIG_EXT3_FS_XATTR_USER */
++
++#endif  /* __KERNEL__ */
++
+Index: linux-2.4.29/include/linux/fs.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/fs.h       2005-05-03 17:23:53.736463896 +0300
++++ linux-2.4.29/include/linux/fs.h    2005-05-03 17:59:40.453113360 +0300
+@@ -915,7 +915,7 @@
+       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);
++      int (*setxattr) (struct dentry *, const char *, const 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 *);
+Index: linux-2.4.29/include/linux/mbcache.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/mbcache.h  2005-05-03 17:59:40.236146344 +0300
++++ linux-2.4.29/include/linux/mbcache.h       2005-05-03 17:59:40.454113208 +0300
+@@ -0,0 +1,69 @@
++/*
++  File: linux/mbcache.h
++
++  (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
++*/
++
++/* Hardwire the number of additional indexes */
++#define MB_CACHE_INDEXES_COUNT 1
++
++struct mb_cache_entry;
++
++struct mb_cache_op {
++      int (*free)(struct mb_cache_entry *, int);
++};
++
++struct mb_cache {
++      struct list_head                c_cache_list;
++      const char                      *c_name;
++      struct mb_cache_op              c_op;
++      atomic_t                        c_entry_count;
++      int                             c_bucket_count;
++#ifndef MB_CACHE_INDEXES_COUNT
++      int                             c_indexes_count;
++#endif
++      kmem_cache_t                    *c_entry_cache;
++      struct list_head                *c_block_hash;
++      struct list_head                *c_indexes_hash[0];
++};
++
++struct mb_cache_entry_index {
++      struct list_head                o_list;
++      unsigned int                    o_key;
++};
++
++struct mb_cache_entry {
++      struct list_head                e_lru_list;
++      struct mb_cache                 *e_cache;
++      atomic_t                        e_used;
++      kdev_t                          e_dev;
++      unsigned long                   e_block;
++      struct list_head                e_block_list;
++      struct mb_cache_entry_index     e_indexes[0];
++};
++
++/* Functions on caches */
++
++struct mb_cache * mb_cache_create(const char *, struct mb_cache_op *, size_t,
++                                int, int);
++void mb_cache_shrink(struct mb_cache *, kdev_t);
++void mb_cache_destroy(struct mb_cache *);
++
++/* Functions on cache entries */
++
++struct mb_cache_entry *mb_cache_entry_alloc(struct mb_cache *);
++int mb_cache_entry_insert(struct mb_cache_entry *, kdev_t, unsigned long,
++                        unsigned int[]);
++void mb_cache_entry_rehash(struct mb_cache_entry *, unsigned int[]);
++void mb_cache_entry_release(struct mb_cache_entry *);
++void mb_cache_entry_takeout(struct mb_cache_entry *);
++void mb_cache_entry_free(struct mb_cache_entry *);
++struct mb_cache_entry *mb_cache_entry_dup(struct mb_cache_entry *);
++struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *, kdev_t,
++                                        unsigned long);
++#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0)
++struct mb_cache_entry *mb_cache_entry_find_first(struct mb_cache *cache, int,
++                                               kdev_t, unsigned int);
++struct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache_entry *, int,
++                                              kdev_t, unsigned int);
++#endif
+Index: linux-2.4.29/kernel/ksyms.c
+===================================================================
+--- linux-2.4.29.orig/kernel/ksyms.c   2005-04-07 19:14:06.000000000 +0300
++++ linux-2.4.29/kernel/ksyms.c        2005-05-03 17:59:40.456112904 +0300
+@@ -11,6 +11,7 @@
+ #include <linux/config.h>
+ #include <linux/slab.h>
++#include <linux/cache_def.h>
+ #include <linux/module.h>
+ #include <linux/blkdev.h>
+ #include <linux/cdrom.h>
+@@ -92,6 +93,7 @@
+ EXPORT_SYMBOL(exit_files);
+ EXPORT_SYMBOL(exit_fs);
+ EXPORT_SYMBOL(exit_sighand);
++EXPORT_SYMBOL(copy_fs_struct);
+ /* internal kernel memory management */
+ EXPORT_SYMBOL(_alloc_pages);
+@@ -109,6 +111,8 @@
+ EXPORT_SYMBOL(kmem_cache_alloc);
+ EXPORT_SYMBOL(kmem_cache_free);
+ EXPORT_SYMBOL(kmem_cache_size);
++EXPORT_SYMBOL(register_cache);
++EXPORT_SYMBOL(unregister_cache);
+ EXPORT_SYMBOL(kmalloc);
+ EXPORT_SYMBOL(kfree);
+ EXPORT_SYMBOL(vfree);
+Index: linux-2.4.29/mm/vmscan.c
+===================================================================
+--- linux-2.4.29.orig/mm/vmscan.c      2005-04-07 18:52:37.000000000 +0300
++++ linux-2.4.29/mm/vmscan.c   2005-05-03 17:59:40.458112600 +0300
+@@ -18,6 +18,7 @@
+ #include <linux/kernel_stat.h>
+ #include <linux/swap.h>
+ #include <linux/swapctl.h>
++#include <linux/cache_def.h>
+ #include <linux/smp_lock.h>
+ #include <linux/pagemap.h>
+ #include <linux/init.h>
+@@ -34,6 +35,39 @@
+  */
+ int vm_passes = 60;
++static DECLARE_MUTEX(other_caches_sem);
++static LIST_HEAD(cache_definitions);
++
++void register_cache(struct cache_definition *cache)
++{
++      down(&other_caches_sem);
++      list_add(&cache->link, &cache_definitions);
++      up(&other_caches_sem);
++}
++
++void unregister_cache(struct cache_definition *cache)
++{
++      down(&other_caches_sem);
++      list_del(&cache->link);
++      up(&other_caches_sem);
++}
++
++static void shrink_other_caches(unsigned int priority, int gfp_mask)
++{
++      struct list_head *p;
++
++      if (down_trylock(&other_caches_sem))
++              return;
++
++      list_for_each_prev(p, &cache_definitions) {
++              struct cache_definition *cache =
++                      list_entry(p, struct cache_definition, link);
++
++              cache->shrink(priority, gfp_mask);
++      }
++      up(&other_caches_sem);
++}
++
+ /*
+  * "vm_cache_scan_ratio" is how much of the inactive LRU queue we will scan
+  * in one go. A value of 6 for vm_cache_scan_ratio implies that we'll
+@@ -544,6 +578,7 @@
+ #ifdef CONFIG_QUOTA
+                               shrink_dqcache_memory(vm_vfs_scan_ratio, gfp_mask);
+ #endif
++                              shrink_other_caches(vm_vfs_scan_ratio, gfp_mask);
+                               if (!*failed_swapout)
+                                       *failed_swapout = !swap_out(classzone);
+@@ -666,6 +701,7 @@
+ #ifdef CONFIG_QUOTA
+                       shrink_dqcache_memory(vm_vfs_scan_ratio, gfp_mask);
+ #endif
++                      shrink_other_caches(vm_vfs_scan_ratio, gfp_mask);
+                       if (!failed_swapout)
+                               failed_swapout = !swap_out(classzone);
+               } while (--tries);
diff --git a/lustre/kernel_patches/patches/nfs_export_kernel-2.4.29.patch b/lustre/kernel_patches/patches/nfs_export_kernel-2.4.29.patch
new file mode 100644 (file)
index 0000000..4708b75
--- /dev/null
@@ -0,0 +1,743 @@
+Index: linux-2.4.29/fs/Makefile
+===================================================================
+--- linux-2.4.29.orig/fs/Makefile      2005-05-03 18:16:44.000000000 +0300
++++ linux-2.4.29/fs/Makefile   2005-05-03 18:46:09.301144016 +0300
+@@ -7,7 +7,8 @@
+ O_TARGET := fs.o
+-export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o inode.o
++export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o inode.o \
++              namei.o file_table.o
+ mod-subdirs :=        nls
+ obj-y :=      open.o read_write.o devices.o file_table.o buffer.o \
+Index: linux-2.4.29/fs/file_table.c
+===================================================================
+--- linux-2.4.29.orig/fs/file_table.c  2005-05-03 16:28:21.000000000 +0300
++++ linux-2.4.29/fs/file_table.c       2005-05-03 18:46:09.303143712 +0300
+@@ -82,7 +82,8 @@
+  * and call the open function (if any).  The caller must verify that
+  * inode->i_fop is not NULL.
+  */
+-int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++int init_private_file_it(struct file *filp, struct dentry *dentry, int mode,
++                       struct lookup_intent *it)
+ {
+       memset(filp, 0, sizeof(*filp));
+       filp->f_mode   = mode;
+@@ -90,12 +91,20 @@
+       filp->f_dentry = dentry;
+       filp->f_uid    = current->fsuid;
+       filp->f_gid    = current->fsgid;
++      if (it)
++              filp->f_it = it;
+       filp->f_op     = dentry->d_inode->i_fop;
+       if (filp->f_op->open)
+               return filp->f_op->open(dentry->d_inode, filp);
+       else
+               return 0;
+ }
++EXPORT_SYMBOL(init_private_file_it);
++
++int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++{
++      return init_private_file_it(filp, dentry, mode, NULL);
++}
+ void fastcall fput(struct file * file)
+ {
+Index: linux-2.4.29/fs/inode.c
+===================================================================
+--- linux-2.4.29.orig/fs/inode.c       2005-05-03 18:16:44.000000000 +0300
++++ linux-2.4.29/fs/inode.c    2005-05-03 18:51:36.389419040 +0300
+@@ -1139,9 +1139,10 @@
+       return inode;
+ }
+-struct inode *iget4_locked(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
++static inline struct inode *ifind(struct super_block *sb, unsigned long ino,
++                                struct list_head *head,
++                                find_inode_t find_actor, void *opaque)
+ {
+-      struct list_head * head = inode_hashtable + hash(sb,ino);
+       struct inode * inode;
+       spin_lock(&inode_lock);
+@@ -1154,6 +1155,24 @@
+       }
+       spin_unlock(&inode_lock);
++      return NULL;
++}
++
++struct inode *ilookup4(struct super_block *sb, unsigned long ino,
++                     find_inode_t find_actor, void *opaque)
++{
++      struct list_head * head = inode_hashtable + hash(sb,ino);
++      return ifind(sb, ino, head, find_actor, opaque);
++}
++
++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 = ifind(sb, ino, head, find_actor, opaque);
++      if (inode)
++              return inode;
++
+       /*
+        * get_new_inode() will do the right thing, re-trying the search
+        * in case it had to block at any point.
+Index: linux-2.4.29/fs/namei.c
+===================================================================
+--- linux-2.4.29.orig/fs/namei.c       2005-05-03 18:16:43.000000000 +0300
++++ linux-2.4.29/fs/namei.c    2005-05-03 18:46:09.310142648 +0300
+@@ -22,6 +22,7 @@
+ #include <linux/dnotify.h>
+ #include <linux/smp_lock.h>
+ #include <linux/personality.h>
++#include <linux/module.h>
+ #include <asm/namei.h>
+ #include <asm/uaccess.h>
+@@ -100,6 +101,7 @@
+               it->it_op_release(it);
+ }
++EXPORT_SYMBOL(intent_release);
+ /* In order to reduce some races, while at the same time doing additional
+  * checking and hopefully speeding things up, we copy filenames to the
+@@ -910,7 +912,8 @@
+ /* SMP-safe */
+-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++struct dentry * lookup_one_len_it(const char * name, struct dentry * base,
++                                int len, struct lookup_intent *it)
+ {
+       unsigned long hash;
+       struct qstr this;
+@@ -930,11 +933,16 @@
+       }
+       this.hash = end_name_hash(hash);
+-      return lookup_hash_it(&this, base, NULL);
++      return lookup_hash_it(&this, base, it);
+ access:
+       return ERR_PTR(-EACCES);
+ }
++struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++{
++      return lookup_one_len_it(name, base, len, NULL);
++}
++
+ /*
+  *    namei()
+  *
+Index: linux-2.4.29/fs/nfsd/export.c
+===================================================================
+--- linux-2.4.29.orig/fs/nfsd/export.c 2005-05-03 16:28:21.000000000 +0300
++++ linux-2.4.29/fs/nfsd/export.c      2005-05-03 18:46:09.312142344 +0300
+@@ -223,6 +223,11 @@
+       inode = nd.dentry->d_inode;
+       dev = inode->i_dev;
+       ino = inode->i_ino;
++      if ((inode->i_sb->s_type->fs_flags & FS_NFSEXP_FSID) &&
++          !(nxp->ex_flags & NFSEXP_FSID)) {
++              nxp->ex_dev = inode->i_sb->s_dev;
++              nxp->ex_flags |= NFSEXP_FSID;
++      }
+       err = -EINVAL;
+       exp = exp_get(clp, dev, ino);
+Index: linux-2.4.29/fs/nfsd/nfsfh.c
+===================================================================
+--- linux-2.4.29.orig/fs/nfsd/nfsfh.c  2005-05-03 16:28:21.000000000 +0300
++++ linux-2.4.29/fs/nfsd/nfsfh.c       2005-05-03 18:46:09.315141888 +0300
+@@ -36,6 +36,13 @@
+       int sequence;           /* sequence counter */
+ };
++static struct dentry *lookup_it(struct inode *inode, struct dentry * dentry)
++{
++      if (inode->i_op->lookup_it)
++              return inode->i_op->lookup_it(inode, dentry, NULL, 0);
++      return inode->i_op->lookup(inode, dentry);
++}
++
+ /*
+  * A rather strange filldir function to capture
+  * the name matching the specified inode number.
+@@ -75,6 +82,8 @@
+       int error;
+       struct file file;
+       struct nfsd_getdents_callback buffer;
++      struct lookup_intent it;
++      struct file *filp = NULL;
+       error = -ENOTDIR;
+       if (!dir || !S_ISDIR(dir->i_mode))
+@@ -85,9 +94,37 @@
+       /*
+        * Open the directory ...
+        */
+-      error = init_private_file(&file, dentry, FMODE_READ);
++      if (dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if ((dentry->d_flags & DCACHE_NFSD_DISCONNECTED) &&
++                  (dentry->d_parent == dentry) ) {
++                      it.it_op_release = NULL;
++                      /*
++                       * XXX Temporary Hack: Simulate init_private_file without
++                       * f_op->open for disconnected dentry as we don't have
++                       * actual dentry->d_name to revalidate in revalidate_it()
++                       */
++                      filp = &file;
++                      memset(filp, 0, sizeof(*filp));
++                      filp->f_mode   = FMODE_READ;
++                      atomic_set(&filp->f_count, 1);
++                      filp->f_dentry = dentry;
++                      filp->f_uid = current->fsuid;
++                      filp->f_gid = current->fsgid;
++                      filp->f_op = dentry->d_inode->i_fop;
++                      error = 0;
++              } else {
++                      intent_init(&it, IT_OPEN, 0);
++                      error = revalidate_it(dentry, &it);
++                      if (error)
++                              goto out;
++                      error = init_private_file_it(&file, dentry, FMODE_READ, &it);
++              }
++      } else {
++              error = init_private_file_it(&file, dentry, FMODE_READ, NULL);
++      }
+       if (error)
+               goto out;
++
+       error = -EINVAL;
+       if (!file.f_op->readdir)
+               goto out_close;
+@@ -113,9 +150,12 @@
+       }
+ out_close:
+-      if (file.f_op->release)
++      if (file.f_op->release && !filp)
+               file.f_op->release(dir, &file);
+ out:
++      if (dentry->d_op && dentry->d_op->d_revalidate_it &&
++          it.it_op_release && !filp)
++              intent_release(&it);
+       return error;
+ }
+@@ -274,7 +314,7 @@
+        * it is well connected.  But nobody returns different dentrys do they?
+        */
+       down(&child->d_inode->i_sem);
+-      pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
++      pdentry = lookup_it(child->d_inode, tdentry);
+       up(&child->d_inode->i_sem);
+       d_drop(tdentry); /* we never want ".." hashed */
+       if (!pdentry && tdentry->d_inode == NULL) {
+@@ -307,6 +347,8 @@
+                               pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
+                               pdentry->d_op = child->d_op;
+                       }
++                      if (child->d_op && child->d_op->d_revalidate_it)
++                              pdentry->d_op = child->d_op;
+               }
+               if (pdentry == NULL)
+                       pdentry = ERR_PTR(-ENOMEM);
+@@ -464,6 +506,8 @@
+               struct dentry *pdentry;
+               struct inode *parent;
++              if (result->d_op && result->d_op->d_revalidate_it)
++                      dentry->d_op = result->d_op;
+               pdentry = nfsd_findparent(dentry);
+               err = PTR_ERR(pdentry);
+               if (IS_ERR(pdentry))
+@@ -670,6 +714,10 @@
+       inode = dentry->d_inode;
++      /* cache coherency for non-device filesystems */
++      if (inode->i_op && inode->i_op->revalidate_it)
++              inode->i_op->revalidate_it(dentry, NULL);
++
+       /* Type check. The correct error return for type mismatches
+        * does not seem to be generally agreed upon. SunOS seems to
+        * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
+@@ -903,8 +951,9 @@
+               dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ out_uptodate:
+-      printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
+-              dentry->d_parent->d_name.name, dentry->d_name.name);
++      if (!dentry->d_parent->d_inode->i_op->mkdir_raw)
++              printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
++                    dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ }
+Index: linux-2.4.29/fs/nfsd/vfs.c
+===================================================================
+--- linux-2.4.29.orig/fs/nfsd/vfs.c    2005-05-03 16:28:21.000000000 +0300
++++ linux-2.4.29/fs/nfsd/vfs.c 2005-05-03 18:46:09.372133224 +0300
+@@ -77,6 +77,126 @@
+ static struct raparms *               raparml;
+ static struct raparms *               raparm_cache;
++static int link_raw(struct dentry *dold, struct dentry *ddir,
++                  struct dentry *dnew)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = dold };
++      struct nameidata nd = { .dentry = ddir, .last = dnew->d_name };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->link_raw(&old_nd, &nd);
++      d_instantiate(dnew, dold->d_inode);
++      if (dold->d_inode->i_op && dold->d_inode->i_op->revalidate_it)
++              dold->d_inode->i_op->revalidate_it(dnew, NULL);
++
++      return err;
++}
++
++static int unlink_raw(struct dentry *dentry, char *fname, int flen,
++                    struct dentry *rdentry)
++{
++      int err;
++      struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->unlink_raw(&nd);
++      if (!err)
++              d_delete(rdentry);
++
++      return err;
++}
++
++static int rmdir_raw(struct dentry *dentry, char *fname, int flen,
++                   struct dentry *rdentry)
++{
++      int err;
++      struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->rmdir_raw(&nd);
++      if (!err) {
++              rdentry->d_inode->i_flags |= S_DEAD;
++              d_delete(rdentry);
++      }
++
++      return err;
++}
++
++static int symlink_raw(struct dentry *dentry, char *fname, int flen,
++                     char *path)
++{
++      int err;
++      struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->symlink_raw(&nd, path);
++
++      return err;
++}
++
++static int mkdir_raw(struct dentry *dentry, char *fname, int flen, int mode)
++{
++      int err;
++      struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mkdir_raw(&nd, mode);
++
++      return err;
++}
++
++static int mknod_raw(struct dentry *dentry, char *fname, int flen, int mode,
++                   dev_t dev)
++{
++      int err;
++      struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mknod_raw(&nd, mode, dev);
++
++      return err;
++}
++
++static int rename_raw(struct dentry *fdentry, struct dentry *tdentry,
++                    struct dentry *odentry, struct dentry *ndentry)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = fdentry, .last = odentry->d_name};
++      struct nameidata new_nd = { .dentry = tdentry, .last = ndentry->d_name};
++      struct inode_operations *op = old_nd.dentry->d_inode->i_op;
++      err = op->rename_raw(&old_nd, &new_nd);
++      d_move(odentry, ndentry);
++
++      return err;
++}
++
++static int setattr_raw(struct inode *inode, struct iattr *iap)
++{
++      int err;
++
++      iap->ia_valid |= ATTR_RAW;
++      err = inode->i_op->setattr_raw(inode, iap);
++
++      return err;
++}
++
++int revalidate_it(struct dentry *dentry, struct lookup_intent *it)
++{
++      int err = 0;
++
++      if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if (!dentry->d_op->d_revalidate_it(dentry, 0, it) &&
++                      !d_invalidate(dentry)) {
++                      err = -EINVAL;
++                      return err;
++              }
++      }
++
++      return err;
++}
++
+ /*
+  * Look up one component of a pathname.
+  * N.B. After this call _both_ fhp and resfh need an fh_put
+@@ -302,7 +422,10 @@
+       }
+       err = nfserr_notsync;
+       if (!check_guard || guardtime == inode->i_ctime) {
+-              err = notify_change(dentry, iap);
++              if (dentry->d_inode->i_op && dentry->d_inode->i_op->setattr_raw)
++                      err = setattr_raw(dentry->d_inode, iap);
++              else
++                      err = notify_change(dentry, iap);
+               err = nfserrno(err);
+       }
+       if (size_change) {
+@@ -429,6 +552,7 @@
+ {
+       struct dentry   *dentry;
+       struct inode    *inode;
++      struct lookup_intent it;
+       int             err;
+       /* If we get here, then the client has already done an "open", and (hopefully)
+@@ -475,6 +599,18 @@
+               filp->f_mode  = FMODE_READ;
+       }
++#ifndef O_OWNER_OVERRIDE
++#define O_OWNER_OVERRIDE 0200000000
++#endif
++      intent_init(&it, IT_OPEN, (filp->f_flags & ~O_ACCMODE) | filp->f_mode |
++                  O_OWNER_OVERRIDE);
++
++      err = revalidate_it(dentry, &it);
++      if (err)
++              goto out_nfserr;
++
++      filp->f_it = &it;
++
+       err = 0;
+       if (filp->f_op && filp->f_op->open) {
+               err = filp->f_op->open(inode, filp);
+@@ -490,6 +626,9 @@
+               }
+       }
+ out_nfserr:
++      if (it.it_op_release)
++              intent_release(&it);
++
+       if (err)
+               err = nfserrno(err);
+ out:
+@@ -837,7 +976,7 @@
+ {
+       struct dentry   *dentry, *dchild;
+       struct inode    *dirp;
+-      int             err;
++      int             err, error = -EOPNOTSUPP;
+       err = nfserr_perm;
+       if (!flen)
+@@ -853,20 +992,47 @@
+       dentry = fhp->fh_dentry;
+       dirp = dentry->d_inode;
++      switch (type) {
++      case S_IFDIR:
++              if (dirp->i_op->mkdir_raw)
++                      error = mkdir_raw(dentry, fname, flen, iap->ia_mode);
++              break;
++      case S_IFCHR:
++      case S_IFBLK:
++      case S_IFIFO:
++      case S_IFSOCK:
++      case S_IFREG:
++              if (dirp->i_op->mknod_raw) {
++                      if (type == S_IFREG)
++                              rdev = 0;
++                      error = mknod_raw(dentry, fname,flen,iap->ia_mode,rdev);
++              }
++              break;
++      default:
++              printk("nfsd: bad file type %o in nfsd_create\n", type);
++      }
++      if (error && error != -EOPNOTSUPP) {
++              err = error;
++              goto out_nfserr;
++      }
++
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if (!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       /*
+        * Check whether the response file handle has been verified yet.
+        * If it has, the parent directory should already be locked.
+        */
+-      if (!resfhp->fh_dentry) {
+-              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
+-              fh_lock(fhp);
++      if (!resfhp->fh_dentry || dirp->i_op->lookup_it) {
++              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create
++               * and nfsd_proc_create in case of lustre */
++              if (!resfhp->fh_dentry)
++                      fh_lock(fhp);
+               dchild = lookup_one_len(fname, dentry, flen);
+               err = PTR_ERR(dchild);
+               if (IS_ERR(dchild))
+                       goto out_nfserr;
++              resfhp->fh_dentry = NULL;
+               err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
+               if (err)
+                       goto out;
+@@ -887,10 +1053,12 @@
+        * Make sure the child dentry is still negative ...
+        */
+       err = nfserr_exist;
+-      if (dchild->d_inode) {
+-              dprintk("nfsd_create: dentry %s/%s not negative!\n",
+-                      dentry->d_name.name, dchild->d_name.name);
+-              goto out; 
++      if (error == -EOPNOTSUPP) {
++              if (dchild->d_inode) {
++                      dprintk("nfsd_create: dentry %s/%s not negative!\n",
++                              dentry->d_name.name, dchild->d_name.name);
++                      goto out;
++              }
+       }
+       if (!(iap->ia_valid & ATTR_MODE))
+@@ -903,16 +1071,19 @@
+       err = nfserr_perm;
+       switch (type) {
+       case S_IFREG:
+-              err = vfs_create(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_create(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFDIR:
+-              err = vfs_mkdir(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_mkdir(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFCHR:
+       case S_IFBLK:
+       case S_IFIFO:
+       case S_IFSOCK:
+-              err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
+               break;
+       default:
+               printk("nfsd: bad file type %o in nfsd_create\n", type);
+@@ -981,7 +1152,13 @@
+       /* Get all the sanity checks out of the way before
+        * we lock the parent. */
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if (dirp->i_op->mknod_raw) {
++              err = mknod_raw(dentry, fname, flen, iap->ia_mode, 0);
++              if (err && err != -EOPNOTSUPP)
++                      goto out_nfserr;
++      }
++
++      if (!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       fh_lock(fhp);
+@@ -1032,6 +1209,8 @@
+               case NFS3_CREATE_GUARDED:
+                       err = nfserr_exist;
+               }
++              if (dirp->i_op->mknod_raw)
++                      err = 0;
+               goto out;
+       }
+@@ -1138,7 +1317,7 @@
+                               struct iattr *iap)
+ {
+       struct dentry   *dentry, *dnew;
+-      int             err, cerr;
++      int             err, cerr, error = -EOPNOTSUPP;
+       err = nfserr_noent;
+       if (!flen || !plen)
+@@ -1152,12 +1331,18 @@
+               goto out;
+       fh_lock(fhp);
+       dentry = fhp->fh_dentry;
++
++      if (dentry->d_inode->i_op->symlink_raw)
++              error = symlink_raw(dentry, fname, flen, path);
++
+       dnew = lookup_one_len(fname, dentry, flen);
+       err = PTR_ERR(dnew);
+       if (IS_ERR(dnew))
+               goto out_nfserr;
+-      err = vfs_symlink(dentry->d_inode, dnew, path);
++      err = error;
++      if (err == -EOPNOTSUPP || !dentry->d_inode->i_op->symlink_raw)
++              err = vfs_symlink(dentry->d_inode, dnew, path);
+       if (!err) {
+               if (EX_ISSYNC(fhp->fh_export))
+                       nfsd_sync_dir(dentry);
+@@ -1167,7 +1352,10 @@
+                               iap->ia_valid |= ATTR_CTIME;
+                               iap->ia_mode = (iap->ia_mode&S_IALLUGO)
+                                       | S_IFLNK;
+-                              err = notify_change(dnew, iap);
++                              if (dnew->d_inode->i_op && dnew->d_inode->i_op->setattr_raw)
++                                      err = setattr_raw(dnew->d_inode, iap);
++                              else
++                                      err = notify_change(dnew, iap);
+                               if (err)
+                                       err = nfserrno(err);
+                               else if (EX_ISSYNC(fhp->fh_export))
+@@ -1227,7 +1415,10 @@
+       dold = tfhp->fh_dentry;
+       dest = dold->d_inode;
+-      err = vfs_link(dold, dirp, dnew);
++      if (dirp->i_op->link_raw)
++              err = link_raw(dold, ddir, dnew);
++      else
++              err = vfs_link(dold, dirp, dnew);
+       if (!err) {
+               if (EX_ISSYNC(ffhp->fh_export)) {
+                       nfsd_sync_dir(ddir);
+@@ -1312,7 +1503,10 @@
+                       err = nfserr_perm;
+       } else
+ #endif
+-      err = vfs_rename(fdir, odentry, tdir, ndentry);
++      if (fdir->i_op->rename_raw)
++              err = rename_raw(fdentry, tdentry, odentry, ndentry);
++      else
++              err = vfs_rename(fdir, odentry, tdir, ndentry);
+       if (!err && EX_ISSYNC(tfhp->fh_export)) {
+               nfsd_sync_dir(tdentry);
+               nfsd_sync_dir(fdentry);
+@@ -1333,7 +1527,7 @@
+       fill_post_wcc(tfhp);
+       double_up(&tdir->i_sem, &fdir->i_sem);
+       ffhp->fh_locked = tfhp->fh_locked = 0;
+-      
++
+ out:
+       return err;
+ }
+@@ -1379,9 +1573,15 @@
+                       err = nfserr_perm;
+               } else
+ #endif
+-              err = vfs_unlink(dirp, rdentry);
++              if (dirp->i_op->unlink_raw)
++                      err = unlink_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_unlink(dirp, rdentry);
+       } else { /* It's RMDIR */
+-              err = vfs_rmdir(dirp, rdentry);
++              if (dirp->i_op->rmdir_raw)
++                      err = rmdir_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_rmdir(dirp, rdentry);
+       }
+       dput(rdentry);
+Index: linux-2.4.29/include/linux/fs.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/fs.h       2005-05-03 18:16:44.000000000 +0300
++++ linux-2.4.29/include/linux/fs.h    2005-05-03 18:52:56.016313912 +0300
+@@ -93,6 +93,8 @@
+ #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_NFSEXP_FSID        64 /* Use file system specific fsid for
++                          * exporting non device filesystems. */
+ #define FS_ODD_RENAME 32768   /* Temporary stuff; will go away as soon
+                                 * as nfs_rename() will be cleaned up
+                                 */
+@@ -1124,6 +1126,9 @@
+                        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 revalidate_it(struct dentry *dentry, struct lookup_intent *it);
++extern int init_private_file_it(struct file *, struct dentry *dentry, int mode,
++                              struct lookup_intent *it);
+ extern int filp_close(struct file *, fl_owner_t id);
+ extern char * getname(const char *);
+@@ -1423,6 +1428,8 @@
+ 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_one_len_it(const char *, struct dentry *, int,
++                                       struct lookup_intent *);
+ 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)
+@@ -1443,6 +1450,8 @@
+ extern struct inode * iget4_locked(struct super_block *, unsigned long,
+                                  find_inode_t, void *);
++ extern struct inode * ilookup4(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)
+Index: linux-2.4.29/kernel/ksyms.c
+===================================================================
+--- linux-2.4.29.orig/kernel/ksyms.c   2005-05-03 18:16:44.000000000 +0300
++++ linux-2.4.29/kernel/ksyms.c        2005-05-03 18:52:05.377012256 +0300
+@@ -150,6 +150,7 @@
+ EXPORT_SYMBOL(iunique);
+ EXPORT_SYMBOL(ilookup);
+ EXPORT_SYMBOL(iget4_locked);
++EXPORT_SYMBOL(ilookup4);
+ EXPORT_SYMBOL(unlock_new_inode);
+ EXPORT_SYMBOL(iput);
+ EXPORT_SYMBOL(inode_init_once);
+@@ -164,6 +165,7 @@
+ EXPORT_SYMBOL(path_release);
+ EXPORT_SYMBOL(__user_walk);
+ EXPORT_SYMBOL(lookup_one_len);
++EXPORT_SYMBOL(lookup_one_len_it);
+ EXPORT_SYMBOL(lookup_hash);
+ EXPORT_SYMBOL(sys_close);
+ EXPORT_SYMBOL(dcache_lock);
diff --git a/lustre/kernel_patches/patches/nfs_export_kernel-2.4.29.patch-1 b/lustre/kernel_patches/patches/nfs_export_kernel-2.4.29.patch-1
new file mode 100644 (file)
index 0000000..7bc7e44
--- /dev/null
@@ -0,0 +1,730 @@
+Index: linux-2.4.29/fs/Makefile
+===================================================================
+--- linux-2.4.29.orig/fs/Makefile      2005-04-07 19:31:00.000000000 +0300
++++ linux-2.4.29/fs/Makefile   2005-05-03 15:59:07.943621928 +0300
+@@ -7,7 +7,8 @@
+ O_TARGET := fs.o
+-export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o inode.o
++export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o inode.o \
++              namei.o file_table.o
+ mod-subdirs :=        nls
+ obj-y :=      open.o read_write.o devices.o file_table.o buffer.o \
+Index: linux-2.4.29/fs/file_table.c
+===================================================================
+--- linux-2.4.29.orig/fs/file_table.c  2005-04-07 18:52:26.000000000 +0300
++++ linux-2.4.29/fs/file_table.c       2005-05-03 15:59:07.945621624 +0300
+@@ -82,7 +82,8 @@
+  * and call the open function (if any).  The caller must verify that
+  * inode->i_fop is not NULL.
+  */
+-int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++int init_private_file_it(struct file *filp, struct dentry *dentry, int mode,
++                       struct lookup_intent *it)
+ {
+       memset(filp, 0, sizeof(*filp));
+       filp->f_mode   = mode;
+@@ -90,12 +91,20 @@
+       filp->f_dentry = dentry;
+       filp->f_uid    = current->fsuid;
+       filp->f_gid    = current->fsgid;
++      if (it)
++              filp->f_it = it;
+       filp->f_op     = dentry->d_inode->i_fop;
+       if (filp->f_op->open)
+               return filp->f_op->open(dentry->d_inode, filp);
+       else
+               return 0;
+ }
++EXPORT_SYMBOL(init_private_file_it);
++
++int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++{
++      return init_private_file_it(filp, dentry, mode, NULL);
++}
+ void fastcall fput(struct file * file)
+ {
+Index: linux-2.4.29/fs/inode.c
+===================================================================
+--- linux-2.4.29.orig/fs/inode.c       2005-04-07 19:18:51.000000000 +0300
++++ linux-2.4.29/fs/inode.c    2005-05-03 16:02:40.198354304 +0300
+@@ -1154,6 +1154,24 @@
+       }
+       spin_unlock(&inode_lock);
++      return NULL;
++}
++
++struct inode *ilookup4(struct super_block *sb, unsigned long ino,
++                     find_inode_t find_actor, void *opaque)
++{
++      struct list_head * head = inode_hashtable + hash(sb,ino);
++      return ifind(sb, ino, head, find_actor, opaque);
++}
++
++static inline struct inode *ifind(struct super_block *sb, unsigned long ino,
++                                struct list_head *head,
++                                find_inode_t find_actor, void *opaque)
++{
++      struct inode *inode = ifind(sb, ino, head, find_actor, opaque);
++      if (inode)
++              return inode;
++
+       /*
+        * get_new_inode() will do the right thing, re-trying the search
+        * in case it had to block at any point.
+Index: linux-2.4.29/fs/namei.c
+===================================================================
+--- linux-2.4.29.orig/fs/namei.c       2005-04-07 19:14:06.000000000 +0300
++++ linux-2.4.29/fs/namei.c    2005-05-03 15:59:07.953620408 +0300
+@@ -22,6 +22,7 @@
+ #include <linux/dnotify.h>
+ #include <linux/smp_lock.h>
+ #include <linux/personality.h>
++#include <linux/module.h>
+ #include <asm/namei.h>
+ #include <asm/uaccess.h>
+@@ -100,6 +101,7 @@
+               it->it_op_release(it);
+ }
++EXPORT_SYMBOL(intent_release);
+ /* In order to reduce some races, while at the same time doing additional
+  * checking and hopefully speeding things up, we copy filenames to the
+@@ -910,7 +912,8 @@
+ /* SMP-safe */
+-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++struct dentry * lookup_one_len_it(const char * name, struct dentry * base,
++                                int len, struct lookup_intent *it)
+ {
+       unsigned long hash;
+       struct qstr this;
+@@ -930,11 +933,16 @@
+       }
+       this.hash = end_name_hash(hash);
+-      return lookup_hash_it(&this, base, NULL);
++      return lookup_hash_it(&this, base, it);
+ access:
+       return ERR_PTR(-EACCES);
+ }
++struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++{
++      return lookup_one_len_it(name, base, len, NULL);
++}
++
+ /*
+  *    namei()
+  *
+Index: linux-2.4.29/fs/nfsd/export.c
+===================================================================
+--- linux-2.4.29.orig/fs/nfsd/export.c 2005-04-07 18:53:59.000000000 +0300
++++ linux-2.4.29/fs/nfsd/export.c      2005-05-03 15:59:07.955620104 +0300
+@@ -223,6 +223,11 @@
+       inode = nd.dentry->d_inode;
+       dev = inode->i_dev;
+       ino = inode->i_ino;
++      if ((inode->i_sb->s_type->fs_flags & FS_NFSEXP_FSID) &&
++          !(nxp->ex_flags & NFSEXP_FSID)) {
++              nxp->ex_dev = inode->i_sb->s_dev;
++              nxp->ex_flags |= NFSEXP_FSID;
++      }
+       err = -EINVAL;
+       exp = exp_get(clp, dev, ino);
+Index: linux-2.4.29/fs/nfsd/nfsfh.c
+===================================================================
+--- linux-2.4.29.orig/fs/nfsd/nfsfh.c  2005-04-07 18:53:14.000000000 +0300
++++ linux-2.4.29/fs/nfsd/nfsfh.c       2005-05-03 15:59:07.958619648 +0300
+@@ -36,6 +36,13 @@
+       int sequence;           /* sequence counter */
+ };
++static struct dentry *lookup_it(struct inode *inode, struct dentry * dentry)
++{
++      if (inode->i_op->lookup_it)
++              return inode->i_op->lookup_it(inode, dentry, NULL, 0);
++      return inode->i_op->lookup(inode, dentry);
++}
++
+ /*
+  * A rather strange filldir function to capture
+  * the name matching the specified inode number.
+@@ -75,6 +82,8 @@
+       int error;
+       struct file file;
+       struct nfsd_getdents_callback buffer;
++      struct lookup_intent it;
++      struct file *filp = NULL;
+       error = -ENOTDIR;
+       if (!dir || !S_ISDIR(dir->i_mode))
+@@ -85,9 +94,37 @@
+       /*
+        * Open the directory ...
+        */
+-      error = init_private_file(&file, dentry, FMODE_READ);
++      if (dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if ((dentry->d_flags & DCACHE_NFSD_DISCONNECTED) &&
++                  (dentry->d_parent == dentry) ) {
++                      it.it_op_release = NULL;
++                      /*
++                       * XXX Temporary Hack: Simulate init_private_file without
++                       * f_op->open for disconnected dentry as we don't have
++                       * actual dentry->d_name to revalidate in revalidate_it()
++                       */
++                      filp = &file;
++                      memset(filp, 0, sizeof(*filp));
++                      filp->f_mode   = FMODE_READ;
++                      atomic_set(&filp->f_count, 1);
++                      filp->f_dentry = dentry;
++                      filp->f_uid = current->fsuid;
++                      filp->f_gid = current->fsgid;
++                      filp->f_op = dentry->d_inode->i_fop;
++                      error = 0;
++              } else {
++                      intent_init(&it, IT_OPEN, 0);
++                      error = revalidate_it(dentry, &it);
++                      if (error)
++                              goto out;
++                      error = init_private_file_it(&file, dentry, FMODE_READ, &it);
++              }
++      } else {
++              error = init_private_file_it(&file, dentry, FMODE_READ, NULL);
++      }
+       if (error)
+               goto out;
++
+       error = -EINVAL;
+       if (!file.f_op->readdir)
+               goto out_close;
+@@ -113,9 +150,12 @@
+       }
+ out_close:
+-      if (file.f_op->release)
++      if (file.f_op->release && !filp)
+               file.f_op->release(dir, &file);
+ out:
++      if (dentry->d_op && dentry->d_op->d_revalidate_it &&
++          it.it_op_release && !filp)
++              intent_release(&it);
+       return error;
+ }
+@@ -274,7 +314,7 @@
+        * it is well connected.  But nobody returns different dentrys do they?
+        */
+       down(&child->d_inode->i_sem);
+-      pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
++      pdentry = lookup_it(child->d_inode, tdentry);
+       up(&child->d_inode->i_sem);
+       d_drop(tdentry); /* we never want ".." hashed */
+       if (!pdentry && tdentry->d_inode == NULL) {
+@@ -307,6 +347,8 @@
+                               pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
+                               pdentry->d_op = child->d_op;
+                       }
++                      if (child->d_op && child->d_op->d_revalidate_it)
++                              pdentry->d_op = child->d_op;
+               }
+               if (pdentry == NULL)
+                       pdentry = ERR_PTR(-ENOMEM);
+@@ -464,6 +506,8 @@
+               struct dentry *pdentry;
+               struct inode *parent;
++              if (result->d_op && result->d_op->d_revalidate_it)
++                      dentry->d_op = result->d_op;
+               pdentry = nfsd_findparent(dentry);
+               err = PTR_ERR(pdentry);
+               if (IS_ERR(pdentry))
+@@ -670,6 +714,10 @@
+       inode = dentry->d_inode;
++      /* cache coherency for non-device filesystems */
++      if (inode->i_op && inode->i_op->revalidate_it)
++              inode->i_op->revalidate_it(dentry, NULL);
++
+       /* Type check. The correct error return for type mismatches
+        * does not seem to be generally agreed upon. SunOS seems to
+        * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
+@@ -903,8 +951,9 @@
+               dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ out_uptodate:
+-      printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
+-              dentry->d_parent->d_name.name, dentry->d_name.name);
++      if (!dentry->d_parent->d_inode->i_op->mkdir_raw)
++              printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
++                    dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ }
+Index: linux-2.4.29/fs/nfsd/vfs.c
+===================================================================
+--- linux-2.4.29.orig/fs/nfsd/vfs.c    2005-04-07 18:53:19.000000000 +0300
++++ linux-2.4.29/fs/nfsd/vfs.c 2005-05-03 15:59:07.965618584 +0300
+@@ -77,6 +77,126 @@
+ static struct raparms *               raparml;
+ static struct raparms *               raparm_cache;
++static int link_raw(struct dentry *dold, struct dentry *ddir,
++                  struct dentry *dnew)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = dold };
++      struct nameidata nd = { .dentry = ddir, .last = dnew->d_name };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->link_raw(&old_nd, &nd);
++      d_instantiate(dnew, dold->d_inode);
++      if (dold->d_inode->i_op && dold->d_inode->i_op->revalidate_it)
++              dold->d_inode->i_op->revalidate_it(dnew, NULL);
++
++      return err;
++}
++
++static int unlink_raw(struct dentry *dentry, char *fname, int flen,
++                    struct dentry *rdentry)
++{
++      int err;
++      struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->unlink_raw(&nd);
++      if (!err)
++              d_delete(rdentry);
++
++      return err;
++}
++
++static int rmdir_raw(struct dentry *dentry, char *fname, int flen,
++                   struct dentry *rdentry)
++{
++      int err;
++      struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->rmdir_raw(&nd);
++      if (!err) {
++              rdentry->d_inode->i_flags |= S_DEAD;
++              d_delete(rdentry);
++      }
++
++      return err;
++}
++
++static int symlink_raw(struct dentry *dentry, char *fname, int flen,
++                     char *path)
++{
++      int err;
++      struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->symlink_raw(&nd, path);
++
++      return err;
++}
++
++static int mkdir_raw(struct dentry *dentry, char *fname, int flen, int mode)
++{
++      int err;
++      struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mkdir_raw(&nd, mode);
++
++      return err;
++}
++
++static int mknod_raw(struct dentry *dentry, char *fname, int flen, int mode,
++                   dev_t dev)
++{
++      int err;
++      struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mknod_raw(&nd, mode, dev);
++
++      return err;
++}
++
++static int rename_raw(struct dentry *fdentry, struct dentry *tdentry,
++                    struct dentry *odentry, struct dentry *ndentry)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = fdentry, .last = odentry->d_name};
++      struct nameidata new_nd = { .dentry = tdentry, .last = ndentry->d_name};
++      struct inode_operations *op = old_nd.dentry->d_inode->i_op;
++      err = op->rename_raw(&old_nd, &new_nd);
++      d_move(odentry, ndentry);
++
++      return err;
++}
++
++static int setattr_raw(struct inode *inode, struct iattr *iap)
++{
++      int err;
++
++      iap->ia_valid |= ATTR_RAW;
++      err = inode->i_op->setattr_raw(inode, iap);
++
++      return err;
++}
++
++int revalidate_it(struct dentry *dentry, struct lookup_intent *it)
++{
++      int err = 0;
++
++      if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if (!dentry->d_op->d_revalidate_it(dentry, 0, it) &&
++                      !d_invalidate(dentry)) {
++                      err = -EINVAL;
++                      return err;
++              }
++      }
++
++      return err;
++}
++
+ /*
+  * Look up one component of a pathname.
+  * N.B. After this call _both_ fhp and resfh need an fh_put
+@@ -302,7 +422,10 @@
+       }
+       err = nfserr_notsync;
+       if (!check_guard || guardtime == inode->i_ctime) {
+-              err = notify_change(dentry, iap);
++              if (dentry->d_inode->i_op && dentry->d_inode->i_op->setattr_raw)
++                      err = setattr_raw(dentry->d_inode, iap);
++              else
++                      err = notify_change(dentry, iap);
+               err = nfserrno(err);
+       }
+       if (size_change) {
+@@ -429,6 +552,7 @@
+ {
+       struct dentry   *dentry;
+       struct inode    *inode;
++      struct lookup_intent it;
+       int             err;
+       /* If we get here, then the client has already done an "open", and (hopefully)
+@@ -475,6 +599,18 @@
+               filp->f_mode  = FMODE_READ;
+       }
++#ifndef O_OWNER_OVERRIDE
++#define O_OWNER_OVERRIDE 0200000000
++#endif
++      intent_init(&it, IT_OPEN, (filp->f_flags & ~O_ACCMODE) | filp->f_mode |
++                  O_OWNER_OVERRIDE);
++
++      err = revalidate_it(dentry, &it);
++      if (err)
++              goto out_nfserr;
++
++      filp->f_it = &it;
++
+       err = 0;
+       if (filp->f_op && filp->f_op->open) {
+               err = filp->f_op->open(inode, filp);
+@@ -490,6 +626,9 @@
+               }
+       }
+ out_nfserr:
++      if (it.it_op_release)
++              intent_release(&it);
++
+       if (err)
+               err = nfserrno(err);
+ out:
+@@ -837,7 +976,7 @@
+ {
+       struct dentry   *dentry, *dchild;
+       struct inode    *dirp;
+-      int             err;
++      int             err, error = -EOPNOTSUPP;
+       err = nfserr_perm;
+       if (!flen)
+@@ -853,20 +992,47 @@
+       dentry = fhp->fh_dentry;
+       dirp = dentry->d_inode;
++      switch (type) {
++      case S_IFDIR:
++              if (dirp->i_op->mkdir_raw)
++                      error = mkdir_raw(dentry, fname, flen, iap->ia_mode);
++              break;
++      case S_IFCHR:
++      case S_IFBLK:
++      case S_IFIFO:
++      case S_IFSOCK:
++      case S_IFREG:
++              if (dirp->i_op->mknod_raw) {
++                      if (type == S_IFREG)
++                              rdev = 0;
++                      error = mknod_raw(dentry, fname,flen,iap->ia_mode,rdev);
++              }
++              break;
++      default:
++              printk("nfsd: bad file type %o in nfsd_create\n", type);
++      }
++      if (error && error != -EOPNOTSUPP) {
++              err = error;
++              goto out_nfserr;
++      }
++
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if (!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       /*
+        * Check whether the response file handle has been verified yet.
+        * If it has, the parent directory should already be locked.
+        */
+-      if (!resfhp->fh_dentry) {
+-              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
+-              fh_lock(fhp);
++      if (!resfhp->fh_dentry || dirp->i_op->lookup_it) {
++              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create
++               * and nfsd_proc_create in case of lustre */
++              if (!resfhp->fh_dentry)
++                      fh_lock(fhp);
+               dchild = lookup_one_len(fname, dentry, flen);
+               err = PTR_ERR(dchild);
+               if (IS_ERR(dchild))
+                       goto out_nfserr;
++              resfhp->fh_dentry = NULL;
+               err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
+               if (err)
+                       goto out;
+@@ -887,10 +1053,12 @@
+        * Make sure the child dentry is still negative ...
+        */
+       err = nfserr_exist;
+-      if (dchild->d_inode) {
+-              dprintk("nfsd_create: dentry %s/%s not negative!\n",
+-                      dentry->d_name.name, dchild->d_name.name);
+-              goto out; 
++      if (error == -EOPNOTSUPP) {
++              if (dchild->d_inode) {
++                      dprintk("nfsd_create: dentry %s/%s not negative!\n",
++                              dentry->d_name.name, dchild->d_name.name);
++                      goto out;
++              }
+       }
+       if (!(iap->ia_valid & ATTR_MODE))
+@@ -903,16 +1071,19 @@
+       err = nfserr_perm;
+       switch (type) {
+       case S_IFREG:
+-              err = vfs_create(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_create(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFDIR:
+-              err = vfs_mkdir(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_mkdir(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFCHR:
+       case S_IFBLK:
+       case S_IFIFO:
+       case S_IFSOCK:
+-              err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
+               break;
+       default:
+               printk("nfsd: bad file type %o in nfsd_create\n", type);
+@@ -981,7 +1152,13 @@
+       /* Get all the sanity checks out of the way before
+        * we lock the parent. */
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if (dirp->i_op->mknod_raw) {
++              err = mknod_raw(dentry, fname, flen, iap->ia_mode, 0);
++              if (err && err != -EOPNOTSUPP)
++                      goto out_nfserr;
++      }
++
++      if (!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       fh_lock(fhp);
+@@ -1032,6 +1209,8 @@
+               case NFS3_CREATE_GUARDED:
+                       err = nfserr_exist;
+               }
++              if (dirp->i_op->mknod_raw)
++                      err = 0;
+               goto out;
+       }
+@@ -1138,7 +1317,7 @@
+                               struct iattr *iap)
+ {
+       struct dentry   *dentry, *dnew;
+-      int             err, cerr;
++      int             err, cerr, error = -EOPNOTSUPP;
+       err = nfserr_noent;
+       if (!flen || !plen)
+@@ -1152,12 +1331,18 @@
+               goto out;
+       fh_lock(fhp);
+       dentry = fhp->fh_dentry;
++
++      if (dentry->d_inode->i_op->symlink_raw)
++              error = symlink_raw(dentry, fname, flen, path);
++
+       dnew = lookup_one_len(fname, dentry, flen);
+       err = PTR_ERR(dnew);
+       if (IS_ERR(dnew))
+               goto out_nfserr;
+-      err = vfs_symlink(dentry->d_inode, dnew, path);
++      err = error;
++      if (err == -EOPNOTSUPP || !dentry->d_inode->i_op->symlink_raw)
++              err = vfs_symlink(dentry->d_inode, dnew, path);
+       if (!err) {
+               if (EX_ISSYNC(fhp->fh_export))
+                       nfsd_sync_dir(dentry);
+@@ -1167,7 +1352,10 @@
+                               iap->ia_valid |= ATTR_CTIME;
+                               iap->ia_mode = (iap->ia_mode&S_IALLUGO)
+                                       | S_IFLNK;
+-                              err = notify_change(dnew, iap);
++                              if (dnew->d_inode->i_op && dnew->d_inode->i_op->setattr_raw)
++                                      err = setattr_raw(dnew->d_inode, iap);
++                              else
++                                      err = notify_change(dnew, iap);
+                               if (err)
+                                       err = nfserrno(err);
+                               else if (EX_ISSYNC(fhp->fh_export))
+@@ -1227,7 +1415,10 @@
+       dold = tfhp->fh_dentry;
+       dest = dold->d_inode;
+-      err = vfs_link(dold, dirp, dnew);
++      if (dirp->i_op->link_raw)
++              err = link_raw(dold, ddir, dnew);
++      else
++              err = vfs_link(dold, dirp, dnew);
+       if (!err) {
+               if (EX_ISSYNC(ffhp->fh_export)) {
+                       nfsd_sync_dir(ddir);
+@@ -1312,7 +1503,10 @@
+                       err = nfserr_perm;
+       } else
+ #endif
+-      err = vfs_rename(fdir, odentry, tdir, ndentry);
++      if (fdir->i_op->rename_raw)
++              err = rename_raw(fdentry, tdentry, odentry, ndentry);
++      else
++              err = vfs_rename(fdir, odentry, tdir, ndentry);
+       if (!err && EX_ISSYNC(tfhp->fh_export)) {
+               nfsd_sync_dir(tdentry);
+               nfsd_sync_dir(fdentry);
+@@ -1333,7 +1527,7 @@
+       fill_post_wcc(tfhp);
+       double_up(&tdir->i_sem, &fdir->i_sem);
+       ffhp->fh_locked = tfhp->fh_locked = 0;
+-      
++
+ out:
+       return err;
+ }
+@@ -1379,9 +1573,15 @@
+                       err = nfserr_perm;
+               } else
+ #endif
+-              err = vfs_unlink(dirp, rdentry);
++              if (dirp->i_op->unlink_raw)
++                      err = unlink_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_unlink(dirp, rdentry);
+       } else { /* It's RMDIR */
+-              err = vfs_rmdir(dirp, rdentry);
++              if (dirp->i_op->rmdir_raw)
++                      err = rmdir_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_rmdir(dirp, rdentry);
+       }
+       dput(rdentry);
+Index: linux-2.4.29/include/linux/fs.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/fs.h       2005-04-07 19:31:00.000000000 +0300
++++ linux-2.4.29/include/linux/fs.h    2005-05-03 16:05:36.094614008 +0300
+@@ -93,6 +93,8 @@
+ #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_NFSEXP_FSID        64 /* Use file system specific fsid for
++                          * exporting non device filesystems. */
+ #define FS_ODD_RENAME 32768   /* Temporary stuff; will go away as soon
+                                 * as nfs_rename() will be cleaned up
+                                 */
+@@ -1118,6 +1120,9 @@
+                        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 revalidate_it(struct dentry *dentry, struct lookup_intent *it);
++extern int init_private_file_it(struct file *, struct dentry *dentry, int mode,
++                              struct lookup_intent *it);
+ extern int filp_close(struct file *, fl_owner_t id);
+ extern char * getname(const char *);
+@@ -1417,6 +1422,8 @@
+ 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_one_len_it(const char *, struct dentry *, int,
++                                       struct lookup_intent *);
+ 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)
+@@ -1437,6 +1444,8 @@
+ extern struct inode * iget4_locked(struct super_block *, unsigned long,
+                                  find_inode_t, void *);
++extern struct inode * ilookup4(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)
+Index: linux-2.4.29/kernel/ksyms.c
+===================================================================
+--- linux-2.4.29.orig/kernel/ksyms.c   2005-04-07 19:31:00.000000000 +0300
++++ linux-2.4.29/kernel/ksyms.c        2005-05-03 16:04:09.445786632 +0300
+@@ -151,6 +151,7 @@
+ EXPORT_SYMBOL(ilookup);
+ EXPORT_SYMBOL(iget4_locked);
+ EXPORT_SYMBOL(unlock_new_inode);
++EXPORT_SYMBOL(ilookup4);
+ EXPORT_SYMBOL(iput);
+ EXPORT_SYMBOL(inode_init_once);
+ EXPORT_SYMBOL(__inode_init_once);
+@@ -164,6 +165,7 @@
+ EXPORT_SYMBOL(path_release);
+ EXPORT_SYMBOL(__user_walk);
+ EXPORT_SYMBOL(lookup_one_len);
++EXPORT_SYMBOL(lookup_one_len_it);
+ EXPORT_SYMBOL(lookup_hash);
+ EXPORT_SYMBOL(sys_close);
+ EXPORT_SYMBOL(dcache_lock);
diff --git a/lustre/kernel_patches/patches/uml-patch-2.4.29-1.patch b/lustre/kernel_patches/patches/uml-patch-2.4.29-1.patch
new file mode 100644 (file)
index 0000000..ec0d8b3
--- /dev/null
@@ -0,0 +1,46719 @@
+Index: linux-2.4.29/arch/um/config_block.in
+===================================================================
+--- linux-2.4.29.orig/arch/um/config_block.in  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/config_block.in       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,22 @@
++mainmenu_option next_comment
++comment 'Block Devices'
++
++bool 'Virtual block device' CONFIG_BLK_DEV_UBD
++dep_bool '  Always do synchronous disk IO for UBD' CONFIG_BLK_DEV_UBD_SYNC $CONFIG_BLK_DEV_UBD
++bool 'COW device' CONFIG_COW
++
++if [ "$CONFIG_BLK_DEV_UBD" = "y" -o "$CONFIG_COW" = "y" ] ; then
++      define_bool CONFIG_COW_COMMON y
++fi
++
++tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
++dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
++tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
++if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
++      int '   Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096
++fi
++dep_bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
++
++tristate 'Example IO memory driver' CONFIG_MMAPPER
++
++endmenu
+Index: linux-2.4.29/arch/um/config_char.in
+===================================================================
+--- linux-2.4.29.orig/arch/um/config_char.in   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/config_char.in        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,37 @@
++mainmenu_option next_comment
++comment 'Character Devices'
++
++define_bool CONFIG_STDIO_CONSOLE y
++
++bool 'Virtual serial line' CONFIG_SSL
++
++bool 'file descriptor channel support' CONFIG_FD_CHAN
++bool 'null channel support' CONFIG_NULL_CHAN
++bool 'port channel support' CONFIG_PORT_CHAN
++bool 'pty channel support' CONFIG_PTY_CHAN
++bool 'tty channel support' CONFIG_TTY_CHAN
++bool 'xterm channel support' CONFIG_XTERM_CHAN
++string 'Default main console channel initialization' CONFIG_CON_ZERO_CHAN \
++            "fd:0,fd:1"
++string 'Default console channel initialization' CONFIG_CON_CHAN "xterm"
++string 'Default serial line channel initialization' CONFIG_SSL_CHAN "pty"
++
++
++bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
++if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
++   int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
++fi
++
++bool 'Watchdog Timer Support' CONFIG_WATCHDOG
++dep_bool '  Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT \
++      $CONFIG_WATCHDOG
++dep_tristate '  Software Watchdog' CONFIG_SOFT_WATCHDOG $CONFIG_WATCHDOG
++dep_tristate '  UML watchdog' CONFIG_UML_WATCHDOG $CONFIG_WATCHDOG
++
++tristate 'Sound support' CONFIG_UML_SOUND
++define_tristate CONFIG_SOUND $CONFIG_UML_SOUND
++define_tristate CONFIG_HOSTAUDIO $CONFIG_UML_SOUND
++
++bool 'Enable tty logging' CONFIG_TTY_LOG
++
++endmenu
+Index: linux-2.4.29/arch/um/config.in
+===================================================================
+--- linux-2.4.29.orig/arch/um/config.in        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/config.in     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,123 @@
++define_bool CONFIG_USERMODE y
++
++mainmenu_name "Linux/Usermode Kernel Configuration"
++
++define_bool CONFIG_ISA n
++define_bool CONFIG_SBUS n
++define_bool CONFIG_PCI n
++
++define_bool CONFIG_UID16 y
++
++define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
++
++mainmenu_option next_comment
++comment 'Code maturity level options'
++bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
++endmenu
++
++mainmenu_option next_comment
++comment 'General Setup'
++
++bool 'Separate kernel address space support' CONFIG_MODE_SKAS
++
++# This is to ensure that at least one of the modes is enabled.  When neither
++# is present in defconfig, they default to N, which is bad.
++if [ "$CONFIG_MODE_SKAS" != "y" ]; then
++   define_bool CONFIG_MODE_TT y
++fi
++
++bool 'Tracing thread support' CONFIG_MODE_TT
++if [ "$CONFIG_MODE_TT" != "y" ]; then
++   bool 'Statically linked binary when CONFIG_MODE_TT is disabled' CONFIG_STATIC_LINK
++fi
++bool 'Networking support' CONFIG_NET
++bool 'System V IPC' CONFIG_SYSVIPC
++bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
++bool 'Sysctl support' CONFIG_SYSCTL
++tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
++tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
++
++tristate 'Host filesystem' CONFIG_HOSTFS
++tristate 'Usable host filesystem' CONFIG_HUMFS
++
++if [ "$CONFIG_HOSTFS" = "y" -o "$CONFIG_HUMFS" = "y" ]; then
++    define_tristate CONFIG_EXTERNFS y
++fi
++
++tristate 'Honeypot proc filesystem' CONFIG_HPPFS
++bool 'Management console' CONFIG_MCONSOLE
++dep_bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_MCONSOLE
++bool '2G/2G host address space split' CONFIG_HOST_2G_2G
++
++bool 'Symmetric multi-processing support' CONFIG_UML_SMP
++define_bool CONFIG_SMP $CONFIG_UML_SMP
++if [ "$CONFIG_SMP" = "y" ]; then
++    int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
++fi
++
++int 'Nesting level' CONFIG_NEST_LEVEL 0
++int 'Kernel address space size (in .5G units)' CONFIG_KERNEL_HALF_GIGS 1
++bool 'Highmem support' CONFIG_HIGHMEM
++bool '/proc/mm' CONFIG_PROC_MM
++int 'Kernel stack size order' CONFIG_KERNEL_STACK_ORDER 2
++bool 'Real-time Clock' CONFIG_UML_REAL_TIME_CLOCK
++endmenu
++
++mainmenu_option next_comment
++comment 'Loadable module support'
++bool 'Enable loadable module support' CONFIG_MODULES
++if [ "$CONFIG_MODULES" = "y" ]; then
++# MODVERSIONS does not yet work in this architecture
++#   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
++    bool '  Kernel module loader' CONFIG_KMOD
++fi
++endmenu
++
++source arch/um/config_char.in
++
++source arch/um/config_block.in
++
++define_bool CONFIG_NETDEVICES $CONFIG_NET
++
++if [ "$CONFIG_NET" = "y" ]; then
++   source arch/um/config_net.in
++   source net/Config.in
++fi
++
++source fs/Config.in
++
++mainmenu_option next_comment
++comment 'SCSI support'
++
++tristate 'SCSI support' CONFIG_SCSI
++
++if [ "$CONFIG_SCSI" != "n" ]; then
++   source arch/um/config_scsi.in
++fi
++endmenu
++
++source drivers/md/Config.in
++
++source drivers/mtd/Config.in
++
++source lib/Config.in
++
++source crypto/Config.in
++
++mainmenu_option next_comment
++comment 'Kernel hacking'
++bool 'Debug memory allocations' CONFIG_DEBUG_SLAB
++bool 'Enable kernel debugging symbols' CONFIG_DEBUGSYM
++if [ "$CONFIG_XTERM_CHAN" = "y" ]; then
++   dep_bool 'Enable ptrace proxy' CONFIG_PT_PROXY $CONFIG_DEBUGSYM
++else 
++   define_bool CONFIG_PT_PROXY n
++fi
++
++if [ "$CONFIG_MODE_TT" = "n" ]; then
++   dep_bool 'Enable gprof support' CONFIG_GPROF $CONFIG_DEBUGSYM
++fi
++
++dep_bool 'Enable gcov support' CONFIG_GCOV $CONFIG_DEBUGSYM
++endmenu
+Index: linux-2.4.29/arch/um/config_net.in
+===================================================================
+--- linux-2.4.29.orig/arch/um/config_net.in    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/config_net.in 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,48 @@
++mainmenu_option next_comment
++comment 'Network Devices'
++
++# UML virtual driver
++bool 'Virtual network device' CONFIG_UML_NET
++
++dep_bool '  Ethertap transport' CONFIG_UML_NET_ETHERTAP $CONFIG_UML_NET
++dep_bool '  TUN/TAP transport' CONFIG_UML_NET_TUNTAP $CONFIG_UML_NET
++dep_bool '  SLIP transport' CONFIG_UML_NET_SLIP $CONFIG_UML_NET
++dep_bool '  SLiRP transport' CONFIG_UML_NET_SLIRP $CONFIG_UML_NET
++dep_bool '  Daemon transport' CONFIG_UML_NET_DAEMON $CONFIG_UML_NET
++dep_bool '  Multicast transport' CONFIG_UML_NET_MCAST $CONFIG_UML_NET
++dep_bool '  pcap transport' CONFIG_UML_NET_PCAP $CONFIG_UML_NET
++
++# Below are hardware-independent drivers mirrored from
++# drivers/net/Config.in. It would be nice if Linux
++# had HW independent drivers separated from the other
++# but it does not. Until then each non-ISA/PCI arch
++# needs to provide it's own menu of network drivers
++
++tristate 'Dummy net driver support' CONFIG_DUMMY
++tristate 'Bonding driver support' CONFIG_BONDING
++tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
++tristate 'Universal TUN/TAP device driver support' CONFIG_TUN
++if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
++   if [ "$CONFIG_NETLINK" = "y" ]; then
++      tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
++   fi
++fi
++
++tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
++if [ ! "$CONFIG_PPP" = "n" ]; then
++   dep_bool '  PPP multilink support (EXPERIMENTAL)' CONFIG_PPP_MULTILINK $CONFIG_EXPERIMENTAL
++   dep_bool '  PPP filtering' CONFIG_PPP_FILTER $CONFIG_FILTER
++   dep_tristate '  PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
++   dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
++   dep_tristate '  PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
++   dep_tristate '  PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP
++   dep_tristate '  PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP $CONFIG_EXPERIMENTAL
++   dep_tristate '  PPP MPPE compression (encryption)' CONFIG_PPP_MPPE $CONFIG_PPP
++fi
++
++tristate 'SLIP (serial line) support' CONFIG_SLIP
++dep_bool '  CSLIP compressed headers' CONFIG_SLIP_COMPRESSED $CONFIG_SLIP
++dep_bool '  Keepalive and linefill' CONFIG_SLIP_SMART $CONFIG_SLIP
++dep_bool '  Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 $CONFIG_SLIP
++
++endmenu
+Index: linux-2.4.29/arch/um/config.release
+===================================================================
+--- linux-2.4.29.orig/arch/um/config.release   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/config.release        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,302 @@
++#
++# Automatically generated make config: don't edit
++#
++CONFIG_USERMODE=y
++# CONFIG_ISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_PCI is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++
++#
++# General Setup
++#
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_SYSCTL=y
++CONFIG_BINFMT_AOUT=y
++CONFIG_BINFMT_ELF=y
++CONFIG_BINFMT_MISC=y
++CONFIG_HOSTFS=y
++# CONFIG_HPPFS is not set
++CONFIG_MCONSOLE=y
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_HOST_2G_2G is not set
++# CONFIG_UML_SMP is not set
++# CONFIG_SMP is not set
++CONFIG_NEST_LEVEL=0
++CONFIG_KERNEL_HALF_GIGS=1
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_KMOD=y
++
++#
++# Character Devices
++#
++CONFIG_STDIO_CONSOLE=y
++CONFIG_SSL=y
++CONFIG_FD_CHAN=y
++# CONFIG_NULL_CHAN is not set
++CONFIG_PORT_CHAN=y
++CONFIG_PTY_CHAN=y
++CONFIG_TTY_CHAN=y
++CONFIG_XTERM_CHAN=y
++CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
++CONFIG_CON_CHAN="xterm"
++CONFIG_SSL_CHAN="pty"
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++# CONFIG_WATCHDOG is not set
++CONFIG_UML_SOUND=y
++CONFIG_SOUND=y
++CONFIG_HOSTAUDIO=y
++# CONFIG_TTY_LOG is not set
++
++#
++# Block Devices
++#
++CONFIG_BLK_DEV_UBD=y
++# CONFIG_BLK_DEV_UBD_SYNC is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_NBD=y
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_INITRD=y
++# CONFIG_MMAPPER is not set
++CONFIG_NETDEVICES=y
++
++#
++# Network Devices
++#
++CONFIG_UML_NET=y
++CONFIG_UML_NET_ETHERTAP=y
++CONFIG_UML_NET_TUNTAP=y
++CONFIG_UML_NET_SLIP=y
++CONFIG_UML_NET_DAEMON=y
++CONFIG_UML_NET_MCAST=y
++CONFIG_DUMMY=y
++CONFIG_BONDING=m
++CONFIG_EQUALIZER=m
++CONFIG_TUN=y
++CONFIG_PPP=m
++CONFIG_PPP_MULTILINK=y
++# CONFIG_PPP_ASYNC is not set
++CONFIG_PPP_SYNC_TTY=m
++CONFIG_PPP_DEFLATE=m
++CONFIG_PPP_BSDCOMP=m
++CONFIG_PPPOE=m
++CONFIG_SLIP=m
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++
++#
++#  
++#
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# File systems
++#
++CONFIG_QUOTA=y
++CONFIG_AUTOFS_FS=m
++CONFIG_AUTOFS4_FS=m
++CONFIG_REISERFS_FS=m
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++CONFIG_ADFS_FS=m
++# CONFIG_ADFS_FS_RW is not set
++CONFIG_AFFS_FS=m
++CONFIG_HFS_FS=m
++CONFIG_BFS_FS=m
++CONFIG_EXT3_FS=y
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_UMSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_EFS_FS=m
++CONFIG_CRAMFS=m
++CONFIG_TMPFS=y
++CONFIG_RAMFS=y
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++CONFIG_MINIX_FS=m
++CONFIG_VXFS_FS=m
++# CONFIG_NTFS_FS is not set
++CONFIG_HPFS_FS=m
++CONFIG_PROC_FS=y
++CONFIG_DEVFS_FS=y
++CONFIG_DEVFS_MOUNT=y
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++CONFIG_QNX4FS_FS=m
++# CONFIG_QNX4FS_RW is not set
++CONFIG_ROMFS_FS=m
++CONFIG_EXT2_FS=y
++CONFIG_SYSV_FS=m
++CONFIG_UDF_FS=m
++# CONFIG_UDF_RW is not set
++CONFIG_UFS_FS=m
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_NFSD=y
++CONFIG_NFSD_V3=y
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_ZISOFS_FS is not set
++CONFIG_ZLIB_FS_INFLATE=m
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++# CONFIG_NLS_CODEPAGE_437 is not set
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ISO8859_1 is not set
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# SCSI support
++#
++CONFIG_SCSI=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++# CONFIG_BLK_DEV_SD is not set
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_BLK_DEV_SR is not set
++# CONFIG_CHR_DEV_SG is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# CONFIG_SCSI_DEBUG_QUEUES is not set
++# CONFIG_SCSI_MULTI_LUN is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++CONFIG_SCSI_DEBUG=m
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++# CONFIG_MTD is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUGSYM is not set
+Index: linux-2.4.29/arch/um/config_scsi.in
+===================================================================
+--- linux-2.4.29.orig/arch/um/config_scsi.in   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/config_scsi.in        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,30 @@
++comment 'SCSI support type (disk, tape, CD-ROM)'
++
++dep_tristate '  SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
++
++if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then
++   int  'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40
++fi
++
++dep_tristate '  SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
++
++dep_tristate '  SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
++
++if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
++   bool '    Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
++   int  'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2
++fi
++dep_tristate '  SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
++
++comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
++
++#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
++   bool '  Enable extra checks in new queueing code' CONFIG_SCSI_DEBUG_QUEUES
++#fi
++
++bool '  Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
++  
++bool '  Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
++bool '  SCSI logging facility' CONFIG_SCSI_LOGGING
++
++dep_tristate 'SCSI debugging host simulator (EXPERIMENTAL)' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+Index: linux-2.4.29/arch/um/defconfig
+===================================================================
+--- linux-2.4.29.orig/arch/um/defconfig        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/defconfig     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,430 @@
++#
++# Automatically generated make config: don't edit
++#
++CONFIG_USERMODE=y
++# CONFIG_ISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_PCI is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++
++#
++# General Setup
++#
++CONFIG_MODE_SKAS=y
++CONFIG_MODE_TT=y
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_SYSCTL=y
++CONFIG_BINFMT_AOUT=y
++CONFIG_BINFMT_ELF=y
++CONFIG_BINFMT_MISC=y
++CONFIG_HOSTFS=y
++CONFIG_HUMFS=y
++CONFIG_EXTERNFS=y
++CONFIG_HPPFS=y
++CONFIG_MCONSOLE=y
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_HOST_2G_2G is not set
++# CONFIG_UML_SMP is not set
++# CONFIG_SMP is not set
++CONFIG_NEST_LEVEL=0
++CONFIG_KERNEL_HALF_GIGS=1
++# CONFIG_HIGHMEM is not set
++CONFIG_PROC_MM=y
++CONFIG_KERNEL_STACK_ORDER=2
++CONFIG_UML_REAL_TIME_CLOCK=y
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_KMOD is not set
++
++#
++# Character Devices
++#
++CONFIG_STDIO_CONSOLE=y
++CONFIG_SSL=y
++CONFIG_FD_CHAN=y
++CONFIG_NULL_CHAN=y
++CONFIG_PORT_CHAN=y
++CONFIG_PTY_CHAN=y
++CONFIG_TTY_CHAN=y
++CONFIG_XTERM_CHAN=y
++CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
++CONFIG_CON_CHAN="xterm"
++CONFIG_SSL_CHAN="pty"
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++# CONFIG_WATCHDOG is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++# CONFIG_SOFT_WATCHDOG is not set
++# CONFIG_UML_WATCHDOG is not set
++CONFIG_UML_SOUND=y
++CONFIG_SOUND=y
++CONFIG_HOSTAUDIO=y
++# CONFIG_TTY_LOG is not set
++
++#
++# Block Devices
++#
++CONFIG_BLK_DEV_UBD=y
++# CONFIG_BLK_DEV_UBD_SYNC is not set
++# CONFIG_COW is not set
++CONFIG_COW_COMMON=y
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_NBD=y
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_INITRD=y
++# CONFIG_MMAPPER is not set
++CONFIG_NETDEVICES=y
++
++#
++# Network Devices
++#
++CONFIG_UML_NET=y
++CONFIG_UML_NET_ETHERTAP=y
++CONFIG_UML_NET_TUNTAP=y
++CONFIG_UML_NET_SLIP=y
++CONFIG_UML_NET_SLIRP=y
++CONFIG_UML_NET_DAEMON=y
++CONFIG_UML_NET_MCAST=y
++# CONFIG_UML_NET_PCAP is not set
++CONFIG_DUMMY=y
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_TUN=y
++CONFIG_PPP=y
++# CONFIG_PPP_MULTILINK is not set
++# CONFIG_PPP_FILTER is not set
++# CONFIG_PPP_ASYNC is not set
++# CONFIG_PPP_SYNC_TTY is not set
++# CONFIG_PPP_DEFLATE is not set
++# CONFIG_PPP_BSDCOMP is not set
++# CONFIG_PPPOE is not set
++# CONFIG_PPP_MPPE is not set
++CONFIG_SLIP=y
++# CONFIG_SLIP_COMPRESSED is not set
++# CONFIG_SLIP_SMART is not set
++# CONFIG_SLIP_MODE_SLIP6 is not set
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++
++#
++#    SCTP Configuration (EXPERIMENTAL)
++#
++CONFIG_IPV6_SCTP__=y
++# CONFIG_IP_SCTP is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++
++#
++#  
++#
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# File systems
++#
++CONFIG_QUOTA=y
++# CONFIG_QFMT_V2 is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++CONFIG_REISERFS_FS=y
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BEFS_DEBUG is not set
++# CONFIG_BFS_FS is not set
++CONFIG_EXT3_FS=y
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_UMSDOS_FS=y
++CONFIG_VFAT_FS=y
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS_FS=y
++CONFIG_JFFS_FS_VERBOSE=0
++CONFIG_JFFS_PROC_FS=y
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++# CONFIG_CRAMFS is not set
++CONFIG_TMPFS=y
++CONFIG_RAMFS=y
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_JFS_DEBUG is not set
++# CONFIG_JFS_STATISTICS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++CONFIG_DEVFS_FS=y
++CONFIG_DEVFS_MOUNT=y
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_XFS_QUOTA is not set
++# CONFIG_XFS_RT is not set
++# CONFIG_XFS_TRACE is not set
++# CONFIG_XFS_DEBUG is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++# CONFIG_NFS_FS is not set
++# CONFIG_NFS_V3 is not set
++# CONFIG_NFS_DIRECTIO is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++# CONFIG_NFSD_TCP is not set
++# CONFIG_SUNRPC is not set
++# CONFIG_LOCKD is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++# CONFIG_NLS_CODEPAGE_437 is not set
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ISO8859_1 is not set
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# SCSI support
++#
++CONFIG_SCSI=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++# CONFIG_BLK_DEV_SD is not set
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_BLK_DEV_SR is not set
++# CONFIG_CHR_DEV_SG is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# CONFIG_SCSI_DEBUG_QUEUES is not set
++# CONFIG_SCSI_MULTI_LUN is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++CONFIG_SCSI_DEBUG=y
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++# CONFIG_MTD_PARTITIONS is not set
++# CONFIG_MTD_CONCAT is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++# CONFIG_MTD_GEN_PROBE is not set
++# CONFIG_MTD_CFI_INTELEXT is not set
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_CFI_STAA is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_PCI is not set
++# CONFIG_MTD_PCMCIA is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLKMTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Library routines
++#
++# CONFIG_CRC32 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++
++#
++# Kernel hacking
++#
++# CONFIG_DEBUG_SLAB is not set
++CONFIG_DEBUGSYM=y
++CONFIG_PT_PROXY=y
++# CONFIG_GCOV is not set
+Index: linux-2.4.29/arch/um/drivers/chan_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/chan_kern.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/chan_kern.c   2005-05-03 22:28:14.196452024 +0300
+@@ -0,0 +1,568 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/tty.h>
++#include <linux/string.h>
++#include <linux/tty_flip.h>
++#include <asm/irq.h>
++#include "chan_kern.h"
++#include "user_util.h"
++#include "kern.h"
++#include "irq_user.h"
++#include "sigio.h"
++#include "line.h"
++#include "os.h"
++
++static void *not_configged_init(char *str, int device, struct chan_opts *opts)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++      return(NULL);
++}
++
++static int not_configged_open(int input, int output, int primary, void *data,
++                            char **dev_out)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++      return(-ENODEV);
++}
++
++static void not_configged_close(int fd, void *data)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++}
++
++static int not_configged_read(int fd, char *c_out, void *data)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++      return(-EIO);
++}
++
++static int not_configged_write(int fd, const char *buf, int len, void *data)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++      return(-EIO);
++}
++
++static int not_configged_console_write(int fd, const char *buf, int len,
++                                     void *data)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++      return(-EIO);
++}
++
++static int not_configged_window_size(int fd, void *data, unsigned short *rows,
++                                   unsigned short *cols)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++      return(-ENODEV);
++}
++
++static void not_configged_free(void *data)
++{
++      printk(KERN_ERR "Using a channel type which is configured out of "
++             "UML\n");
++}
++
++static struct chan_ops not_configged_ops = {
++      .init           = not_configged_init,
++      .open           = not_configged_open,
++      .close          = not_configged_close,
++      .read           = not_configged_read,
++      .write          = not_configged_write,
++      .console_write  = not_configged_console_write,
++      .window_size    = not_configged_window_size,
++      .free           = not_configged_free,
++      .winch          = 0,
++};
++
++void generic_close(int fd, void *unused)
++{
++      os_close_file(fd);
++}
++
++int generic_read(int fd, char *c_out, void *unused)
++{
++      int n;
++
++      n = os_read_file(fd, c_out, sizeof(*c_out));
++
++      if(n == -EAGAIN)
++              return(0);
++      else if(n == 0)
++              return(-EIO);
++      return(n);
++}
++
++/* XXX Trivial wrapper around os_write_file */
++
++int generic_write(int fd, const char *buf, int n, void *unused)
++{
++      return(os_write_file(fd, buf, n));
++}
++
++int generic_window_size(int fd, void *unused, unsigned short *rows_out,
++                      unsigned short *cols_out)
++{
++      int rows, cols;
++      int ret;
++
++      ret = os_window_size(fd, &rows, &cols);
++      if(ret < 0)
++              return(ret);
++
++      ret = ((*rows_out != rows) || (*cols_out != cols));
++
++      *rows_out = rows;
++      *cols_out = cols;
++
++      return(ret);
++}
++
++void generic_free(void *data)
++{
++      kfree(data);
++}
++
++static void tty_receive_char(struct tty_struct *tty, char ch)
++{
++      if(tty == NULL) return;
++
++      if(I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) {
++              if(ch == STOP_CHAR(tty)){
++                      stop_tty(tty);
++                      return;
++              }
++              else if(ch == START_CHAR(tty)){
++                      start_tty(tty);
++                      return;
++              }
++      }
++
++      if((tty->flip.flag_buf_ptr == NULL) || 
++         (tty->flip.char_buf_ptr == NULL))
++              return;
++      tty_insert_flip_char(tty, ch, TTY_NORMAL);
++}
++
++static int open_one_chan(struct chan *chan, int input, int output, int primary)
++{
++      int fd;
++
++      if(chan->opened) return(0);
++      if(chan->ops->open == NULL) fd = 0;
++      else fd = (*chan->ops->open)(input, output, primary, chan->data,
++                                   &chan->dev);
++      if(fd < 0) return(fd);
++      chan->fd = fd;
++
++      chan->opened = 1;
++      return(0);
++}
++
++int open_chan(struct list_head *chans)
++{
++      struct list_head *ele;
++      struct chan *chan;
++      int ret, err = 0;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              ret = open_one_chan(chan, chan->input, chan->output,
++                                  chan->primary);
++              if(chan->primary) err = ret;
++      }
++      return(err);
++}
++
++void chan_enable_winch(struct list_head *chans, void *line)
++{
++      struct list_head *ele;
++      struct chan *chan;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(chan->primary && chan->output && chan->ops->winch){
++                      register_winch(chan->fd, line);
++                      return;
++              }
++      }
++}
++
++void enable_chan(struct list_head *chans, void *data)
++{
++      struct list_head *ele;
++      struct chan *chan;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(!chan->opened) continue;
++
++              line_setup_irq(chan->fd, chan->input, chan->output, data);
++      }
++}
++
++void close_chan(struct list_head *chans)
++{
++      struct list_head *ele;
++      struct chan *chan;
++
++      /* Close in reverse order as open in case more than one of them
++       * refers to the same device and they save and restore that device's
++       * state.  Then, the first one opened will have the original state,
++       * so it must be the last closed.
++       */
++        for(ele = chans->prev; ele != chans; ele = ele->prev){
++                chan = list_entry(ele, struct chan, list);
++              if(!chan->opened) continue;
++              if(chan->ops->close != NULL)
++                      (*chan->ops->close)(chan->fd, chan->data);
++              chan->opened = 0;
++              chan->fd = -1;
++      }
++}
++
++int write_chan(struct list_head *chans, const char *buf, int len, 
++             int write_irq)
++{
++      struct list_head *ele;
++      struct chan *chan;
++      int n, ret = 0;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(!chan->output || (chan->ops->write == NULL)) continue;
++              n = chan->ops->write(chan->fd, buf, len, chan->data);
++              if(chan->primary){
++                      ret = n;
++                      if((ret == -EAGAIN) || ((ret >= 0) && (ret < len))){
++                              reactivate_fd(chan->fd, write_irq);
++                              if(ret == -EAGAIN) ret = 0;
++                      }
++              }
++      }
++      return(ret);
++}
++
++int console_write_chan(struct list_head *chans, const char *buf, int len)
++{
++      struct list_head *ele;
++      struct chan *chan;
++      int n, ret = 0;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(!chan->output || (chan->ops->console_write == NULL))
++                      continue;
++              n = chan->ops->console_write(chan->fd, buf, len, chan->data);
++              if(chan->primary) ret = n;
++      }
++      return(ret);
++}
++
++int chan_window_size(struct list_head *chans, unsigned short *rows_out,
++                    unsigned short *cols_out)
++{
++      struct list_head *ele;
++      struct chan *chan;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(chan->primary){
++                      if(chan->ops->window_size == NULL) return(0);
++                      return(chan->ops->window_size(chan->fd, chan->data,
++                                                    rows_out, cols_out));
++              }
++      }
++      return(0);
++}
++
++void free_one_chan(struct chan *chan)
++{
++      list_del(&chan->list);
++      if(chan->ops->free != NULL)
++              (*chan->ops->free)(chan->data);
++      free_irq_by_fd(chan->fd);
++      if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
++      kfree(chan);
++}
++
++void free_chan(struct list_head *chans)
++{
++      struct list_head *ele, *next;
++      struct chan *chan;
++
++      list_for_each_safe(ele, next, chans){
++              chan = list_entry(ele, struct chan, list);
++              free_one_chan(chan);
++      }
++}
++
++static int one_chan_config_string(struct chan *chan, char *str, int size,
++                                char **error_out)
++{
++      int n = 0;
++
++      if(chan == NULL){
++              CONFIG_CHUNK(str, size, n, "none", 1);
++              return(n);
++      }
++
++      CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
++
++      if(chan->dev == NULL){
++              CONFIG_CHUNK(str, size, n, "", 1);
++              return(n);
++      }
++
++      CONFIG_CHUNK(str, size, n, ":", 0);
++      CONFIG_CHUNK(str, size, n, chan->dev, 0);
++
++      return(n);
++}
++
++static int chan_pair_config_string(struct chan *in, struct chan *out, 
++                                 char *str, int size, char **error_out)
++{
++      int n;
++
++      n = one_chan_config_string(in, str, size, error_out);
++      str += n;
++      size -= n;
++
++      if(in == out){
++              CONFIG_CHUNK(str, size, n, "", 1);
++              return(n);
++      }
++
++      CONFIG_CHUNK(str, size, n, ",", 1);
++      n = one_chan_config_string(out, str, size, error_out);
++      str += n;
++      size -= n;
++      CONFIG_CHUNK(str, size, n, "", 1);
++
++      return(n);
++}
++
++int chan_config_string(struct list_head *chans, char *str, int size, 
++                     char **error_out)
++{
++      struct list_head *ele;
++      struct chan *chan, *in = NULL, *out = NULL;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(!chan->primary)
++                      continue;
++              if(chan->input)
++                      in = chan;
++              if(chan->output)
++                      out = chan;
++      }
++
++      return(chan_pair_config_string(in, out, str, size, error_out));
++}
++
++struct chan_type {
++      char *key;
++      struct chan_ops *ops;
++};
++
++struct chan_type chan_table[] = {
++#ifdef CONFIG_FD_CHAN
++      { "fd", &fd_ops },
++#else
++      { "fd", &not_configged_ops },
++#endif
++
++#ifdef CONFIG_NULL_CHAN
++      { "null", &null_ops },
++#else
++      { "null", &not_configged_ops },
++#endif
++
++#ifdef CONFIG_PORT_CHAN
++      { "port", &port_ops },
++#else
++      { "port", &not_configged_ops },
++#endif
++
++#ifdef CONFIG_PTY_CHAN
++      { "pty", &pty_ops },
++      { "pts", &pts_ops },
++#else
++      { "pty", &not_configged_ops },
++      { "pts", &not_configged_ops },
++#endif
++
++#ifdef CONFIG_TTY_CHAN
++      { "tty", &tty_ops },
++#else
++      { "tty", &not_configged_ops },
++#endif
++
++#ifdef CONFIG_XTERM_CHAN
++      { "xterm", &xterm_ops },
++#else
++      { "xterm", &not_configged_ops },
++#endif
++};
++
++static struct chan *parse_chan(char *str, int pri, int device, 
++                             struct chan_opts *opts)
++{
++      struct chan_type *entry;
++      struct chan_ops *ops;
++      struct chan *chan;
++      void *data;
++      int i;
++
++      ops = NULL;
++      data = NULL;
++      for(i = 0; i < sizeof(chan_table)/sizeof(chan_table[0]); i++){
++              entry = &chan_table[i];
++              if(!strncmp(str, entry->key, strlen(entry->key))){
++                      ops = entry->ops;
++                      str += strlen(entry->key);
++                      break;
++              }
++      }
++      if(ops == NULL){
++              printk(KERN_ERR "parse_chan couldn't parse \"%s\"\n", 
++                     str);
++              return(NULL);
++      }
++      if(ops->init == NULL) return(NULL); 
++      data = (*ops->init)(str, device, opts);
++      if(data == NULL) return(NULL);
++
++      chan = kmalloc(sizeof(*chan), GFP_KERNEL);
++      if(chan == NULL) return(NULL);
++      *chan = ((struct chan) { .list          = LIST_HEAD_INIT(chan->list),
++                               .primary       = 1,
++                               .input         = 0,
++                               .output        = 0,
++                               .opened        = 0,
++                               .fd            = -1,
++                               .pri           = pri,
++                               .ops           = ops,
++                               .data          = data });
++      return(chan);
++}
++
++int parse_chan_pair(char *str, struct list_head *chans, int pri, int device,
++                  struct chan_opts *opts)
++{
++      struct chan *new, *chan;
++      char *in, *out;
++
++      if(!list_empty(chans)){
++              chan = list_entry(chans->next, struct chan, list);
++              if(chan->pri >= pri) return(0);
++              free_chan(chans);
++              INIT_LIST_HEAD(chans);
++      }
++
++      out = strchr(str, ',');
++      if(out != NULL){
++              in = str;
++              *out = '\0';
++              out++;
++              new = parse_chan(in, pri, device, opts);
++              if(new == NULL) return(-1);
++              new->input = 1;
++              list_add(&new->list, chans);
++
++              new = parse_chan(out, pri, device, opts);
++              if(new == NULL) return(-1);
++              list_add(&new->list, chans);
++              new->output = 1;
++      }
++      else {
++              new = parse_chan(str, pri, device, opts);
++              if(new == NULL) return(-1);
++              list_add(&new->list, chans);
++              new->input = 1;
++              new->output = 1;
++      }
++      return(0);
++}
++
++int chan_out_fd(struct list_head *chans)
++{
++      struct list_head *ele;
++      struct chan *chan;
++
++      list_for_each(ele, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(chan->primary && chan->output)
++                      return(chan->fd);
++      }
++      return(-1);
++}
++
++void chan_interrupt(struct list_head *chans, struct tq_struct *task,
++                  struct tty_struct *tty, int irq, void *dev)
++{
++      struct list_head *ele, *next;
++      struct chan *chan;
++      int err;
++      char c;
++
++      list_for_each_safe(ele, next, chans){
++              chan = list_entry(ele, struct chan, list);
++              if(!chan->input || (chan->ops->read == NULL)) continue;
++              do {
++                      if((tty != NULL) && 
++                         (tty->flip.count >= TTY_FLIPBUF_SIZE)){
++                              queue_task(task, &tq_timer);
++                              goto out;
++                      }
++                      err = chan->ops->read(chan->fd, &c, chan->data);
++                      if(err > 0) 
++                              tty_receive_char(tty, c);
++              } while(err > 0);
++
++              if(err == 0) reactivate_fd(chan->fd, irq);
++              if(err == -EIO){
++                      if(chan->primary){
++                              if(tty != NULL) 
++                                      tty_hangup(tty);
++                              line_disable(dev, irq);
++                              close_chan(chans);
++                              free_chan(chans);
++                              return;
++                      }
++                      else {
++                              if(chan->ops->close != NULL)
++                                      chan->ops->close(chan->fd, chan->data);
++                              free_one_chan(chan);
++                      }
++              }
++      }
++ out:
++      if(tty) tty_flip_buffer_push(tty);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/chan_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/chan_user.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/chan_user.c   2005-05-03 22:28:14.197451872 +0300
+@@ -0,0 +1,172 @@
++/* 
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <termios.h>
++#include <string.h>
++#include <signal.h>
++#include <sys/stat.h>
++#include <sys/ioctl.h>
++#include <sys/socket.h>
++#include "kern_util.h"
++#include "user_util.h"
++#include "chan_user.h"
++#include "user.h"
++#include "helper.h"
++#include "os.h"
++#include "choose-mode.h"
++#include "mode.h"
++
++static void winch_handler(int sig)
++{
++}
++
++struct winch_data {
++      int pty_fd;
++      int pipe_fd;
++      int close_me;
++};
++
++/* XXX This breaks horribly (by hanging UML) when moved to chan_kern.c - 
++ * needs investigation
++ */
++int generic_console_write(int fd, const char *buf, int n, void *unused)
++{
++      struct termios save, new;
++      int err;
++
++      if(isatty(fd)){
++              tcgetattr(fd, &save);
++              new = save;
++              new.c_oflag |= OPOST;
++              tcsetattr(fd, TCSAFLUSH, &new);
++      }
++      err = generic_write(fd, buf, n, NULL);
++      if(isatty(fd)) tcsetattr(fd, TCSAFLUSH, &save);
++      return(err);
++}
++
++static int winch_thread(void *arg)
++{
++      struct winch_data *data = arg;
++      sigset_t sigs;
++      int pty_fd, pipe_fd;
++      int count, err;
++      char c = 1;
++
++      os_close_file(data->close_me);
++      pty_fd = data->pty_fd;
++      pipe_fd = data->pipe_fd;
++      count = os_write_file(pipe_fd, &c, sizeof(c));
++      if(count != sizeof(c))
++              printk("winch_thread : failed to write synchronization "
++                     "byte, err = %d\n", -count);
++
++      signal(SIGWINCH, winch_handler);
++      sigfillset(&sigs);
++      sigdelset(&sigs, SIGWINCH);
++      if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){
++              printk("winch_thread : sigprocmask failed, errno = %d\n", 
++                     errno);
++              exit(1);
++      }
++
++      if(setsid() < 0){
++              printk("winch_thread : setsid failed, errno = %d\n", errno);
++              exit(1);
++      }
++
++      err = os_new_tty_pgrp(pty_fd, os_getpid());
++      if(err < 0){
++              printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err);
++              exit(1);
++      }
++
++      count = os_read_file(pipe_fd, &c, sizeof(c));
++      if(count != sizeof(c))
++              printk("winch_thread : failed to read synchronization byte, "
++                     "err = %d\n", -count);
++
++      while(1){
++              pause();
++
++              count = os_write_file(pipe_fd, &c, sizeof(c));
++              if(count != sizeof(c))
++                      printk("winch_thread : write failed, err = %d\n",
++                             -count);
++      }
++}
++
++static int winch_tramp(int fd, void *device_data, int *fd_out)
++{
++      struct winch_data data;
++      unsigned long stack;
++      int fds[2], pid, n, err;
++      char c;
++
++      err = os_pipe(fds, 1, 1);
++      if(err < 0){
++              printk("winch_tramp : os_pipe failed, err = %d\n", -err);
++              return(err);
++      }
++
++      data = ((struct winch_data) { .pty_fd           = fd,
++                                    .pipe_fd          = fds[1],
++                                    .close_me         = fds[0] } );
++      pid = run_helper_thread(winch_thread, &data, 0, &stack, 0);
++      if(pid < 0){
++              printk("fork of winch_thread failed - errno = %d\n", errno);
++              return(pid);
++      }
++
++      os_close_file(fds[1]);
++      *fd_out = fds[0];
++      n = os_read_file(fds[0], &c, sizeof(c));
++      if(n != sizeof(c)){
++              printk("winch_tramp : failed to read synchronization byte\n");
++              printk("read failed, err = %d\n", -n);
++              printk("fd %d will not support SIGWINCH\n", fd);
++              *fd_out = -1;
++      }
++      return(pid);
++}
++
++void register_winch(int fd, void *device_data)
++{
++      int pid, thread, thread_fd;
++      int count;
++      char c = 1;
++
++      if(!isatty(fd)) 
++              return;
++
++      pid = tcgetpgrp(fd);
++      if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, 
++                           device_data) && (pid == -1)){
++              thread = winch_tramp(fd, device_data, &thread_fd);
++              if(fd != -1){
++                      register_winch_irq(thread_fd, fd, thread, device_data);
++
++                      count = os_write_file(thread_fd, &c, sizeof(c));
++                      if(count != sizeof(c))
++                              printk("register_winch : failed to write "
++                                     "synchronization byte, err = %d\n",
++                                      -count);
++              }
++      }
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/cow.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/cow.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/cow.h 2005-05-03 22:43:32.718815400 +0300
+@@ -0,0 +1,41 @@
++#ifndef __COW_H__
++#define __COW_H__
++
++#include <asm/types.h>
++
++#if __BYTE_ORDER == __BIG_ENDIAN
++# define ntohll(x) (x)
++# define htonll(x) (x)
++#elif __BYTE_ORDER == __LITTLE_ENDIAN
++# define ntohll(x)  bswap_64(x)
++# define htonll(x)  bswap_64(x)
++#else
++#error "__BYTE_ORDER not defined"
++#endif
++
++extern int init_cow_file(int fd, char *cow_file, char *backing_file, 
++                       int sectorsize, int alignment, int *bitmap_offset_out, 
++                       unsigned long *bitmap_len_out, int *data_offset_out);
++
++extern int file_reader(__u64 offset, char *buf, int len, void *arg);
++extern int read_cow_header(int (*reader)(__u64, char *, int, void *), 
++                         void *arg, __u32 *version_out, 
++                         char **backing_file_out, time_t *mtime_out, 
++                         __u64 *size_out, int *sectorsize_out, 
++                         __u32 *align_out, int *bitmap_offset_out);
++
++extern int write_cow_header(char *cow_file, int fd, char *backing_file, 
++                          int sectorsize, int alignment, long long *size);
++
++extern void cow_sizes(int version, __u64 size, int sectorsize, int align,
++                    int bitmap_offset, unsigned long *bitmap_len_out, 
++                    int *data_offset_out);
++
++#endif
++
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/cow_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/cow_kern.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/cow_kern.c    2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,630 @@
++#define COW_MAJOR 60
++#define MAJOR_NR COW_MAJOR
++
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/ctype.h>
++#include <linux/stat.h>
++#include <linux/vmalloc.h>
++#include <linux/blkdev.h>
++#include <linux/blk.h>
++#include <linux/fs.h>
++#include <linux/genhd.h>
++#include <linux/devfs_fs.h>
++#include <asm/uaccess.h>
++#include "2_5compat.h"
++#include "cow.h"
++#include "ubd_user.h"
++
++#define COW_SHIFT 4
++
++struct cow {
++      int count;
++      char *cow_path;
++      dev_t cow_dev;
++      struct block_device *cow_bdev;
++      char *backing_path;
++      dev_t backing_dev;
++      struct block_device *backing_bdev;
++      int sectorsize;
++      unsigned long *bitmap;
++      unsigned long bitmap_len;
++      int bitmap_offset;
++      int data_offset;
++      devfs_handle_t devfs;
++      struct semaphore sem;
++      struct semaphore io_sem;
++      atomic_t working;
++      spinlock_t io_lock;
++      struct buffer_head *bh;
++      struct buffer_head *bhtail;
++      void *end_io;
++};
++
++#define DEFAULT_COW { \
++      .count                  = 0, \
++      .cow_path               = NULL, \
++      .cow_dev                = 0, \
++      .backing_path           = NULL, \
++      .backing_dev            = 0, \
++        .bitmap                       = NULL, \
++      .bitmap_len             = 0, \
++      .bitmap_offset          = 0, \
++        .data_offset          = 0, \
++      .devfs                  = NULL, \
++      .working                = ATOMIC_INIT(0), \
++      .io_lock                = SPIN_LOCK_UNLOCKED, \
++}
++
++#define MAX_DEV (8)
++#define MAX_MINOR (MAX_DEV << COW_SHIFT)
++
++struct cow cow_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_COW };
++
++/* Not modified by this driver */
++static int blk_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = BLOCK_SIZE };
++static int hardsect_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 512 };
++
++/* Protected by cow_lock */
++static int sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 0 };
++
++static struct hd_struct       cow_part[MAX_MINOR] =
++      { [ 0 ... MAX_MINOR - 1 ] = { 0, 0, 0 } };
++
++/* Protected by io_request_lock */
++static request_queue_t *cow_queue;
++
++static int cow_open(struct inode *inode, struct file *filp);
++static int cow_release(struct inode * inode, struct file * file);
++static int cow_ioctl(struct inode * inode, struct file * file,
++                   unsigned int cmd, unsigned long arg);
++static int cow_revalidate(kdev_t rdev);
++
++static struct block_device_operations cow_blops = {
++      .open           = cow_open,
++      .release        = cow_release,
++      .ioctl          = cow_ioctl,
++      .revalidate     = cow_revalidate,
++};
++
++/* Initialized in an initcall, and unchanged thereafter */
++devfs_handle_t cow_dir_handle;
++
++#define INIT_GENDISK(maj, name, parts, shift, bsizes, max, blops) \
++{ \
++      .major          = maj, \
++      .major_name     = name, \
++      .minor_shift    = shift, \
++      .max_p          = 1 << shift, \
++      .part           = parts, \
++      .sizes          = bsizes, \
++      .nr_real        = max, \
++      .real_devices   = NULL, \
++      .next           = NULL, \
++      .fops           = blops, \
++      .de_arr         = NULL, \
++      .flags          = 0 \
++}
++
++static spinlock_t cow_lock = SPIN_LOCK_UNLOCKED;
++
++static struct gendisk cow_gendisk = INIT_GENDISK(MAJOR_NR, "cow", cow_part,
++                                               COW_SHIFT, sizes, MAX_DEV, 
++                                               &cow_blops);
++
++static int cow_add(int n)
++{
++      struct cow *dev = &cow_dev[n];
++      char name[sizeof("nnnnnn\0")];
++      int err = -ENODEV;
++
++      if(dev->cow_path == NULL)
++              goto out;
++
++      sprintf(name, "%d", n);
++      dev->devfs = devfs_register(cow_dir_handle, name, DEVFS_FL_REMOVABLE,
++                                  MAJOR_NR, n << COW_SHIFT, S_IFBLK | 
++                                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
++                                  &cow_blops, NULL);
++
++      init_MUTEX_LOCKED(&dev->sem);
++      init_MUTEX(&dev->io_sem);
++
++      return(0);
++
++ out:
++      return(err);
++}
++
++/*
++ * Add buffer_head to back of pending list
++ */
++static void cow_add_bh(struct cow *cow, struct buffer_head *bh)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&cow->io_lock, flags);
++      if(cow->bhtail != NULL){
++              cow->bhtail->b_reqnext = bh;
++              cow->bhtail = bh;
++      }
++      else {
++              cow->bh = bh;
++              cow->bhtail = bh;
++      }
++      spin_unlock_irqrestore(&cow->io_lock, flags);
++}
++
++/*
++ * Grab first pending buffer
++ */
++static struct buffer_head *cow_get_bh(struct cow *cow)
++{
++      struct buffer_head *bh;
++
++      spin_lock_irq(&cow->io_lock);
++      bh = cow->bh;
++      if(bh != NULL){
++              if(bh == cow->bhtail)
++                      cow->bhtail = NULL;
++              cow->bh = bh->b_reqnext;
++              bh->b_reqnext = NULL;
++      }
++      spin_unlock_irq(&cow->io_lock);
++
++      return(bh);
++}
++
++static void cow_handle_bh(struct cow *cow, struct buffer_head *bh, 
++                        struct buffer_head **cow_bh, int ncow_bh)
++{
++      int i;
++
++      if(ncow_bh > 0)
++              ll_rw_block(WRITE, ncow_bh, cow_bh);
++
++      for(i = 0; i < ncow_bh ; i++){
++              wait_on_buffer(cow_bh[i]);
++              brelse(cow_bh[i]);
++      }
++
++      ll_rw_block(WRITE, 1, &bh);
++      brelse(bh);
++}
++
++static struct buffer_head *cow_new_bh(struct cow *dev, int sector)
++{
++      struct buffer_head *bh;
++
++      sector = (dev->bitmap_offset + sector / 8) / dev->sectorsize;
++      bh = getblk(dev->cow_dev, sector, dev->sectorsize);
++      memcpy(bh->b_data, dev->bitmap + sector / (8 * sizeof(dev->bitmap[0])),
++             dev->sectorsize);
++      return(bh);
++}
++
++/* Copied from loop.c, needed to avoid deadlocking in make_request. */
++
++static int cow_thread(void *data)
++{
++      struct cow *dev = data;
++      struct buffer_head *bh;
++
++      daemonize();
++      exit_files(current);
++
++      sprintf(current->comm, "cow%d", dev - cow_dev);
++
++      spin_lock_irq(&current->sigmask_lock);
++      sigfillset(&current->blocked);
++      flush_signals(current);
++      spin_unlock_irq(&current->sigmask_lock);
++
++      atomic_inc(&dev->working);
++
++      current->policy = SCHED_OTHER;
++      current->nice = -20;
++
++      current->flags |= PF_NOIO;
++
++      /*
++       * up sem, we are running
++       */
++      up(&dev->sem);
++
++      for(;;){
++              int start, len, nbh, i, update_bitmap = 0;
++              struct buffer_head *cow_bh[2];
++
++              down_interruptible(&dev->io_sem);
++              /*
++               * could be upped because of tear-down, not because of
++               * pending work
++               */
++              if(!atomic_read(&dev->working))
++                      break;
++
++              bh = cow_get_bh(dev);
++              if(bh == NULL){
++                      printk(KERN_ERR "cow: missing bh\n");
++                      continue;
++              }
++
++              start = bh->b_blocknr * bh->b_size / dev->sectorsize;
++              len = bh->b_size / dev->sectorsize;
++              for(i = 0; i < len ; i++){
++                      if(ubd_test_bit(start + i, 
++                                      (unsigned char *) dev->bitmap))
++                              continue;
++
++                      update_bitmap = 1;
++                      ubd_set_bit(start + i, (unsigned char *) dev->bitmap);
++              }
++
++              cow_bh[0] = NULL;
++              cow_bh[1] = NULL;
++              nbh = 0;
++              if(update_bitmap){
++                      cow_bh[0] = cow_new_bh(dev, start);
++                      nbh++;
++                      if(start / dev->sectorsize != 
++                         (start + len) / dev->sectorsize){
++                              cow_bh[1] = cow_new_bh(dev, start + len);
++                              nbh++;
++                      }
++              }
++              
++              bh->b_dev = dev->cow_dev;
++              bh->b_blocknr += dev->data_offset / dev->sectorsize;
++
++              cow_handle_bh(dev, bh, cow_bh, nbh);
++
++              /*
++               * upped both for pending work and tear-down, lo_pending
++               * will hit zero then
++               */
++              if(atomic_dec_and_test(&dev->working))
++                      break;
++      }
++
++      up(&dev->sem);
++      return(0);
++}
++
++static int cow_make_request(request_queue_t *q, int rw, struct buffer_head *bh)
++{
++      struct cow *dev;
++      int n, minor;
++
++      minor = MINOR(bh->b_rdev);
++      n = minor >> COW_SHIFT;
++      dev = &cow_dev[n];
++
++      dev->end_io = NULL;
++      if(ubd_test_bit(bh->b_rsector, (unsigned char *) dev->bitmap)){
++              bh->b_rdev = dev->cow_dev;
++              bh->b_rsector += dev->data_offset / dev->sectorsize;
++      }
++      else if(rw == WRITE){
++              bh->b_dev = dev->cow_dev;
++              bh->b_blocknr += dev->data_offset / dev->sectorsize;
++
++              cow_add_bh(dev, bh);
++              up(&dev->io_sem);
++              return(0);
++      }
++      else {
++              bh->b_rdev = dev->backing_dev;
++      }
++
++      return(1);
++}
++
++int cow_init(void)
++{
++      int i;
++
++      cow_dir_handle = devfs_mk_dir (NULL, "cow", NULL);
++      if (devfs_register_blkdev(MAJOR_NR, "cow", &cow_blops)) {
++              printk(KERN_ERR "cow: unable to get major %d\n", MAJOR_NR);
++              return -1;
++      }
++      read_ahead[MAJOR_NR] = 8;               /* 8 sector (4kB) read-ahead */
++      blksize_size[MAJOR_NR] = blk_sizes;
++      blk_size[MAJOR_NR] = sizes;
++      INIT_HARDSECT(hardsect_size, MAJOR_NR, hardsect_sizes);
++
++      cow_queue = BLK_DEFAULT_QUEUE(MAJOR_NR);
++      blk_init_queue(cow_queue, NULL);
++      INIT_ELV(cow_queue, &cow_queue->elevator);
++      blk_queue_make_request(cow_queue, cow_make_request);
++
++        add_gendisk(&cow_gendisk);
++
++      for(i=0;i<MAX_DEV;i++) 
++              cow_add(i);
++
++      return(0);
++}
++
++__initcall(cow_init);
++
++static int reader(__u64 start, char *buf, int count, void *arg)
++{
++      dev_t dev = *((dev_t *) arg);
++      struct buffer_head *bh;
++      __u64 block;
++      int cur, offset, left, n, blocksize = get_hardsect_size(dev);
++
++      if(blocksize == 0)
++              panic("Zero blocksize");
++
++      block = start / blocksize;
++      offset = start % blocksize;
++      left = count;
++      cur = 0;
++      while(left > 0){
++              n = (left > blocksize) ? blocksize : left;
++
++              bh = bread(dev, block, (n < 512) ? 512 : n);
++              if(bh == NULL)
++                      return(-EIO);
++
++              n -= offset;
++              memcpy(&buf[cur], bh->b_data + offset, n);
++              block++;
++              left -= n;
++              cur += n;
++              offset = 0;
++              brelse(bh);
++      }
++
++      return(count);
++}
++
++static int cow_open(struct inode *inode, struct file *filp)
++{
++      int (*dev_ioctl)(struct inode *, struct file *, unsigned int, 
++                       unsigned long);
++      mm_segment_t fs;
++      struct cow *dev;
++      __u64 size;
++      __u32 version, align;
++      time_t mtime;
++      char *backing_file;
++      int n, offset, err = 0;
++
++      n = DEVICE_NR(inode->i_rdev);
++      if(n >= MAX_DEV)
++              return(-ENODEV);
++      dev = &cow_dev[n];
++      offset = n << COW_SHIFT;
++
++      spin_lock(&cow_lock);
++
++      if(dev->count == 0){
++              dev->cow_dev = name_to_kdev_t(dev->cow_path);
++              if(dev->cow_dev == 0){
++                      printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") "
++                             "failed\n", dev->cow_path);
++                      err = -ENODEV;
++              }
++
++              dev->backing_dev = name_to_kdev_t(dev->backing_path);
++              if(dev->backing_dev == 0){
++                      printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") "
++                             "failed\n", dev->backing_path);
++                      err = -ENODEV;
++              }
++
++              if(err) 
++                      goto out;
++
++              dev->cow_bdev = bdget(dev->cow_dev);
++              if(dev->cow_bdev == NULL){
++                      printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n", 
++                             dev->cow_path);
++                      err = -ENOMEM;
++              }
++              dev->backing_bdev = bdget(dev->backing_dev);
++              if(dev->backing_bdev == NULL){
++                      printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n", 
++                             dev->backing_path);
++                      err = -ENOMEM;
++              }
++
++              if(err) 
++                      goto out;
++
++              err = blkdev_get(dev->cow_bdev, FMODE_READ|FMODE_WRITE, 0, 
++                               BDEV_RAW);
++              if(err){
++                      printk("cow_open - blkdev_get of COW device failed, "
++                             "error = %d\n", err);
++                      goto out;
++              }
++              
++              err = blkdev_get(dev->backing_bdev, FMODE_READ, 0, BDEV_RAW);
++              if(err){
++                      printk("cow_open - blkdev_get of backing device "
++                             "failed, error = %d\n", err);
++                      goto out;
++              }
++              
++              err = read_cow_header(reader, &dev->cow_dev, &version, 
++                                    &backing_file, &mtime, &size,
++                                    &dev->sectorsize, &align, 
++                                    &dev->bitmap_offset);
++              if(err){
++                      printk(KERN_ERR "cow_open - read_cow_header failed, "
++                             "err = %d\n", err);
++                      goto out;
++              }
++
++              cow_sizes(version, size, dev->sectorsize, align, 
++                        dev->bitmap_offset, &dev->bitmap_len, 
++                        &dev->data_offset);
++              dev->bitmap = (void *) vmalloc(dev->bitmap_len);
++              if(dev->bitmap == NULL){
++                      err = -ENOMEM;
++                      printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
++                      goto out;
++              }
++              flush_tlb_kernel_vm();
++              
++              err = reader(dev->bitmap_offset, (char *) dev->bitmap, 
++                           dev->bitmap_len, &dev->cow_dev);
++              if(err < 0){
++                      printk(KERN_ERR "Failed to read COW bitmap\n");
++                      vfree(dev->bitmap);
++                      goto out;
++              }
++
++              dev_ioctl = dev->backing_bdev->bd_op->ioctl;
++              fs = get_fs();
++              set_fs(KERNEL_DS);
++              err = (*dev_ioctl)(inode, filp, BLKGETSIZE, 
++                                 (unsigned long) &sizes[offset]);
++              set_fs(fs);
++              if(err){
++                      printk(KERN_ERR "cow_open - BLKGETSIZE failed, "
++                             "error = %d\n", err);
++                      goto out;
++              }
++
++              kernel_thread(cow_thread, dev, 
++                            CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
++              down(&dev->sem);
++      }
++      dev->count++;
++ out:
++      spin_unlock(&cow_lock);
++      return(err);
++}
++
++static int cow_release(struct inode * inode, struct file * file)
++{
++      struct cow *dev;
++      int n, err;
++
++      n = DEVICE_NR(inode->i_rdev);
++      if(n >= MAX_DEV)
++              return(-ENODEV);
++      dev = &cow_dev[n];
++
++      spin_lock(&cow_lock);
++
++      if(--dev->count > 0)
++              goto out;
++
++      err = blkdev_put(dev->cow_bdev, BDEV_RAW);
++      if(err)
++              printk("cow_release - blkdev_put of cow device failed, "
++                     "error = %d\n", err);
++      bdput(dev->cow_bdev);
++      dev->cow_bdev = 0;
++
++      err = blkdev_put(dev->backing_bdev, BDEV_RAW);
++      if(err)
++              printk("cow_release - blkdev_put of backing device failed, "
++                     "error = %d\n", err);
++      bdput(dev->backing_bdev);
++      dev->backing_bdev = 0;
++
++ out:
++      spin_unlock(&cow_lock);
++      return(0);
++}
++
++static int cow_ioctl(struct inode * inode, struct file * file,
++                   unsigned int cmd, unsigned long arg)
++{
++      struct cow *dev;
++      int (*dev_ioctl)(struct inode *, struct file *, unsigned int, 
++                       unsigned long);
++      int n;
++
++      n = DEVICE_NR(inode->i_rdev);
++      if(n >= MAX_DEV)
++              return(-ENODEV);
++      dev = &cow_dev[n];
++
++      dev_ioctl = dev->backing_bdev->bd_op->ioctl;
++      return((*dev_ioctl)(inode, file, cmd, arg));
++}
++
++static int cow_revalidate(kdev_t rdev)
++{
++      printk(KERN_ERR "Need to implement cow_revalidate\n");
++      return(0);
++}
++
++static int parse_unit(char **ptr)
++{
++      char *str = *ptr, *end;
++      int n = -1;
++
++      if(isdigit(*str)) {
++              n = simple_strtoul(str, &end, 0);
++              if(end == str)
++                      return(-1);
++              *ptr = end;
++      }
++      else if (('a' <= *str) && (*str <= 'h')) {
++              n = *str - 'a';
++              str++;
++              *ptr = str;
++      }
++      return(n);
++}
++
++static int cow_setup(char *str)
++{
++      struct cow *dev;
++      char *cow_name, *backing_name;
++      int unit;
++
++      unit = parse_unit(&str);
++      if(unit < 0){
++              printk(KERN_ERR "cow_setup - Couldn't parse unit number\n");
++              return(1);
++      }
++
++      if(*str != '='){
++              printk(KERN_ERR "cow_setup - Missing '=' after unit "
++                     "number\n");
++              return(1);
++      }
++      str++;
++
++      cow_name = str;
++      backing_name = strchr(str, ',');
++      if(backing_name == NULL){
++              printk(KERN_ERR "cow_setup - missing backing device name\n");
++              return(0);
++      }
++      *backing_name = '\0';
++      backing_name++;
++
++      spin_lock(&cow_lock);
++
++      dev = &cow_dev[unit];
++      dev->cow_path = cow_name;
++      dev->backing_path = backing_name;
++      
++      spin_unlock(&cow_lock);
++      return(0);
++}
++
++__setup("cow", cow_setup);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/cow_sys.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/cow_sys.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/cow_sys.h     2005-05-03 22:43:34.768503800 +0300
+@@ -0,0 +1,48 @@
++#ifndef __COW_SYS_H__
++#define __COW_SYS_H__
++
++#include "kern_util.h"
++#include "user_util.h"
++#include "os.h"
++#include "user.h"
++
++static inline void *cow_malloc(int size)
++{
++      return(um_kmalloc(size));
++}
++
++static inline void cow_free(void *ptr)
++{
++      kfree(ptr);
++}
++
++#define cow_printf printk
++
++static inline char *cow_strdup(char *str)
++{
++      return(uml_strdup(str));
++}
++
++static inline int cow_seek_file(int fd, __u64 offset)
++{
++      return(os_seek_file(fd, offset));
++}
++
++static inline int cow_file_size(char *file, __u64 *size_out)
++{
++      return(os_file_size(file, size_out));
++}
++
++static inline int cow_write_file(int fd, char *buf, int size)
++{
++      return(os_write_file(fd, buf, size));
++}
++
++#endif
++
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/cow_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/cow_user.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/cow_user.c    2005-05-03 22:28:14.203450960 +0300
+@@ -0,0 +1,375 @@
++#include <stddef.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <byteswap.h>
++#include <sys/time.h>
++#include <sys/param.h>
++#include <sys/user.h>
++#include <netinet/in.h>
++
++#include "os.h"
++
++#include "cow.h"
++#include "cow_sys.h"
++
++#define PATH_LEN_V1 256
++
++struct cow_header_v1 {
++      int magic;
++      int version;
++      char backing_file[PATH_LEN_V1];
++      time_t mtime;
++      __u64 size;
++      int sectorsize;
++};
++
++#define PATH_LEN_V2 MAXPATHLEN
++
++struct cow_header_v2 {
++      __u32 magic;
++      __u32 version;
++      char backing_file[PATH_LEN_V2];
++      time_t mtime;
++      __u64 size;
++      int sectorsize;
++};
++
++/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in 
++ * case other systems have different values for MAXPATHLEN
++ */
++#define PATH_LEN_V3 4096
++
++/* Changes from V2 - 
++ *    PATH_LEN_V3 as described above
++ *    Explicitly specify field bit lengths for systems with different
++ *            lengths for the usual C types.  Not sure whether char or
++ *            time_t should be changed, this can be changed later without
++ *            breaking compatibility
++ *    Add alignment field so that different alignments can be used for the
++ *            bitmap and data
++ *    Add cow_format field to allow for the possibility of different ways
++ *            of specifying the COW blocks.  For now, the only value is 0,
++ *            for the traditional COW bitmap.
++ *    Move the backing_file field to the end of the header.  This allows
++ *            for the possibility of expanding it into the padding required
++ *            by the bitmap alignment.
++ *    The bitmap and data portions of the file will be aligned as specified
++ *            by the alignment field.  This is to allow COW files to be
++ *            put on devices with restrictions on access alignments, such as
++ *            /dev/raw, with a 512 byte alignment restriction.  This also
++ *            allows the data to be more aligned more strictly than on
++ *            sector boundaries.  This is needed for ubd-mmap, which needs
++ *            the data to be page aligned.
++ *    Fixed (finally!) the rounding bug
++ */
++
++struct cow_header_v3 {
++      __u32 magic;
++      __u32 version;
++      time_t mtime;
++      __u64 size;
++      __u32 sectorsize;
++      __u32 alignment;
++      __u32 cow_format;
++      char backing_file[PATH_LEN_V3];
++};
++
++/* COW format definitions - for now, we have only the usual COW bitmap */
++#define COW_BITMAP 0
++
++union cow_header {
++      struct cow_header_v1 v1;
++      struct cow_header_v2 v2;
++      struct cow_header_v3 v3;
++};
++
++#define COW_MAGIC 0x4f4f4f4d  /* MOOO */
++#define COW_VERSION 3
++
++#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len))
++#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align)
++
++void cow_sizes(int version, __u64 size, int sectorsize, int align, 
++             int bitmap_offset, unsigned long *bitmap_len_out, 
++             int *data_offset_out)
++{
++      if(version < 3){
++              *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
++
++              *data_offset_out = bitmap_offset + *bitmap_len_out;
++              *data_offset_out = (*data_offset_out + sectorsize - 1) / 
++                      sectorsize;
++              *data_offset_out *= sectorsize;
++      }
++      else {
++              *bitmap_len_out = DIV_ROUND(size, sectorsize);
++              *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8);
++
++              *data_offset_out = bitmap_offset + *bitmap_len_out;
++              *data_offset_out = ROUND_UP(*data_offset_out, align);
++      }
++}
++
++static int absolutize(char *to, int size, char *from)
++{
++      char save_cwd[256], *slash;
++      int remaining;
++
++      if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
++              cow_printf("absolutize : unable to get cwd - errno = %d\n", 
++                         errno);
++              return(-1);
++      }
++      slash = strrchr(from, '/');
++      if(slash != NULL){
++              *slash = '\0';
++              if(chdir(from)){
++                      *slash = '/';
++                      cow_printf("absolutize : Can't cd to '%s' - " 
++                                 "errno = %d\n", from, errno);
++                      return(-1);
++              }
++              *slash = '/';
++              if(getcwd(to, size) == NULL){
++                      cow_printf("absolutize : unable to get cwd of '%s' - "
++                             "errno = %d\n", from, errno);
++                      return(-1);
++              }
++              remaining = size - strlen(to);
++              if(strlen(slash) + 1 > remaining){
++                      cow_printf("absolutize : unable to fit '%s' into %d "
++                             "chars\n", from, size);
++                      return(-1);
++              }
++              strcat(to, slash);
++      }
++      else {
++              if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
++                      cow_printf("absolutize : unable to fit '%s' into %d "
++                             "chars\n", from, size);
++                      return(-1);
++              }
++              strcpy(to, save_cwd);
++              strcat(to, "/");
++              strcat(to, from);
++      }
++      chdir(save_cwd);
++      return(0);
++}
++
++int write_cow_header(char *cow_file, int fd, char *backing_file, 
++                   int sectorsize, int alignment, long long *size)
++{
++      struct cow_header_v3 *header;
++      unsigned long modtime;
++      int err;
++
++      err = cow_seek_file(fd, 0);
++      if(err < 0){
++              cow_printf("write_cow_header - lseek failed, err = %d\n", -err);
++              goto out;
++      }
++
++      err = -ENOMEM;
++      header = cow_malloc(sizeof(*header));
++      if(header == NULL){
++              cow_printf("Failed to allocate COW V3 header\n");
++              goto out;
++      }
++      header->magic = htonl(COW_MAGIC);
++      header->version = htonl(COW_VERSION);
++
++      err = -EINVAL;
++      if(strlen(backing_file) > sizeof(header->backing_file) - 1){
++              cow_printf("Backing file name \"%s\" is too long - names are "
++                         "limited to %d characters\n", backing_file, 
++                         sizeof(header->backing_file) - 1);
++              goto out_free;
++      }
++
++      if(absolutize(header->backing_file, sizeof(header->backing_file), 
++                    backing_file))
++              goto out_free;
++
++      err = os_file_modtime(header->backing_file, &modtime);
++      if(err < 0){
++              cow_printf("Backing file '%s' mtime request failed, "
++                         "err = %d\n", header->backing_file, -err);
++              goto out_free;
++      }
++
++      err = cow_file_size(header->backing_file, size);
++      if(err < 0){
++              cow_printf("Couldn't get size of backing file '%s', "
++                         "err = %d\n", header->backing_file, -err);
++              goto out_free;
++      }
++
++      header->mtime = htonl(modtime);
++      header->size = htonll(*size);
++      header->sectorsize = htonl(sectorsize);
++      header->alignment = htonl(alignment);
++      header->cow_format = COW_BITMAP;
++
++      err = os_write_file(fd, header, sizeof(*header));
++      if(err != sizeof(*header)){
++              cow_printf("Write of header to new COW file '%s' failed, "
++                         "err = %d\n", cow_file, -err);
++              goto out_free;
++      }
++      err = 0;
++ out_free:
++      cow_free(header);
++ out:
++      return(err);
++}
++
++int file_reader(__u64 offset, char *buf, int len, void *arg)
++{
++      int fd = *((int *) arg);
++
++      return(pread(fd, buf, len, offset));
++}
++
++/* XXX Need to sanity-check the values read from the header */
++
++int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, 
++                  __u32 *version_out, char **backing_file_out, 
++                  time_t *mtime_out, __u64 *size_out, 
++                  int *sectorsize_out, __u32 *align_out, 
++                  int *bitmap_offset_out)
++{
++      union cow_header *header;
++      char *file;
++      int err, n;
++      unsigned long version, magic;
++
++      header = cow_malloc(sizeof(*header));
++      if(header == NULL){
++              cow_printf("read_cow_header - Failed to allocate header\n");
++              return(-ENOMEM);
++      }
++      err = -EINVAL;
++      n = (*reader)(0, (char *) header, sizeof(*header), arg);
++      if(n < offsetof(typeof(header->v1), backing_file)){
++              cow_printf("read_cow_header - short header\n");
++              goto out;
++      }
++
++      magic = header->v1.magic;
++      if(magic == COW_MAGIC) {
++              version = header->v1.version;
++      }
++      else if(magic == ntohl(COW_MAGIC)){
++              version = ntohl(header->v1.version);
++      }
++      /* No error printed because the non-COW case comes through here */
++      else goto out;
++
++      *version_out = version;
++
++      if(version == 1){
++              if(n < sizeof(header->v1)){
++                      cow_printf("read_cow_header - failed to read V1 "
++                                 "header\n");
++                      goto out;
++              }
++              *mtime_out = header->v1.mtime;
++              *size_out = header->v1.size;
++              *sectorsize_out = header->v1.sectorsize;
++              *bitmap_offset_out = sizeof(header->v1);
++              *align_out = *sectorsize_out;
++              file = header->v1.backing_file;
++      }
++      else if(version == 2){
++              if(n < sizeof(header->v2)){
++                      cow_printf("read_cow_header - failed to read V2 "
++                                 "header\n");
++                      goto out;
++              }
++              *mtime_out = ntohl(header->v2.mtime);
++              *size_out = ntohll(header->v2.size);
++              *sectorsize_out = ntohl(header->v2.sectorsize);
++              *bitmap_offset_out = sizeof(header->v2);
++              *align_out = *sectorsize_out;
++              file = header->v2.backing_file;
++      }
++      else if(version == 3){
++              if(n < sizeof(header->v3)){
++                      cow_printf("read_cow_header - failed to read V2 "
++                                 "header\n");
++                      goto out;
++              }
++              *mtime_out = ntohl(header->v3.mtime);
++              *size_out = ntohll(header->v3.size);
++              *sectorsize_out = ntohl(header->v3.sectorsize);
++              *align_out = ntohl(header->v3.alignment);
++              *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out);
++              file = header->v3.backing_file;
++      }
++      else {
++              cow_printf("read_cow_header - invalid COW version\n");
++              goto out;               
++      }
++      err = -ENOMEM;
++      *backing_file_out = cow_strdup(file);
++      if(*backing_file_out == NULL){
++              cow_printf("read_cow_header - failed to allocate backing "
++                         "file\n");
++              goto out;
++      }
++      err = 0;
++ out:
++      cow_free(header);
++      return(err);
++}
++
++int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize,
++                int alignment, int *bitmap_offset_out, 
++                unsigned long *bitmap_len_out, int *data_offset_out)
++{
++      __u64 size, offset;
++      char zero = 0;
++      int err;
++
++      err = write_cow_header(cow_file, fd, backing_file, sectorsize, 
++                             alignment, &size);
++      if(err) 
++              goto out;
++      
++      *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment);
++      cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out,
++                bitmap_len_out, data_offset_out);
++
++      offset = *data_offset_out + size - sizeof(zero);
++      err = cow_seek_file(fd, offset);
++      if(err < 0){
++              cow_printf("cow bitmap lseek failed : err = %d\n", -err);
++              goto out;
++      }
++
++      /* does not really matter how much we write it is just to set EOF 
++       * this also sets the entire COW bitmap
++       * to zero without having to allocate it 
++       */
++      err = cow_write_file(fd, &zero, sizeof(zero));
++      if(err != sizeof(zero)){
++              cow_printf("Write of bitmap to new COW file '%s' failed, "
++                         "err = %d\n", cow_file, -err);
++              err = -EINVAL;
++              goto out;
++      }
++
++      return(0);
++
++ out:
++      return(err);
++}
++
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/daemon.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/daemon.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/daemon.h      2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,35 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "net_user.h"
++
++#define SWITCH_VERSION 3
++
++struct daemon_data {
++      char *sock_type;
++      char *ctl_sock;
++      void *ctl_addr;
++      void *data_addr;
++      void *local_addr;
++      int fd;
++      int control;
++      void *dev;
++};
++
++extern struct net_user_info daemon_user_info;
++
++extern int daemon_user_write(int fd, void *buf, int len, 
++                           struct daemon_data *pri);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/daemon_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/daemon_kern.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/daemon_kern.c 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,113 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ * Licensed under the GPL.
++ */
++
++#include "linux/kernel.h"
++#include "linux/init.h"
++#include "linux/netdevice.h"
++#include "linux/etherdevice.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "daemon.h"
++
++struct daemon_init {
++      char *sock_type;
++      char *ctl_sock;
++};
++
++void daemon_init(struct net_device *dev, void *data)
++{
++      struct uml_net_private *pri;
++      struct daemon_data *dpri;
++      struct daemon_init *init = data;
++
++      init_etherdev(dev, 0);
++      pri = dev->priv;
++      dpri = (struct daemon_data *) pri->user;
++      *dpri = ((struct daemon_data)
++              { .sock_type            = init->sock_type,
++                .ctl_sock             = init->ctl_sock,
++                .ctl_addr             = NULL,
++                .data_addr            = NULL,
++                .local_addr           = NULL,
++                .fd                   = -1,
++                .control              = -1,
++                .dev                  = dev });
++
++      printk("daemon backend (uml_switch version %d) - %s:%s", 
++             SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock);
++      printk("\n");
++}
++
++static int daemon_read(int fd, struct sk_buff **skb, 
++                     struct uml_net_private *lp)
++{
++      *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
++      if(*skb == NULL) return(-ENOMEM);
++      return(net_recvfrom(fd, (*skb)->mac.raw, 
++                          (*skb)->dev->mtu + ETH_HEADER_OTHER));
++}
++
++static int daemon_write(int fd, struct sk_buff **skb,
++                      struct uml_net_private *lp)
++{
++      return(daemon_user_write(fd, (*skb)->data, (*skb)->len, 
++                               (struct daemon_data *) &lp->user));
++}
++
++static struct net_kern_info daemon_kern_info = {
++      .init                   = daemon_init,
++      .protocol               = eth_protocol,
++      .read                   = daemon_read,
++      .write                  = daemon_write,
++};
++
++int daemon_setup(char *str, char **mac_out, void *data)
++{
++      struct daemon_init *init = data;
++      char *remain;
++
++      *init = ((struct daemon_init)
++              { .sock_type            = "unix",
++                .ctl_sock             = "/tmp/uml.ctl" });
++      
++      remain = split_if_spec(str, mac_out, &init->sock_type, &init->ctl_sock,
++                             NULL);
++      if(remain != NULL)
++              printk(KERN_WARNING "daemon_setup : Ignoring data socket "
++                     "specification\n");
++      
++      return(1);
++}
++
++static struct transport daemon_transport = {
++      .list           = LIST_HEAD_INIT(daemon_transport.list),
++      .name           = "daemon",
++      .setup          = daemon_setup,
++      .user           = &daemon_user_info,
++      .kern           = &daemon_kern_info,
++      .private_size   = sizeof(struct daemon_data),
++      .setup_size     = sizeof(struct daemon_init),
++};
++
++static int register_daemon(void)
++{
++      register_transport(&daemon_transport);
++      return(1);
++}
++
++__initcall(register_daemon);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/daemon_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/daemon_user.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/daemon_user.c 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,197 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ * Licensed under the GPL.
++ */
++
++#include <errno.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <sys/time.h>
++#include "net_user.h"
++#include "daemon.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "user.h"
++#include "os.h"
++
++#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
++
++enum request_type { REQ_NEW_CONTROL };
++
++#define SWITCH_MAGIC 0xfeedface
++
++struct request_v3 {
++      uint32_t magic;
++      uint32_t version;
++      enum request_type type;
++      struct sockaddr_un sock;
++};
++
++static struct sockaddr_un *new_addr(void *name, int len)
++{
++      struct sockaddr_un *sun;
++
++      sun = um_kmalloc(sizeof(struct sockaddr_un));
++      if(sun == NULL){
++              printk("new_addr: allocation of sockaddr_un failed\n");
++              return(NULL);
++      }
++      sun->sun_family = AF_UNIX;
++      memcpy(sun->sun_path, name, len);
++      return(sun);
++}
++
++static int connect_to_switch(struct daemon_data *pri)
++{
++      struct sockaddr_un *ctl_addr = pri->ctl_addr;
++      struct sockaddr_un *local_addr = pri->local_addr;
++      struct sockaddr_un *sun;
++      struct request_v3 req;
++      int fd, n, err;
++
++      pri->control = socket(AF_UNIX, SOCK_STREAM, 0);
++      if(pri->control < 0){
++              printk("daemon_open : control socket failed, errno = %d\n", 
++                     errno);          
++              return(-errno);
++      }
++
++      if(connect(pri->control, (struct sockaddr *) ctl_addr, 
++                 sizeof(*ctl_addr)) < 0){
++              printk("daemon_open : control connect failed, errno = %d\n",
++                     errno);
++              err = -errno;
++              goto out;
++      }
++
++      fd = socket(AF_UNIX, SOCK_DGRAM, 0);
++      if(fd < 0){
++              printk("daemon_open : data socket failed, errno = %d\n", 
++                     errno);
++              err = -errno;
++              goto out;
++      }
++      if(bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0){
++              printk("daemon_open : data bind failed, errno = %d\n", 
++                     errno);
++              err = -errno;
++              goto out_close;
++      }
++
++      sun = um_kmalloc(sizeof(struct sockaddr_un));
++      if(sun == NULL){
++              printk("new_addr: allocation of sockaddr_un failed\n");
++              err = -ENOMEM;
++              goto out_close;
++      }
++
++      req.magic = SWITCH_MAGIC;
++      req.version = SWITCH_VERSION;
++      req.type = REQ_NEW_CONTROL;
++      req.sock = *local_addr;
++      n = os_write_file(pri->control, &req, sizeof(req));
++      if(n != sizeof(req)){
++              printk("daemon_open : control setup request failed, err = %d\n",
++                     -n);
++              err = -ENOTCONN;
++              goto out;               
++      }
++
++      n = os_read_file(pri->control, sun, sizeof(*sun));
++      if(n != sizeof(*sun)){
++              printk("daemon_open : read of data socket failed, err = %d\n", 
++                     -n);
++              err = -ENOTCONN;
++              goto out_close;         
++      }
++
++      pri->data_addr = sun;
++      return(fd);
++
++ out_close:
++      os_close_file(fd);
++ out:
++      os_close_file(pri->control);
++      return(err);
++}
++
++static void daemon_user_init(void *data, void *dev)
++{
++      struct daemon_data *pri = data;
++      struct timeval tv;
++      struct {
++              char zero;
++              int pid;
++              int usecs;
++      } name;
++
++      if(!strcmp(pri->sock_type, "unix"))
++              pri->ctl_addr = new_addr(pri->ctl_sock, 
++                                       strlen(pri->ctl_sock) + 1);
++      name.zero = 0;
++      name.pid = os_getpid();
++      gettimeofday(&tv, NULL);
++      name.usecs = tv.tv_usec;
++      pri->local_addr = new_addr(&name, sizeof(name));
++      pri->dev = dev;
++      pri->fd = connect_to_switch(pri);
++      if(pri->fd < 0){
++              kfree(pri->local_addr);
++              pri->local_addr = NULL;
++      }
++}
++
++static int daemon_open(void *data)
++{
++      struct daemon_data *pri = data;
++      return(pri->fd);
++}
++
++static void daemon_remove(void *data)
++{
++      struct daemon_data *pri = data;
++
++      os_close_file(pri->fd);
++      os_close_file(pri->control);
++      if(pri->data_addr != NULL) kfree(pri->data_addr);
++      if(pri->ctl_addr != NULL) kfree(pri->ctl_addr);
++      if(pri->local_addr != NULL) kfree(pri->local_addr);
++}
++
++int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
++{
++      struct sockaddr_un *data_addr = pri->data_addr;
++
++      return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
++}
++
++static int daemon_set_mtu(int mtu, void *data)
++{
++      return(mtu);
++}
++
++struct net_user_info daemon_user_info = {
++      .init           = daemon_user_init,
++      .open           = daemon_open,
++      .close          = NULL,
++      .remove         = daemon_remove,
++      .set_mtu        = daemon_set_mtu,
++      .add_address    = NULL,
++      .delete_address = NULL,
++      .max_packet     = MAX_PACKET - ETH_HEADER_OTHER
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/fd.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/fd.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/fd.c  2005-05-03 22:28:14.208450200 +0300
+@@ -0,0 +1,108 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <termios.h>
++#include <errno.h>
++#include "user.h"
++#include "user_util.h"
++#include "chan_user.h"
++
++struct fd_chan {
++      int fd;
++      int raw;
++      struct termios tt;
++      char str[sizeof("1234567890\0")];
++};
++
++void *fd_init(char *str, int device, struct chan_opts *opts)
++{
++      struct fd_chan *data;
++      char *end;
++      int n;
++
++      if(*str != ':'){
++              printk("fd_init : channel type 'fd' must specify a file "
++                     "descriptor\n");
++              return(NULL);
++      }
++      str++;
++      n = strtoul(str, &end, 0);
++      if((*end != '\0') || (end == str)){
++              printk("fd_init : couldn't parse file descriptor '%s'\n", str);
++              return(NULL);
++      }
++      data = um_kmalloc(sizeof(*data));
++      if(data == NULL) return(NULL);
++      *data = ((struct fd_chan) { .fd         = n,
++                                  .raw        = opts->raw });
++      return(data);
++}
++
++int fd_open(int input, int output, int primary, void *d, char **dev_out)
++{
++      struct fd_chan *data = d;
++      int err;
++
++      if(data->raw && isatty(data->fd)){
++              CATCH_EINTR(err = tcgetattr(data->fd, &data->tt));
++              if(err)
++                      return(err);
++
++              err = raw(data->fd);
++              if(err)
++                      return(err);
++      }
++      sprintf(data->str, "%d", data->fd);
++      *dev_out = data->str;
++      return(data->fd);
++}
++
++void fd_close(int fd, void *d)
++{
++      struct fd_chan *data = d;
++      int err;
++
++      if(data->raw && isatty(fd)){
++              CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &data->tt));
++              if(err)
++                      printk("Failed to restore terminal state - " 
++                             "errno = %d\n", -err);
++              data->raw = 0;
++      }
++}
++
++int fd_console_write(int fd, const char *buf, int n, void *d)
++{
++      struct fd_chan *data = d;
++
++      return(generic_console_write(fd, buf, n, &data->tt));
++}
++
++struct chan_ops fd_ops = {
++      .type           = "fd",
++      .init           = fd_init,
++      .open           = fd_open,
++      .close          = fd_close,
++      .read           = generic_read,
++      .write          = generic_write,
++      .console_write  = fd_console_write,
++      .window_size    = generic_window_size,
++      .free           = generic_free,
++      .winch          = 1,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/harddog_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/harddog_kern.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/harddog_kern.c        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,194 @@
++/* UML hardware watchdog, shamelessly stolen from:
++ *
++ *    SoftDog 0.05:   A Software Watchdog Device
++ *
++ *    (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
++ *                            http://www.redhat.com
++ *
++ *    This program is free software; you can redistribute it and/or
++ *    modify it under the terms of the GNU General Public License
++ *    as published by the Free Software Foundation; either version
++ *    2 of the License, or (at your option) any later version.
++ *    
++ *    Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
++ *    warranty for any of this software. This material is provided 
++ *    "AS-IS" and at no charge.       
++ *
++ *    (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
++ *
++ *    Software only watchdog driver. Unlike its big brother the WDT501P
++ *    driver this won't always recover a failed machine.
++ *
++ *  03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
++ *    Modularised.
++ *    Added soft_margin; use upon insmod to change the timer delay.
++ *    NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
++ *        minors.
++ *
++ *  19980911 Alan Cox
++ *    Made SMP safe for 2.3.x
++ *
++ *  20011127 Joel Becker (jlbec@evilplan.org>
++ *    Added soft_noboot; Allows testing the softdog trigger without 
++ *    requiring a recompile.
++ *    Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
++ */
++ 
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/reboot.h>
++#include <linux/smp_lock.h>
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include "helper.h"
++#include "mconsole.h"
++
++MODULE_LICENSE("GPL");
++
++/* Locked by the BKL in harddog_open and harddog_release */
++static int timer_alive;
++static int harddog_in_fd = -1;
++static int harddog_out_fd = -1;
++
++/*
++ *    Allow only one person to hold it open
++ */
++ 
++extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock);
++
++static int harddog_open(struct inode *inode, struct file *file)
++{
++      int err;
++      char *sock = NULL;
++
++      lock_kernel();
++      if(timer_alive)
++              return -EBUSY;
++#ifdef CONFIG_HARDDOG_NOWAYOUT         
++      MOD_INC_USE_COUNT;
++#endif
++
++#ifdef CONFIG_MCONSOLE
++      sock = mconsole_notify_socket();
++#endif
++      err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock);
++      if(err) return(err);
++
++      timer_alive = 1;
++      unlock_kernel();
++      return 0;
++}
++
++extern void stop_watchdog(int in_fd, int out_fd);
++
++static int harddog_release(struct inode *inode, struct file *file)
++{
++      /*
++       *      Shut off the timer.
++       */
++      lock_kernel();
++
++      stop_watchdog(harddog_in_fd, harddog_out_fd);
++      harddog_in_fd = -1;
++      harddog_out_fd = -1;
++
++      timer_alive=0;
++      unlock_kernel();
++      return 0;
++}
++
++extern int ping_watchdog(int fd);
++
++static ssize_t harddog_write(struct file *file, const char *data, size_t len,
++                           loff_t *ppos)
++{
++      /*  Can't seek (pwrite) on this device  */
++      if (ppos != &file->f_pos)
++              return -ESPIPE;
++
++      /*
++       *      Refresh the timer.
++       */
++      if(len)
++              return(ping_watchdog(harddog_out_fd));
++      return 0;
++}
++
++static int harddog_ioctl(struct inode *inode, struct file *file,
++                       unsigned int cmd, unsigned long arg)
++{
++      static struct watchdog_info ident = {
++              WDIOF_SETTIMEOUT,
++              0,
++              "UML Hardware Watchdog"
++      };
++      switch (cmd) {
++              default:
++                      return -ENOTTY;
++              case WDIOC_GETSUPPORT:
++                      if(copy_to_user((struct harddog_info *)arg, &ident,
++                                      sizeof(ident)))
++                              return -EFAULT;
++                      return 0;
++              case WDIOC_GETSTATUS:
++              case WDIOC_GETBOOTSTATUS:
++                      return put_user(0,(int *)arg);
++              case WDIOC_KEEPALIVE:
++                      return(ping_watchdog(harddog_out_fd));
++      }
++}
++
++static struct file_operations harddog_fops = {
++      .owner          = THIS_MODULE,
++      .write          = harddog_write,
++      .ioctl          = harddog_ioctl,
++      .open           = harddog_open,
++      .release        = harddog_release,
++};
++
++static struct miscdevice harddog_miscdev = {
++      .minor          = WATCHDOG_MINOR,
++      .name           = "watchdog",
++      .fops           = &harddog_fops,
++};
++
++static char banner[] __initdata = KERN_INFO "UML Watchdog Timer\n";
++
++static int __init harddog_init(void)
++{
++      int ret;
++
++      ret = misc_register(&harddog_miscdev);
++
++      if (ret)
++              return ret;
++
++      printk(banner);
++
++      return(0);
++}
++
++static void __exit harddog_exit(void)
++{
++      misc_deregister(&harddog_miscdev);
++}
++
++module_init(harddog_init);
++module_exit(harddog_exit);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/harddog_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/harddog_user.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/harddog_user.c        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,143 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <errno.h>
++#include "user_util.h"
++#include "user.h"
++#include "helper.h"
++#include "mconsole.h"
++#include "os.h"
++#include "choose-mode.h"
++#include "mode.h"
++
++struct dog_data {
++      int stdin;
++      int stdout;
++      int close_me[2];
++};
++
++static void pre_exec(void *d)
++{
++      struct dog_data *data = d;
++
++      dup2(data->stdin, 0);
++      dup2(data->stdout, 1);
++      dup2(data->stdout, 2);
++      os_close_file(data->stdin);
++      os_close_file(data->stdout);
++      os_close_file(data->close_me[0]);
++      os_close_file(data->close_me[1]);
++}
++
++int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
++{
++      struct dog_data data;
++      int in_fds[2], out_fds[2], pid, n, err;
++      char pid_buf[sizeof("nnnnn\0")], c;
++      char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL };
++      char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, 
++                                NULL };
++      char **args = NULL;
++
++      err = os_pipe(in_fds, 1, 0);
++      if(err < 0){
++              printk("harddog_open - os_pipe failed, err = %d\n", -err);
++              goto out;
++      }
++
++      err = os_pipe(out_fds, 1, 0);
++      if(err < 0){
++              printk("harddog_open - os_pipe failed, err = %d\n", -err);
++              goto out_close_in;
++      }
++
++      data.stdin = out_fds[0];
++      data.stdout = in_fds[1];
++      data.close_me[0] = out_fds[1];
++      data.close_me[1] = in_fds[0];
++
++      if(sock != NULL){
++              mconsole_args[2] = sock;
++              args = mconsole_args;
++      }
++      else {
++              /* XXX The os_getpid() is not SMP correct */
++              sprintf(pid_buf, "%d", CHOOSE_MODE(tracing_pid, os_getpid()));
++              args = pid_args;
++      }
++
++      pid = run_helper(pre_exec, &data, args, NULL);
++
++      os_close_file(out_fds[0]);
++      os_close_file(in_fds[1]);
++
++      if(pid < 0){
++              err = -pid;
++              printk("harddog_open - run_helper failed, errno = %d\n", -err);
++              goto out_close_out;
++      }
++
++      n = os_read_file(in_fds[0], &c, sizeof(c));
++      if(n == 0){
++              printk("harddog_open - EOF on watchdog pipe\n");
++              helper_wait(pid);
++              err = -EIO;
++              goto out_close_out;
++      }
++      else if(n < 0){
++              printk("harddog_open - read of watchdog pipe failed, "
++                     "err = %d\n", -n);
++              helper_wait(pid);
++              err = n;
++              goto out_close_out;
++      }
++      *in_fd_ret = in_fds[0];
++      *out_fd_ret = out_fds[1];
++      return(0);
++
++ out_close_in:
++      os_close_file(in_fds[0]);
++      os_close_file(in_fds[1]);
++ out_close_out:
++      os_close_file(out_fds[0]);
++      os_close_file(out_fds[1]);
++ out:
++      return(err);
++}
++
++void stop_watchdog(int in_fd, int out_fd)
++{
++      os_close_file(in_fd);
++      os_close_file(out_fd);
++}
++
++int ping_watchdog(int fd)
++{
++      int n;
++      char c = '\n';
++
++      n = os_write_file(fd, &c, sizeof(c));
++      if(n != sizeof(c)){
++              printk("ping_watchdog - write failed, err = %d\n", -n);
++              if(n < 0) 
++                      return(n);
++              return(-EIO);
++      }
++      return 1;
++
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/hostaudio_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/hostaudio_kern.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/hostaudio_kern.c      2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,352 @@
++/* 
++ * Copyright (C) 2002 Steve Schmidtke 
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/module.h"
++#include "linux/init.h"
++#include "linux/slab.h"
++#include "linux/fs.h"
++#include "linux/sound.h"
++#include "linux/soundcard.h"
++#include "asm/uaccess.h"
++#include "kern_util.h"
++#include "init.h"
++#include "os.h"
++
++struct hostaudio_state {
++      int fd;
++};
++
++struct hostmixer_state {
++      int fd;
++};
++
++#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp"
++#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer"
++
++/* Only changed from linux_main at boot time */
++char *dsp = HOSTAUDIO_DEV_DSP;
++char *mixer = HOSTAUDIO_DEV_MIXER;
++
++#define DSP_HELP \
++"    This is used to specify the host dsp device to the hostaudio driver.\n" \
++"    The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
++
++#define MIXER_HELP \
++"    This is used to specify the host mixer device to the hostaudio driver.\n"\
++"    The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
++
++#ifndef MODULE
++static int set_dsp(char *name, int *add)
++{
++      dsp = name;
++      return(0);
++}
++
++__uml_setup("dsp=", set_dsp, "dsp=<dsp device>\n" DSP_HELP);
++
++static int set_mixer(char *name, int *add)
++{
++      mixer = name;
++      return(0);
++}
++
++__uml_setup("mixer=", set_mixer, "mixer=<mixer device>\n" MIXER_HELP);
++
++#else /*MODULE*/
++
++MODULE_PARM(dsp, "s");
++MODULE_PARM_DESC(dsp, DSP_HELP);
++
++MODULE_PARM(mixer, "s");
++MODULE_PARM_DESC(mixer, MIXER_HELP);
++
++#endif
++
++/* /dev/dsp file operations */
++
++static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, 
++                            loff_t *ppos)
++{
++        struct hostaudio_state *state = file->private_data;
++      void *kbuf;
++      int err;
++
++#ifdef DEBUG
++        printk("hostaudio: read called, count = %d\n", count);
++#endif
++
++      kbuf = kmalloc(count, GFP_KERNEL);
++      if(kbuf == NULL)
++              return(-ENOMEM);
++
++      err = os_read_file(state->fd, kbuf, count);
++      if(err < 0)
++              goto out;
++
++      if(copy_to_user(buffer, kbuf, err))
++              err = -EFAULT;
++
++ out:
++      kfree(kbuf);
++      return(err);
++}
++
++static ssize_t hostaudio_write(struct file *file, const char *buffer, 
++                             size_t count, loff_t *ppos)
++{
++        struct hostaudio_state *state = file->private_data;
++      void *kbuf;
++      int err;
++
++#ifdef DEBUG
++        printk("hostaudio: write called, count = %d\n", count);
++#endif
++
++      kbuf = kmalloc(count, GFP_KERNEL);
++      if(kbuf == NULL)
++              return(-ENOMEM);
++
++      err = -EFAULT;
++      if(copy_from_user(kbuf, buffer, count))
++              goto out;
++
++      err = os_write_file(state->fd, kbuf, count);
++      if(err < 0)
++              goto out;
++      *ppos += err;
++
++ out:
++      kfree(kbuf);
++      return(err);
++}
++
++static unsigned int hostaudio_poll(struct file *file, 
++                                 struct poll_table_struct *wait)
++{
++        unsigned int mask = 0;
++
++#ifdef DEBUG
++        printk("hostaudio: poll called (unimplemented)\n");
++#endif
++
++        return(mask);
++}
++
++static int hostaudio_ioctl(struct inode *inode, struct file *file, 
++                         unsigned int cmd, unsigned long arg)
++{
++        struct hostaudio_state *state = file->private_data;
++      unsigned long data = 0;
++      int err;
++
++#ifdef DEBUG
++        printk("hostaudio: ioctl called, cmd = %u\n", cmd);
++#endif
++      switch(cmd){
++      case SNDCTL_DSP_SPEED:
++      case SNDCTL_DSP_STEREO:
++      case SNDCTL_DSP_GETBLKSIZE:
++      case SNDCTL_DSP_CHANNELS:
++      case SNDCTL_DSP_SUBDIVIDE:
++      case SNDCTL_DSP_SETFRAGMENT:
++              if(get_user(data, (int *) arg))
++                      return(-EFAULT);
++              break;
++      default:
++              break;
++      }
++
++      err = os_ioctl_generic(state->fd, cmd, (unsigned long) &data);
++
++      switch(cmd){
++      case SNDCTL_DSP_SPEED:
++      case SNDCTL_DSP_STEREO:
++      case SNDCTL_DSP_GETBLKSIZE:
++      case SNDCTL_DSP_CHANNELS:
++      case SNDCTL_DSP_SUBDIVIDE:
++      case SNDCTL_DSP_SETFRAGMENT:
++              if(put_user(data, (int *) arg))
++                      return(-EFAULT);
++              break;
++      default:
++              break;
++      }
++
++      return(err);
++}
++
++static int hostaudio_open(struct inode *inode, struct file *file)
++{
++        struct hostaudio_state *state;
++        int r = 0, w = 0;
++        int ret;
++
++#ifdef DEBUG
++        printk("hostaudio: open called (host: %s)\n", dsp);
++#endif
++
++        state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL);
++        if(state == NULL) 
++              return(-ENOMEM);
++
++        if(file->f_mode & FMODE_READ) r = 1;
++        if(file->f_mode & FMODE_WRITE) w = 1;
++
++      ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
++        if(ret < 0){
++              kfree(state);
++              return(ret);
++        }
++
++      state->fd = ret;
++        file->private_data = state;
++        return(0);
++}
++
++static int hostaudio_release(struct inode *inode, struct file *file)
++{
++        struct hostaudio_state *state = file->private_data;
++
++#ifdef DEBUG
++        printk("hostaudio: release called\n");
++#endif
++
++      os_close_file(state->fd);
++        kfree(state);
++
++        return(0);
++}
++
++/* /dev/mixer file operations */
++
++static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file, 
++                                unsigned int cmd, unsigned long arg)
++{
++        struct hostmixer_state *state = file->private_data;
++
++#ifdef DEBUG
++        printk("hostmixer: ioctl called\n");
++#endif
++
++      return(os_ioctl_generic(state->fd, cmd, arg));
++}
++
++static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
++{
++        struct hostmixer_state *state;
++        int r = 0, w = 0;
++        int ret;
++
++#ifdef DEBUG
++        printk("hostmixer: open called (host: %s)\n", mixer);
++#endif
++
++        state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL);
++        if(state == NULL) return(-ENOMEM);
++
++        if(file->f_mode & FMODE_READ) r = 1;
++        if(file->f_mode & FMODE_WRITE) w = 1;
++
++      ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
++        
++        if(ret < 0){
++              printk("hostaudio_open_mixdev failed to open '%s', err = %d\n",
++                     dsp, -ret);
++              kfree(state);
++              return(ret);
++        }
++
++        file->private_data = state;
++        return(0);
++}
++
++static int hostmixer_release(struct inode *inode, struct file *file)
++{
++        struct hostmixer_state *state = file->private_data;
++
++#ifdef DEBUG
++        printk("hostmixer: release called\n");
++#endif
++
++      os_close_file(state->fd);
++        kfree(state);
++
++        return(0);
++}
++
++
++/* kernel module operations */
++
++static struct file_operations hostaudio_fops = {
++        .owner          = THIS_MODULE,
++        .llseek         = no_llseek,
++        .read           = hostaudio_read,
++        .write          = hostaudio_write,
++        .poll           = hostaudio_poll,
++        .ioctl          = hostaudio_ioctl,
++        .mmap           = NULL,
++        .open           = hostaudio_open,
++        .release        = hostaudio_release,
++};
++
++static struct file_operations hostmixer_fops = {
++        .owner          = THIS_MODULE,
++        .llseek         = no_llseek,
++        .ioctl          = hostmixer_ioctl_mixdev,
++        .open           = hostmixer_open_mixdev,
++        .release        = hostmixer_release,
++};
++
++struct {
++      int dev_audio;
++      int dev_mixer;
++} module_data;
++
++MODULE_AUTHOR("Steve Schmidtke");
++MODULE_DESCRIPTION("UML Audio Relay");
++MODULE_LICENSE("GPL");
++
++static int __init hostaudio_init_module(void)
++{
++        printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n",
++             dsp, mixer);
++
++      module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
++        if(module_data.dev_audio < 0){
++                printk(KERN_ERR "hostaudio: couldn't register DSP device!\n");
++                return -ENODEV;
++        }
++
++      module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1);
++        if(module_data.dev_mixer < 0){
++                printk(KERN_ERR "hostmixer: couldn't register mixer "
++                     "device!\n");
++                unregister_sound_dsp(module_data.dev_audio);
++                return -ENODEV;
++        }
++
++        return 0;
++}
++
++static void __exit hostaudio_cleanup_module (void)
++{
++       unregister_sound_mixer(module_data.dev_mixer);
++       unregister_sound_dsp(module_data.dev_audio);
++}
++
++module_init(hostaudio_init_module);
++module_exit(hostaudio_cleanup_module);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/line.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/line.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/line.c        2005-05-03 22:28:14.214449288 +0300
+@@ -0,0 +1,610 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/slab.h"
++#include "linux/list.h"
++#include "linux/devfs_fs_kernel.h"
++#include "asm/irq.h"
++#include "asm/uaccess.h"
++#include "chan_kern.h"
++#include "irq_user.h"
++#include "line.h"
++#include "kern.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "os.h"
++#include "irq_kern.h"
++
++#define LINE_BUFSIZE 4096
++
++static void line_interrupt(int irq, void *data, struct pt_regs *unused)
++{
++      struct line *dev = data;
++
++      if(dev->count > 0) 
++              chan_interrupt(&dev->chan_list, &dev->task, dev->tty, irq, 
++                             dev);
++}
++
++static void line_timer_cb(void *arg)
++{
++      struct line *dev = arg;
++
++      line_interrupt(dev->driver->read_irq, dev, NULL);
++}
++
++static int write_room(struct line *dev)
++{
++      int n;
++
++      if(dev->buffer == NULL) return(LINE_BUFSIZE - 1);
++
++      n = dev->head - dev->tail;
++      if(n <= 0) n = LINE_BUFSIZE + n;
++      return(n - 1);
++}
++
++static int buffer_data(struct line *line, const char *buf, int len)
++{
++      int end, room;
++
++      if(line->buffer == NULL){
++              line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
++              if(line->buffer == NULL){
++                      printk("buffer_data - atomic allocation failed\n");
++                      return(0);
++              }
++              line->head = line->buffer;
++              line->tail = line->buffer;
++      }
++
++      room = write_room(line);
++      len = (len > room) ? room : len;
++
++      end = line->buffer + LINE_BUFSIZE - line->tail;
++      if(len < end){
++              memcpy(line->tail, buf, len);
++              line->tail += len;
++      }
++      else {
++              memcpy(line->tail, buf, end);
++              buf += end;
++              len -= end;
++              memcpy(line->buffer, buf, len);
++              line->tail = line->buffer + len;
++      }
++
++      return(len);
++}
++
++static int flush_buffer(struct line *line)
++{
++      int n, count;
++
++      if((line->buffer == NULL) || (line->head == line->tail)) return(1);
++
++      if(line->tail < line->head){
++              count = line->buffer + LINE_BUFSIZE - line->head;
++              n = write_chan(&line->chan_list, line->head, count,
++                             line->driver->write_irq);
++              if(n < 0) return(n);
++              if(n == count) line->head = line->buffer;
++              else {
++                      line->head += n;
++                      return(0);
++              }
++      }
++
++      count = line->tail - line->head;
++      n = write_chan(&line->chan_list, line->head, count, 
++                     line->driver->write_irq);
++      if(n < 0) return(n);
++
++      line->head += n;
++      return(line->head == line->tail);
++}
++
++int line_write(struct line *lines, struct tty_struct *tty, int from_user,
++             const char *buf, int len)
++{
++      struct line *line;
++      char *new;
++      unsigned long flags;
++      int n, err, i, ret = 0;
++
++      if(tty->stopped) return 0;
++
++      if(from_user){
++              new = kmalloc(len, GFP_KERNEL);
++              if(new == NULL)
++                      return(0);
++              n = copy_from_user(new, buf, len);
++              buf = new;
++              if(n == len){
++                      len = -EFAULT;
++                      goto out_free;
++              }
++
++              len -= n;
++      }
++
++      i = minor(tty->device) - tty->driver.minor_start;
++      line = &lines[i];
++
++      down(&line->sem);
++      if(line->head != line->tail){
++              local_irq_save(flags);
++              ret += buffer_data(line, buf, len);
++              err = flush_buffer(line);
++              local_irq_restore(flags);
++              if(err <= 0)
++                      goto out_up;
++      }
++      else {
++              n = write_chan(&line->chan_list, buf, len, 
++                             line->driver->write_irq);
++              if(n < 0){
++                      ret = n;
++                      goto out_up;
++              }
++
++              len -= n;
++              ret += n;
++              if(len > 0)
++                      ret += buffer_data(line, buf + n, len);
++      }
++ out_up:
++      up(&line->sem);
++
++ out_free:
++      if(from_user)
++              kfree(buf);
++      return(ret);
++}
++
++static void line_write_interrupt(int irq, void *data, struct pt_regs *unused)
++{
++      struct line *dev = data;
++      struct tty_struct *tty = dev->tty;
++      int err;
++
++      err = flush_buffer(dev);
++      if(err == 0) return;
++      else if(err < 0){
++              dev->head = dev->buffer;
++              dev->tail = dev->buffer;
++      }
++
++      if(tty == NULL) return;
++
++      if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
++         (tty->ldisc.write_wakeup != NULL))
++              (tty->ldisc.write_wakeup)(tty);
++      
++      /* BLOCKING mode
++       * In blocking mode, everything sleeps on tty->write_wait.
++       * Sleeping in the console driver would break non-blocking
++       * writes.
++       */
++
++      if (waitqueue_active(&tty->write_wait))
++              wake_up_interruptible(&tty->write_wait);
++
++}
++
++int line_setup_irq(int fd, int input, int output, void *data)
++{
++      struct line *line = data;
++      struct line_driver *driver = line->driver;
++      int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM;
++
++      if(input) err = um_request_irq(driver->read_irq, fd, IRQ_READ, 
++                                     line_interrupt, flags, 
++                                     driver->read_irq_name, line);
++      if(err) return(err);
++      if(output) err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, 
++                                      line_write_interrupt, flags, 
++                                      driver->write_irq_name, line);
++      line->have_irq = 1;
++      return(err);
++}
++
++void line_disable(struct line *line, int current_irq)
++{
++      if(!line->have_irq) return;
++
++      if(line->driver->read_irq == current_irq)
++              free_irq_later(line->driver->read_irq, line);
++      else
++              free_irq(line->driver->read_irq, line);
++
++      if(line->driver->write_irq == current_irq)
++              free_irq_later(line->driver->write_irq, line);
++      else
++              free_irq(line->driver->write_irq, line);
++
++      line->have_irq = 0;
++}
++
++int line_open(struct line *lines, struct tty_struct *tty,
++            struct chan_opts *opts)
++{
++      struct line *line;
++      int n, err = 0;
++
++      if(tty == NULL) n = 0;
++      else n = minor(tty->device) - tty->driver.minor_start;
++      line = &lines[n];
++
++      down(&line->sem);
++      if(line->count == 0){
++              if(!line->valid){
++                      err = -ENODEV;
++                      goto out;
++              }
++              if(list_empty(&line->chan_list)){
++                      err = parse_chan_pair(line->init_str, &line->chan_list,
++                                            line->init_pri, n, opts);
++                      if(err) goto out;
++                      err = open_chan(&line->chan_list);
++                      if(err) goto out;
++              }
++              enable_chan(&line->chan_list, line);
++              INIT_TQUEUE(&line->task, line_timer_cb, line);
++      }
++
++      if(!line->sigio){
++              chan_enable_winch(&line->chan_list, line);
++              line->sigio = 1;
++      }
++
++      /* This is outside the if because the initial console is opened
++       * with tty == NULL
++       */
++      line->tty = tty;
++
++      if(tty != NULL){
++              tty->driver_data = line;
++              chan_window_size(&line->chan_list, &tty->winsize.ws_row, 
++                               &tty->winsize.ws_col);
++      }
++
++      line->count++;
++ out:
++      up(&line->sem);
++      return(err);
++}
++
++void line_close(struct line *lines, struct tty_struct *tty)
++{
++      struct line *line;
++      int n;
++
++      if(tty == NULL) n = 0;
++      else n = minor(tty->device) - tty->driver.minor_start;
++      line = &lines[n];
++
++      down(&line->sem);
++      line->count--;
++
++      /* I don't like this, but I can't think of anything better.  What's
++       * going on is that the tty is in the process of being closed for
++       * the last time.  Its count hasn't been dropped yet, so it's still
++       * at 1.  This may happen when line->count != 0 because of the initial
++       * console open (without a tty) bumping it up to 1.
++       */
++      if((line->tty != NULL) && (line->tty->count == 1))
++              line->tty = NULL;
++      if(line->count == 0)
++              line_disable(line, -1);
++      up(&line->sem);
++}
++
++void close_lines(struct line *lines, int nlines)
++{
++      int i;
++
++      for(i = 0; i < nlines; i++)
++              close_chan(&lines[i].chan_list);
++}
++
++int line_setup(struct line *lines, int num, char *init, int all_allowed)
++{
++      int i, n;
++      char *end;
++
++      if(*init == '=') n = -1;
++      else {
++              n = simple_strtoul(init, &end, 0);
++              if(*end != '='){
++                      printk(KERN_ERR "line_setup failed to parse \"%s\"\n", 
++                             init);
++                      return(0);
++              }
++              init = end;
++      }
++      init++;
++      if((n >= 0) && (n >= num)){
++              printk("line_setup - %d out of range ((0 ... %d) allowed)\n",
++                     n, num);
++              return(0);
++      }
++      else if(n >= 0){
++              if(lines[n].count > 0){
++                      printk("line_setup - device %d is open\n", n);
++                      return(0);
++              }
++              if(lines[n].init_pri <= INIT_ONE){
++                      lines[n].init_pri = INIT_ONE;
++                      if(!strcmp(init, "none")) lines[n].valid = 0;
++                      else {
++                              lines[n].init_str = init;
++                              lines[n].valid = 1;
++                      }       
++              }
++      }
++      else if(!all_allowed){
++              printk("line_setup - can't configure all devices from "
++                     "mconsole\n");
++              return(0);
++      }
++      else {
++              for(i = 0; i < num; i++){
++                      if(lines[i].init_pri <= INIT_ALL){
++                              lines[i].init_pri = INIT_ALL;
++                              if(!strcmp(init, "none")) lines[i].valid = 0;
++                              else {
++                                      lines[i].init_str = init;
++                                      lines[i].valid = 1;
++                              }
++                      }
++              }
++      }
++      return(1);
++}
++
++int line_config(struct line *lines, int num, char *str)
++{
++      char *new = uml_strdup(str);
++
++      if(new == NULL){
++              printk("line_config - uml_strdup failed\n");
++              return(-ENOMEM);
++      }
++      return(!line_setup(lines, num, new, 0));
++}
++
++int line_get_config(char *name, struct line *lines, int num, char *str, 
++                  int size, char **error_out)
++{
++      struct line *line;
++      char *end;
++      int dev, n = 0;
++
++      dev = simple_strtoul(name, &end, 0);
++      if((*end != '\0') || (end == name)){
++              *error_out = "line_get_config failed to parse device number";
++              return(0);
++      }
++
++      if((dev < 0) || (dev >= num)){
++              *error_out = "device number of of range";
++              return(0);
++      }
++
++      line = &lines[dev];
++
++      down(&line->sem);
++      if(!line->valid)
++              CONFIG_CHUNK(str, size, n, "none", 1);
++      else if(line->count == 0)
++              CONFIG_CHUNK(str, size, n, line->init_str, 1);
++      else n = chan_config_string(&line->chan_list, str, size, error_out);
++      up(&line->sem);
++
++      return(n);
++}
++
++int line_remove(struct line *lines, int num, char *str)
++{
++      char config[sizeof("conxxxx=none\0")];
++
++      sprintf(config, "%s=none", str);
++      return(!line_setup(lines, num, config, 0));
++}
++
++static int line_write_room(struct tty_struct *tty)
++{
++      struct line *dev = tty->driver_data;
++
++      return(write_room(dev));
++}
++
++void line_register_devfs(struct lines *set, struct line_driver *line_driver, 
++                       struct tty_driver *driver, struct line *lines,
++                       int nlines)
++{
++      int err, i, n;
++      char *from, *to;
++
++      driver->driver_name = line_driver->name;
++      driver->name = line_driver->devfs_name;
++      driver->major = line_driver->major;
++      driver->minor_start = line_driver->minor_start;
++      driver->type = line_driver->type;
++      driver->subtype = line_driver->subtype;
++      driver->magic = TTY_DRIVER_MAGIC;
++      driver->flags = TTY_DRIVER_REAL_RAW;
++
++      n = set->num;
++      driver->num = n;
++      driver->table = kmalloc(n * sizeof(driver->table[0]), GFP_KERNEL);
++      driver->termios = kmalloc(n * sizeof(driver->termios[0]), GFP_KERNEL);
++      driver->termios_locked = kmalloc(n * sizeof(driver->termios_locked[0]),
++                                       GFP_KERNEL);
++      if((driver->table == NULL) || (driver->termios == NULL) ||
++         (driver->termios_locked == NULL))
++              panic("Failed to allocate driver table");
++
++      memset(driver->table, 0, n * sizeof(driver->table[0]));
++      memset(driver->termios, 0, n * sizeof(driver->termios[0]));
++      memset(driver->termios_locked, 0, 
++             n * sizeof(driver->termios_locked[0]));
++
++      driver->write_room = line_write_room;
++      driver->init_termios = tty_std_termios;
++
++      if (tty_register_driver(driver))
++              panic("line_register_devfs : Couldn't register driver\n");
++
++      from = line_driver->symlink_from;
++      to = line_driver->symlink_to;
++      err = devfs_mk_symlink(NULL, from, 0, to, NULL, NULL);
++      if(err) printk("Symlink creation from /dev/%s to /dev/%s "
++                     "returned %d\n", from, to, err);
++
++      for(i = 0; i < nlines; i++){
++              if(!lines[i].valid) 
++                      tty_unregister_devfs(driver, driver->minor_start + i);
++      }
++
++      mconsole_register_dev(&line_driver->mc);
++}
++
++void lines_init(struct line *lines, int nlines)
++{
++      struct line *line;
++      int i;
++
++      for(i = 0; i < nlines; i++){
++              line = &lines[i];
++              INIT_LIST_HEAD(&line->chan_list);
++              sema_init(&line->sem, 1);
++              if(line->init_str != NULL){
++                      line->init_str = uml_strdup(line->init_str);
++                      if(line->init_str == NULL)
++                              printk("lines_init - uml_strdup returned "
++                                     "NULL\n");
++              }
++      }
++}
++
++struct winch {
++      struct list_head list;
++      int fd;
++      int tty_fd;
++      int pid;
++      struct line *line;
++};
++
++void winch_interrupt(int irq, void *data, struct pt_regs *unused)
++{
++      struct winch *winch = data;
++      struct tty_struct *tty;
++      int err;
++      char c;
++
++      if(winch->fd != -1){
++              err = generic_read(winch->fd, &c, NULL);
++              if(err < 0){
++                      if(err != -EAGAIN){
++                              printk("winch_interrupt : read failed, "
++                                     "errno = %d\n", -err);
++                              printk("fd %d is losing SIGWINCH support\n", 
++                                     winch->tty_fd);
++                              return;
++                      }
++                      goto out;
++              }
++      }
++      tty = winch->line->tty;
++      if(tty != NULL){
++              chan_window_size(&winch->line->chan_list, 
++                               &tty->winsize.ws_row, 
++                               &tty->winsize.ws_col);
++              kill_pg(tty->pgrp, SIGWINCH, 1);
++      }
++ out:
++      if(winch->fd != -1)
++              reactivate_fd(winch->fd, WINCH_IRQ);
++}
++
++DECLARE_MUTEX(winch_handler_sem);
++LIST_HEAD(winch_handlers);
++
++void register_winch_irq(int fd, int tty_fd, int pid, void *line)
++{
++      struct winch *winch;
++
++      down(&winch_handler_sem);
++      winch = kmalloc(sizeof(*winch), GFP_KERNEL);
++      if(winch == NULL){
++              printk("register_winch_irq - kmalloc failed\n");
++              goto out;
++      }
++      *winch = ((struct winch) { .list        = LIST_HEAD_INIT(winch->list),
++                                 .fd          = fd,
++                                 .tty_fd      = tty_fd,
++                                 .pid         = pid,
++                                 .line        = line });
++      list_add(&winch->list, &winch_handlers);
++      if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, 
++                        SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
++                        "winch", winch) < 0)
++              printk("register_winch_irq - failed to register IRQ\n");
++ out:
++      up(&winch_handler_sem);
++}
++
++static void winch_cleanup(void)
++{
++      struct list_head *ele;
++      struct winch *winch;
++
++      list_for_each(ele, &winch_handlers){
++              winch = list_entry(ele, struct winch, list);
++              if(winch->fd != -1){
++                      deactivate_fd(winch->fd, WINCH_IRQ);
++                      os_close_file(winch->fd);
++              }
++              if(winch->pid != -1) 
++                      os_kill_process(winch->pid, 1);
++      }
++}
++
++__uml_exitcall(winch_cleanup);
++
++char *add_xterm_umid(char *base)
++{
++      char *umid, *title;
++      int len;
++
++      umid = get_umid(1);
++      if(umid == NULL) return(base);
++      
++      len = strlen(base) + strlen(" ()") + strlen(umid) + 1;
++      title = kmalloc(len, GFP_KERNEL);
++      if(title == NULL){
++              printk("Failed to allocate buffer for xterm title\n");
++              return(base);
++      }
++
++      strncpy(title, base, len);
++      len -= strlen(title);
++      snprintf(&title[strlen(title)], len, " (%s)", umid);
++      return(title);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/Makefile 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/Makefile      2005-05-03 22:28:14.215449136 +0300
+@@ -0,0 +1,97 @@
++# 
++# Copyright (C) 2000, 2002, 2003 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET := built-in.o 
++
++CHAN_OBJS := chan_kern.o chan_user.o line.o 
++
++list-multi := slip.o slirp.o daemon.o mcast.o mconsole.o net.o ubd.o \
++      hostaudio.o pcap.o port.o harddog.o
++
++slip-objs := slip_kern.o slip_user.o
++slirp-objs := slirp_kern.o slirp_user.o
++daemon-objs := daemon_kern.o daemon_user.o
++mcast-objs := mcast_kern.o mcast_user.o
++pcap-objs := pcap_kern.o pcap_user.o
++pcap-libs := -lpcap -L/usr/lib
++net-objs := net_kern.o net_user.o
++mconsole-objs := mconsole_kern.o mconsole_user.o
++hostaudio-objs := hostaudio_kern.o
++ubd-objs := ubd_kern.o ubd_user.o
++port-objs := port_kern.o port_user.o
++harddog-objs := harddog_kern.o harddog_user.o
++
++export-objs := mconsole_kern.o
++
++obj-y = 
++obj-$(CONFIG_SSL) += ssl.o 
++obj-$(CONFIG_UML_NET_SLIP) += slip.o
++obj-$(CONFIG_UML_NET_SLIRP) += slirp.o
++obj-$(CONFIG_UML_NET_DAEMON) += daemon.o 
++obj-$(CONFIG_UML_NET_MCAST) += mcast.o 
++obj-$(CONFIG_UML_NET_PCAP) += pcap.o 
++obj-$(CONFIG_UML_NET) += net.o 
++obj-$(CONFIG_MCONSOLE) += mconsole.o
++obj-$(CONFIG_MMAPPER) += mmapper_kern.o 
++obj-$(CONFIG_BLK_DEV_UBD) += ubd.o 
++obj-$(CONFIG_HOSTAUDIO) += hostaudio.o
++obj-$(CONFIG_FD_CHAN) += fd.o 
++obj-$(CONFIG_NULL_CHAN) += null.o 
++obj-$(CONFIG_PORT_CHAN) += port.o
++obj-$(CONFIG_PTY_CHAN) += pty.o
++obj-$(CONFIG_TTY_CHAN) += tty.o 
++obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
++obj-$(CONFIG_UML_WATCHDOG) += harddog.o
++obj-$(CONFIG_COW) += cow_kern.o
++obj-$(CONFIG_COW_COMMON) += cow_user.o
++
++CFLAGS_pcap_user.o = -I/usr/include/pcap
++
++obj-y += stdio_console.o $(CHAN_OBJS)
++
++USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
++
++USER_OBJS = $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \
++      null.o pty.o tty.o xterm.o
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++clean:
++
++modules:
++
++fastdep:
++
++dep:
++
++archmrproper:
++
++daemon.o : $(daemon-objs)
++
++slip.o : $(slip-objs)
++
++slirp.o : $(slirp-objs)
++
++mcast.o : $(mcast-objs)
++
++pcap.o : $(pcap-objs)
++
++mconsole.o : $(mconsole-objs)
++
++net.o : $(net-objs)
++
++hostaudio.o : $(hostaudio-objs)
++
++ubd.o : $(ubd-objs)
++
++port.o : $(port-objs)
++
++harddog.o : $(harddog-objs)
++
++$(list-multi) : # This doesn't work, but should : '%.o : $(%-objs)'
++      $(LD) -r -o $@ $($(patsubst %.o,%,$@)-objs) $($(patsubst %.o,%,$@)-libs)
+Index: linux-2.4.29/arch/um/drivers/mcast.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/mcast.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/mcast.h       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,30 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "net_user.h"
++
++struct mcast_data {
++      char *addr;
++      unsigned short port;
++      void *mcast_addr;
++      int ttl;
++      void *dev;
++};
++
++extern struct net_user_info mcast_user_info;
++
++extern int mcast_user_write(int fd, void *buf, int len, 
++                          struct mcast_data *pri);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/mcast_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/mcast_kern.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/mcast_kern.c  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,145 @@
++/*
++ * user-mode-linux networking multicast transport
++ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
++ *
++ * based on the existing uml-networking code, which is
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ *
++ * Licensed under the GPL.
++ */
++
++#include "linux/kernel.h"
++#include "linux/init.h"
++#include "linux/netdevice.h"
++#include "linux/etherdevice.h"
++#include "linux/in.h"
++#include "linux/inet.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "mcast.h"
++
++struct mcast_init {
++      char *addr;
++      int port;
++      int ttl;
++};
++
++void mcast_init(struct net_device *dev, void *data)
++{
++      struct uml_net_private *pri;
++      struct mcast_data *dpri;
++      struct mcast_init *init = data;
++
++      init_etherdev(dev, 0);
++      pri = dev->priv;
++      dpri = (struct mcast_data *) pri->user;
++      *dpri = ((struct mcast_data)
++              { .addr         = init->addr,
++                .port         = init->port,
++                .ttl          = init->ttl,
++                .mcast_addr   = NULL,
++                .dev          = dev });
++      printk("mcast backend ");
++      printk("multicast adddress: %s:%u, TTL:%u ",
++             dpri->addr, dpri->port, dpri->ttl);
++
++      printk("\n");
++}
++
++static int mcast_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
++{
++      *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
++      if(*skb == NULL) return(-ENOMEM);
++      return(net_recvfrom(fd, (*skb)->mac.raw, 
++                          (*skb)->dev->mtu + ETH_HEADER_OTHER));
++}
++
++static int mcast_write(int fd, struct sk_buff **skb,
++                      struct uml_net_private *lp)
++{
++      return mcast_user_write(fd, (*skb)->data, (*skb)->len, 
++                               (struct mcast_data *) &lp->user);
++}
++
++static struct net_kern_info mcast_kern_info = {
++      .init                   = mcast_init,
++      .protocol               = eth_protocol,
++      .read                   = mcast_read,
++      .write                  = mcast_write,
++};
++
++int mcast_setup(char *str, char **mac_out, void *data)
++{
++      struct mcast_init *init = data;
++      char *port_str = NULL, *ttl_str = NULL, *remain;
++      char *last;
++      int n;
++
++      *init = ((struct mcast_init)
++              { .addr         = "239.192.168.1",
++                .port         = 1102,
++                .ttl          = 1 });
++
++      remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
++                             NULL);
++      if(remain != NULL){
++              printk(KERN_ERR "mcast_setup - Extra garbage on "
++                     "specification : '%s'\n", remain);
++              return(0);
++      }
++      
++      if(port_str != NULL){
++              n = simple_strtoul(port_str, &last, 10);
++              if((*last != '\0') || (last == port_str)){
++                      printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", 
++                             port_str);
++                      return(0);
++              }
++              init->port = htons(n);
++      }
++
++      if(ttl_str != NULL){
++              init->ttl = simple_strtoul(ttl_str, &last, 10);
++              if((*last != '\0') || (last == ttl_str)){
++                      printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n", 
++                             ttl_str);
++                      return(0);
++              }
++      }
++
++      printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
++             init->port, init->ttl);
++
++      return(1);
++}
++
++static struct transport mcast_transport = {
++      .list           = LIST_HEAD_INIT(mcast_transport.list),
++      .name           = "mcast",
++      .setup          = mcast_setup,
++      .user           = &mcast_user_info,
++      .kern           = &mcast_kern_info,
++      .private_size   = sizeof(struct mcast_data),
++      .setup_size     = sizeof(struct mcast_init),
++};
++
++static int register_mcast(void)
++{
++      register_transport(&mcast_transport);
++      return(1);
++}
++
++__initcall(register_mcast);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/mcast_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/mcast_user.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/mcast_user.c  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,177 @@
++/*
++ * user-mode-linux networking multicast transport
++ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
++ *
++ * based on the existing uml-networking code, which is
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ *
++ * Licensed under the GPL.
++ *
++ */
++
++#include <errno.h>
++#include <unistd.h>
++#include <linux/inet.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <sys/time.h>
++#include <netinet/in.h>
++#include "net_user.h"
++#include "mcast.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "user.h"
++#include "os.h"
++
++#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
++
++static struct sockaddr_in *new_addr(char *addr, unsigned short port)
++{
++      struct sockaddr_in *sin;
++
++      sin = um_kmalloc(sizeof(struct sockaddr_in));
++      if(sin == NULL){
++              printk("new_addr: allocation of sockaddr_in failed\n");
++              return(NULL);
++      }
++      sin->sin_family = AF_INET;
++      sin->sin_addr.s_addr = in_aton(addr);
++      sin->sin_port = port;
++      return(sin);
++}
++
++static void mcast_user_init(void *data, void *dev)
++{
++      struct mcast_data *pri = data;
++
++      pri->mcast_addr = new_addr(pri->addr, pri->port);
++      pri->dev = dev;
++}
++
++static int mcast_open(void *data)
++{
++      struct mcast_data *pri = data;
++      struct sockaddr_in *sin = pri->mcast_addr;
++      struct ip_mreq mreq;
++      int fd, yes = 1;
++
++
++      if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) {
++              fd = -EINVAL;
++              goto out;
++      }
++
++      fd = socket(AF_INET, SOCK_DGRAM, 0);
++      if (fd < 0){
++              printk("mcast_open : data socket failed, errno = %d\n", 
++                     errno);
++              fd = -ENOMEM;
++              goto out;
++      }
++
++      if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
++              printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
++                      errno);
++              os_close_file(fd);
++              fd = -EINVAL;
++              goto out;
++      }
++
++      /* set ttl according to config */
++      if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
++                     sizeof(pri->ttl)) < 0) {
++              printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
++                      errno);
++              os_close_file(fd);
++              fd = -EINVAL;
++              goto out;
++      }
++
++      /* set LOOP, so data does get fed back to local sockets */
++      if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
++              printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
++                      errno);
++              os_close_file(fd);
++              fd = -EINVAL;
++              goto out;
++      }
++
++      /* bind socket to mcast address */
++      if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
++              printk("mcast_open : data bind failed, errno = %d\n", errno);
++              os_close_file(fd);
++              fd = -EINVAL;
++              goto out;
++      }               
++      
++      /* subscribe to the multicast group */
++      mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
++      mreq.imr_interface.s_addr = 0;
++      if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, 
++                     &mreq, sizeof(mreq)) < 0) {
++              printk("mcast_open: IP_ADD_MEMBERSHIP failed, error = %d\n",
++                      errno);
++              printk("There appears not to be a multicast-capable network "
++                     "interface on the host.\n");
++              printk("eth0 should be configured in order to use the "
++                     "multicast transport.\n");
++              os_close_file(fd);
++              fd = -EINVAL;
++      }
++
++ out:
++      return(fd);
++}
++
++static void mcast_close(int fd, void *data)
++{
++      struct ip_mreq mreq;
++      struct mcast_data *pri = data;
++      struct sockaddr_in *sin = pri->mcast_addr;
++
++      mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
++      mreq.imr_interface.s_addr = 0;
++      if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
++                     &mreq, sizeof(mreq)) < 0) {
++              printk("mcast_open: IP_DROP_MEMBERSHIP failed, error = %d\n",
++                      errno);
++      }
++
++      os_close_file(fd);
++}
++
++int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
++{
++      struct sockaddr_in *data_addr = pri->mcast_addr;
++
++      return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
++}
++
++static int mcast_set_mtu(int mtu, void *data)
++{
++      return(mtu);
++}
++
++struct net_user_info mcast_user_info = {
++      .init           = mcast_user_init,
++      .open           = mcast_open,
++      .close          = mcast_close,
++      .remove         = NULL,
++      .set_mtu        = mcast_set_mtu,
++      .add_address    = NULL,
++      .delete_address = NULL,
++      .max_packet     = MAX_PACKET - ETH_HEADER_OTHER
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/mconsole_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/mconsole_kern.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/mconsole_kern.c       2005-05-03 22:28:14.222448072 +0300
+@@ -0,0 +1,560 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
++ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "linux/slab.h"
++#include "linux/init.h"
++#include "linux/notifier.h"
++#include "linux/reboot.h"
++#include "linux/utsname.h"
++#include "linux/ctype.h"
++#include "linux/interrupt.h"
++#include "linux/sysrq.h"
++#include "linux/tqueue.h"
++#include "linux/module.h"
++#include "linux/file.h"
++#include "linux/fs.h"
++#include "linux/proc_fs.h"
++#include "asm/irq.h"
++#include "asm/uaccess.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "mconsole.h"
++#include "mconsole_kern.h"
++#include "irq_user.h"
++#include "init.h"
++#include "os.h"
++#include "umid.h"
++#include "irq_kern.h"
++
++static int do_unlink_socket(struct notifier_block *notifier, 
++                          unsigned long what, void *data)
++{
++      return(mconsole_unlink_socket());
++}
++
++
++static struct notifier_block reboot_notifier = {
++      .notifier_call          = do_unlink_socket,
++      .priority               = 0,
++};
++
++/* Safe without explicit locking for now.  Tasklets provide their own 
++ * locking, and the interrupt handler is safe because it can't interrupt
++ * itself and it can only happen on CPU 0.
++ */
++
++LIST_HEAD(mc_requests);
++
++static void mc_task_proc(void *unused)
++{
++      struct mconsole_entry *req;
++      unsigned long flags;
++
++      while(!list_empty(&mc_requests)){
++              local_irq_save(flags);
++              req = list_entry(mc_requests.next, struct mconsole_entry, 
++                               list);
++              list_del(&req->list);
++              local_irq_restore(flags);
++              req->request.cmd->handler(&req->request);
++              kfree(req);
++      }
++}
++
++struct tq_struct mconsole_task = {
++      .routine        = mc_task_proc,
++      .data           = NULL
++};
++
++static void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++      int fd;
++      struct mconsole_entry *new;
++      struct mc_request req;
++
++      fd = (int) dev_id;
++      while (mconsole_get_request(fd, &req)){
++              if(req.cmd->context == MCONSOLE_INTR) 
++                      (*req.cmd->handler)(&req);
++              else {
++                      new = kmalloc(sizeof(*new), GFP_ATOMIC);
++                      if(new == NULL)
++                              mconsole_reply(&req, "Out of memory", 1, 0);
++                      else {
++                              new->request = req;
++                              list_add(&new->list, &mc_requests);
++                      }
++              }
++      }
++
++      if(!list_empty(&mc_requests))
++              schedule_task(&mconsole_task);
++      reactivate_fd(fd, MCONSOLE_IRQ);
++}
++
++void mconsole_version(struct mc_request *req)
++{
++      char version[256];
++
++      sprintf(version, "%s %s %s %s %s", system_utsname.sysname, 
++              system_utsname.nodename, system_utsname.release, 
++              system_utsname.version, system_utsname.machine);
++      mconsole_reply(req, version, 0, 0);
++}
++
++void mconsole_log(struct mc_request *req)
++{
++      int len;
++      char *ptr = req->request.data;
++      
++      ptr += strlen("log ");
++
++      len = req->len - (ptr - req->request.data);
++      printk("%.*s", len, ptr);
++      mconsole_reply(req, "", 0, 0);
++}
++
++void mconsole_proc(struct mc_request *req)
++{
++      struct nameidata nd;
++      struct file_system_type *proc;
++      struct super_block *super;
++      struct file *file;
++      int n, err;
++      char *ptr = req->request.data, *buf;
++      
++      ptr += strlen("proc");
++      while(isspace(*ptr)) ptr++;
++
++      proc = get_fs_type("proc");
++      if(proc == NULL){
++              mconsole_reply(req, "procfs not registered", 1, 0);
++              goto out;
++      }
++
++      super = get_anon_super(proc, NULL, NULL);
++      if(super == NULL){
++              mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
++              goto out_put;
++      }
++
++      if(super->s_root == NULL){
++              super = (*proc->read_super)(super, NULL, 0);
++              if(super == NULL){
++                      mconsole_reply(req, "Failed to read superblock", 1, 0);
++                      goto out_put;
++              }
++      }
++      up_write(&super->s_umount);
++
++      nd.dentry = super->s_root;
++      nd.mnt = NULL;
++      nd.flags = O_RDONLY + 1;
++      nd.last_type = LAST_ROOT;
++
++      err = link_path_walk(ptr, &nd);
++      if(err){
++              mconsole_reply(req, "Failed to look up file", 1, 0);
++              goto out_kill;
++      }
++
++      file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
++      if(IS_ERR(file)){
++              mconsole_reply(req, "Failed to open file", 1, 0);
++              goto out_kill;
++      }
++
++      buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
++      if(buf == NULL){
++              mconsole_reply(req, "Failed to allocate buffer", 1, 0);
++              goto out_fput;
++      }
++
++      if((file->f_op != NULL) && (file->f_op->read != NULL)){
++              do {
++                      n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1, 
++                                              &file->f_pos);
++                      if(n >= 0){
++                              buf[n] = '\0';
++                              mconsole_reply(req, buf, 0, (n > 0));
++                      }
++                      else {
++                              mconsole_reply(req, "Read of file failed", 
++                                             1, 0);
++                              goto out_free;
++                      }
++              } while(n > 0);
++      }
++      else mconsole_reply(req, "", 0, 0);
++
++ out_free:
++      kfree(buf);
++ out_fput:
++      fput(file);
++ out_kill:
++      kill_super(super);
++ out_put:
++      /* put_filesystem(proc); */
++ out: ;
++}
++
++#define UML_MCONSOLE_HELPTEXT \
++"Commands: \n\
++    version - Get kernel version \n\
++    help - Print this message \n\
++    halt - Halt UML \n\
++    reboot - Reboot UML \n\
++    config <dev>=<config> - Add a new device to UML;  \n\
++      same syntax as command line \n\
++    config <dev> - Query the configuration of a device \n\
++    remove <dev> - Remove a device from UML \n\
++    sysrq <letter> - Performs the SysRq action controlled by the letter \n\
++    cad - invoke the Ctl-Alt-Del handler \n\
++    stop - pause the UML; it will do nothing until it receives a 'go' \n\
++    go - continue the UML after a 'stop' \n\
++    log <string> - make UML enter <string> into the kernel log\n\
++    proc <file> - returns the contents of the UML's /proc/<file>\n\
++"
++
++void mconsole_help(struct mc_request *req)
++{
++      mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0);
++}
++
++void mconsole_halt(struct mc_request *req)
++{
++      mconsole_reply(req, "", 0, 0);
++      machine_halt();
++}
++
++void mconsole_reboot(struct mc_request *req)
++{
++      mconsole_reply(req, "", 0, 0);
++      machine_restart(NULL);
++}
++
++extern void ctrl_alt_del(void);
++
++void mconsole_cad(struct mc_request *req)
++{
++      mconsole_reply(req, "", 0, 0);
++      ctrl_alt_del();
++}
++
++void mconsole_go(struct mc_request *req)
++{
++      mconsole_reply(req, "Not stopped", 1, 0);
++}
++
++void mconsole_stop(struct mc_request *req)
++{
++      deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
++      os_set_fd_block(req->originating_fd, 1);
++      mconsole_reply(req, "", 0, 0);
++      while(mconsole_get_request(req->originating_fd, req)){
++              if(req->cmd->handler == mconsole_go) break;
++              (*req->cmd->handler)(req);
++      }
++      os_set_fd_block(req->originating_fd, 0);
++      reactivate_fd(req->originating_fd, MCONSOLE_IRQ);
++      mconsole_reply(req, "", 0, 0);
++}
++
++/* This list is populated by __initcall routines. */
++
++LIST_HEAD(mconsole_devices);
++
++void mconsole_register_dev(struct mc_device *new)
++{
++      list_add(&new->list, &mconsole_devices);
++}
++
++static struct mc_device *mconsole_find_dev(char *name)
++{
++      struct list_head *ele;
++      struct mc_device *dev;
++
++      list_for_each(ele, &mconsole_devices){
++              dev = list_entry(ele, struct mc_device, list);
++              if(!strncmp(name, dev->name, strlen(dev->name)))
++                      return(dev);
++      }
++      return(NULL);
++}
++
++#define CONFIG_BUF_SIZE 64
++
++static void mconsole_get_config(int (*get_config)(char *, char *, int, 
++                                                char **),
++                              struct mc_request *req, char *name)
++{
++      char default_buf[CONFIG_BUF_SIZE], *error, *buf;
++      int n, size;
++
++      if(get_config == NULL){
++              mconsole_reply(req, "No get_config routine defined", 1, 0);
++              return;
++      }
++
++      error = NULL;
++      size = sizeof(default_buf)/sizeof(default_buf[0]);
++      buf = default_buf;
++
++      while(1){
++              n = (*get_config)(name, buf, size, &error);
++              if(error != NULL){
++                      mconsole_reply(req, error, 1, 0);
++                      goto out;
++              }
++
++              if(n <= size){
++                      mconsole_reply(req, buf, 0, 0);
++                      goto out;
++              }
++
++              if(buf != default_buf)
++                      kfree(buf);
++
++              size = n;
++              buf = kmalloc(size, GFP_KERNEL);
++              if(buf == NULL){
++                      mconsole_reply(req, "Failed to allocate buffer", 1, 0);
++                      return;
++              }
++      }
++ out:
++      if(buf != default_buf)
++              kfree(buf);
++      
++}
++
++void mconsole_config(struct mc_request *req)
++{
++      struct mc_device *dev;
++      char *ptr = req->request.data, *name;
++      int err;
++
++      ptr += strlen("config");
++      while(isspace(*ptr)) ptr++;
++      dev = mconsole_find_dev(ptr);
++      if(dev == NULL){
++              mconsole_reply(req, "Bad configuration option", 1, 0);
++              return;
++      }
++
++      name = &ptr[strlen(dev->name)];
++      ptr = name;
++      while((*ptr != '=') && (*ptr != '\0'))
++              ptr++;
++
++      if(*ptr == '='){
++              err = (*dev->config)(name);
++              mconsole_reply(req, "", err, 0);
++      }
++      else mconsole_get_config(dev->get_config, req, name);
++}
++
++void mconsole_remove(struct mc_request *req)
++{
++      struct mc_device *dev;  
++      char *ptr = req->request.data;
++      int err;
++
++      ptr += strlen("remove");
++      while(isspace(*ptr)) ptr++;
++      dev = mconsole_find_dev(ptr);
++      if(dev == NULL){
++              mconsole_reply(req, "Bad remove option", 1, 0);
++              return;
++      }
++      err = (*dev->remove)(&ptr[strlen(dev->name)]);
++      mconsole_reply(req, "", err, 0);
++}
++
++#ifdef CONFIG_MAGIC_SYSRQ
++void mconsole_sysrq(struct mc_request *req)
++{
++      char *ptr = req->request.data;
++
++      ptr += strlen("sysrq");
++      while(isspace(*ptr)) ptr++;
++
++      mconsole_reply(req, "", 0, 0);
++      handle_sysrq(*ptr, &current->thread.regs, NULL, NULL);
++}
++#else
++void mconsole_sysrq(struct mc_request *req)
++{
++      mconsole_reply(req, "Sysrq not compiled in", 1, 0);
++}
++#endif
++
++/* Changed by mconsole_setup, which is __setup, and called before SMP is
++ * active.
++ */
++static char *notify_socket = NULL; 
++
++int mconsole_init(void)
++{
++      int err, sock;
++      char file[256];
++
++      if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
++      snprintf(mconsole_socket_name, sizeof(file), "%s", file);
++
++      sock = os_create_unix_socket(file, sizeof(file), 1);
++      if (sock < 0){
++              printk("Failed to initialize management console\n");
++              return(1);
++      }
++
++      register_reboot_notifier(&reboot_notifier);
++
++      err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
++                           SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
++                           "mconsole", (void *)sock);
++      if (err){
++              printk("Failed to get IRQ for management console\n");
++              return(1);
++      }
++
++      if(notify_socket != NULL){
++              notify_socket = uml_strdup(notify_socket);
++              if(notify_socket != NULL)
++                      mconsole_notify(notify_socket, MCONSOLE_SOCKET,
++                                      mconsole_socket_name, 
++                                      strlen(mconsole_socket_name) + 1);
++              else printk(KERN_ERR "mconsole_setup failed to strdup "
++                          "string\n");
++      }
++
++      printk("mconsole (version %d) initialized on %s\n", 
++             MCONSOLE_VERSION, mconsole_socket_name);
++      return(0);
++}
++
++__initcall(mconsole_init);
++
++static int write_proc_mconsole(struct file *file, const char *buffer,
++                             unsigned long count, void *data)
++{
++      char *buf;
++
++      buf = kmalloc(count + 1, GFP_KERNEL);
++      if(buf == NULL) 
++              return(-ENOMEM);
++
++      if(copy_from_user(buf, buffer, count)){
++              count = -EFAULT;
++              goto out;
++      }
++
++      buf[count] = '\0';
++
++      mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
++ out:
++      kfree(buf);
++      return(count);
++}
++
++static int create_proc_mconsole(void)
++{
++      struct proc_dir_entry *ent;
++
++      if(notify_socket == NULL) return(0);
++
++      ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL);
++      if(ent == NULL){
++              printk("create_proc_mconsole : create_proc_entry failed\n");
++              return(0);
++      }
++
++      ent->read_proc = NULL;
++      ent->write_proc = write_proc_mconsole;
++      return(0);
++}
++
++static spinlock_t notify_spinlock = SPIN_LOCK_UNLOCKED;
++
++void lock_notify(void)
++{
++      spin_lock(&notify_spinlock);
++}
++
++void unlock_notify(void)
++{
++      spin_unlock(&notify_spinlock);
++}
++
++__initcall(create_proc_mconsole);
++
++#define NOTIFY "=notify:"
++
++static int mconsole_setup(char *str)
++{
++      if(!strncmp(str, NOTIFY, strlen(NOTIFY))){
++              str += strlen(NOTIFY);
++              notify_socket = str;
++      }
++      else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str);
++      return(1);
++}
++
++__setup("mconsole", mconsole_setup);
++
++__uml_help(mconsole_setup,
++"mconsole=notify:<socket>\n"
++"    Requests that the mconsole driver send a message to the named Unix\n"
++"    socket containing the name of the mconsole socket.  This also serves\n"
++"    to notify outside processes when UML has booted far enough to respond\n"
++"    to mconsole requests.\n\n"
++);
++
++static int notify_panic(struct notifier_block *self, unsigned long unused1,
++                      void *ptr)
++{
++      char *message = ptr;
++
++      if(notify_socket == NULL) return(0);
++
++      mconsole_notify(notify_socket, MCONSOLE_PANIC, message, 
++                      strlen(message) + 1);
++      return(0);
++}
++
++static struct notifier_block panic_exit_notifier = {
++      .notifier_call          = notify_panic,
++      .next                   = NULL,
++      .priority               = 1
++};
++
++static int add_notifier(void)
++{
++      notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
++      return(0);
++}
++
++__initcall(add_notifier);
++
++char *mconsole_notify_socket(void)
++{
++      return(notify_socket);
++}
++
++EXPORT_SYMBOL(mconsole_notify_socket);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/mconsole_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/mconsole_user.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/mconsole_user.c       2005-05-03 22:28:14.223447920 +0300
+@@ -0,0 +1,215 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
++ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <signal.h>
++#include <sys/socket.h>
++#include <sys/types.h>
++#include <sys/uio.h>
++#include <sys/un.h>
++#include <unistd.h>
++#include "user.h"
++#include "mconsole.h"
++#include "umid.h"
++
++static struct mconsole_command commands[] = {
++      { "version", mconsole_version, MCONSOLE_INTR },
++      { "halt", mconsole_halt, MCONSOLE_PROC },
++      { "reboot", mconsole_reboot, MCONSOLE_PROC },
++      { "config", mconsole_config, MCONSOLE_PROC },
++      { "remove", mconsole_remove, MCONSOLE_PROC },
++      { "sysrq", mconsole_sysrq, MCONSOLE_INTR },
++      { "help", mconsole_help, MCONSOLE_INTR },
++      { "cad", mconsole_cad, MCONSOLE_INTR },
++      { "stop", mconsole_stop, MCONSOLE_PROC },
++      { "go", mconsole_go, MCONSOLE_INTR },
++      { "log", mconsole_log, MCONSOLE_INTR },
++      { "proc", mconsole_proc, MCONSOLE_PROC },
++};
++
++/* Initialized in mconsole_init, which is an initcall */
++char mconsole_socket_name[256];
++
++int mconsole_reply_v0(struct mc_request *req, char *reply)
++{
++        struct iovec iov;
++        struct msghdr msg;
++
++        iov.iov_base = reply;
++        iov.iov_len = strlen(reply);
++
++        msg.msg_name = &(req->origin);
++        msg.msg_namelen = req->originlen;
++        msg.msg_iov = &iov;
++        msg.msg_iovlen = 1;
++        msg.msg_control = NULL;
++        msg.msg_controllen = 0;
++        msg.msg_flags = 0;
++
++        return sendmsg(req->originating_fd, &msg, 0);
++}
++
++static struct mconsole_command *mconsole_parse(struct mc_request *req)
++{
++      struct mconsole_command *cmd;
++      int i;
++
++      for(i=0;i<sizeof(commands)/sizeof(commands[0]);i++){
++              cmd = &commands[i];
++              if(!strncmp(req->request.data, cmd->command, 
++                          strlen(cmd->command))){
++                      return(cmd);
++              }
++      }
++      return(NULL);
++}
++
++#define MIN(a,b) ((a)<(b) ? (a):(b))
++
++#define STRINGX(x) #x
++#define STRING(x) STRINGX(x)
++
++int mconsole_get_request(int fd, struct mc_request *req)
++{
++      int len;
++
++      req->originlen = sizeof(req->origin);
++      req->len = recvfrom(fd, &req->request, sizeof(req->request), 0,
++                          (struct sockaddr *) req->origin, &req->originlen);
++      if (req->len < 0)
++              return 0;
++
++      req->originating_fd = fd;
++
++      if(req->request.magic != MCONSOLE_MAGIC){
++              /* Unversioned request */
++              len = MIN(sizeof(req->request.data) - 1, 
++                        strlen((char *) &req->request));
++              memmove(req->request.data, &req->request, len);
++              req->request.data[len] = '\0';
++
++              req->request.magic = MCONSOLE_MAGIC;
++              req->request.version = 0;
++              req->request.len = len;
++
++              mconsole_reply_v0(req, "ERR Version 0 mconsole clients are "
++                                "not supported by this driver");
++              return(0);
++      }
++
++      if(req->request.len >= MCONSOLE_MAX_DATA){
++              mconsole_reply(req, "Request too large", 1, 0);
++              return(0);
++      }
++      if(req->request.version != MCONSOLE_VERSION){
++              mconsole_reply(req, "This driver only supports version " 
++                               STRING(MCONSOLE_VERSION) " clients", 1, 0);
++      }
++      
++      req->request.data[req->request.len] = '\0';
++      req->cmd = mconsole_parse(req);
++      if(req->cmd == NULL){
++              mconsole_reply(req, "Unknown command", 1, 0);
++              return(0);
++      }
++
++      return(1);
++}
++
++int mconsole_reply(struct mc_request *req, char *str, int err, int more)
++{
++      struct mconsole_reply reply;
++      int total, len, n;
++
++      total = strlen(str);
++      do {
++              reply.err = err;
++
++              /* err can only be true on the first packet */
++              err = 0;
++
++              len = MIN(total, MCONSOLE_MAX_DATA - 1);
++
++              if(len == total) reply.more = more;
++              else reply.more = 1;
++
++              memcpy(reply.data, str, len);
++              reply.data[len] = '\0';
++              total -= len;
++              str += len;
++              reply.len = len + 1;
++
++              len = sizeof(reply) + reply.len - sizeof(reply.data);
++
++              n = sendto(req->originating_fd, &reply, len, 0,
++                         (struct sockaddr *) req->origin, req->originlen);
++
++              if(n < 0) return(-errno);
++      } while(total > 0);
++      return(0);
++}
++
++int mconsole_unlink_socket(void)
++{
++      unlink(mconsole_socket_name);
++      return 0;
++}
++
++static int notify_sock = -1;
++
++int mconsole_notify(char *sock_name, int type, const void *data, int len)
++{
++      struct sockaddr_un target;
++      struct mconsole_notify packet;
++      int n, err = 0;
++
++      lock_notify();
++      if(notify_sock < 0){
++              notify_sock = socket(PF_UNIX, SOCK_DGRAM, 0);
++              if(notify_sock < 0){
++                      printk("mconsole_notify - socket failed, errno = %d\n",
++                             errno);
++                      err = -errno;
++              }
++      }
++      unlock_notify();
++      
++      if(err)
++              return(err);
++
++      target.sun_family = AF_UNIX;
++      strcpy(target.sun_path, sock_name);
++
++      packet.magic = MCONSOLE_MAGIC;
++      packet.version = MCONSOLE_VERSION;
++      packet.type = type;
++      len = (len > sizeof(packet.data)) ? sizeof(packet.data) : len;
++      packet.len = len;
++      memcpy(packet.data, data, len);
++
++      err = 0;
++      len = sizeof(packet) + packet.len - sizeof(packet.data);
++      n = sendto(notify_sock, &packet, len, 0, (struct sockaddr *) &target, 
++                 sizeof(target));
++      if(n < 0){
++              printk("mconsole_notify - sendto failed, errno = %d\n", errno);
++              err = -errno;
++      }
++      return(err);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/mmapper_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/mmapper_kern.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/mmapper_kern.c        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,151 @@
++/*
++ * arch/um/drivers/mmapper_kern.c
++ *
++ * BRIEF MODULE DESCRIPTION
++ *
++ * Copyright (C) 2000 RidgeRun, Inc.
++ * Author: RidgeRun, Inc.
++ *         Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
++ *
++ */
++#include <linux/kdev_t.h>
++#include <linux/time.h>
++#include <linux/devfs_fs_kernel.h>
++#include <linux/module.h>
++#include <linux/mm.h> 
++#include <linux/slab.h>
++#include <linux/init.h> 
++#include <asm/uaccess.h>
++#include <asm/irq.h>
++#include <asm/smplock.h>
++#include <asm/pgtable.h>
++#include "mem_user.h"
++#include "user_util.h"
++ 
++/* These are set in mmapper_init, which is called at boot time */
++static unsigned long mmapper_size;
++static unsigned long p_buf = 0;
++static char *v_buf = NULL;
++
++static ssize_t
++mmapper_read(struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++      if(*ppos > mmapper_size)
++              return -EINVAL;
++
++      if(count + *ppos > mmapper_size)
++              count = count + *ppos - mmapper_size;
++
++      if(count < 0)
++              return -EINVAL;
++ 
++      copy_to_user(buf,&v_buf[*ppos],count);
++      
++      return count;
++}
++
++static ssize_t
++mmapper_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
++{
++      if(*ppos > mmapper_size)
++              return -EINVAL;
++
++      if(count + *ppos > mmapper_size)
++              count = count + *ppos - mmapper_size;
++
++      if(count < 0)
++              return -EINVAL;
++
++      copy_from_user(&v_buf[*ppos],buf,count);
++      
++      return count;
++}
++
++static int 
++mmapper_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++       unsigned long arg)
++{
++      return(-ENOIOCTLCMD);
++}
++
++static int 
++mmapper_mmap(struct file *file, struct vm_area_struct * vma)
++{
++      int ret = -EINVAL;
++      int size;
++
++      lock_kernel();
++      if (vma->vm_pgoff != 0)
++              goto out;
++      
++      size = vma->vm_end - vma->vm_start;
++      if(size > mmapper_size) return(-EFAULT);
++
++      /* XXX A comment above remap_page_range says it should only be
++       * called when the mm semaphore is held
++       */
++      if (remap_page_range(vma->vm_start, p_buf, size, vma->vm_page_prot))
++              goto out;
++      ret = 0;
++out:
++      unlock_kernel();
++      return ret;
++}
++
++static int
++mmapper_open(struct inode *inode, struct file *file)
++{
++      return 0;
++}
++
++static int 
++mmapper_release(struct inode *inode, struct file *file)
++{
++      return 0;
++}
++
++static struct file_operations mmapper_fops = {
++      .owner          = THIS_MODULE,
++      .read           = mmapper_read,
++      .write          = mmapper_write,
++      .ioctl          = mmapper_ioctl,
++      .mmap           = mmapper_mmap,
++      .open           = mmapper_open,
++      .release        = mmapper_release,
++};
++
++static int __init mmapper_init(void)
++{
++      printk(KERN_INFO "Mapper v0.1\n");
++
++      v_buf = (char *) find_iomem("mmapper", &mmapper_size);
++      if(mmapper_size == 0){
++              printk(KERN_ERR "mmapper_init - find_iomem failed\n");
++              return(0);
++      }
++
++      p_buf = __pa(v_buf);
++
++      devfs_register (NULL, "mmapper", DEVFS_FL_DEFAULT, 
++                      30, 0, S_IFCHR | S_IRUGO | S_IWUGO, 
++                      &mmapper_fops, NULL); 
++      devfs_mk_symlink(NULL, "mmapper0", DEVFS_FL_DEFAULT, "mmapper",
++                       NULL, NULL);
++      return(0);
++}
++
++static void mmapper_exit(void)
++{
++}
++
++module_init(mmapper_init);
++module_exit(mmapper_exit);
++
++MODULE_AUTHOR("Greg Lonnon <glonnon@ridgerun.com>");
++MODULE_DESCRIPTION("DSPLinux simulator mmapper driver");
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/net_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/net_kern.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/net_kern.c    2005-05-03 22:28:14.228447160 +0300
+@@ -0,0 +1,903 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ * Licensed under the GPL.
++ */
++
++#include "linux/config.h"
++#include "linux/kernel.h"
++#include "linux/netdevice.h"
++#include "linux/rtnetlink.h"
++#include "linux/skbuff.h"
++#include "linux/socket.h"
++#include "linux/spinlock.h"
++#include "linux/module.h"
++#include "linux/init.h"
++#include "linux/etherdevice.h"
++#include "linux/list.h"
++#include "linux/inetdevice.h"
++#include "linux/ctype.h"
++#include "linux/bootmem.h"
++#include "linux/ethtool.h"
++#include "asm/uaccess.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "mconsole_kern.h"
++#include "init.h"
++#include "irq_user.h"
++#include "irq_kern.h"
++
++static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED;
++LIST_HEAD(opened);
++
++static int uml_net_rx(struct net_device *dev)
++{
++      struct uml_net_private *lp = dev->priv;
++      int pkt_len;
++      struct sk_buff *skb;
++
++      /* If we can't allocate memory, try again next round. */
++      skb = dev_alloc_skb(dev->mtu);
++      if (skb == NULL) {
++              lp->stats.rx_dropped++;
++              return 0;
++      }
++
++      skb->dev = dev;
++      skb_put(skb, dev->mtu);
++      skb->mac.raw = skb->data;
++      pkt_len = (*lp->read)(lp->fd, &skb, lp);
++
++      if (pkt_len > 0) {
++              skb_trim(skb, pkt_len);
++              skb->protocol = (*lp->protocol)(skb);
++              netif_rx(skb);
++
++              lp->stats.rx_bytes += skb->len;
++              lp->stats.rx_packets++;
++              return pkt_len;
++      }
++
++      kfree_skb(skb);
++      return pkt_len;
++}
++
++void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++      struct net_device *dev = dev_id;
++      struct uml_net_private *lp = dev->priv;
++      int err;
++
++      if(!netif_running(dev))
++              return;
++
++      spin_lock(&lp->lock);
++      while((err = uml_net_rx(dev)) > 0) ;
++      if(err < 0) {
++              printk(KERN_ERR 
++                     "Device '%s' read returned %d, shutting it down\n", 
++                     dev->name, err);
++              dev_close(dev);
++              goto out;
++      }
++      reactivate_fd(lp->fd, UM_ETH_IRQ);
++
++ out:
++      spin_unlock(&lp->lock);
++}
++
++static int uml_net_open(struct net_device *dev)
++{
++      struct uml_net_private *lp = dev->priv;
++      char addr[sizeof("255.255.255.255\0")];
++      int err;
++
++      spin_lock(&lp->lock);
++
++      if(lp->fd >= 0){
++              err = -ENXIO;
++              goto out;
++      }
++
++      if(!lp->have_mac){
++              dev_ip_addr(dev, addr, &lp->mac[2]);
++              set_ether_mac(dev, lp->mac);
++      }
++
++      lp->fd = (*lp->open)(&lp->user);
++      if(lp->fd < 0){
++              err = lp->fd;
++              goto out;
++      }
++
++      err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt,
++                           SA_INTERRUPT | SA_SHIRQ, dev->name, dev);
++      if(err != 0){
++              printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err);
++              if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
++              lp->fd = -1;
++              err = -ENETUNREACH;
++      }
++
++      lp->tl.data = (unsigned long) &lp->user;
++      netif_start_queue(dev);
++
++      spin_lock(&opened_lock);
++      list_add(&lp->list, &opened);
++      spin_unlock(&opened_lock);
++       /* clear buffer - it can happen that the host side of the interface
++        * is full when we get here.  In this case, new data is never queued,
++        * SIGIOs never arrive, and the net never works.
++        */
++      while((err = uml_net_rx(dev)) > 0) ;
++
++      MOD_INC_USE_COUNT;
++ out:
++      spin_unlock(&lp->lock);
++      return(err);
++}
++
++static int uml_net_close(struct net_device *dev)
++{
++      struct uml_net_private *lp = dev->priv;
++      
++      netif_stop_queue(dev);
++      spin_lock(&lp->lock);
++
++      free_irq(dev->irq, dev);
++      if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
++      lp->fd = -1;
++      spin_lock(&opened_lock);
++      list_del(&lp->list);
++      spin_unlock(&opened_lock);
++
++      MOD_DEC_USE_COUNT;
++      spin_unlock(&lp->lock);
++      return 0;
++}
++
++static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++      struct uml_net_private *lp = dev->priv;
++      unsigned long flags;
++      int len;
++
++      netif_stop_queue(dev);
++
++      spin_lock_irqsave(&lp->lock, flags);
++
++      len = (*lp->write)(lp->fd, &skb, lp);
++
++      if(len == skb->len) {
++              lp->stats.tx_packets++;
++              lp->stats.tx_bytes += skb->len;
++              dev->trans_start = jiffies;
++              netif_start_queue(dev);
++
++              /* this is normally done in the interrupt when tx finishes */
++              netif_wake_queue(dev);
++      } 
++      else if(len == 0){
++              netif_start_queue(dev);
++              lp->stats.tx_dropped++;
++      }
++      else {
++              netif_start_queue(dev);
++              printk(KERN_ERR "uml_net_start_xmit: failed(%d)\n", len);
++      }
++
++      spin_unlock_irqrestore(&lp->lock, flags);
++
++      dev_kfree_skb(skb);
++
++      return 0;
++}
++
++static struct net_device_stats *uml_net_get_stats(struct net_device *dev)
++{
++      struct uml_net_private *lp = dev->priv;
++      return &lp->stats;
++}
++
++static void uml_net_set_multicast_list(struct net_device *dev)
++{
++      if (dev->flags & IFF_PROMISC) return;
++      else if (dev->mc_count) dev->flags |= IFF_ALLMULTI;
++      else dev->flags &= ~IFF_ALLMULTI;
++}
++
++static void uml_net_tx_timeout(struct net_device *dev)
++{
++      dev->trans_start = jiffies;
++      netif_wake_queue(dev);
++}
++
++static int uml_net_set_mac(struct net_device *dev, void *addr)
++{
++      struct uml_net_private *lp = dev->priv;
++      struct sockaddr *hwaddr = addr;
++
++      spin_lock(&lp->lock);
++      memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);
++      spin_unlock(&lp->lock);
++
++      return(0);
++}
++
++static int uml_net_change_mtu(struct net_device *dev, int new_mtu)
++{
++      struct uml_net_private *lp = dev->priv;
++      int err = 0;
++
++      spin_lock(&lp->lock);
++
++      new_mtu = (*lp->set_mtu)(new_mtu, &lp->user);
++      if(new_mtu < 0){
++              err = new_mtu;
++              goto out;
++      }
++
++      dev->mtu = new_mtu;
++
++ out:
++      spin_unlock(&lp->lock);
++      return err;
++}
++
++static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++      static const struct ethtool_drvinfo info = {
++              .cmd     = ETHTOOL_GDRVINFO,
++              .driver  = "uml virtual ethernet",
++              .version = "42",
++      };
++      void *useraddr;
++      u32 ethcmd;
++
++      switch (cmd) {
++      case SIOCETHTOOL:
++              useraddr = ifr->ifr_data;
++              if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
++                      return -EFAULT;
++              switch (ethcmd) {
++              case ETHTOOL_GDRVINFO:
++                      if (copy_to_user(useraddr, &info, sizeof(info)))
++                              return -EFAULT;
++                      return 0;
++              default:
++                      return -EOPNOTSUPP;
++              }
++      default:
++              return -EINVAL;
++      }
++}
++
++void uml_net_user_timer_expire(unsigned long _conn)
++{
++#ifdef undef
++      struct connection *conn = (struct connection *)_conn;
++
++      dprintk(KERN_INFO "uml_net_user_timer_expire [%p]\n", conn);
++      do_connect(conn);
++#endif
++}
++
++/*
++ * default do nothing hard header packet routines for struct net_device init.
++ * real ethernet transports will overwrite with real routines.
++ */
++static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev,
++                 unsigned short type, void *daddr, void *saddr, unsigned len)
++{
++      return(0); /* no change */
++}
++
++static int uml_net_rebuild_header(struct sk_buff *skb)
++{
++      return(0); /* ignore */ 
++}
++
++static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh)
++{
++      return(-1); /* fail */
++}
++
++static void uml_net_header_cache_update(struct hh_cache *hh,
++                 struct net_device *dev, unsigned char * haddr)
++{
++      /* ignore */
++}
++
++static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr)
++{
++      return(0); /* nothing */
++}
++
++static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED;
++static struct list_head devices = LIST_HEAD_INIT(devices);
++
++static int eth_configure(int n, void *init, char *mac,
++                       struct transport *transport)
++{
++      struct uml_net *device;
++      struct net_device *dev;
++      struct uml_net_private *lp;
++      int save, err, size;
++
++      size = transport->private_size + sizeof(struct uml_net_private) + 
++              sizeof(((struct uml_net_private *) 0)->user);
++
++      device = kmalloc(sizeof(*device), GFP_KERNEL);
++      if(device == NULL){
++              printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
++              return(1);
++      }
++
++      *device = ((struct uml_net) { .list     = LIST_HEAD_INIT(device->list),
++                                    .dev      = NULL,
++                                    .index    = n,
++                                    .mac      = { [ 0 ... 5 ] = 0 },
++                                    .have_mac = 0 });
++
++      spin_lock(&devices_lock);
++      list_add(&device->list, &devices);
++      spin_unlock(&devices_lock);
++
++      if(setup_etheraddr(mac, device->mac))
++              device->have_mac = 1;
++
++      printk(KERN_INFO "Netdevice %d ", n);
++      if(device->have_mac) printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
++                                  device->mac[0], device->mac[1], 
++                                  device->mac[2], device->mac[3], 
++                                  device->mac[4], device->mac[5]);
++      printk(": ");
++      dev = kmalloc(sizeof(*dev) + size, GFP_KERNEL);
++      if(dev == NULL){
++              printk(KERN_ERR "eth_configure: failed to allocate device\n");
++              return(1);
++      }
++      memset(dev, 0, sizeof(*dev) + size);
++
++      snprintf(dev->name, sizeof(dev->name), "eth%d", n);
++      dev->priv = (void *) &dev[1];
++      device->dev = dev;
++
++        dev->hard_header = uml_net_hard_header;
++        dev->rebuild_header = uml_net_rebuild_header;
++        dev->hard_header_cache = uml_net_header_cache;
++        dev->header_cache_update= uml_net_header_cache_update;
++        dev->hard_header_parse = uml_net_header_parse;
++
++      (*transport->kern->init)(dev, init);
++
++      dev->mtu = transport->user->max_packet;
++      dev->open = uml_net_open;
++      dev->hard_start_xmit = uml_net_start_xmit;
++      dev->stop = uml_net_close;
++      dev->get_stats = uml_net_get_stats;
++      dev->set_multicast_list = uml_net_set_multicast_list;
++      dev->tx_timeout = uml_net_tx_timeout;
++      dev->set_mac_address = uml_net_set_mac;
++      dev->change_mtu = uml_net_change_mtu;
++      dev->do_ioctl = uml_net_ioctl;
++      dev->watchdog_timeo = (HZ >> 1);
++      dev->irq = UM_ETH_IRQ;
++
++      rtnl_lock();
++      err = register_netdevice(dev);
++      rtnl_unlock();
++      if(err)
++              return(1);
++      lp = dev->priv;
++
++      /* lp.user is the first four bytes of the transport data, which
++       * has already been initialized.  This structure assignment will
++       * overwrite that, so we make sure that .user gets overwritten with
++       * what it already has.
++       */
++      save = lp->user[0];
++      *lp = ((struct uml_net_private) 
++              { .list                 = LIST_HEAD_INIT(lp->list),
++                .lock                 = SPIN_LOCK_UNLOCKED,
++                .dev                  = dev,
++                .fd                   = -1,
++                .mac                  = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
++                .have_mac             = device->have_mac,
++                .protocol             = transport->kern->protocol,
++                .open                 = transport->user->open,
++                .close                = transport->user->close,
++                .remove               = transport->user->remove,
++                .read                 = transport->kern->read,
++                .write                = transport->kern->write,
++                .add_address          = transport->user->add_address,
++                .delete_address       = transport->user->delete_address,
++                .set_mtu              = transport->user->set_mtu,
++                .user                 = { save } });
++      init_timer(&lp->tl);
++      lp->tl.function = uml_net_user_timer_expire;
++      memset(&lp->stats, 0, sizeof(lp->stats));
++      if(lp->have_mac) memcpy(lp->mac, device->mac, sizeof(lp->mac));
++
++      if(transport->user->init) 
++              (*transport->user->init)(&lp->user, dev);
++
++      if(device->have_mac)
++              set_ether_mac(dev, device->mac);
++      return(0);
++}
++
++static struct uml_net *find_device(int n)
++{
++      struct uml_net *device;
++      struct list_head *ele;
++
++      spin_lock(&devices_lock);
++      list_for_each(ele, &devices){
++              device = list_entry(ele, struct uml_net, list);
++              if(device->index == n)
++                      goto out;
++      }
++      device = NULL;
++ out:
++      spin_unlock(&devices_lock);
++      return(device);
++}
++
++static int eth_parse(char *str, int *index_out, char **str_out)
++{
++      char *end;
++      int n;
++
++      n = simple_strtoul(str, &end, 0);
++      if(end == str){
++              printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str);
++              return(1);
++      }
++      if(n < 0){
++              printk(KERN_ERR "eth_setup: device %d is negative\n", n);
++              return(1);
++      }
++      str = end;
++      if(*str != '='){
++              printk(KERN_ERR 
++                     "eth_setup: expected '=' after device number\n");
++              return(1);
++      }
++      str++;
++      if(find_device(n)){
++              printk(KERN_ERR "eth_setup: Device %d already configured\n",
++                     n);
++              return(1);
++      }
++      if(index_out) *index_out = n;
++      *str_out = str;
++      return(0);
++}
++
++struct eth_init {
++      struct list_head list;
++      char *init;
++      int index;
++};
++
++/* Filled in at boot time.  Will need locking if the transports become
++ * modular.
++ */
++struct list_head transports = LIST_HEAD_INIT(transports);
++
++/* Filled in during early boot */
++struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
++
++static int check_transport(struct transport *transport, char *eth, int n,
++                         void **init_out, char **mac_out)
++{
++      int len;
++
++      len = strlen(transport->name);
++      if(strncmp(eth, transport->name, len))
++              return(0);
++
++      eth += len;
++      if(*eth == ',')
++              eth++;
++      else if(*eth != '\0')
++              return(0);
++
++      *init_out = kmalloc(transport->setup_size, GFP_KERNEL);
++      if(*init_out == NULL)
++              return(1);
++
++      if(!transport->setup(eth, mac_out, *init_out)){
++              kfree(*init_out);
++              *init_out = NULL;
++      }
++      return(1);
++}
++
++void register_transport(struct transport *new)
++{
++      struct list_head *ele, *next;
++      struct eth_init *eth;
++      void *init;
++      char *mac = NULL;
++      int match;
++
++      list_add(&new->list, &transports);
++
++      list_for_each_safe(ele, next, &eth_cmd_line){
++              eth = list_entry(ele, struct eth_init, list);
++              match = check_transport(new, eth->init, eth->index, &init,
++                                      &mac);
++              if(!match)
++                      continue;
++              else if(init != NULL){
++                      eth_configure(eth->index, init, mac, new);
++                      kfree(init);
++              }
++              list_del(&eth->list);
++      }
++}
++
++static int eth_setup_common(char *str, int index)
++{
++      struct list_head *ele;
++      struct transport *transport;
++      void *init;
++      char *mac = NULL;
++
++      list_for_each(ele, &transports){
++              transport = list_entry(ele, struct transport, list);
++              if(!check_transport(transport, str, index, &init, &mac))
++                      continue;
++              if(init != NULL){
++                      eth_configure(index, init, mac, transport);
++                      kfree(init);
++              }
++              return(1);
++      }
++      return(0);
++}
++
++static int eth_setup(char *str)
++{
++      struct eth_init *new;
++      int n, err;
++
++      err = eth_parse(str, &n, &str);
++      if(err) return(1);
++
++      new = alloc_bootmem(sizeof(new));
++      if(new == NULL){
++              printk("eth_init : alloc_bootmem failed\n");
++              return(1);
++      }
++      *new = ((struct eth_init) { .list       = LIST_HEAD_INIT(new->list),
++                                  .index      = n,
++                                  .init       = str });
++      list_add_tail(&new->list, &eth_cmd_line);
++      return(1);
++}
++
++__setup("eth", eth_setup);
++__uml_help(eth_setup,
++"eth[0-9]+=<transport>,<options>\n"
++"    Configure a network device.\n\n"
++);
++
++static int eth_init(void)
++{
++      struct list_head *ele, *next;
++      struct eth_init *eth;
++
++      list_for_each_safe(ele, next, &eth_cmd_line){
++              eth = list_entry(ele, struct eth_init, list);
++
++              if(eth_setup_common(eth->init, eth->index))
++                      list_del(&eth->list);
++      }
++      
++      return(1);
++}
++
++__initcall(eth_init);
++
++static int net_config(char *str)
++{
++      int n, err;
++
++      err = eth_parse(str, &n, &str);
++      if(err) return(err);
++
++      str = uml_strdup(str);
++      if(str == NULL){
++              printk(KERN_ERR "net_config failed to strdup string\n");
++              return(-1);
++      }
++      err = !eth_setup_common(str, n);
++      if(err) 
++              kfree(str);
++      return(err);
++}
++
++static int net_remove(char *str)
++{
++      struct uml_net *device;
++      struct net_device *dev;
++      struct uml_net_private *lp;
++      char *end;
++      int n;
++
++      n = simple_strtoul(str, &end, 0);
++      if((*end != '\0') || (end == str))
++              return(-1);
++
++      device = find_device(n);
++      if(device == NULL)
++              return(0);
++
++      dev = device->dev;
++      lp = dev->priv;
++      if(lp->fd > 0) return(-1);
++      if(lp->remove != NULL) (*lp->remove)(&lp->user);
++      unregister_netdev(dev);
++
++      list_del(&device->list);
++      kfree(device);
++      return(0);
++}
++
++static struct mc_device net_mc = {
++      .name           = "eth",
++      .config         = net_config,
++      .get_config     = NULL,
++      .remove         = net_remove,
++};
++
++static int uml_inetaddr_event(struct notifier_block *this, unsigned long event,
++                            void *ptr)
++{
++      struct in_ifaddr *ifa = ptr;
++      u32 addr = ifa->ifa_address;
++      u32 netmask = ifa->ifa_mask;
++      struct net_device *dev = ifa->ifa_dev->dev;
++      struct uml_net_private *lp;
++      void (*proc)(unsigned char *, unsigned char *, void *);
++      unsigned char addr_buf[4], netmask_buf[4];
++
++      if(dev->open != uml_net_open) return(NOTIFY_DONE);
++
++      lp = dev->priv;
++
++      proc = NULL;
++      switch (event){
++      case NETDEV_UP:
++              proc = lp->add_address;
++              break;
++      case NETDEV_DOWN:
++              proc = lp->delete_address;
++              break;
++      }
++      if(proc != NULL){
++              addr_buf[0] = addr & 0xff;
++              addr_buf[1] = (addr >> 8) & 0xff;
++              addr_buf[2] = (addr >> 16) & 0xff;
++              addr_buf[3] = addr >> 24;
++              netmask_buf[0] = netmask & 0xff;
++              netmask_buf[1] = (netmask >> 8) & 0xff;
++              netmask_buf[2] = (netmask >> 16) & 0xff;
++              netmask_buf[3] = netmask >> 24;
++              (*proc)(addr_buf, netmask_buf, &lp->user);
++      }
++      return(NOTIFY_DONE);
++}
++
++struct notifier_block uml_inetaddr_notifier = {
++      .notifier_call          = uml_inetaddr_event,
++};
++
++static int uml_net_init(void)
++{
++      struct list_head *ele;
++      struct uml_net_private *lp;     
++      struct in_device *ip;
++      struct in_ifaddr *in;
++
++      mconsole_register_dev(&net_mc);
++      register_inetaddr_notifier(&uml_inetaddr_notifier);
++
++      /* Devices may have been opened already, so the uml_inetaddr_notifier
++       * didn't get a chance to run for them.  This fakes it so that
++       * addresses which have already been set up get handled properly.
++       */
++      list_for_each(ele, &opened){
++              lp = list_entry(ele, struct uml_net_private, list);
++              ip = lp->dev->ip_ptr;
++              if(ip == NULL) continue;
++              in = ip->ifa_list;
++              while(in != NULL){
++                      uml_inetaddr_event(NULL, NETDEV_UP, in);
++                      in = in->ifa_next;
++              }
++      }       
++
++      return(0);
++}
++
++__initcall(uml_net_init);
++
++static void close_devices(void)
++{
++      struct list_head *ele;
++      struct uml_net_private *lp;     
++
++      list_for_each(ele, &opened){
++              lp = list_entry(ele, struct uml_net_private, list);
++              if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
++              if(lp->remove != NULL) (*lp->remove)(&lp->user);
++      }
++}
++
++__uml_exitcall(close_devices);
++
++int setup_etheraddr(char *str, unsigned char *addr)
++{
++      char *end;
++      int i;
++
++      if(str == NULL)
++              return(0);
++      for(i=0;i<6;i++){
++              addr[i] = simple_strtoul(str, &end, 16);
++              if((end == str) ||
++                 ((*end != ':') && (*end != ',') && (*end != '\0'))){
++                      printk(KERN_ERR 
++                             "setup_etheraddr: failed to parse '%s' "
++                             "as an ethernet address\n", str);
++                      return(0);
++              }
++              str = end + 1;
++      }
++      if(addr[0] & 1){
++              printk(KERN_ERR 
++                     "Attempt to assign a broadcast ethernet address to a "
++                     "device disallowed\n");
++              return(0);
++      }
++      return(1);
++}
++
++void dev_ip_addr(void *d, char *buf, char *bin_buf)
++{
++      struct net_device *dev = d;
++      struct in_device *ip = dev->ip_ptr;
++      struct in_ifaddr *in;
++      u32 addr;
++
++      if((ip == NULL) || ((in = ip->ifa_list) == NULL)){
++              printk(KERN_WARNING "dev_ip_addr - device not assigned an "
++                     "IP address\n");
++              return;
++      }
++      addr = in->ifa_address;
++      sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, 
++              (addr >> 16) & 0xff, addr >> 24);
++      if(bin_buf){
++              bin_buf[0] = addr & 0xff;
++              bin_buf[1] = (addr >> 8) & 0xff;
++              bin_buf[2] = (addr >> 16) & 0xff;
++              bin_buf[3] = addr >> 24;
++      }
++}
++
++void set_ether_mac(void *d, unsigned char *addr)
++{
++      struct net_device *dev = d;
++
++      memcpy(dev->dev_addr, addr, ETH_ALEN);  
++}
++
++struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra)
++{
++      if((skb != NULL) && (skb_tailroom(skb) < extra)){
++              struct sk_buff *skb2;
++
++              skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC);
++              dev_kfree_skb(skb);
++              skb = skb2;
++      }
++      if(skb != NULL) skb_put(skb, extra);
++      return(skb);
++}
++
++void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, 
++                                      void *), 
++                  void *arg)
++{
++      struct net_device *dev = d;
++      struct in_device *ip = dev->ip_ptr;
++      struct in_ifaddr *in;
++      unsigned char address[4], netmask[4];
++
++      if(ip == NULL) return;
++      in = ip->ifa_list;
++      while(in != NULL){
++              address[0] = in->ifa_address & 0xff;
++              address[1] = (in->ifa_address >> 8) & 0xff;
++              address[2] = (in->ifa_address >> 16) & 0xff;
++              address[3] = in->ifa_address >> 24;
++              netmask[0] = in->ifa_mask & 0xff;
++              netmask[1] = (in->ifa_mask >> 8) & 0xff;
++              netmask[2] = (in->ifa_mask >> 16) & 0xff;
++              netmask[3] = in->ifa_mask >> 24;
++              (*cb)(address, netmask, arg);
++              in = in->ifa_next;
++      }
++}
++
++int dev_netmask(void *d, void *m)
++{
++      struct net_device *dev = d;
++      struct in_device *ip = dev->ip_ptr;
++      struct in_ifaddr *in;
++      __u32 *mask_out = m;
++
++      if(ip == NULL) 
++              return(1);
++
++      in = ip->ifa_list;
++      if(in == NULL) 
++              return(1);
++
++      *mask_out = in->ifa_mask;
++      return(0);
++}
++
++void *get_output_buffer(int *len_out)
++{
++      void *ret;
++
++      ret = (void *) __get_free_pages(GFP_KERNEL, 0);
++      if(ret) *len_out = PAGE_SIZE;
++      else *len_out = 0;
++      return(ret);
++}
++
++void free_output_buffer(void *buffer)
++{
++      free_pages((unsigned long) buffer, 0);
++}
++
++int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, 
++                   char **gate_addr)
++{
++      char *remain;
++
++      remain = split_if_spec(str, dev_name, mac_out, gate_addr, NULL);
++      if(remain != NULL){
++              printk("tap_setup_common - Extra garbage on specification : "
++                     "'%s'\n", remain);
++              return(1);
++      }
++
++      return(0);
++}
++
++unsigned short eth_protocol(struct sk_buff *skb)
++{
++      return(eth_type_trans(skb, skb->dev));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/net_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/net_user.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/net_user.c    2005-05-03 22:28:14.229447008 +0300
+@@ -0,0 +1,253 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stddef.h>
++#include <stdarg.h>
++#include <unistd.h>
++#include <stdio.h>
++#include <errno.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/socket.h>
++#include <sys/wait.h>
++#include "user.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "net_user.h"
++#include "helper.h"
++#include "os.h"
++
++int tap_open_common(void *dev, char *gate_addr)
++{
++      int tap_addr[4];
++
++      if(gate_addr == NULL) return(0);
++      if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], 
++                &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){
++              printk("Invalid tap IP address - '%s'\n", gate_addr);
++              return(-EINVAL);
++      }
++      return(0);
++}
++
++void tap_check_ips(char *gate_addr, char *eth_addr)
++{
++      int tap_addr[4];
++
++      if((gate_addr != NULL) && 
++         (sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], 
++                 &tap_addr[1], &tap_addr[2], &tap_addr[3]) == 4) &&
++         (eth_addr[0] == tap_addr[0]) && 
++         (eth_addr[1] == tap_addr[1]) && 
++         (eth_addr[2] == tap_addr[2]) && 
++         (eth_addr[3] == tap_addr[3])){
++              printk("The tap IP address and the UML eth IP address"
++                     " must be different\n");
++      }
++}
++
++void read_output(int fd, char *output, int len)
++{
++      int remain, n, actual;
++      char c;
++
++      if(output == NULL){
++              output = &c;
++              len = sizeof(c);
++      }
++              
++      *output = '\0';
++      n = os_read_file(fd, &remain, sizeof(remain));
++      if(n != sizeof(remain)){
++              printk("read_output - read of length failed, err = %d\n", -n);
++              return;
++      }
++
++      while(remain != 0){
++              n = (remain < len) ? remain : len;
++              actual = os_read_file(fd, output, n);
++              if(actual != n){
++                      printk("read_output - read of data failed, "
++                             "err = %d\n", -actual);
++                      return;
++              }
++              remain -= actual;
++      }
++      return;
++}
++
++int net_read(int fd, void *buf, int len)
++{
++      int n;
++
++      n = os_read_file(fd,  buf,  len);
++
++      if(n == -EAGAIN) 
++              return(0);
++      else if(n == 0) 
++              return(-ENOTCONN);
++      return(n);
++}
++
++int net_recvfrom(int fd, void *buf, int len)
++{
++      int n;
++
++      while(((n = recvfrom(fd,  buf,  len, 0, NULL, NULL)) < 0) && 
++            (errno == EINTR)) ;
++
++      if(n < 0){
++              if(errno == EAGAIN) return(0);
++              return(-errno);
++      }
++      else if(n == 0) return(-ENOTCONN);
++      return(n);
++}
++
++int net_write(int fd, void *buf, int len)
++{
++      int n;
++
++      n = os_write_file(fd, buf, len);
++
++      if(n == -EAGAIN) 
++              return(0);
++      else if(n == 0) 
++              return(-ENOTCONN);
++      return(n);
++}
++
++int net_send(int fd, void *buf, int len)
++{
++      int n;
++
++      while(((n = send(fd, buf, len, 0)) < 0) && (errno == EINTR)) ;
++      if(n < 0){
++              if(errno == EAGAIN) return(0);
++              return(-errno);
++      }
++      else if(n == 0) return(-ENOTCONN);
++      return(n);      
++}
++
++int net_sendto(int fd, void *buf, int len, void *to, int sock_len)
++{
++      int n;
++
++      while(((n = sendto(fd, buf, len, 0, (struct sockaddr *) to,
++                         sock_len)) < 0) && (errno == EINTR)) ;
++      if(n < 0){
++              if(errno == EAGAIN) return(0);
++              return(-errno);
++      }
++      else if(n == 0) return(-ENOTCONN);
++      return(n);      
++}
++
++struct change_pre_exec_data {
++      int close_me;
++      int stdout;
++};
++
++static void change_pre_exec(void *arg)
++{
++      struct change_pre_exec_data *data = arg;
++
++      os_close_file(data->close_me);
++      dup2(data->stdout, 1);
++}
++
++static int change_tramp(char **argv, char *output, int output_len)
++{
++      int pid, fds[2], err;
++      struct change_pre_exec_data pe_data;
++
++      err = os_pipe(fds, 1, 0);
++      if(err < 0){
++              printk("change_tramp - pipe failed, err = %d\n", -err);
++              return(err);
++      }
++      pe_data.close_me = fds[0];
++      pe_data.stdout = fds[1];
++      pid = run_helper(change_pre_exec, &pe_data, argv, NULL);
++
++      read_output(fds[0], output, output_len);
++      os_close_file(fds[0]);
++      os_close_file(fds[1]);
++      CATCH_EINTR(waitpid(pid, NULL, 0));     
++      return(pid);
++}
++
++static void change(char *dev, char *what, unsigned char *addr,
++                 unsigned char *netmask)
++{
++      char addr_buf[sizeof("255.255.255.255\0")];
++      char netmask_buf[sizeof("255.255.255.255\0")];
++      char version[sizeof("nnnnn\0")];
++      char *argv[] = { "uml_net", version, what, dev, addr_buf, 
++                       netmask_buf, NULL };
++      char *output;
++      int output_len, pid;
++
++      sprintf(version, "%d", UML_NET_VERSION);
++      sprintf(addr_buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
++      sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1], 
++              netmask[2], netmask[3]);
++
++      output_len = page_size();
++      output = um_kmalloc(output_len);
++      if(output == NULL)
++              printk("change : failed to allocate output buffer\n");
++
++      pid = change_tramp(argv, output, output_len);
++      if(pid < 0) return;
++
++      if(output != NULL){
++              printk("%s", output);
++              kfree(output);
++      }
++}
++
++void open_addr(unsigned char *addr, unsigned char *netmask, void *arg)
++{
++      change(arg, "add", addr, netmask);
++}
++
++void close_addr(unsigned char *addr, unsigned char *netmask, void *arg)
++{
++      change(arg, "del", addr, netmask);
++}
++
++char *split_if_spec(char *str, ...)
++{
++      char **arg, *end;
++      va_list ap;
++
++      va_start(ap, str);
++      while((arg = va_arg(ap, char **)) != NULL){
++              if(*str == '\0')
++                      return(NULL);
++              end = strchr(str, ',');
++              if(end != str)
++                      *arg = str;
++              if(end == NULL)
++                      return(NULL);
++              *end++ = '\0';
++              str = end;
++      }
++      va_end(ap);
++      return(str);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/null.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/null.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/null.c        2005-05-03 22:28:14.230446856 +0300
+@@ -0,0 +1,55 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <errno.h>
++#include "chan_user.h"
++#include "os.h"
++
++static int null_chan;
++
++void *null_init(char *str, int device, struct chan_opts *opts)
++{
++      return(&null_chan);
++}
++
++int null_open(int input, int output, int primary, void *d, char **dev_out)
++{
++      *dev_out = NULL;
++      return(os_open_file(DEV_NULL, of_rdwr(OPENFLAGS()), 0));
++}
++
++int null_read(int fd, char *c_out, void *unused)
++{
++      return(-ENODEV);
++}
++
++void null_free(void *data)
++{
++}
++
++struct chan_ops null_ops = {
++      .type           = "null",
++      .init           = null_init,
++      .open           = null_open,
++      .close          = generic_close,
++      .read           = null_read,
++      .write          = generic_write,
++      .console_write  = generic_console_write,
++      .window_size    = generic_window_size,
++      .free           = null_free,
++      .winch          = 0,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/pcap_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/pcap_kern.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/pcap_kern.c   2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,127 @@
++/*
++ * Copyright (C) 2002 Jeff Dike <jdike@karaya.com>
++ * Licensed under the GPL.
++ */
++
++#include "linux/init.h"
++#include "linux/netdevice.h"
++#include "linux/etherdevice.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "pcap_user.h"
++
++struct pcap_init {
++      char *host_if;
++      int promisc;
++      int optimize;
++      char *filter;
++};
++
++void pcap_init(struct net_device *dev, void *data)
++{
++      struct uml_net_private *pri;
++      struct pcap_data *ppri;
++      struct pcap_init *init = data;
++
++      init_etherdev(dev, 0);
++      pri = dev->priv;
++      ppri = (struct pcap_data *) pri->user;
++      *ppri = ((struct pcap_data)
++              { .host_if      = init->host_if,
++                .promisc      = init->promisc,
++                .optimize     = init->optimize,
++                .filter       = init->filter,
++                .compiled     = NULL,
++                .pcap         = NULL });
++}
++
++static int pcap_read(int fd, struct sk_buff **skb, 
++                     struct uml_net_private *lp)
++{
++      *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
++      if(*skb == NULL) return(-ENOMEM);
++      return(pcap_user_read(fd, (*skb)->mac.raw, 
++                            (*skb)->dev->mtu + ETH_HEADER_OTHER,
++                            (struct pcap_data *) &lp->user));
++}
++
++static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
++{
++      return(-EPERM);
++}
++
++static struct net_kern_info pcap_kern_info = {
++      .init                   = pcap_init,
++      .protocol               = eth_protocol,
++      .read                   = pcap_read,
++      .write                  = pcap_write,
++};
++
++int pcap_setup(char *str, char **mac_out, void *data)
++{
++      struct pcap_init *init = data;
++      char *remain, *host_if = NULL, *options[2] = { NULL, NULL };
++      int i;
++
++      *init = ((struct pcap_init)
++              { .host_if      = "eth0",
++                .promisc      = 1,
++                .optimize     = 0,
++                .filter       = NULL });
++
++      remain = split_if_spec(str, &host_if, &init->filter, 
++                             &options[0], &options[1], NULL);
++      if(remain != NULL){
++              printk(KERN_ERR "pcap_setup - Extra garbage on "
++                     "specification : '%s'\n", remain);
++              return(0);
++      }
++
++      if(host_if != NULL)
++              init->host_if = host_if;
++
++      for(i = 0; i < sizeof(options)/sizeof(options[0]); i++){
++              if(options[i] == NULL)
++                      continue;
++              if(!strcmp(options[i], "promisc"))
++                      init->promisc = 1;
++              else if(!strcmp(options[i], "nopromisc"))
++                      init->promisc = 0;
++              else if(!strcmp(options[i], "optimize"))
++                      init->optimize = 1;
++              else if(!strcmp(options[i], "nooptimize"))
++                      init->optimize = 0;
++              else printk("pcap_setup : bad option - '%s'\n", options[i]);
++      }
++
++      return(1);
++}
++
++static struct transport pcap_transport = {
++      .list           = LIST_HEAD_INIT(pcap_transport.list),
++      .name           = "pcap",
++      .setup          = pcap_setup,
++      .user           = &pcap_user_info,
++      .kern           = &pcap_kern_info,
++      .private_size   = sizeof(struct pcap_data),
++      .setup_size     = sizeof(struct pcap_init),
++};
++
++static int register_pcap(void)
++{
++      register_transport(&pcap_transport);
++      return(1);
++}
++
++__initcall(register_pcap);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/pcap_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/pcap_user.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/pcap_user.c   2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,143 @@
++/*
++ * Copyright (C) 2002 Jeff Dike <jdike@karaya.com>
++ * Licensed under the GPL.
++ */
++
++#include <unistd.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <pcap.h>
++#include <asm/types.h>
++#include "net_user.h"
++#include "pcap_user.h"
++#include "user.h"
++
++#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
++
++#define PCAP_FD(p) (*(int *)(p))
++
++static void pcap_user_init(void *data, void *dev)
++{
++      struct pcap_data *pri = data;
++      pcap_t *p;
++      char errors[PCAP_ERRBUF_SIZE];
++
++      p = pcap_open_live(pri->host_if, MAX_PACKET, pri->promisc, 0, errors);
++      if(p == NULL){
++              printk("pcap_user_init : pcap_open_live failed - '%s'\n", 
++                     errors);
++              return;
++      }
++
++      pri->dev = dev;
++      pri->pcap = p;
++}
++
++static int pcap_open(void *data)
++{
++      struct pcap_data *pri = data;
++      __u32 netmask;
++      int err;
++
++      if(pri->pcap == NULL)
++              return(-ENODEV);
++
++      if(pri->filter != NULL){
++              err = dev_netmask(pri->dev, &netmask);
++              if(err < 0){
++                      printk("pcap_open : dev_netmask failed\n");
++                      return(-EIO);
++              }
++
++              pri->compiled = um_kmalloc(sizeof(struct bpf_program));
++              if(pri->compiled == NULL){
++                      printk("pcap_open : kmalloc failed\n");
++                      return(-ENOMEM);
++              }
++              
++              err = pcap_compile(pri->pcap, 
++                                 (struct bpf_program *) pri->compiled, 
++                                 pri->filter, pri->optimize, netmask);
++              if(err < 0){
++                      printk("pcap_open : pcap_compile failed - '%s'\n", 
++                             pcap_geterr(pri->pcap));
++                      return(-EIO);
++              }
++
++              err = pcap_setfilter(pri->pcap, pri->compiled);
++              if(err < 0){
++                      printk("pcap_open : pcap_setfilter failed - '%s'\n", 
++                             pcap_geterr(pri->pcap));
++                      return(-EIO);
++              }
++      }
++      
++      return(PCAP_FD(pri->pcap));
++}
++
++static void pcap_remove(void *data)
++{
++      struct pcap_data *pri = data;
++
++      if(pri->compiled != NULL)
++              pcap_freecode(pri->compiled);
++
++      pcap_close(pri->pcap);
++}
++
++struct pcap_handler_data {
++      char *buffer;
++      int len;
++};
++
++static void handler(u_char *data, const struct pcap_pkthdr *header, 
++                  const u_char *packet)
++{
++      int len;
++
++      struct pcap_handler_data *hdata = (struct pcap_handler_data *) data;
++
++      len = hdata->len < header->caplen ? hdata->len : header->caplen;
++      memcpy(hdata->buffer, packet, len);
++      hdata->len = len;
++}
++
++int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri)
++{
++      struct pcap_handler_data hdata = ((struct pcap_handler_data)
++                                        { .buffer     = buffer,
++                                          .len        = len });
++      int n;
++
++      n = pcap_dispatch(pri->pcap, 1, handler, (u_char *) &hdata);
++      if(n < 0){
++              printk("pcap_dispatch failed - %s\n", pcap_geterr(pri->pcap));
++              return(-EIO);
++      }
++      else if(n == 0) 
++              return(0);
++      return(hdata.len);
++}
++
++struct net_user_info pcap_user_info = {
++      .init           = pcap_user_init,
++      .open           = pcap_open,
++      .close          = NULL,
++      .remove         = pcap_remove,
++      .set_mtu        = NULL,
++      .add_address    = NULL,
++      .delete_address = NULL,
++      .max_packet     = MAX_PACKET - ETH_HEADER_OTHER
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/pcap_user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/pcap_user.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/pcap_user.h   2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,31 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "net_user.h"
++
++struct pcap_data {
++      char *host_if;
++      int promisc;
++      int optimize;
++      char *filter;
++      void *compiled;
++      void *pcap;
++      void *dev;
++};
++
++extern struct net_user_info pcap_user_info;
++
++extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/port.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/port.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/port.h        2005-05-03 22:28:14.234446248 +0300
+@@ -0,0 +1,30 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PORT_H__
++#define __PORT_H__
++
++extern void *port_data(int port);
++extern int port_wait(void *data);
++extern void port_kern_close(void *d);
++extern int port_connection(int fd, int *socket_out, int *pid_out);
++extern int port_listen_fd(int port);
++extern void port_read(int fd, void *data);
++extern void port_kern_free(void *d);
++extern int port_rcv_fd(int fd);
++extern void port_remove_dev(void *d);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/port_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/port_kern.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/port_kern.c   2005-05-03 22:28:14.235446096 +0300
+@@ -0,0 +1,303 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/list.h"
++#include "linux/sched.h"
++#include "linux/slab.h"
++#include "linux/irq.h"
++#include "linux/spinlock.h"
++#include "linux/errno.h"
++#include "asm/semaphore.h"
++#include "asm/errno.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "irq_user.h"
++#include "irq_kern.h"
++#include "port.h"
++#include "init.h"
++#include "os.h"
++
++struct port_list {
++      struct list_head list;
++      int has_connection;
++      struct semaphore sem;
++      int port;
++      int fd;
++      spinlock_t lock;
++      struct list_head pending;
++      struct list_head connections;
++};
++
++struct port_dev {
++      struct port_list *port;
++      int helper_pid;
++      int telnetd_pid;
++};
++
++struct connection {
++      struct list_head list;
++      int fd;
++      int helper_pid;
++      int socket[2];
++      int telnetd_pid;
++      struct port_list *port;
++};
++
++static void pipe_interrupt(int irq, void *data, struct pt_regs *regs)
++{
++      struct connection *conn = data;
++      int fd;
++
++      fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
++      if(fd < 0){
++              if(fd == -EAGAIN)
++                      return;
++
++              printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", 
++                     -fd);
++              os_close_file(conn->fd);
++      }
++
++      list_del(&conn->list);
++
++      conn->fd = fd;
++      list_add(&conn->list, &conn->port->connections);
++
++      up(&conn->port->sem);
++}
++
++static int port_accept(struct port_list *port)
++{
++      struct connection *conn;
++      int fd, socket[2], pid, ret = 0;
++
++      fd = port_connection(port->fd, socket, &pid);
++      if(fd < 0){
++              if(fd != -EAGAIN)
++                      printk(KERN_ERR "port_accept : port_connection "
++                             "returned %d\n", -fd);
++              goto out;
++      }
++
++      conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
++      if(conn == NULL){
++              printk(KERN_ERR "port_accept : failed to allocate "
++                     "connection\n");
++              goto out_close;
++      }
++      *conn = ((struct connection) 
++              { .list         = LIST_HEAD_INIT(conn->list),
++                .fd           = fd,
++                .socket       = { socket[0], socket[1] },
++                .telnetd_pid  = pid,
++                .port         = port });
++
++      if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, 
++                        SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
++                        "telnetd", conn)){
++              printk(KERN_ERR "port_accept : failed to get IRQ for "
++                     "telnetd\n");
++              goto out_free;
++      }
++
++      list_add(&conn->list, &port->pending);
++      return(1);
++
++ out_free:
++      kfree(conn);
++ out_close:
++      os_close_file(fd);
++      if(pid != -1) 
++              os_kill_process(pid, 1);
++ out:
++      return(ret);
++} 
++
++DECLARE_MUTEX(ports_sem);
++struct list_head ports = LIST_HEAD_INIT(ports);
++
++void port_task_proc(void *unused)
++{
++      struct port_list *port;
++      struct list_head *ele;
++      unsigned long flags;
++
++      save_flags(flags);
++      list_for_each(ele, &ports){
++              port = list_entry(ele, struct port_list, list);
++              if(!port->has_connection)
++                      continue;
++              reactivate_fd(port->fd, ACCEPT_IRQ);
++              while(port_accept(port)) ;
++              port->has_connection = 0;
++      }
++      restore_flags(flags);
++}
++
++struct tq_struct port_task = {
++      .routine        = port_task_proc,
++      .data           = NULL
++};
++
++static void port_interrupt(int irq, void *data, struct pt_regs *regs)
++{
++      struct port_list *port = data;
++
++      port->has_connection = 1;
++      schedule_task(&port_task);
++} 
++
++void *port_data(int port_num)
++{
++      struct list_head *ele;
++      struct port_list *port;
++      struct port_dev *dev = NULL;
++      int fd;
++
++      down(&ports_sem);
++      list_for_each(ele, &ports){
++              port = list_entry(ele, struct port_list, list);
++              if(port->port == port_num) goto found;
++      }
++      port = kmalloc(sizeof(struct port_list), GFP_KERNEL);
++      if(port == NULL){
++              printk(KERN_ERR "Allocation of port list failed\n");
++              goto out;
++      }
++
++      fd = port_listen_fd(port_num);
++      if(fd < 0){
++              printk(KERN_ERR "binding to port %d failed, errno = %d\n",
++                     port_num, -fd);
++              goto out_free;
++      }
++      if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, 
++                        SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "port",
++                        port)){
++              printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
++              goto out_close;
++      }
++
++      *port = ((struct port_list) 
++              { .list                 = LIST_HEAD_INIT(port->list),
++                .has_connection       = 0,
++                .sem                  = __SEMAPHORE_INITIALIZER(port->sem, 
++                                                                0),
++                .lock                 = SPIN_LOCK_UNLOCKED,
++                .port                 = port_num,
++                .fd                   = fd,
++                .pending              = LIST_HEAD_INIT(port->pending),
++                .connections          = LIST_HEAD_INIT(port->connections) });
++      list_add(&port->list, &ports);
++
++ found:
++      dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL);
++      if(dev == NULL){
++              printk(KERN_ERR "Allocation of port device entry failed\n");
++              goto out;
++      }
++
++      *dev = ((struct port_dev) { .port               = port,
++                                  .helper_pid         = -1,
++                                  .telnetd_pid        = -1 });
++      goto out;
++
++ out_free:
++      kfree(port);
++ out_close:
++      os_close_file(fd);
++ out:
++      up(&ports_sem);
++      return(dev);
++}
++
++int port_wait(void *data)
++{
++      struct port_dev *dev = data;
++      struct connection *conn;
++      struct port_list *port = dev->port;
++      int fd;
++
++      while(1){
++              if(down_interruptible(&port->sem))
++                      return(-ERESTARTSYS);
++
++              spin_lock(&port->lock);
++
++              conn = list_entry(port->connections.next, struct connection, 
++                                list);
++              list_del(&conn->list);
++              spin_unlock(&port->lock);
++
++              os_shutdown_socket(conn->socket[0], 1, 1);
++              os_close_file(conn->socket[0]);
++              os_shutdown_socket(conn->socket[1], 1, 1);
++              os_close_file(conn->socket[1]); 
++
++              /* This is done here because freeing an IRQ can't be done
++               * within the IRQ handler.  So, pipe_interrupt always ups
++               * the semaphore regardless of whether it got a successful
++               * connection.  Then we loop here throwing out failed 
++               * connections until a good one is found.
++               */
++              free_irq(TELNETD_IRQ, conn);
++
++              if(conn->fd >= 0) break;
++              os_close_file(conn->fd);
++              kfree(conn);
++      }
++
++      fd = conn->fd;
++      dev->helper_pid = conn->helper_pid;
++      dev->telnetd_pid = conn->telnetd_pid;
++      kfree(conn);
++
++      return(fd);
++}
++
++void port_remove_dev(void *d)
++{
++      struct port_dev *dev = d;
++
++      if(dev->helper_pid != -1)
++              os_kill_process(dev->helper_pid, 0);
++      if(dev->telnetd_pid != -1)
++              os_kill_process(dev->telnetd_pid, 1);
++      dev->helper_pid = -1;
++      dev->telnetd_pid = -1;
++}
++
++void port_kern_free(void *d)
++{
++      struct port_dev *dev = d;
++
++      port_remove_dev(dev);
++      kfree(dev);
++}
++
++static void free_port(void)
++{
++      struct list_head *ele;
++      struct port_list *port;
++
++      list_for_each(ele, &ports){
++              port = list_entry(ele, struct port_list, list);
++              free_irq_by_fd(port->fd);
++              os_close_file(port->fd);
++      }
++}
++
++__uml_exitcall(free_port);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/port_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/port_user.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/port_user.c   2005-05-03 22:28:14.237445792 +0300
+@@ -0,0 +1,224 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stddef.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <termios.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <netinet/in.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "chan_user.h"
++#include "port.h"
++#include "helper.h"
++#include "os.h"
++
++struct port_chan {
++      int raw;
++      struct termios tt;
++      void *kernel_data;
++      char dev[sizeof("32768\0")];
++};
++
++void *port_init(char *str, int device, struct chan_opts *opts)
++{
++      struct port_chan *data;
++      void *kern_data;
++      char *end;
++      int port;
++
++      if(*str != ':'){
++              printk("port_init : channel type 'port' must specify a "
++                     "port number\n");
++              return(NULL);
++      }
++      str++;
++      port = strtoul(str, &end, 0);
++      if((*end != '\0') || (end == str)){
++              printk("port_init : couldn't parse port '%s'\n", str);
++              return(NULL);
++      }
++
++      kern_data = port_data(port);
++      if(kern_data == NULL) 
++              return(NULL);
++
++      data = um_kmalloc(sizeof(*data));
++      if(data == NULL) 
++              goto err;
++
++      *data = ((struct port_chan) { .raw              = opts->raw,
++                                    .kernel_data      = kern_data });
++      sprintf(data->dev, "%d", port);
++
++      return(data);
++ err:
++      port_kern_free(kern_data);
++      return(NULL);
++}
++
++void port_free(void *d)
++{
++      struct port_chan *data = d;
++
++      port_kern_free(data->kernel_data);
++      kfree(data);
++}
++
++int port_open(int input, int output, int primary, void *d, char **dev_out)
++{
++      struct port_chan *data = d;
++      int fd, err;
++
++      fd = port_wait(data->kernel_data);
++      if((fd >= 0) && data->raw){
++              CATCH_EINTR(err = tcgetattr(fd, &data->tt));
++              if(err)
++                      return(err);
++
++              err = raw(fd);
++              if(err)
++                      return(err);
++      }
++      *dev_out = data->dev;
++      return(fd);
++}
++
++void port_close(int fd, void *d)
++{
++      struct port_chan *data = d;
++
++      port_remove_dev(data->kernel_data);
++      os_close_file(fd);
++}
++
++int port_console_write(int fd, const char *buf, int n, void *d)
++{
++      struct port_chan *data = d;
++
++      return(generic_console_write(fd, buf, n, &data->tt));
++}
++
++struct chan_ops port_ops = {
++      .type           = "port",
++      .init           = port_init,
++      .open           = port_open,
++      .close          = port_close,
++      .read           = generic_read,
++      .write          = generic_write,
++      .console_write  = port_console_write,
++      .window_size    = generic_window_size,
++      .free           = port_free,
++      .winch          = 1,
++};
++
++int port_listen_fd(int port)
++{
++      struct sockaddr_in addr;
++      int fd, err, arg;
++
++      fd = socket(PF_INET, SOCK_STREAM, 0);
++      if(fd == -1) 
++              return(-errno);
++
++      arg = 1;
++      if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0){
++              err = -errno;
++              goto out;
++      }
++
++      addr.sin_family = AF_INET;
++      addr.sin_port = htons(port);
++      addr.sin_addr.s_addr = htonl(INADDR_ANY);
++      if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0){
++              err = -errno;
++              goto out;
++      }
++  
++      if(listen(fd, 1) < 0){
++              err = -errno;
++              goto out;
++      }
++
++      err = os_set_fd_block(fd, 0);
++      if(err < 0)
++              goto out;
++
++      return(fd);
++ out:
++      os_close_file(fd);
++      return(err);
++}
++
++struct port_pre_exec_data {
++      int sock_fd;
++      int pipe_fd;
++};
++
++void port_pre_exec(void *arg)
++{
++      struct port_pre_exec_data *data = arg;
++
++      dup2(data->sock_fd, 0);
++      dup2(data->sock_fd, 1);
++      dup2(data->sock_fd, 2);
++      os_close_file(data->sock_fd);
++      dup2(data->pipe_fd, 3);
++      os_shutdown_socket(3, 1, 0);
++      os_close_file(data->pipe_fd);
++}
++
++int port_connection(int fd, int *socket, int *pid_out)
++{
++      int new, err;
++      char *argv[] = { "/usr/sbin/in.telnetd", "-L", 
++                       "/usr/lib/uml/port-helper", NULL };
++      struct port_pre_exec_data data;
++
++      new = os_accept_connection(fd);
++      if(new < 0)
++              return(new);
++
++      err = os_pipe(socket, 0, 0);
++      if(err < 0) 
++              goto out_close;
++
++      data = ((struct port_pre_exec_data)
++              { .sock_fd              = new,
++                .pipe_fd              = socket[1] });
++
++      err = run_helper(port_pre_exec, &data, argv, NULL);
++      if(err < 0) 
++              goto out_shutdown;
++
++      *pid_out = err;
++      return(new);
++
++ out_shutdown:
++      os_shutdown_socket(socket[0], 1, 1);
++      os_close_file(socket[0]);
++      os_shutdown_socket(socket[1], 1, 1);    
++      os_close_file(socket[1]);
++ out_close:
++      os_close_file(new);
++      return(err);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/pty.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/pty.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/pty.c 2005-05-03 22:28:14.238445640 +0300
+@@ -0,0 +1,159 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <termios.h>
++#include "chan_user.h"
++#include "user.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "os.h"
++
++struct pty_chan {
++      void (*announce)(char *dev_name, int dev);
++      int dev;
++      int raw;
++      struct termios tt;
++      char dev_name[sizeof("/dev/pts/0123456\0")];
++};
++
++void *pty_chan_init(char *str, int device, struct chan_opts *opts)
++{
++      struct pty_chan *data;
++
++      data = um_kmalloc(sizeof(*data));
++      if(data == NULL) return(NULL);
++      *data = ((struct pty_chan) { .announce          = opts->announce, 
++                                   .dev               = device,
++                                   .raw               = opts->raw });
++      return(data);
++}
++
++int pts_open(int input, int output, int primary, void *d, char **dev_out)
++{
++      struct pty_chan *data = d;
++      char *dev;
++      int fd, err;
++
++      fd = get_pty();
++      if(fd < 0){
++              printk("open_pts : Failed to open pts\n");
++              return(-errno);
++      }
++      if(data->raw){
++              CATCH_EINTR(err = tcgetattr(fd, &data->tt));
++              if(err)
++                      return(err);
++
++              err = raw(fd);
++              if(err)
++                      return(err);
++      }
++
++      dev = ptsname(fd);
++      sprintf(data->dev_name, "%s", dev);
++      *dev_out = data->dev_name;
++      if(data->announce) (*data->announce)(dev, data->dev);
++      return(fd);
++}
++
++int getmaster(char *line)
++{
++      char *pty, *bank, *cp;
++      int master, err;
++
++      pty = &line[strlen("/dev/ptyp")];
++      for (bank = "pqrs"; *bank; bank++) {
++              line[strlen("/dev/pty")] = *bank;
++              *pty = '0';
++              if (os_stat_file(line, NULL) < 0)
++                      break;
++              for (cp = "0123456789abcdef"; *cp; cp++) {
++                      *pty = *cp;
++                      master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
++                      if (master >= 0) {
++                              char *tp = &line[strlen("/dev/")];
++
++                              /* verify slave side is usable */
++                              *tp = 't';
++                              err = os_access(line, OS_ACC_RW_OK);
++                              *tp = 'p';
++                              if(err == 0) return(master);
++                              (void) os_close_file(master);
++                      }
++              }
++      }
++      return(-1);
++}
++
++int pty_open(int input, int output, int primary, void *d, char **dev_out)
++{
++      struct pty_chan *data = d;
++      int fd, err;
++      char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
++
++      fd = getmaster(dev);
++      if(fd < 0) 
++              return(-errno);
++      
++      if(data->raw){
++              err = raw(fd);
++              if(err)
++                      return(err);
++      }
++      
++      if(data->announce) (*data->announce)(dev, data->dev);
++
++      sprintf(data->dev_name, "%s", dev);
++      *dev_out = data->dev_name;
++      return(fd);
++}
++
++int pty_console_write(int fd, const char *buf, int n, void *d)
++{
++      struct pty_chan *data = d;
++
++      return(generic_console_write(fd, buf, n, &data->tt));
++}
++
++struct chan_ops pty_ops = {
++      .type           = "pty",
++      .init           = pty_chan_init,
++      .open           = pty_open,
++      .close          = generic_close,
++      .read           = generic_read,
++      .write          = generic_write,
++      .console_write  = pty_console_write,
++      .window_size    = generic_window_size,
++      .free           = generic_free,
++      .winch          = 0,
++};
++
++struct chan_ops pts_ops = {
++      .type           = "pts",
++      .init           = pty_chan_init,
++      .open           = pts_open,
++      .close          = generic_close,
++      .read           = generic_read,
++      .write          = generic_write,
++      .console_write  = pty_console_write,
++      .window_size    = generic_window_size,
++      .free           = generic_free,
++      .winch          = 0,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/slip.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/slip.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/slip.h        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,39 @@
++#ifndef __UM_SLIP_H
++#define __UM_SLIP_H
++
++#define BUF_SIZE 1500
++ /* two bytes each for a (pathological) max packet of escaped chars +  * 
++  * terminating END char + initial END char                            */
++#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
++
++struct slip_data {
++      void *dev;
++      char name[sizeof("slnnnnn\0")];
++      char *addr;
++      char *gate_addr;
++      int slave;
++      char ibuf[ENC_BUF_SIZE];
++      char obuf[ENC_BUF_SIZE];
++      int more; /* more data: do not read fd until ibuf has been drained */
++      int pos;
++      int esc;
++};
++
++extern struct net_user_info slip_user_info;
++
++extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
++extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri);
++extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/slip_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/slip_kern.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/slip_kern.c   2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,109 @@
++#include "linux/config.h"
++#include "linux/kernel.h"
++#include "linux/stddef.h"
++#include "linux/init.h"
++#include "linux/netdevice.h"
++#include "linux/if_arp.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "kern.h"
++#include "slip.h"
++
++struct slip_init {
++      char *gate_addr;
++};
++
++void slip_init(struct net_device *dev, void *data)
++{
++      struct uml_net_private *private;
++      struct slip_data *spri;
++      struct slip_init *init = data;
++
++      private = dev->priv;
++      spri = (struct slip_data *) private->user;
++      *spri = ((struct slip_data)
++              { .name         = { '\0' },
++                .addr         = NULL,
++                .gate_addr    = init->gate_addr,
++                .slave        = -1,
++                .ibuf         = { '\0' },
++                .obuf         = { '\0' },
++                .pos          = 0,
++                .esc          = 0,
++                .dev          = dev });
++
++      dev->init = NULL;
++      dev->hard_header_len = 0;
++      dev->addr_len = 4;
++      dev->type = ARPHRD_ETHER;
++      dev->tx_queue_len = 256;
++      dev->flags = IFF_NOARP;
++      printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr);
++}
++
++static unsigned short slip_protocol(struct sk_buff *skbuff)
++{
++      return(htons(ETH_P_IP));
++}
++
++static int slip_read(int fd, struct sk_buff **skb, 
++                     struct uml_net_private *lp)
++{
++      return(slip_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, 
++                            (struct slip_data *) &lp->user));
++}
++
++static int slip_write(int fd, struct sk_buff **skb,
++                    struct uml_net_private *lp)
++{
++      return(slip_user_write(fd, (*skb)->data, (*skb)->len, 
++                             (struct slip_data *) &lp->user));
++}
++
++struct net_kern_info slip_kern_info = {
++      .init                   = slip_init,
++      .protocol               = slip_protocol,
++      .read                   = slip_read,
++      .write                  = slip_write,
++};
++
++static int slip_setup(char *str, char **mac_out, void *data)
++{
++      struct slip_init *init = data;
++
++      *init = ((struct slip_init)
++              { .gate_addr            = NULL });
++
++      if(str[0] != '\0') 
++              init->gate_addr = str;
++      return(1);
++}
++
++static struct transport slip_transport = {
++      .list           = LIST_HEAD_INIT(slip_transport.list),
++      .name           = "slip",
++      .setup          = slip_setup,
++      .user           = &slip_user_info,
++      .kern           = &slip_kern_info,
++      .private_size   = sizeof(struct slip_data),
++      .setup_size     = sizeof(struct slip_init),
++};
++
++static int register_slip(void)
++{
++      register_transport(&slip_transport);
++      return(1);
++}
++
++__initcall(register_slip);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/slip_proto.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/slip_proto.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/slip_proto.h  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,93 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_SLIP_PROTO_H__
++#define __UM_SLIP_PROTO_H__
++
++/* SLIP protocol characters. */
++#define SLIP_END             0300     /* indicates end of frame       */
++#define SLIP_ESC             0333     /* indicates byte stuffing      */
++#define SLIP_ESC_END         0334     /* ESC ESC_END means END 'data' */
++#define SLIP_ESC_ESC         0335     /* ESC ESC_ESC means ESC 'data' */
++
++static inline int slip_unesc(unsigned char c,char *buf,int *pos, int *esc)
++{
++      int ret;
++
++      switch(c){
++      case SLIP_END:
++              *esc = 0;
++              ret=*pos;
++              *pos=0;
++              return(ret);
++      case SLIP_ESC:
++              *esc = 1;
++              return(0);
++      case SLIP_ESC_ESC:
++              if(*esc){
++                      *esc = 0;
++                      c = SLIP_ESC;
++              }
++              break;
++      case SLIP_ESC_END:
++              if(*esc){
++                      *esc = 0;
++                      c = SLIP_END;
++              }
++              break;
++      }
++      buf[(*pos)++] = c;
++      return(0);
++}
++
++static inline int slip_esc(unsigned char *s, unsigned char *d, int len)
++{
++      unsigned char *ptr = d;
++      unsigned char c;
++
++      /*
++       * Send an initial END character to flush out any
++       * data that may have accumulated in the receiver
++       * due to line noise.
++       */
++
++      *ptr++ = SLIP_END;
++
++      /*
++       * For each byte in the packet, send the appropriate
++       * character sequence, according to the SLIP protocol.
++       */
++
++      while (len-- > 0) {
++              switch(c = *s++) {
++              case SLIP_END:
++                      *ptr++ = SLIP_ESC;
++                      *ptr++ = SLIP_ESC_END;
++                      break;
++              case SLIP_ESC:
++                      *ptr++ = SLIP_ESC;
++                      *ptr++ = SLIP_ESC_ESC;
++                      break;
++              default:
++                      *ptr++ = c;
++                      break;
++              }
++      }
++      *ptr++ = SLIP_END;
++      return (ptr - d);
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/slip_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/slip_user.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/slip_user.c   2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,276 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <stddef.h>
++#include <sched.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/termios.h>
++#include <sys/wait.h>
++#include <sys/signal.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "net_user.h"
++#include "slip.h"
++#include "slip_proto.h"
++#include "helper.h"
++#include "os.h"
++
++void slip_user_init(void *data, void *dev)
++{
++      struct slip_data *pri = data;
++
++      pri->dev = dev;
++}
++
++static int set_up_tty(int fd)
++{
++      int i;
++      struct termios tios;
++
++      if (tcgetattr(fd, &tios) < 0) {
++              printk("could not get initial terminal attributes\n");
++              return(-1);
++      }
++
++      tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
++      tios.c_iflag = IGNBRK | IGNPAR;
++      tios.c_oflag = 0;
++      tios.c_lflag = 0;
++      for (i = 0; i < NCCS; i++)
++              tios.c_cc[i] = 0;
++      tios.c_cc[VMIN] = 1;
++      tios.c_cc[VTIME] = 0;
++
++      cfsetospeed(&tios, B38400);
++      cfsetispeed(&tios, B38400);
++
++      if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
++              printk("failed to set terminal attributes\n");
++              return(-1);
++      }
++      return(0);
++}
++
++struct slip_pre_exec_data {
++      int stdin;
++      int stdout;
++      int close_me;
++};
++
++static void slip_pre_exec(void *arg)
++{
++      struct slip_pre_exec_data *data = arg;
++
++      if(data->stdin >= 0) dup2(data->stdin, 0);
++      dup2(data->stdout, 1);
++      if(data->close_me >= 0) os_close_file(data->close_me);
++}
++
++static int slip_tramp(char **argv, int fd)
++{
++      struct slip_pre_exec_data pe_data;
++      char *output;
++      int status, pid, fds[2], err, output_len;
++
++      err = os_pipe(fds, 1, 0);
++      if(err < 0){
++              printk("slip_tramp : pipe failed, err = %d\n", -err);
++              return(err);
++      }
++
++      err = 0;
++      pe_data.stdin = fd;
++      pe_data.stdout = fds[1];
++      pe_data.close_me = fds[0];
++      pid = run_helper(slip_pre_exec, &pe_data, argv, NULL);
++
++      if(pid < 0) err = pid;
++      else {
++              output_len = page_size();
++              output = um_kmalloc(output_len);
++              if(output == NULL)
++                      printk("slip_tramp : failed to allocate output "
++                             "buffer\n");
++
++              os_close_file(fds[1]);
++              read_output(fds[0], output, output_len);
++              if(output != NULL){
++                      printk("%s", output);
++                      kfree(output);
++              }
++              CATCH_EINTR(err = waitpid(pid, &status, 0));
++              if(err < 0)
++                      err = errno;
++              else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
++                      printk("'%s' didn't exit with status 0\n", argv[0]);
++                      err = -EINVAL;
++              }
++      }
++      return(err);
++}
++
++static int slip_open(void *data)
++{
++      struct slip_data *pri = data;
++      char version_buf[sizeof("nnnnn\0")];
++      char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
++      char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, 
++                       NULL };
++      int sfd, mfd, err;
++
++      mfd = get_pty();
++      if(mfd < 0){
++              printk("umn : Failed to open pty, err = %d\n", -mfd);
++              return(mfd);
++      }
++      sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0);
++      if(sfd < 0){
++              printk("Couldn't open tty for slip line, err = %d\n", -sfd);
++              return(sfd);
++      }
++      if(set_up_tty(sfd)) return(-1);
++      pri->slave = sfd;
++      pri->pos = 0;
++      pri->esc = 0;
++      if(pri->gate_addr != NULL){
++              sprintf(version_buf, "%d", UML_NET_VERSION);
++              strcpy(gate_buf, pri->gate_addr);
++
++              err = slip_tramp(argv, sfd);
++
++              if(err < 0){
++                      printk("slip_tramp failed - err = %d\n", -err);
++                      return(err);
++              }
++              err = os_get_ifname(pri->slave, pri->name);
++              if(err < 0){
++                      printk("get_ifname failed, err = %d\n", -err);
++                      return(err);
++              }
++              iter_addresses(pri->dev, open_addr, pri->name);
++      }
++      else {
++              err = os_set_slip(sfd);
++              if(err < 0){
++                      printk("Failed to set slip discipline encapsulation - "
++                             "err = %d\n", -err);
++                      return(err);
++              }
++      }
++      return(mfd);
++}
++
++static void slip_close(int fd, void *data)
++{
++      struct slip_data *pri = data;
++      char version_buf[sizeof("nnnnn\0")];
++      char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name, 
++                       NULL };
++      int err;
++
++      if(pri->gate_addr != NULL)
++              iter_addresses(pri->dev, close_addr, pri->name);
++
++      sprintf(version_buf, "%d", UML_NET_VERSION);
++
++      err = slip_tramp(argv, -1);
++
++      if(err != 0)
++              printk("slip_tramp failed - errno = %d\n", -err);
++      os_close_file(fd);
++      os_close_file(pri->slave);
++      pri->slave = -1;
++}
++
++int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
++{
++      int i, n, size, start;
++
++      if(pri->more>0) {
++              i = 0;
++              while(i < pri->more) {
++                      size = slip_unesc(pri->ibuf[i++],
++                                      pri->ibuf, &pri->pos, &pri->esc);
++                      if(size){
++                              memcpy(buf, pri->ibuf, size);
++                              memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
++                              pri->more=pri->more-i; 
++                              return(size);
++                      }
++              }
++              pri->more=0;
++      }
++
++      n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
++      if(n <= 0) return(n);
++
++      start = pri->pos;
++      for(i = 0; i < n; i++){
++              size = slip_unesc(pri->ibuf[start + i],
++                              pri->ibuf, &pri->pos, &pri->esc);
++              if(size){
++                      memcpy(buf, pri->ibuf, size);
++                      memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
++                      pri->more=n-(i+1); 
++                      return(size);
++              }
++      }
++      return(0);
++}
++
++int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
++{
++      int actual, n;
++
++      actual = slip_esc(buf, pri->obuf, len);
++      n = net_write(fd, pri->obuf, actual);
++      if(n < 0) return(n);
++      else return(len);
++}
++
++static int slip_set_mtu(int mtu, void *data)
++{
++      return(mtu);
++}
++
++static void slip_add_addr(unsigned char *addr, unsigned char *netmask,
++                        void *data)
++{
++      struct slip_data *pri = data;
++
++      if(pri->slave < 0) return;
++      open_addr(addr, netmask, pri->name);
++}
++
++static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
++                          void *data)
++{
++      struct slip_data *pri = data;
++
++      if(pri->slave < 0) return;
++      close_addr(addr, netmask, pri->name);
++}
++
++struct net_user_info slip_user_info = {
++      .init           = slip_user_init,
++      .open           = slip_open,
++      .close          = slip_close,
++      .remove         = NULL,
++      .set_mtu        = slip_set_mtu,
++      .add_address    = slip_add_addr,
++      .delete_address = slip_del_addr,
++      .max_packet     = BUF_SIZE
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/slirp.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/slirp.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/slirp.h       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,51 @@
++#ifndef __UM_SLIRP_H
++#define __UM_SLIRP_H
++
++#define BUF_SIZE 1500
++ /* two bytes each for a (pathological) max packet of escaped chars +  * 
++  * terminating END char + initial END char                            */
++#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
++
++#define SLIRP_MAX_ARGS 100
++/*
++ * XXX this next definition is here because I don't understand why this
++ * initializer doesn't work in slirp_kern.c:
++ *
++ *   argv :  { init->argv[ 0 ... SLIRP_MAX_ARGS-1 ] },
++ *
++ * or why I can't typecast like this:
++ *
++ *   argv :  (char* [SLIRP_MAX_ARGS])(init->argv), 
++ */
++struct arg_list_dummy_wrapper { char *argv[SLIRP_MAX_ARGS]; };
++
++struct slirp_data {
++      void *dev;
++      struct arg_list_dummy_wrapper argw;
++      int pid;
++      int slave;
++      char ibuf[ENC_BUF_SIZE];
++      char obuf[ENC_BUF_SIZE];
++      int more; /* more data: do not read fd until ibuf has been drained */
++      int pos;
++      int esc;
++};
++
++extern struct net_user_info slirp_user_info;
++
++extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
++extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri);
++extern int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/slirp_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/slirp_kern.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/slirp_kern.c  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,132 @@
++#include "linux/kernel.h"
++#include "linux/stddef.h"
++#include "linux/init.h"
++#include "linux/netdevice.h"
++#include "linux/if_arp.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "kern.h"
++#include "slirp.h"
++
++struct slirp_init {
++      struct arg_list_dummy_wrapper argw;  /* XXX should be simpler... */
++};
++
++void slirp_init(struct net_device *dev, void *data)
++{
++      struct uml_net_private *private;
++      struct slirp_data *spri;
++      struct slirp_init *init = data;
++      int i;
++
++      private = dev->priv;
++      spri = (struct slirp_data *) private->user;
++      *spri = ((struct slirp_data)
++              { .argw         = init->argw,
++                .pid          = -1,
++                .slave        = -1,
++                .ibuf         = { '\0' },
++                .obuf         = { '\0' },
++                .pos          = 0,
++                .esc          = 0,
++                .dev          = dev });
++
++      dev->init = NULL;
++      dev->hard_header_len = 0;
++      dev->addr_len = 4;
++      dev->type = ARPHRD_ETHER;
++      dev->tx_queue_len = 256;
++      dev->flags = IFF_NOARP;
++      printk("SLIRP backend - command line:");
++      for(i=0;spri->argw.argv[i]!=NULL;i++) {
++              printk(" '%s'",spri->argw.argv[i]);
++      }
++      printk("\n");
++}
++
++static unsigned short slirp_protocol(struct sk_buff *skbuff)
++{
++      return(htons(ETH_P_IP));
++}
++
++static int slirp_read(int fd, struct sk_buff **skb, 
++                     struct uml_net_private *lp)
++{
++      return(slirp_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, 
++                            (struct slirp_data *) &lp->user));
++}
++
++static int slirp_write(int fd, struct sk_buff **skb,
++                    struct uml_net_private *lp)
++{
++      return(slirp_user_write(fd, (*skb)->data, (*skb)->len, 
++                             (struct slirp_data *) &lp->user));
++}
++
++struct net_kern_info slirp_kern_info = {
++      .init                   = slirp_init,
++      .protocol               = slirp_protocol,
++      .read                   = slirp_read,
++      .write                  = slirp_write,
++};
++
++static int slirp_setup(char *str, char **mac_out, void *data)
++{
++      struct slirp_init *init = data;
++      int i=0;
++
++      *init = ((struct slirp_init)
++              { argw :                { { "slirp", NULL  } } });
++
++      str = split_if_spec(str, mac_out, NULL);
++
++      if(str == NULL) { /* no command line given after MAC addr */
++              return(1);
++      }
++
++      do {
++              if(i>=SLIRP_MAX_ARGS-1) {
++                      printk("slirp_setup: truncating slirp arguments\n");
++                      break;
++              }
++              init->argw.argv[i++] = str;
++              while(*str && *str!=',') {
++                      if(*str=='_') *str=' ';
++                      str++;
++              }
++              if(*str!=',')
++                      break;
++              *str++='\0';
++      } while(1);
++      init->argw.argv[i]=NULL;
++      return(1);
++}
++
++static struct transport slirp_transport = {
++      .list           = LIST_HEAD_INIT(slirp_transport.list),
++      .name           = "slirp",
++      .setup          = slirp_setup,
++      .user           = &slirp_user_info,
++      .kern           = &slirp_kern_info,
++      .private_size   = sizeof(struct slirp_data),
++      .setup_size     = sizeof(struct slirp_init),
++};
++
++static int register_slirp(void)
++{
++      register_transport(&slirp_transport);
++      return(1);
++}
++
++__initcall(register_slirp);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/slirp_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/slirp_user.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/slirp_user.c  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,201 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <stddef.h>
++#include <sched.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/wait.h>
++#include <sys/signal.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "net_user.h"
++#include "slirp.h"
++#include "slip_proto.h"
++#include "helper.h"
++#include "os.h"
++
++void slirp_user_init(void *data, void *dev)
++{
++      struct slirp_data *pri = data;
++
++      pri->dev = dev;
++}
++
++struct slirp_pre_exec_data {
++      int stdin;
++      int stdout;
++};
++
++static void slirp_pre_exec(void *arg)
++{
++      struct slirp_pre_exec_data *data = arg;
++
++      if(data->stdin != -1) dup2(data->stdin, 0);
++      if(data->stdout != -1) dup2(data->stdout, 1);
++}
++
++static int slirp_tramp(char **argv, int fd)
++{
++      struct slirp_pre_exec_data pe_data;
++      int pid;
++
++      pe_data.stdin = fd;
++      pe_data.stdout = fd;
++      pid = run_helper(slirp_pre_exec, &pe_data, argv, NULL);
++
++      return(pid);
++}
++
++/* XXX This is just a trivial wrapper around os_pipe */ 
++static int slirp_datachan(int *mfd, int *sfd)
++{
++      int fds[2], err;
++
++      err = os_pipe(fds, 1, 1);
++      if(err < 0){
++              printk("slirp_datachan: Failed to open pipe, err = %d\n", -err);
++              return(err);
++      }
++
++      *mfd = fds[0];
++      *sfd = fds[1];
++      return(0);
++}
++
++static int slirp_open(void *data)
++{
++      struct slirp_data *pri = data;
++      int sfd, mfd, pid, err;
++
++      err = slirp_datachan(&mfd, &sfd);
++      if(err)
++              return(err);
++
++      pid = slirp_tramp(pri->argw.argv, sfd);
++
++      if(pid < 0){
++              printk("slirp_tramp failed - errno = %d\n", -pid);
++              os_close_file(sfd);     
++              os_close_file(mfd);     
++              return(pid);
++      }
++
++      pri->slave = sfd;
++      pri->pos = 0;
++      pri->esc = 0;
++
++      pri->pid = pid;
++
++      return(mfd);
++}
++
++static void slirp_close(int fd, void *data)
++{
++      struct slirp_data *pri = data;
++      int status,err;
++
++      os_close_file(fd);
++      os_close_file(pri->slave);
++
++      pri->slave = -1;
++
++      if(pri->pid<1) {
++              printk("slirp_close: no child process to shut down\n");
++              return;
++      }
++
++#if 0
++      if(kill(pri->pid, SIGHUP)<0) {
++              printk("slirp_close: sending hangup to %d failed (%d)\n",
++                      pri->pid, errno);
++      }
++#endif
++
++      CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG));
++      if(err < 0) {
++              printk("slirp_close: waitpid returned %d\n", errno);
++              return;
++      }
++
++      if(err == 0) {
++              printk("slirp_close: process %d has not exited\n");
++              return;
++      }
++
++      pri->pid = -1;
++}
++
++int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri)
++{
++      int i, n, size, start;
++
++      if(pri->more>0) {
++              i = 0;
++              while(i < pri->more) {
++                      size = slip_unesc(pri->ibuf[i++],
++                                      pri->ibuf,&pri->pos,&pri->esc);
++                      if(size){
++                              memcpy(buf, pri->ibuf, size);
++                              memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
++                              pri->more=pri->more-i; 
++                              return(size);
++                      }
++              }
++              pri->more=0;
++      }
++
++      n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
++      if(n <= 0) return(n);
++
++      start = pri->pos;
++      for(i = 0; i < n; i++){
++              size = slip_unesc(pri->ibuf[start + i],
++                              pri->ibuf,&pri->pos,&pri->esc);
++              if(size){
++                      memcpy(buf, pri->ibuf, size);
++                      memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
++                      pri->more=n-(i+1); 
++                      return(size);
++              }
++      }
++      return(0);
++}
++
++int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri)
++{
++      int actual, n;
++
++      actual = slip_esc(buf, pri->obuf, len);
++      n = net_write(fd, pri->obuf, actual);
++      if(n < 0) return(n);
++      else return(len);
++}
++
++static int slirp_set_mtu(int mtu, void *data)
++{
++      return(mtu);
++}
++
++struct net_user_info slirp_user_info = {
++      .init           = slirp_user_init,
++      .open           = slirp_open,
++      .close          = slirp_close,
++      .remove         = NULL,
++      .set_mtu        = slirp_set_mtu,
++      .add_address    = NULL,
++      .delete_address = NULL,
++      .max_packet     = BUF_SIZE
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/ssl.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/ssl.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/ssl.c 2005-05-03 22:28:14.247444272 +0300
+@@ -0,0 +1,300 @@
++/* 
++ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/fs.h"
++#include "linux/tty.h"
++#include "linux/tty_driver.h"
++#include "linux/major.h"
++#include "linux/mm.h"
++#include "linux/init.h"
++#include "linux/console.h"
++#include "asm/termbits.h"
++#include "asm/irq.h"
++#include "line.h"
++#include "ssl.h"
++#include "chan_kern.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "init.h"
++#include "irq_user.h"
++#include "mconsole_kern.h"
++#include "2_5compat.h"
++
++static int ssl_version = 1;
++
++/* Referenced only by tty_driver below - presumably it's locked correctly
++ * by the tty driver.
++ */
++static int ssl_refcount = 0;
++
++static struct tty_driver ssl_driver;
++
++#define NR_PORTS 64
++
++void ssl_announce(char *dev_name, int dev)
++{
++      printk(KERN_INFO "Serial line %d assigned device '%s'\n", dev,
++             dev_name);
++}
++
++static struct chan_opts opts = {
++      .announce       = ssl_announce,
++      .xterm_title    = "Serial Line #%d",
++      .raw            = 1,
++      .tramp_stack    = 0,
++      .in_kernel      = 1,
++};
++
++static int ssl_config(char *str);
++static int ssl_get_config(char *dev, char *str, int size, char **error_out);
++static int ssl_remove(char *str);
++
++static struct line_driver driver = {
++      .name                   = "UML serial line",
++      .devfs_name             = "tts/%d",
++      .major                  = TTY_MAJOR,
++      .minor_start            = 64,
++      .type                   = TTY_DRIVER_TYPE_SERIAL,
++      .subtype                = 0,
++      .read_irq               = SSL_IRQ,
++      .read_irq_name          = "ssl",
++      .write_irq              = SSL_WRITE_IRQ,
++      .write_irq_name         = "ssl-write",
++      .symlink_from           = "serial",
++      .symlink_to             = "tts",
++      .mc  = {
++              .name           = "ssl",
++              .config         = ssl_config,
++              .get_config     = ssl_get_config,
++              .remove         = ssl_remove,
++      },
++};
++
++/* The array is initialized by line_init, which is an initcall.  The 
++ * individual elements are protected by individual semaphores.
++ */
++static struct line serial_lines[NR_PORTS] =
++      { [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) };
++
++static struct lines lines = LINES_INIT(NR_PORTS);
++
++static int ssl_config(char *str)
++{
++      return(line_config(serial_lines, 
++                         sizeof(serial_lines)/sizeof(serial_lines[0]), str));
++}
++
++static int ssl_get_config(char *dev, char *str, int size, char **error_out)
++{
++      return(line_get_config(dev, serial_lines, 
++                             sizeof(serial_lines)/sizeof(serial_lines[0]), 
++                             str, size, error_out));
++}
++
++static int ssl_remove(char *str)
++{
++      return(line_remove(serial_lines, 
++                         sizeof(serial_lines)/sizeof(serial_lines[0]), str));
++}
++
++int ssl_open(struct tty_struct *tty, struct file *filp)
++{
++      return(line_open(serial_lines, tty, &opts));
++}
++
++static void ssl_close(struct tty_struct *tty, struct file * filp)
++{
++      line_close(serial_lines, tty);
++}
++
++static int ssl_write(struct tty_struct * tty, int from_user,
++                   const unsigned char *buf, int count)
++{
++      return(line_write(serial_lines, tty, from_user, buf, count));
++}
++
++static void ssl_put_char(struct tty_struct *tty, unsigned char ch)
++{
++      line_write(serial_lines, tty, 0, &ch, sizeof(ch));
++}
++
++static void ssl_flush_chars(struct tty_struct *tty)
++{
++      return;
++}
++
++static int ssl_chars_in_buffer(struct tty_struct *tty)
++{
++      return(0);
++}
++
++static void ssl_flush_buffer(struct tty_struct *tty)
++{
++      return;
++}
++
++static int ssl_ioctl(struct tty_struct *tty, struct file * file,
++                   unsigned int cmd, unsigned long arg)
++{
++      int ret;
++
++      ret = 0;
++      switch(cmd){
++      case TCGETS:
++      case TCSETS:
++      case TCFLSH:
++      case TCSETSF:
++      case TCSETSW:
++      case TCGETA:
++      case TIOCMGET:
++      case TCSBRK:
++      case TCSBRKP:
++      case TIOCMSET:
++              ret = -ENOIOCTLCMD;
++              break;
++      default:
++              printk(KERN_ERR 
++                     "Unimplemented ioctl in ssl_ioctl : 0x%x\n", cmd);
++              ret = -ENOIOCTLCMD;
++              break;
++      }
++      return(ret);
++}
++
++static void ssl_throttle(struct tty_struct * tty)
++{
++      printk(KERN_ERR "Someone should implement ssl_throttle\n");
++}
++
++static void ssl_unthrottle(struct tty_struct * tty)
++{
++      printk(KERN_ERR "Someone should implement ssl_unthrottle\n");
++}
++
++static void ssl_set_termios(struct tty_struct *tty, 
++                          struct termios *old_termios)
++{
++}
++
++static void ssl_stop(struct tty_struct *tty)
++{
++      printk(KERN_ERR "Someone should implement ssl_stop\n");
++}
++
++static void ssl_start(struct tty_struct *tty)
++{
++      printk(KERN_ERR "Someone should implement ssl_start\n");
++}
++
++void ssl_hangup(struct tty_struct *tty)
++{
++}
++
++static struct tty_driver ssl_driver = {
++      .refcount               = &ssl_refcount,
++      .open                   = ssl_open,
++      .close                  = ssl_close,
++      .write                  = ssl_write,
++      .put_char               = ssl_put_char,
++      .flush_chars            = ssl_flush_chars,
++      .chars_in_buffer        = ssl_chars_in_buffer,
++      .flush_buffer           = ssl_flush_buffer,
++      .ioctl                  = ssl_ioctl,
++      .throttle               = ssl_throttle,
++      .unthrottle             = ssl_unthrottle,
++      .set_termios            = ssl_set_termios,
++      .stop                   = ssl_stop,
++      .start                  = ssl_start,
++      .hangup                 = ssl_hangup
++};
++
++/* Changed by ssl_init and referenced by ssl_exit, which are both serialized
++ * by being an initcall and exitcall, respectively.
++ */
++static int ssl_init_done = 0;
++
++static void ssl_console_write(struct console *c, const char *string, 
++                            unsigned len)
++{
++      struct line *line = &serial_lines[c->index];
++      if(ssl_init_done)
++              down(&line->sem);
++      console_write_chan(&line->chan_list, string, len);
++      if(ssl_init_done)
++              up(&line->sem);
++}
++
++static kdev_t ssl_console_device(struct console *c)
++{
++      return mk_kdev(TTY_MAJOR, c->index);
++}
++
++static int ssl_console_setup(struct console *co, char *options)
++{
++      return(0);
++}
++
++static struct console ssl_cons = {
++      name:           "ttyS",
++      write:          ssl_console_write,
++      device:         ssl_console_device,
++      setup:          ssl_console_setup,
++      flags:          CON_PRINTBUFFER,
++      index:          -1,
++};
++
++int ssl_init(void)
++{
++      char *new_title;
++
++      printk(KERN_INFO "Initializing software serial port version %d\n", 
++             ssl_version);
++
++      line_register_devfs(&lines, &driver, &ssl_driver, serial_lines, 
++                          sizeof(serial_lines)/sizeof(serial_lines[0]));
++
++      lines_init(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]));
++
++      new_title = add_xterm_umid(opts.xterm_title);
++      if(new_title != NULL) opts.xterm_title = new_title;
++
++      register_console(&ssl_cons);
++      ssl_init_done = 1;
++      return(0);
++}
++
++__initcall(ssl_init);
++
++static int ssl_chan_setup(char *str)
++{
++      return(line_setup(serial_lines, 
++                        sizeof(serial_lines)/sizeof(serial_lines[0]), 
++                        str, 1));
++}
++
++__setup("ssl", ssl_chan_setup);
++__channel_help(ssl_chan_setup, "ssl");
++
++static void ssl_exit(void)
++{
++      if(!ssl_init_done) return;
++      close_lines(serial_lines, 
++                  sizeof(serial_lines)/sizeof(serial_lines[0]));
++}
++
++__uml_exitcall(ssl_exit);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/ssl.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/ssl.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/ssl.h 2005-05-03 22:28:14.248444120 +0300
+@@ -0,0 +1,23 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SSL_H__
++#define __SSL_H__
++
++extern int ssl_read(int fd, int line);
++extern void ssl_receive_char(int line, char ch);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/stdio_console.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/stdio_console.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/stdio_console.c       2005-05-03 22:28:14.249443968 +0300
+@@ -0,0 +1,258 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/posix_types.h"
++#include "linux/tty.h"
++#include "linux/tty_flip.h"
++#include "linux/types.h"
++#include "linux/major.h"
++#include "linux/kdev_t.h"
++#include "linux/console.h"
++#include "linux/string.h"
++#include "linux/sched.h"
++#include "linux/list.h"
++#include "linux/init.h"
++#include "linux/interrupt.h"
++#include "linux/slab.h"
++#include "asm/current.h"
++#include "asm/softirq.h"
++#include "asm/hardirq.h"
++#include "asm/irq.h"
++#include "stdio_console.h"
++#include "line.h"
++#include "chan_kern.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "irq_user.h"
++#include "mconsole_kern.h"
++#include "init.h"
++#include "2_5compat.h"
++
++#define MAX_TTYS (8)
++
++/* Referenced only by tty_driver below - presumably it's locked correctly
++ * by the tty driver.
++ */
++
++static struct tty_driver console_driver;
++
++static int console_refcount = 0;
++
++static struct chan_ops init_console_ops = {
++      .type           = "you shouldn't see this",
++      .init           = NULL,
++      .open           = NULL,
++      .close          = NULL,
++      .read           = NULL,
++      .write          = NULL,
++      .console_write  = generic_write,
++      .window_size    = NULL,
++      .free           = NULL,
++      .winch          = 0,
++};
++
++static struct chan init_console_chan = {
++      .list           = { },
++      .primary        = 1,
++      .input          = 0,
++      .output         = 1,
++      .opened         = 1,
++      .fd             = 1,
++      .pri            = INIT_STATIC,
++      .ops            = &init_console_ops,
++      .data           = NULL
++};
++
++void stdio_announce(char *dev_name, int dev)
++{
++      printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev,
++             dev_name);
++}
++
++static struct chan_opts opts = {
++      .announce       = stdio_announce,
++      .xterm_title    = "Virtual Console #%d",
++      .raw            = 1,
++      .tramp_stack    = 0,
++      .in_kernel      = 1,
++};
++
++static int con_config(char *str);
++static int con_get_config(char *dev, char *str, int size, char **error_out);
++static int con_remove(char *str);
++
++static struct line_driver driver = {
++      .name                   = "UML console",
++      .devfs_name             = "vc/%d",
++      .major                  = TTY_MAJOR,
++      .minor_start            = 0,
++      .type                   = TTY_DRIVER_TYPE_CONSOLE,
++      .subtype                = SYSTEM_TYPE_CONSOLE,
++      .read_irq               = CONSOLE_IRQ,
++      .read_irq_name          = "console",
++      .write_irq              = CONSOLE_WRITE_IRQ,
++      .write_irq_name         = "console-write",
++      .symlink_from           = "ttys",
++      .symlink_to             = "vc",
++      .mc  = {
++              .name           = "con",
++              .config         = con_config,
++              .get_config     = con_get_config,
++              .remove         = con_remove,
++      },
++};
++
++static struct lines console_lines = LINES_INIT(MAX_TTYS);
++
++/* The array is initialized by line_init, which is an initcall.  The 
++ * individual elements are protected by individual semaphores.
++ */
++struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
++                            [ 1 ... MAX_TTYS - 1 ] = 
++                            LINE_INIT(CONFIG_CON_CHAN, &driver) };
++
++static int con_config(char *str)
++{
++      return(line_config(vts, sizeof(vts)/sizeof(vts[0]), str));
++}
++
++static int con_get_config(char *dev, char *str, int size, char **error_out)
++{
++      return(line_get_config(dev, vts, sizeof(vts)/sizeof(vts[0]), str, 
++                             size, error_out));
++}
++
++static int con_remove(char *str)
++{
++      return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str));
++}
++
++static int open_console(struct tty_struct *tty)
++{
++      return(line_open(vts, tty, &opts));
++}
++
++static int con_open(struct tty_struct *tty, struct file *filp)
++{
++      return(open_console(tty));
++}
++
++static void con_close(struct tty_struct *tty, struct file *filp)
++{
++      line_close(vts, tty);
++}
++
++static int con_write(struct tty_struct *tty, int from_user, 
++                   const unsigned char *buf, int count)
++{
++       return(line_write(vts, tty, from_user, buf, count));
++}
++
++static void set_termios(struct tty_struct *tty, struct termios * old)
++{
++}
++
++static int chars_in_buffer(struct tty_struct *tty)
++{
++      return(0);
++}
++
++static int con_init_done = 0;
++
++int stdio_init(void)
++{
++      char *new_title;
++
++      printk(KERN_INFO "Initializing stdio console driver\n");
++
++      line_register_devfs(&console_lines, &driver, &console_driver, vts, 
++                          sizeof(vts)/sizeof(vts[0]));
++
++      lines_init(vts, sizeof(vts)/sizeof(vts[0]));
++
++      new_title = add_xterm_umid(opts.xterm_title);
++      if(new_title != NULL) opts.xterm_title = new_title;
++
++      open_console(NULL);
++      con_init_done = 1;
++      return(0);
++}
++
++__initcall(stdio_init);
++
++static void console_write(struct console *console, const char *string, 
++                        unsigned len)
++{
++      struct line *line = &vts[console->index];
++
++      if(con_init_done)
++              down(&line->sem);
++      console_write_chan(&line->chan_list, string, len);
++      if(con_init_done)
++              up(&line->sem);
++}
++
++static struct tty_driver console_driver = {
++      .refcount               = &console_refcount,
++      .open                   = con_open,
++      .close                  = con_close,
++      .write                  = con_write,
++      .chars_in_buffer        = chars_in_buffer,
++      .set_termios            = set_termios
++};
++
++static kdev_t console_device(struct console *c)
++{
++      return mk_kdev(TTY_MAJOR, c->index);
++}
++
++static int console_setup(struct console *co, char *options)
++{
++      return(0);
++}
++
++static struct console stdiocons = {
++      name:           "tty",
++      write:          console_write,
++      device:         console_device,
++      setup:          console_setup,
++      flags:          CON_PRINTBUFFER,
++      index:          -1,
++};
++
++void stdio_console_init(void)
++{
++      INIT_LIST_HEAD(&vts[0].chan_list);
++      list_add(&init_console_chan.list, &vts[0].chan_list);
++      register_console(&stdiocons);
++}
++
++static int console_chan_setup(char *str)
++{
++      return(line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1));
++}
++
++__setup("con", console_chan_setup);
++__channel_help(console_chan_setup, "con");
++
++static void console_exit(void)
++{
++      if(!con_init_done) return;
++      close_lines(vts, sizeof(vts)/sizeof(vts[0]));
++}
++
++__uml_exitcall(console_exit);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/stdio_console.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/stdio_console.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/stdio_console.h       2005-05-03 22:28:14.250443816 +0300
+@@ -0,0 +1,21 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __STDIO_CONSOLE_H
++#define __STDIO_CONSOLE_H
++
++extern void save_console_flags(void);
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/tty.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/tty.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/tty.c 2005-05-03 22:28:14.251443664 +0300
+@@ -0,0 +1,91 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <termios.h>
++#include <errno.h>
++#include <unistd.h>
++#include "chan_user.h"
++#include "user_util.h"
++#include "user.h"
++#include "os.h"
++
++struct tty_chan {
++      char *dev;
++      int raw;
++      struct termios tt;
++};
++
++void *tty_chan_init(char *str, int device, struct chan_opts *opts)
++{
++      struct tty_chan *data;
++
++      if(*str != ':'){
++              printk("tty_init : channel type 'tty' must specify "
++                     "a device\n");
++              return(NULL);
++      }
++      str++;
++
++      data = um_kmalloc(sizeof(*data)); 
++      if(data == NULL) 
++              return(NULL);
++      *data = ((struct tty_chan) { .dev       = str,
++                                   .raw       = opts->raw });
++                                   
++      return(data);
++}
++
++int tty_open(int input, int output, int primary, void *d, char **dev_out)
++{
++      struct tty_chan *data = d;
++      int fd, err;
++
++      fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0);
++      if(fd < 0) return(fd);
++      if(data->raw){
++              CATCH_EINTR(err = tcgetattr(fd, &data->tt));
++              if(err)
++                      return(err);
++
++              err = raw(fd);
++              if(err)
++                      return(err);
++      }
++
++      *dev_out = data->dev;
++      return(fd);
++}
++
++int tty_console_write(int fd, const char *buf, int n, void *d)
++{
++      struct tty_chan *data = d;
++
++      return(generic_console_write(fd, buf, n, &data->tt));
++}
++
++struct chan_ops tty_ops = {
++      .type           = "tty",
++      .init           = tty_chan_init,
++      .open           = tty_open,
++      .close          = generic_close,
++      .read           = generic_read,
++      .write          = generic_write,
++      .console_write  = tty_console_write,
++      .window_size    = generic_window_size,
++      .free           = generic_free,
++      .winch          = 0,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/ubd_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/ubd_kern.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/ubd_kern.c    2005-05-03 22:28:14.257442752 +0300
+@@ -0,0 +1,1380 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++/* 2001-09-28...2002-04-17
++ * Partition stuff by James_McMechan@hotmail.com
++ * old style ubd by setting UBD_SHIFT to 0
++ */
++
++#define MAJOR_NR UBD_MAJOR
++#define UBD_SHIFT 4
++
++#include "linux/config.h"
++#include "linux/blk.h"
++#include "linux/blkdev.h"
++#include "linux/hdreg.h"
++#include "linux/init.h"
++#include "linux/devfs_fs_kernel.h"
++#include "linux/cdrom.h"
++#include "linux/proc_fs.h"
++#include "linux/ctype.h"
++#include "linux/capability.h"
++#include "linux/mm.h"
++#include "linux/vmalloc.h"
++#include "linux/blkpg.h"
++#include "linux/genhd.h"
++#include "linux/spinlock.h"
++#include "asm/segment.h"
++#include "asm/uaccess.h"
++#include "asm/irq.h"
++#include "asm/types.h"
++#include "user_util.h"
++#include "mem_user.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "mconsole_kern.h"
++#include "init.h"
++#include "irq_user.h"
++#include "irq_kern.h"
++#include "ubd_user.h"
++#include "2_5compat.h"
++#include "os.h"
++#include "mem.h"
++#include "mem_kern.h"
++
++static int ubd_open(struct inode * inode, struct file * filp);
++static int ubd_release(struct inode * inode, struct file * file);
++static int ubd_ioctl(struct inode * inode, struct file * file,
++                   unsigned int cmd, unsigned long arg);
++static int ubd_revalidate(kdev_t rdev);
++static int ubd_revalidate1(kdev_t rdev);
++
++#define MAX_DEV (8)
++#define MAX_MINOR (MAX_DEV << UBD_SHIFT)
++
++/* Changed in early boot */
++static int ubd_do_mmap = 0;
++#define UBD_MMAP_BLOCK_SIZE PAGE_SIZE
++
++/* Not modified by this driver */
++static int blk_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = BLOCK_SIZE };
++static int hardsect_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 512 };
++
++/* Protected by ubd_lock */
++static int sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 0 };
++
++static struct block_device_operations ubd_blops = {
++        .open         = ubd_open,
++        .release      = ubd_release,
++        .ioctl                = ubd_ioctl,
++        .revalidate   = ubd_revalidate,
++};
++
++/* Protected by ubd_lock, except in prepare_request and ubd_ioctl because 
++ * the block layer should ensure that the device is idle before closing it.
++ */
++static struct hd_struct       ubd_part[MAX_MINOR] =
++      { [ 0 ... MAX_MINOR - 1 ] = { 0, 0, 0 } };
++
++/* Protected by io_request_lock */
++static request_queue_t *ubd_queue;
++
++/* Protected by ubd_lock */
++static int fake_major = MAJOR_NR;
++
++static spinlock_t ubd_lock = SPIN_LOCK_UNLOCKED;
++
++#define INIT_GENDISK(maj, name, parts, shift, bsizes, max, blops) \
++{ \
++      .major          = maj, \
++      .major_name     = name, \
++      .minor_shift    = shift, \
++      .max_p          = 1 << shift, \
++      .part           = parts, \
++      .sizes          = bsizes, \
++      .nr_real        = max, \
++      .real_devices   = NULL, \
++      .next           = NULL, \
++      .fops           = blops, \
++      .de_arr         = NULL, \
++      .flags          = 0 \
++}
++
++static struct gendisk ubd_gendisk = INIT_GENDISK(MAJOR_NR, "ubd", ubd_part,
++                                               UBD_SHIFT, sizes, MAX_DEV, 
++                                               &ubd_blops);
++static struct gendisk fake_gendisk = INIT_GENDISK(0, "ubd", ubd_part, 
++                                                UBD_SHIFT, sizes, MAX_DEV, 
++                                                &ubd_blops);
++
++#ifdef CONFIG_BLK_DEV_UBD_SYNC
++#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
++                                       .cl = 1 })
++#else
++#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
++                                       .cl = 1 })
++#endif
++
++/* Not protected - changed only in ubd_setup_common and then only to
++ * to enable O_SYNC.
++ */
++static struct openflags global_openflags = OPEN_FLAGS;
++
++struct cow {
++      char *file;
++      int fd;
++      unsigned long *bitmap;
++      unsigned long bitmap_len;
++      int bitmap_offset;
++        int data_offset;
++};
++
++struct ubd {
++      char *file;
++      int count;
++      int fd;
++      __u64 size;
++      struct openflags boot_openflags;
++      struct openflags openflags;
++      devfs_handle_t devfs;
++      int no_cow;
++      struct cow cow;
++
++      int map_writes;
++      int map_reads;
++      int nomap_writes;
++      int nomap_reads;
++      int write_maps;
++};
++
++#define DEFAULT_COW { \
++      .file                   = NULL, \
++        .fd                   = -1, \
++        .bitmap                       = NULL, \
++      .bitmap_offset          = 0, \
++        .data_offset          = 0, \
++}
++
++#define DEFAULT_UBD { \
++      .file                   = NULL, \
++      .count                  = 0, \
++      .fd                     = -1, \
++      .size                   = -1, \
++      .boot_openflags         = OPEN_FLAGS, \
++      .openflags              = OPEN_FLAGS, \
++      .devfs                  = NULL, \
++      .no_cow                 = 0, \
++        .cow                  = DEFAULT_COW, \
++      .map_writes             = 0, \
++      .map_reads              = 0, \
++      .nomap_writes           = 0, \
++      .nomap_reads            = 0, \
++      .write_maps             = 0, \
++}
++
++struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
++
++static int ubd0_init(void)
++{
++      struct ubd *dev = &ubd_dev[0];
++
++      if(dev->file == NULL)
++              dev->file = "root_fs";
++      return(0);
++}
++
++__initcall(ubd0_init);
++
++/* Only changed by fake_ide_setup which is a setup */
++static int fake_ide = 0;
++static struct proc_dir_entry *proc_ide_root = NULL;
++static struct proc_dir_entry *proc_ide = NULL;
++
++static void make_proc_ide(void)
++{
++      proc_ide_root = proc_mkdir("ide", 0);
++      proc_ide = proc_mkdir("ide0", proc_ide_root);
++}
++
++static int proc_ide_read_media(char *page, char **start, off_t off, int count,
++                             int *eof, void *data)
++{
++      int len;
++
++      strcpy(page, "disk\n");
++      len = strlen("disk\n");
++      len -= off;
++      if (len < count){
++              *eof = 1;
++              if (len <= 0) return 0;
++      }
++      else len = count;
++      *start = page + off;
++      return len;
++}
++
++static void make_ide_entries(char *dev_name)
++{
++      struct proc_dir_entry *dir, *ent;
++      char name[64];
++
++      if(!fake_ide) return;
++
++      /* Without locking this could race if a UML was booted with no 
++       * disks and then two mconsole requests which add disks came in 
++       * at the same time.
++       */
++      spin_lock(&ubd_lock);
++      if(proc_ide_root == NULL) make_proc_ide();
++      spin_unlock(&ubd_lock);
++
++      dir = proc_mkdir(dev_name, proc_ide);
++      if(!dir) return;
++
++      ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
++      if(!ent) return;
++      ent->nlink = 1;
++      ent->data = NULL;
++      ent->read_proc = proc_ide_read_media;
++      ent->write_proc = NULL;
++      sprintf(name,"ide0/%s", dev_name);
++      proc_symlink(dev_name, proc_ide_root, name);
++}
++
++static int fake_ide_setup(char *str)
++{
++      fake_ide = 1;
++      return(1);
++}
++
++__setup("fake_ide", fake_ide_setup);
++
++__uml_help(fake_ide_setup,
++"fake_ide\n"
++"    Create ide0 entries that map onto ubd devices.\n\n"
++);
++
++static int parse_unit(char **ptr)
++{
++      char *str = *ptr, *end;
++      int n = -1;
++
++      if(isdigit(*str)) {
++              n = simple_strtoul(str, &end, 0);
++              if(end == str)
++                      return(-1);
++              *ptr = end;
++      }
++      else if (('a' <= *str) && (*str <= 'h')) {
++              n = *str - 'a';
++              str++;
++              *ptr = str;
++      }
++      return(n);
++}
++
++static int ubd_setup_common(char *str, int *index_out)
++{
++      struct openflags flags = global_openflags;
++      struct ubd *dev;
++      char *backing_file;
++      int n, err;
++
++      if(index_out) *index_out = -1;
++      n = *str;
++      if(n == '='){
++              char *end;
++              int major;
++
++              str++;
++              if(!strcmp(str, "mmap")){
++                      CHOOSE_MODE(printk("mmap not supported by the ubd "
++                                         "driver in tt mode\n"),
++                                  ubd_do_mmap = 1);
++                      return(0);
++              }
++
++              if(!strcmp(str, "sync")){
++                      global_openflags.s = 1;
++                      return(0);
++              }
++              major = simple_strtoul(str, &end, 0);
++              if((*end != '\0') || (end == str)){
++                      printk(KERN_ERR 
++                             "ubd_setup : didn't parse major number\n");
++                      return(1);
++              }
++
++              err = 1;
++              spin_lock(&ubd_lock);
++              if(fake_major != MAJOR_NR){
++                      printk(KERN_ERR "Can't assign a fake major twice\n");
++                      goto out1;
++              }
++
++              fake_gendisk.major = major;
++              fake_major = major;
++      
++              printk(KERN_INFO "Setting extra ubd major number to %d\n",
++                     major);
++              err = 0;
++      out1:
++              spin_unlock(&ubd_lock);
++              return(err);
++      }
++
++      n = parse_unit(&str);
++      if(n < 0){
++              printk(KERN_ERR "ubd_setup : couldn't parse unit number "
++                     "'%s'\n", str);
++              return(1);
++      }
++
++      if(n >= MAX_DEV){
++              printk(KERN_ERR "ubd_setup : index %d out of range "
++                     "(%d devices)\n", n, MAX_DEV);   
++              return(1);
++      }
++
++      err = 1;
++      spin_lock(&ubd_lock);
++
++      dev = &ubd_dev[n];
++      if(dev->file != NULL){
++              printk(KERN_ERR "ubd_setup : device already configured\n");
++              goto out2;
++      }
++
++      if(index_out) *index_out = n;
++
++      if(*str == 'r'){
++              flags.w = 0;
++              str++;
++      }
++      if(*str == 's'){
++              flags.s = 1;
++              str++;
++      }
++      if(*str == 'd'){
++              dev->no_cow = 1;
++              str++;
++      }
++
++      if(*str++ != '='){
++              printk(KERN_ERR "ubd_setup : Expected '='\n");
++              goto out2;
++      }
++
++      err = 0;
++      backing_file = strchr(str, ',');
++      if(backing_file){
++              if(dev->no_cow)
++                      printk(KERN_ERR "Can't specify both 'd' and a "
++                             "cow file\n");
++              else {
++                      *backing_file = '\0';
++                      backing_file++;
++              }
++      }
++      dev->file = str;
++      dev->cow.file = backing_file;
++      dev->boot_openflags = flags;
++ out2:
++      spin_unlock(&ubd_lock);
++      return(err);
++}
++
++static int ubd_setup(char *str)
++{
++      ubd_setup_common(str, NULL);
++      return(1);
++}
++
++__setup("ubd", ubd_setup);
++__uml_help(ubd_setup,
++"ubd<n>=<filename>\n"
++"    This is used to associate a device with a file in the underlying\n"
++"    filesystem. Usually, there is a filesystem in the file, but \n"
++"    that's not required. Swap devices containing swap files can be\n"
++"    specified like this. Also, a file which doesn't contain a\n"
++"    filesystem can have its contents read in the virtual \n"
++"    machine by running dd on the device. n must be in the range\n"
++"    0 to 7. Appending an 'r' to the number will cause that device\n"
++"    to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
++"    an 's' (has to be _after_ 'r', if there is one) will cause data\n"
++"    to be written to disk on the host immediately.\n\n"
++);
++
++static int fakehd(char *str)
++{
++      printk(KERN_INFO 
++             "fakehd : Changing ubd_gendisk.major_name to \"hd\".\n");
++      ubd_gendisk.major_name = "hd";
++      return(1);
++}
++
++__setup("fakehd", fakehd);
++__uml_help(fakehd,
++"fakehd\n"
++"    Change the ubd device name to \"hd\".\n\n"
++);
++
++static void do_ubd_request(request_queue_t * q);
++
++/* Only changed by ubd_init, which is an initcall. */
++int thread_fd = -1;
++
++/* Changed by ubd_handler, which is serialized because interrupts only
++ * happen on CPU 0.
++ */
++int intr_count = 0;
++
++static void ubd_finish(int error)
++{
++      int nsect;
++
++      if(error){
++              end_request(0);
++              return;
++      }
++      nsect = CURRENT->current_nr_sectors;
++      CURRENT->sector += nsect;
++      CURRENT->buffer += nsect << 9;
++      CURRENT->errors = 0;
++      CURRENT->nr_sectors -= nsect;
++      CURRENT->current_nr_sectors = 0;
++      end_request(1);
++}
++
++static void ubd_handler(void)
++{
++      struct io_thread_req req;
++      int n, err;
++
++      DEVICE_INTR = NULL;
++      intr_count++;
++      n = read_ubd_fs(thread_fd, &req, sizeof(req));
++      if(n != sizeof(req)){
++              printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
++                     "err = %d\n", os_getpid(), -n);
++              spin_lock(&io_request_lock);
++              end_request(0);
++              spin_unlock(&io_request_lock);
++              return;
++      }
++        
++        if((req.op != UBD_MMAP) && 
++         ((req.offset != ((__u64) (CURRENT->sector)) << 9) ||
++          (req.length != (CURRENT->current_nr_sectors) << 9)))
++              panic("I/O op mismatch");
++
++      if(req.map_fd != -1){
++              err = physmem_subst_mapping(req.buffer, req.map_fd, 
++                                          req.map_offset, 1);
++              if(err)
++                      printk("ubd_handler - physmem_subst_mapping failed, "
++                             "err = %d\n", -err);
++      }
++
++      spin_lock(&io_request_lock);
++      ubd_finish(req.error);
++      reactivate_fd(thread_fd, UBD_IRQ);      
++      do_ubd_request(ubd_queue);
++      spin_unlock(&io_request_lock);
++}
++
++static void ubd_intr(int irq, void *dev, struct pt_regs *unused)
++{
++      ubd_handler();
++}
++
++/* Only changed by ubd_init, which is an initcall. */
++static int io_pid = -1;
++
++void kill_io_thread(void)
++{
++      if(io_pid != -1)
++              os_kill_process(io_pid, 1);
++}
++
++__uml_exitcall(kill_io_thread);
++
++/* Initialized in an initcall, and unchanged thereafter */
++devfs_handle_t ubd_dir_handle;
++
++static int ubd_add(int n)
++{
++      struct ubd *dev = &ubd_dev[n];
++      char name[sizeof("nnnnnn\0")], dev_name[sizeof("ubd0x")];
++      int err = -EISDIR;
++
++      if(dev->file == NULL)
++              goto out;
++
++      err = ubd_revalidate1(MKDEV(MAJOR_NR, n << UBD_SHIFT));
++      if(err)
++              goto out;
++
++      if(dev->cow.file == NULL)
++              blk_sizes[n] = UBD_MMAP_BLOCK_SIZE;
++
++      sprintf(name, "%d", n);
++      dev->devfs = devfs_register(ubd_dir_handle, name, DEVFS_FL_REMOVABLE,
++                                  MAJOR_NR, n << UBD_SHIFT, S_IFBLK | 
++                                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
++                                  &ubd_blops, NULL);
++
++#if 0 /* 2.5 ... */
++      sprintf(disk->disk_name, "ubd%c", 'a' + unit);
++#endif
++
++      sprintf(dev_name, "%s%c", ubd_gendisk.major_name, 
++                   n + 'a');
++
++      make_ide_entries(dev_name);
++      return(0);
++
++ out:
++      return(err);
++}
++
++static int ubd_config(char *str)
++{
++      int n, err;
++
++      str = uml_strdup(str);
++      if(str == NULL){
++              printk(KERN_ERR "ubd_config failed to strdup string\n");
++              return(1);
++      }
++      err = ubd_setup_common(str, &n);
++      if(err){
++              kfree(str);
++              return(-1);
++      }
++      if(n == -1) return(0);
++
++      spin_lock(&ubd_lock);
++      err = ubd_add(n);
++      if(err)
++              ubd_dev[n].file = NULL;
++      spin_unlock(&ubd_lock);
++
++      return(err);
++}
++
++static int ubd_get_config(char *name, char *str, int size, char **error_out)
++{
++      struct ubd *dev;
++      char *end;
++      int n, len = 0;
++
++      n = simple_strtoul(name, &end, 0);
++      if((*end != '\0') || (end == name)){
++              *error_out = "ubd_get_config : didn't parse device number";
++              return(-1);
++      }
++
++      if((n >= MAX_DEV) || (n < 0)){
++              *error_out = "ubd_get_config : device number out of range";
++              return(-1);
++      }
++
++      dev = &ubd_dev[n];
++      spin_lock(&ubd_lock);
++
++      if(dev->file == NULL){
++              CONFIG_CHUNK(str, size, len, "", 1);
++              goto out;
++      }
++
++      CONFIG_CHUNK(str, size, len, dev->file, 0);
++
++      if(dev->cow.file != NULL){
++              CONFIG_CHUNK(str, size, len, ",", 0);
++              CONFIG_CHUNK(str, size, len, dev->cow.file, 1);
++      }
++      else CONFIG_CHUNK(str, size, len, "", 1);
++
++ out:
++      spin_unlock(&ubd_lock);
++      return(len);
++}
++
++static int ubd_remove(char *str)
++{
++      struct ubd *dev;
++      int n, err = -ENODEV;
++
++      if(isdigit(*str)){
++              char *end;
++              n = simple_strtoul(str, &end, 0);
++              if ((*end != '\0') || (end == str)) 
++                      return(err);
++      }
++      else if (('a' <= *str) && (*str <= 'h'))
++              n = *str - 'a';
++      else
++              return(err);    /* it should be a number 0-7/a-h */
++
++      if((n < 0) || (n >= MAX_DEV))
++              return(err);
++
++      dev = &ubd_dev[n];
++
++      spin_lock(&ubd_lock);
++      err = 0;
++      if(dev->file == NULL)
++              goto out;
++      err = -1;
++      if(dev->count > 0)
++              goto out;
++      if(dev->devfs != NULL) 
++              devfs_unregister(dev->devfs);
++
++      *dev = ((struct ubd) DEFAULT_UBD);
++      err = 0;
++ out:
++      spin_unlock(&ubd_lock);
++      return(err);
++}
++
++static struct mc_device ubd_mc = {
++      .name           = "ubd",
++      .config         = ubd_config,
++      .get_config     = ubd_get_config,
++      .remove         = ubd_remove,
++};
++
++static int ubd_mc_init(void)
++{
++      mconsole_register_dev(&ubd_mc);
++      return(0);
++}
++
++__initcall(ubd_mc_init);
++
++static request_queue_t *ubd_get_queue(kdev_t device)
++{
++      return(ubd_queue);
++}
++
++int ubd_init(void)
++{
++      unsigned long stack;
++        int i, err;
++
++      ubd_dir_handle = devfs_mk_dir (NULL, "ubd", NULL);
++      if (devfs_register_blkdev(MAJOR_NR, "ubd", &ubd_blops)) {
++              printk(KERN_ERR "ubd: unable to get major %d\n", MAJOR_NR);
++              return -1;
++      }
++      read_ahead[MAJOR_NR] = 8;               /* 8 sector (4kB) read-ahead */
++      blksize_size[MAJOR_NR] = blk_sizes;
++      blk_size[MAJOR_NR] = sizes;
++      INIT_HARDSECT(hardsect_size, MAJOR_NR, hardsect_sizes);
++
++      ubd_queue = BLK_DEFAULT_QUEUE(MAJOR_NR);
++      blk_init_queue(ubd_queue, DEVICE_REQUEST);
++      INIT_ELV(ubd_queue, &ubd_queue->elevator);
++
++        add_gendisk(&ubd_gendisk);
++      if (fake_major != MAJOR_NR){
++              /* major number 0 is used to auto select */
++              err = devfs_register_blkdev(fake_major, "fake", &ubd_blops);
++              if(fake_major == 0){
++              /* auto device number case */
++                      fake_major = err;
++                      if(err == 0)
++                              return(-ENODEV);
++              } 
++              else if (err){
++                      /* not auto so normal error */
++                      printk(KERN_ERR "ubd: error %d getting major %d\n", 
++                             -err, fake_major);
++                      return(-ENODEV);
++              }
++
++              blk_dev[fake_major].queue = ubd_get_queue;
++              read_ahead[fake_major] = 8;     /* 8 sector (4kB) read-ahead */
++              blksize_size[fake_major] = blk_sizes;
++              blk_size[fake_major] = sizes;
++              INIT_HARDSECT(hardsect_size, fake_major, hardsect_sizes);
++                add_gendisk(&fake_gendisk);
++      }
++
++      for(i=0;i<MAX_DEV;i++) 
++              ubd_add(i);
++
++      if(global_openflags.s){
++              printk(KERN_INFO "ubd : Synchronous mode\n");
++              return(0);
++      }
++      stack = alloc_stack(0, 0);
++      io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), 
++                               &thread_fd);
++      if(io_pid < 0){
++              io_pid = -1;
++              printk(KERN_ERR 
++                     "ubd : Failed to start I/O thread (errno = %d) - "
++                     "falling back to synchronous I/O\n", -io_pid);
++              return(0);
++      }
++      err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, 
++                           SA_INTERRUPT, "ubd", ubd_dev);
++      if(err != 0) 
++              printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
++      return(err);
++}
++
++__initcall(ubd_init);
++
++static void ubd_close(struct ubd *dev)
++{
++      if(ubd_do_mmap)
++              physmem_forget_descriptor(dev->fd);
++      os_close_file(dev->fd);
++      if(dev->cow.file != NULL)
++              return;
++
++      if(ubd_do_mmap)
++              physmem_forget_descriptor(dev->cow.fd);
++      os_close_file(dev->cow.fd);
++      vfree(dev->cow.bitmap);
++      dev->cow.bitmap = NULL;
++}
++
++static int ubd_open_dev(struct ubd *dev)
++{
++      struct openflags flags;
++      char **back_ptr;
++      int err, create_cow, *create_ptr;
++
++      dev->openflags = dev->boot_openflags;
++      create_cow = 0;
++      create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
++      back_ptr = dev->no_cow ? NULL : &dev->cow.file;
++      dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr,
++                              &dev->cow.bitmap_offset, &dev->cow.bitmap_len, 
++                              &dev->cow.data_offset, create_ptr);
++
++      if((dev->fd == -ENOENT) && create_cow){
++              dev->fd = create_cow_file(dev->file, dev->cow.file, 
++                                        dev->openflags, 1 << 9, PAGE_SIZE,
++                                        &dev->cow.bitmap_offset, 
++                                        &dev->cow.bitmap_len,
++                                        &dev->cow.data_offset);
++              if(dev->fd >= 0){
++                      printk(KERN_INFO "Creating \"%s\" as COW file for "
++                             "\"%s\"\n", dev->file, dev->cow.file);
++              }
++      }
++
++      if(dev->fd < 0) return(dev->fd);
++
++      if(dev->cow.file != NULL){
++              err = -ENOMEM;
++              dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len);
++              if(dev->cow.bitmap == NULL){
++                      printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
++                      goto error;
++              }
++              flush_tlb_kernel_vm();
++
++              err = read_cow_bitmap(dev->fd, dev->cow.bitmap, 
++                                    dev->cow.bitmap_offset, 
++                                    dev->cow.bitmap_len);
++              if(err < 0) 
++                      goto error;
++
++              flags = dev->openflags;
++              flags.w = 0;
++              err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, 
++                                  NULL, NULL);
++              if(err < 0) goto error;
++              dev->cow.fd = err;
++      }
++      return(0);
++ error:
++      os_close_file(dev->fd);
++      return(err);
++}
++
++static int ubd_file_size(struct ubd *dev, __u64 *size_out)
++{
++      char *file;
++
++      file = dev->cow.file ? dev->cow.file : dev->file;
++      return(os_file_size(file, size_out));
++}
++
++static int ubd_open(struct inode *inode, struct file *filp)
++{
++      struct ubd *dev;
++      int n, offset, err = 0;
++
++      n = DEVICE_NR(inode->i_rdev);
++      dev = &ubd_dev[n];
++      if(n >= MAX_DEV)
++              return -ENODEV;
++
++      spin_lock(&ubd_lock);
++      offset = n << UBD_SHIFT;
++
++      if(dev->count == 0){
++              err = ubd_open_dev(dev);
++              if(err){
++                      printk(KERN_ERR "ubd%d: Can't open \"%s\": "
++                             "errno = %d\n", n, dev->file, -err);
++                      goto out;
++              }
++              err = ubd_file_size(dev, &dev->size);
++              if(err < 0)
++                      goto out;
++              sizes[offset] = dev->size / BLOCK_SIZE;
++              ubd_part[offset].nr_sects = dev->size / hardsect_sizes[offset];
++      }
++      dev->count++;
++      if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){
++              if(--dev->count == 0) ubd_close(dev);
++              err = -EROFS;
++      }
++ out:
++      spin_unlock(&ubd_lock);
++      return(err);
++}
++
++static int ubd_release(struct inode * inode, struct file * file)
++{
++        int n, offset;
++
++      n =  DEVICE_NR(inode->i_rdev);
++      offset = n << UBD_SHIFT;
++      if(n >= MAX_DEV)
++              return -ENODEV;
++
++      spin_lock(&ubd_lock);
++      if(--ubd_dev[n].count == 0)
++              ubd_close(&ubd_dev[n]);
++      spin_unlock(&ubd_lock);
++
++      return(0);
++}
++
++static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, 
++                        __u64 *cow_offset, unsigned long *bitmap, 
++                        __u64 bitmap_offset, unsigned long *bitmap_words,
++                        __u64 bitmap_len)
++{
++      __u64 sector = io_offset >> 9;
++      int i, update_bitmap = 0;
++
++      for(i = 0; i < length >> 9; i++){
++              if(cow_mask != NULL)
++                      ubd_set_bit(i, (unsigned char *) cow_mask);
++              if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
++                      continue;
++
++              update_bitmap = 1;
++              ubd_set_bit(sector + i, (unsigned char *) bitmap);
++      }
++
++      if(!update_bitmap)
++              return;
++
++      *cow_offset = sector / (sizeof(unsigned long) * 8);
++
++      /* This takes care of the case where we're exactly at the end of the
++       * device, and *cow_offset + 1 is off the end.  So, just back it up
++       * by one word.  Thanks to Lynn Kerby for the fix and James McMechan
++       * for the original diagnosis.
++       */
++      if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) / 
++                         sizeof(unsigned long) - 1))
++              (*cow_offset)--;
++
++      bitmap_words[0] = bitmap[*cow_offset];
++      bitmap_words[1] = bitmap[*cow_offset + 1];
++
++      *cow_offset *= sizeof(unsigned long);
++      *cow_offset += bitmap_offset;
++}
++
++static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, 
++                     __u64 bitmap_offset, __u64 bitmap_len)
++{
++      __u64 sector = req->offset >> 9;
++        int i;
++
++      if(req->length > (sizeof(req->sector_mask) * 8) << 9)
++              panic("Operation too long");
++
++      if(req->op == UBD_READ) {
++              for(i = 0; i < req->length >> 9; i++){
++                      if(ubd_test_bit(sector + i, (unsigned char *) bitmap)){
++                              ubd_set_bit(i, (unsigned char *) 
++                                          &req->sector_mask);
++                      }
++                }
++        } 
++        else cowify_bitmap(req->offset, req->length, &req->sector_mask,
++                         &req->cow_offset, bitmap, bitmap_offset, 
++                         req->bitmap_words, bitmap_len);
++}
++
++static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset)
++{
++      __u64 sector;
++      unsigned char *bitmap;
++      int bit, i;
++
++      /* mmap must have been requested on the command line */
++      if(!ubd_do_mmap)
++              return(-1);
++
++      /* The buffer must be page aligned */
++      if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0)
++              return(-1);
++
++      /* The request must be a page long */
++      if((req->current_nr_sectors << 9) != PAGE_SIZE)
++              return(-1);
++
++      if(dev->cow.file == NULL)
++              return(dev->fd);
++
++      sector = offset >> 9;
++      bitmap = (unsigned char *) dev->cow.bitmap;
++      bit = ubd_test_bit(sector, bitmap);
++
++      for(i = 1; i < req->current_nr_sectors; i++){
++              if(ubd_test_bit(sector + i, bitmap) != bit)
++                      return(-1);
++      }
++
++      if(bit || (req->cmd == WRITE))
++              offset += dev->cow.data_offset;
++
++      /* The data on disk must be page aligned */
++      if((offset % UBD_MMAP_BLOCK_SIZE) != 0)
++              return(-1);
++
++      return(bit ? dev->fd : dev->cow.fd);
++}
++
++static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset, 
++                              struct request *req, 
++                              struct io_thread_req *io_req)
++{
++      int err;
++
++      if(req->cmd == WRITE){
++              /* Writes are almost no-ops since the new data is already in the
++               * host page cache
++               */
++              dev->map_writes++;
++              if(dev->cow.file != NULL)
++                      cowify_bitmap(io_req->offset, io_req->length, 
++                                    &io_req->sector_mask, &io_req->cow_offset,
++                                    dev->cow.bitmap, dev->cow.bitmap_offset,
++                                    io_req->bitmap_words, 
++                                    dev->cow.bitmap_len);
++      }
++      else {
++              int w;
++
++              if((dev->cow.file != NULL) && (fd == dev->cow.fd))
++                      w = 0;
++              else w = dev->openflags.w;
++
++              if((dev->cow.file != NULL) && (fd == dev->fd))
++                      offset += dev->cow.data_offset;
++
++              err = physmem_subst_mapping(req->buffer, fd, offset, w);
++              if(err){
++                      printk("physmem_subst_mapping failed, err = %d\n", 
++                             -err);
++                      return(1);
++              }
++              dev->map_reads++;
++      }
++      io_req->op = UBD_MMAP;
++      io_req->buffer = req->buffer;
++      return(0);
++}
++
++static int prepare_request(struct request *req, struct io_thread_req *io_req)
++{
++      struct ubd *dev;
++      __u64 offset;
++      int minor, n, len, fd;
++
++      if(req->rq_status == RQ_INACTIVE) return(1);
++
++      minor = MINOR(req->rq_dev);
++      n = minor >> UBD_SHIFT;
++      dev = &ubd_dev[n];
++
++      if(IS_WRITE(req) && !dev->openflags.w){
++              printk("Write attempted on readonly ubd device %d\n", n);
++              end_request(0);
++              return(1);
++      }
++
++        req->sector += ubd_part[minor].start_sect;
++      offset = ((__u64) req->sector) << 9;
++      len = req->current_nr_sectors << 9;
++
++      io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
++      io_req->fds[1] = dev->fd;
++      io_req->map_fd = -1;
++      io_req->cow_offset = -1;
++      io_req->offset = offset;
++      io_req->length = len;
++      io_req->error = 0;
++      io_req->sector_mask = 0;
++
++      fd = mmap_fd(req, dev, io_req->offset);
++      if(fd > 0){
++              /* If mmapping is otherwise OK, but the first access to the 
++               * page is a write, then it's not mapped in yet.  So we have 
++               * to write the data to disk first, then we can map the disk
++               * page in and continue normally from there.
++               */
++              if((req->cmd == WRITE) && !is_remapped(req->buffer, dev->fd, io_req->offset + dev->cow.data_offset)){
++                      io_req->map_fd = dev->fd;
++                      io_req->map_offset = io_req->offset + 
++                              dev->cow.data_offset;
++                      dev->write_maps++;
++              }
++              else return(prepare_mmap_request(dev, fd, io_req->offset, req, 
++                                               io_req));
++      }
++
++      if(req->cmd == READ)
++              dev->nomap_reads++;
++      else dev->nomap_writes++;
++
++      io_req->op = (req->cmd == READ) ? UBD_READ : UBD_WRITE;
++      io_req->offsets[0] = 0;
++      io_req->offsets[1] = dev->cow.data_offset;
++      io_req->buffer = req->buffer;
++      io_req->sectorsize = 1 << 9;
++
++        if(dev->cow.file != NULL) 
++              cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,
++                         dev->cow.bitmap_len);
++      return(0);
++}
++
++static void do_ubd_request(request_queue_t *q)
++{
++      struct io_thread_req io_req;
++      struct request *req;
++      int err, n;
++
++      if(thread_fd == -1){
++              while(!list_empty(&q->queue_head)){
++                      req = blkdev_entry_next_request(&q->queue_head);
++                      err = prepare_request(req, &io_req);
++                      if(!err){
++                              do_io(&io_req);
++                              ubd_finish(io_req.error);
++                      }
++              }
++      }
++      else {
++              if(DEVICE_INTR || list_empty(&q->queue_head)) return;
++              req = blkdev_entry_next_request(&q->queue_head);
++              err = prepare_request(req, &io_req);
++              if(!err){
++                      SET_INTR(ubd_handler);
++                      n = write_ubd_fs(thread_fd, (char *) &io_req, 
++                                       sizeof(io_req));
++                      if(n != sizeof(io_req))
++                              printk("write to io thread failed, "
++                                     "errno = %d\n", -n);
++              }
++      }
++}
++
++static int ubd_ioctl(struct inode * inode, struct file * file,
++                   unsigned int cmd, unsigned long arg)
++{
++      struct hd_geometry *loc = (struct hd_geometry *) arg;
++      struct ubd *dev;
++      int n, minor, err;
++      struct hd_driveid ubd_id = {
++              .cyls           = 0,
++              .heads          = 128,
++              .sectors        = 32,
++      };
++      
++        if(!inode) return(-EINVAL);
++      minor = MINOR(inode->i_rdev);
++      n = minor >> UBD_SHIFT;
++      if(n >= MAX_DEV)
++              return(-EINVAL);
++      dev = &ubd_dev[n];
++      switch (cmd) {
++              struct hd_geometry g;
++              struct cdrom_volctrl volume;
++      case HDIO_GETGEO:
++              if(!loc) return(-EINVAL);
++              g.heads = 128;
++              g.sectors = 32;
++              g.cylinders = dev->size / (128 * 32 * hardsect_sizes[minor]);
++              g.start = ubd_part[minor].start_sect;
++              return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0);
++      case BLKGETSIZE:   /* Return device size */
++              if(!arg) return(-EINVAL);
++              err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
++              if(err)
++                      return(err);
++              put_user(ubd_part[minor].nr_sects, (long *) arg);
++              return(0);
++      case BLKRRPART: /* Re-read partition tables */
++              return(ubd_revalidate(inode->i_rdev));
++
++      case HDIO_GET_IDENTITY:
++              ubd_id.cyls = dev->size / (128 * 32 * hardsect_sizes[minor]);
++              if(copy_to_user((char *) arg, (char *) &ubd_id, 
++                               sizeof(ubd_id)))
++                      return(-EFAULT);
++              return(0);
++              
++      case CDROMVOLREAD:
++              if(copy_from_user(&volume, (char *) arg, sizeof(volume)))
++                      return(-EFAULT);
++              volume.channel0 = 255;
++              volume.channel1 = 255;
++              volume.channel2 = 255;
++              volume.channel3 = 255;
++              if(copy_to_user((char *) arg, &volume, sizeof(volume)))
++                      return(-EFAULT);
++              return(0);
++
++      default:
++              return blk_ioctl(inode->i_rdev, cmd, arg);
++      }
++}
++
++static int ubd_revalidate1(kdev_t rdev)
++{
++      int i, n, offset, err = 0, pcount = 1 << UBD_SHIFT;
++      struct ubd *dev;
++      struct hd_struct *part;
++
++      n = DEVICE_NR(rdev);
++      offset = n << UBD_SHIFT;
++      dev = &ubd_dev[n];
++
++      part = &ubd_part[offset];
++
++      /* clear all old partition counts */
++      for(i = 1; i < pcount; i++) {
++              part[i].start_sect = 0;
++              part[i].nr_sects = 0;
++      }
++
++      /* If it already has been opened we can check the partitions 
++       * directly 
++       */
++      if(dev->count){
++              part->start_sect = 0;
++              register_disk(&ubd_gendisk, MKDEV(MAJOR_NR, offset), pcount, 
++                            &ubd_blops, part->nr_sects);
++      } 
++      else if(dev->file){
++              err = ubd_open_dev(dev);
++              if(err){
++                      printk(KERN_ERR "unable to open %s for validation\n",
++                             dev->file);
++                      goto out;
++              }
++
++              /* have to recompute sizes since we opened it */
++              err = ubd_file_size(dev, &dev->size);
++              if(err < 0) {
++                      ubd_close(dev);
++                      goto out;
++              }
++              part->start_sect = 0;
++              part->nr_sects = dev->size / hardsect_sizes[offset];
++              register_disk(&ubd_gendisk, MKDEV(MAJOR_NR, offset), pcount, 
++                            &ubd_blops, part->nr_sects);
++
++              /* we are done so close it */
++              ubd_close(dev);
++      } 
++      else err = -ENODEV;
++ out:
++      return(err);
++}
++
++static int ubd_revalidate(kdev_t rdev)
++{
++      int err;
++
++      spin_lock(&ubd_lock);
++      err = ubd_revalidate1(rdev);
++      spin_unlock(&ubd_lock);
++      return(err);
++}
++
++static int ubd_check_remapped(int fd, unsigned long address, int is_write,
++                            __u64 offset, int is_user)
++{
++      __u64 bitmap_offset;
++      unsigned long new_bitmap[2];
++      int i, err, n;
++
++      /* This can only fix kernelspace faults */
++      if(is_user)
++              return(0);
++
++      /* ubd-mmap is only enabled in skas mode */
++      if(CHOOSE_MODE(1, 0))
++              return(0);
++
++      /* If it's not a write access, we can't do anything about it */
++      if(!is_write)
++              return(0);
++
++      /* We have a write */
++      for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){
++              struct ubd *dev = &ubd_dev[i];
++
++              if((dev->fd != fd) && (dev->cow.fd != fd))
++                      continue;
++
++              /* It's a write to a ubd device */
++
++              if(!dev->openflags.w){
++                      /* It's a write access on a read-only device - probably
++                       * shouldn't happen.  If the kernel is trying to change
++                       * something with no intention of writing it back out,
++                       * then this message will clue us in that this needs
++                       * fixing
++                       */
++                      printk("Write access to mapped page from readonly ubd "
++                             "device %d\n", i);
++                      return(0);
++              }
++
++              /* It's a write to a writeable ubd device - it must be COWed
++               * because, otherwise, the page would have been mapped in 
++               * writeable
++               */
++
++              if(!dev->cow.file)
++                      panic("Write fault on writeable non-COW ubd device %d",
++                            i);
++
++              /* It should also be an access to the backing file since the 
++               * COW pages should be mapped in read-write
++               */
++
++              if(fd == dev->fd)
++                      panic("Write fault on a backing page of ubd "
++                            "device %d\n", i);
++
++              /* So, we do the write, copying the backing data to the COW 
++               * file... 
++               */
++
++              err = os_seek_file(dev->fd, offset + dev->cow.data_offset);
++              if(err < 0)
++                      panic("Couldn't seek to %lld in COW file of ubd "
++                            "device %d, err = %d", 
++                            offset + dev->cow.data_offset, i, -err);
++
++              n = os_write_file(dev->fd, (void *) address, PAGE_SIZE);
++              if(n != PAGE_SIZE)
++                      panic("Couldn't copy data to COW file of ubd "
++                            "device %d, err = %d", i, -n);
++
++              /* ... updating the COW bitmap... */
++
++              cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset, 
++                            dev->cow.bitmap, dev->cow.bitmap_offset, 
++                            new_bitmap, dev->cow.bitmap_len);
++
++              err = os_seek_file(dev->fd, bitmap_offset);
++              if(err < 0)
++                      panic("Couldn't seek to %lld in COW file of ubd "
++                            "device %d, err = %d", bitmap_offset, i, -err);
++
++              n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap));
++              if(n != sizeof(new_bitmap))
++                      panic("Couldn't update bitmap  of ubd device %d, "
++                            "err = %d", i, -n);
++              
++              /* Maybe we can map the COW page in, and maybe we can't.  If
++               * it is a pre-V3 COW file, we can't, since the alignment will 
++               * be wrong.  If it is a V3 or later COW file which has been 
++               * moved to a system with a larger page size, then maybe we 
++               * can't, depending on the exact location of the page.
++               */
++
++              offset += dev->cow.data_offset;
++
++              /* Remove the remapping, putting the original anonymous page
++               * back.  If the COW file can be mapped in, that is done.
++               * Otherwise, the COW page is read in.
++               */
++
++              if(!physmem_remove_mapping((void *) address))
++                      panic("Address 0x%lx not remapped by ubd device %d", 
++                            address, i);
++              if((offset % UBD_MMAP_BLOCK_SIZE) == 0)
++                      physmem_subst_mapping((void *) address, dev->fd, 
++                                            offset, 1);
++              else {
++                      err = os_seek_file(dev->fd, offset);
++                      if(err < 0)
++                              panic("Couldn't seek to %lld in COW file of "
++                                    "ubd device %d, err = %d", offset, i, 
++                                    -err);
++
++                      n = os_read_file(dev->fd, (void *) address, PAGE_SIZE);
++                      if(n != PAGE_SIZE)
++                              panic("Failed to read page from offset %llx of "
++                                    "COW file of ubd device %d, err = %d",
++                                    offset, i, -n);
++              }
++
++              return(1);
++      }
++
++      /* It's not a write on a ubd device */
++      return(0);
++}
++
++static struct remapper ubd_remapper = {
++      .list   = LIST_HEAD_INIT(ubd_remapper.list),
++      .proc   = ubd_check_remapped,
++};
++
++static int ubd_remapper_setup(void)
++{
++      if(ubd_do_mmap)
++              register_remapper(&ubd_remapper);
++
++      return(0);
++}
++
++__initcall(ubd_remapper_setup);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/ubd_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/ubd_user.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/ubd_user.c    2005-05-03 22:28:14.259442448 +0300
+@@ -0,0 +1,379 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com)
++ * Licensed under the GPL
++ */
++
++#include <stddef.h>
++#include <unistd.h>
++#include <errno.h>
++#include <sched.h>
++#include <signal.h>
++#include <string.h>
++#include <netinet/in.h>
++#include <sys/time.h>
++#include <sys/socket.h>
++#include <sys/mman.h>
++#include <sys/param.h>
++#include "asm/types.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "ubd_user.h"
++#include "os.h"
++#include "cow.h"
++
++#include <endian.h>
++#include <byteswap.h>
++
++static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
++{
++      struct uml_stat buf1, buf2;
++      int err;
++
++      if(from_cmdline == NULL) return(1);
++      if(!strcmp(from_cmdline, from_cow)) return(1);
++
++      err = os_stat_file(from_cmdline, &buf1);
++      if(err < 0){
++              printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
++              return(1);
++      }
++      err = os_stat_file(from_cow, &buf2);
++      if(err < 0){
++              printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
++              return(1);
++      }
++      if((buf1.ust_major == buf2.ust_major) && 
++         (buf1.ust_minor == buf2.ust_minor) && 
++         (buf1.ust_ino == buf2.ust_ino))
++              return(1);
++
++      printk("Backing file mismatch - \"%s\" requested,\n"
++             "\"%s\" specified in COW header of \"%s\"\n",
++             from_cmdline, from_cow, cow);
++      return(0);
++}
++
++static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
++{
++      unsigned long modtime;
++      long long actual;
++      int err;
++
++      err = os_file_modtime(file, &modtime);
++      if(err < 0){
++              printk("Failed to get modification time of backing file "
++                     "\"%s\", err = %d\n", file, -err);
++              return(err);
++      }
++
++      err = os_file_size(file, &actual);
++      if(err < 0){
++              printk("Failed to get size of backing file \"%s\", "
++                     "err = %d\n", file, -err);
++              return(err);
++      }
++
++      if(actual != size){
++              printk("Size mismatch (%ld vs %ld) of COW header vs backing "
++                     "file\n", size, actual);
++              return(-EINVAL);
++      }
++      if(modtime != mtime){
++              printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
++                     "file\n", mtime, modtime);
++              return(-EINVAL);
++      }
++      return(0);
++}
++
++int read_cow_bitmap(int fd, void *buf, int offset, int len)
++{
++      int err;
++
++      err = os_seek_file(fd, offset);
++      if(err < 0) 
++              return(err);
++
++      err = os_read_file(fd, buf, len);
++      if(err < 0) 
++              return(err);
++
++      return(0);
++}
++
++int open_ubd_file(char *file, struct openflags *openflags, 
++                char **backing_file_out, int *bitmap_offset_out, 
++                unsigned long *bitmap_len_out, int *data_offset_out, 
++                int *create_cow_out)
++{
++      time_t mtime;
++      __u64 size;
++      __u32 version, align;
++      char *backing_file;
++      int fd, err, sectorsize, same, mode = 0644;
++
++      fd = os_open_file(file, *openflags, mode);
++      if(fd < 0){
++              if((fd == -ENOENT) && (create_cow_out != NULL))
++                      *create_cow_out = 1;
++                if(!openflags->w ||
++                   ((errno != EROFS) && (errno != EACCES))) return(-errno);
++              openflags->w = 0;
++              fd = os_open_file(file, *openflags, mode); 
++              if(fd < 0) 
++                      return(fd);
++        }
++
++      err = os_lock_file(fd, openflags->w);
++      if(err < 0){
++              printk("Failed to lock '%s', err = %d\n", file, -err);
++              goto out_close;
++      }
++      
++      if(backing_file_out == NULL) return(fd);
++
++      err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
++                            &size, &sectorsize, &align, bitmap_offset_out);
++      if(err && (*backing_file_out != NULL)){
++              printk("Failed to read COW header from COW file \"%s\", "
++                     "errno = %d\n", file, -err);
++              goto out_close;
++      }
++      if(err) return(fd);
++
++      if(backing_file_out == NULL) return(fd);
++      
++      same = same_backing_files(*backing_file_out, backing_file, file);
++
++      if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){
++              printk("Switching backing file to '%s'\n", *backing_file_out);
++              err = write_cow_header(file, fd, *backing_file_out,
++                                     sectorsize, align, &size);
++              if(err){
++                      printk("Switch failed, errno = %d\n", -err);
++                      return(err);
++              }
++      }
++      else {
++              *backing_file_out = backing_file;
++              err = backing_file_mismatch(*backing_file_out, size, mtime);
++              if(err) goto out_close;
++      }
++
++      cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, 
++                bitmap_len_out, data_offset_out);
++
++        return(fd);
++ out_close:
++      os_close_file(fd);
++      return(err);
++}
++
++int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
++                  int sectorsize, int alignment, int *bitmap_offset_out, 
++                  unsigned long *bitmap_len_out, int *data_offset_out)
++{
++      int err, fd;
++
++      flags.c = 1;
++      fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL);
++      if(fd < 0){
++              err = fd;
++              printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
++                     -err);
++              goto out;
++      }
++
++      err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
++                          bitmap_offset_out, bitmap_len_out, 
++                          data_offset_out);
++      if(!err)
++              return(fd);
++
++      os_close_file(fd);
++ out:
++      return(err);
++}
++
++/* XXX Just trivial wrappers around os_read_file and os_write_file */
++int read_ubd_fs(int fd, void *buffer, int len)
++{
++      return(os_read_file(fd, buffer, len));
++}
++
++int write_ubd_fs(int fd, char *buffer, int len)
++{
++      return(os_write_file(fd, buffer, len));
++}
++
++static int update_bitmap(struct io_thread_req *req)
++{
++      int n;
++
++      if(req->cow_offset == -1)
++              return(0);
++
++      n = os_seek_file(req->fds[1], req->cow_offset);
++      if(n < 0){
++              printk("do_io - bitmap lseek failed : err = %d\n", -n);
++              return(1);
++      }
++
++      n = os_write_file(req->fds[1], &req->bitmap_words,
++                        sizeof(req->bitmap_words));
++      if(n != sizeof(req->bitmap_words)){
++              printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
++                     req->fds[1]);
++              return(1);
++      }
++
++      return(0);
++}
++
++void do_io(struct io_thread_req *req)
++{
++      char *buf;
++      unsigned long len;
++      int n, nsectors, start, end, bit;
++      int err;
++      __u64 off;
++
++      if(req->op == UBD_MMAP){
++              /* Touch the page to force the host to do any necessary IO to 
++               * get it into memory 
++               */
++              n = *((volatile int *) req->buffer);
++              req->error = update_bitmap(req);
++              return;
++      }
++
++      nsectors = req->length / req->sectorsize;
++      start = 0;
++      do {
++              bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
++              end = start;
++              while((end < nsectors) && 
++                    (ubd_test_bit(end, (unsigned char *) 
++                                  &req->sector_mask) == bit))
++                      end++;
++
++              off = req->offset + req->offsets[bit] + 
++                      start * req->sectorsize;
++              len = (end - start) * req->sectorsize;
++              buf = &req->buffer[start * req->sectorsize];
++
++              err = os_seek_file(req->fds[bit], off);
++              if(err < 0){
++                      printk("do_io - lseek failed : err = %d\n", -err);
++                      req->error = 1;
++                      return;
++              }
++              if(req->op == UBD_READ){
++                      n = 0;
++                      do {
++                              buf = &buf[n];
++                              len -= n;
++                              n = os_read_file(req->fds[bit], buf, len);
++                              if (n < 0) {
++                                      printk("do_io - read failed, err = %d "
++                                             "fd = %d\n", -n, req->fds[bit]);
++                                      req->error = 1;
++                                      return;
++                              }
++                      } while((n < len) && (n != 0));
++                      if (n < len) memset(&buf[n], 0, len - n);
++              }
++              else {
++                      n = os_write_file(req->fds[bit], buf, len);
++                      if(n != len){
++                              printk("do_io - write failed err = %d "
++                                     "fd = %d\n", -n, req->fds[bit]);
++                              req->error = 1;
++                              return;
++                      }
++              }
++
++              start = end;
++      } while(start < nsectors);
++
++      req->error = update_bitmap(req);
++}
++
++/* Changed in start_io_thread, which is serialized by being called only
++ * from ubd_init, which is an initcall.
++ */
++int kernel_fd = -1;
++
++/* Only changed by the io thread */
++int io_count = 0;
++
++int io_thread(void *arg)
++{
++      struct io_thread_req req;
++      int n;
++
++      signal(SIGWINCH, SIG_IGN);
++      while(1){
++              n = os_read_file(kernel_fd, &req, sizeof(req));
++              if(n != sizeof(req)){
++                      if(n < 0)
++                              printk("io_thread - read failed, fd = %d, "
++                                     "err = %d\n", kernel_fd, -n);
++                      else {
++                              printk("io_thread - short read, fd = %d, "
++                                     "length = %d\n", kernel_fd, n);
++                      }
++                      continue;
++              }
++              io_count++;
++              do_io(&req);
++              n = os_write_file(kernel_fd, &req, sizeof(req));
++              if(n != sizeof(req))
++                      printk("io_thread - write failed, fd = %d, err = %d\n",
++                             kernel_fd, -n);
++      }
++}
++
++int start_io_thread(unsigned long sp, int *fd_out)
++{
++      int pid, fds[2], err;
++
++      err = os_pipe(fds, 1, 1);
++      if(err < 0){
++              printk("start_io_thread - os_pipe failed, err = %d\n", -err);
++              goto out;
++      }
++
++      kernel_fd = fds[0];
++      *fd_out = fds[1];
++
++      pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
++                  NULL);
++      if(pid < 0){
++              printk("start_io_thread - clone failed : errno = %d\n", errno);
++              goto out_close;
++      }
++
++      return(pid);
++
++ out_close:
++      os_close_file(fds[0]);
++      os_close_file(fds[1]);
++      kernel_fd = -1;
++      *fd_out = -1;
++ out:
++      return(err);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/xterm.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/xterm.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/xterm.c       2005-05-03 22:28:14.260442296 +0300
+@@ -0,0 +1,213 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <termios.h>
++#include <signal.h>
++#include <sched.h>
++#include <sys/socket.h>
++#include "kern_util.h"
++#include "chan_user.h"
++#include "helper.h"
++#include "user_util.h"
++#include "user.h"
++#include "os.h"
++#include "xterm.h"
++
++struct xterm_chan {
++      int pid;
++      int helper_pid;
++      char *title;
++      int device;
++      int raw;
++      struct termios tt;
++      unsigned long stack;
++      int direct_rcv;
++};
++
++void *xterm_init(char *str, int device, struct chan_opts *opts)
++{
++      struct xterm_chan *data;
++
++      data = malloc(sizeof(*data));
++      if(data == NULL) return(NULL);
++      *data = ((struct xterm_chan) { .pid             = -1, 
++                                     .helper_pid      = -1,
++                                     .device          = device, 
++                                     .title           = opts->xterm_title,
++                                     .raw             = opts->raw,
++                                     .stack           = opts->tramp_stack,
++                                     .direct_rcv      = !opts->in_kernel } );
++      return(data);
++}
++
++/* Only changed by xterm_setup, which is a setup */
++static char *terminal_emulator = "xterm";
++static char *title_switch = "-T";
++static char *exec_switch = "-e";
++
++static int __init xterm_setup(char *line, int *add)
++{
++      *add = 0;
++      terminal_emulator = line;
++
++      line = strchr(line, ',');
++      if(line == NULL) return(0);
++      *line++ = '\0';
++      if(*line) title_switch = line;
++
++      line = strchr(line, ',');
++      if(line == NULL) return(0);
++      *line++ = '\0';
++      if(*line) exec_switch = line;
++
++      return(0);
++}
++
++__uml_setup("xterm=", xterm_setup,
++"xterm=<terminal emulator>,<title switch>,<exec switch>\n"
++"    Specifies an alternate terminal emulator to use for the debugger,\n"
++"    consoles, and serial lines when they are attached to the xterm channel.\n"
++"    The values are the terminal emulator binary, the switch it uses to set\n"
++"    its title, and the switch it uses to execute a subprocess,\n"
++"    respectively.  The title switch must have the form '<switch> title',\n"
++"    not '<switch>=title'.  Similarly, the exec switch must have the form\n"
++"    '<switch> command arg1 arg2 ...'.\n"
++"    The default values are 'xterm=xterm,-T,-e'.  Values for gnome-terminal\n"
++"    are 'xterm=gnome-terminal,-t,-x'.\n\n"
++);
++
++/* XXX This badly needs some cleaning up in the error paths */
++int xterm_open(int input, int output, int primary, void *d, char **dev_out)
++{
++      struct xterm_chan *data = d;
++      unsigned long stack;
++      int pid, fd, new, err;
++      char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
++      char *argv[] = { terminal_emulator, title_switch, title, exec_switch, 
++                       "/usr/lib/uml/port-helper", "-uml-socket",
++                       file, NULL };
++
++      if(os_access(argv[4], OS_ACC_X_OK) < 0)
++              argv[4] = "port-helper";
++
++      fd = mkstemp(file);
++      if(fd < 0){
++              printk("xterm_open : mkstemp failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      if(unlink(file)){
++              printk("xterm_open : unlink failed, errno = %d\n", errno);
++              return(-errno);
++      }
++      os_close_file(fd);
++
++      fd = os_create_unix_socket(file, sizeof(file), 1);
++      if(fd < 0){
++              printk("xterm_open : create_unix_socket failed, errno = %d\n", 
++                     -fd);
++              return(fd);
++      }
++
++      sprintf(title, data->title, data->device);
++      stack = data->stack;
++      pid = run_helper(NULL, NULL, argv, &stack);
++      if(pid < 0){
++              printk("xterm_open : run_helper failed, errno = %d\n", -pid);
++              return(pid);
++      }
++
++      if(data->stack == 0) free_stack(stack, 0);
++
++      if(data->direct_rcv)
++              new = os_rcv_fd(fd, &data->helper_pid);
++      else {
++              err = os_set_fd_block(fd, 0);
++              if(err < 0){
++                      printk("xterm_open : failed to set descriptor "
++                             "non-blocking, err = %d\n", -err);
++                      return(err);
++              }
++              new = xterm_fd(fd, &data->helper_pid);
++      }
++      if(new < 0){
++              printk("xterm_open : os_rcv_fd failed, err = %d\n", -new);
++              goto out;
++      }
++
++      CATCH_EINTR(err = tcgetattr(new, &data->tt));
++      if(err){
++              new = err;
++              goto out;
++      }
++
++      if(data->raw){
++              err = raw(new);
++              if(err){
++                      new = err;
++                      goto out;
++              }
++      }
++
++      data->pid = pid;
++      *dev_out = NULL;
++ out:
++      unlink(file);
++      return(new);
++}
++
++void xterm_close(int fd, void *d)
++{
++      struct xterm_chan *data = d;
++      
++      if(data->pid != -1) 
++              os_kill_process(data->pid, 1);
++      data->pid = -1;
++      if(data->helper_pid != -1) 
++              os_kill_process(data->helper_pid, 0);
++      data->helper_pid = -1;
++      os_close_file(fd);
++}
++
++void xterm_free(void *d)
++{
++      free(d);
++}
++
++int xterm_console_write(int fd, const char *buf, int n, void *d)
++{
++      struct xterm_chan *data = d;
++
++      return(generic_console_write(fd, buf, n, &data->tt));
++}
++
++struct chan_ops xterm_ops = {
++      .type           = "xterm",
++      .init           = xterm_init,
++      .open           = xterm_open,
++      .close          = xterm_close,
++      .read           = generic_read,
++      .write          = generic_write,
++      .console_write  = xterm_console_write,
++      .window_size    = generic_window_size,
++      .free           = xterm_free,
++      .winch          = 1,
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/xterm.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/xterm.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/xterm.h       2005-05-03 22:28:14.261442144 +0300
+@@ -0,0 +1,22 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __XTERM_H__
++#define __XTERM_H__
++
++extern int xterm_fd(int socket, int *pid_out);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/drivers/xterm_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/drivers/xterm_kern.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/drivers/xterm_kern.c  2005-05-03 22:28:14.262441992 +0300
+@@ -0,0 +1,82 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/errno.h"
++#include "linux/slab.h"
++#include "asm/semaphore.h"
++#include "asm/irq.h"
++#include "irq_user.h"
++#include "irq_kern.h"
++#include "kern_util.h"
++#include "os.h"
++#include "xterm.h"
++
++struct xterm_wait {
++      struct semaphore sem;
++      int fd;
++      int pid;
++      int new_fd;
++};
++
++static void xterm_interrupt(int irq, void *data, struct pt_regs *regs)
++{
++      struct xterm_wait *xterm = data;
++      int fd;
++
++      fd = os_rcv_fd(xterm->fd, &xterm->pid);
++      if(fd == -EAGAIN)
++              return;
++
++      xterm->new_fd = fd;
++      up(&xterm->sem);
++}
++
++int xterm_fd(int socket, int *pid_out)
++{
++      struct xterm_wait *data;
++      int err, ret;
++
++      data = kmalloc(sizeof(*data), GFP_KERNEL);
++      if(data == NULL){
++              printk(KERN_ERR "xterm_fd : failed to allocate xterm_wait\n");
++              return(-ENOMEM);
++      }
++      *data = ((struct xterm_wait) 
++              { .sem          = __SEMAPHORE_INITIALIZER(data->sem, 0),
++                .fd           = socket,
++                .pid          = -1,
++                .new_fd       = -1 });
++
++      err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt, 
++                           SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
++                           "xterm", data);
++      if(err){
++              printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, "
++                     "err = %d\n",  err);
++              ret = err;
++              goto out;
++      }
++      down(&data->sem);
++
++      free_irq(XTERM_IRQ, data);
++
++      ret = data->new_fd;
++      *pid_out = data->pid;
++ out:
++      kfree(data);
++
++      return(ret);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/fs/hostfs/externfs.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/fs/hostfs/externfs.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/fs/hostfs/externfs.c  2005-05-03 22:28:14.269440928 +0300
+@@ -0,0 +1,1283 @@
++/* 
++ * Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/stddef.h>
++#include <linux/fs.h>
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/pagemap.h>
++#include <linux/blkdev.h>
++#include <asm/uaccess.h>
++#include "hostfs.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "user_util.h"
++#include "2_5compat.h"
++#include "mem.h"
++#include "filehandle.h"
++
++struct externfs {
++      struct list_head list;
++      struct externfs_mount_ops *mount_ops;
++      struct file_system_type type;
++};
++
++static inline struct externfs_inode *EXTERNFS_I(struct inode *inode)
++{
++      return(inode->u.generic_ip);
++}
++
++#define file_externfs_i(file) EXTERNFS_I((file)->f_dentry->d_inode)
++
++int externfs_d_delete(struct dentry *dentry)
++{
++      return(1);
++}
++
++struct dentry_operations externfs_dentry_ops = {
++};
++
++#define EXTERNFS_SUPER_MAGIC 0x00c0ffee
++
++static struct inode_operations externfs_iops;
++static struct inode_operations externfs_dir_iops;
++static struct address_space_operations externfs_link_aops;
++
++static char *dentry_name(struct dentry *dentry, int extra)
++{
++      struct dentry *parent;
++      char *name;
++      int len;
++
++      len = 0;
++      parent = dentry;
++      while(parent->d_parent != parent){
++              len += parent->d_name.len + 1;
++              parent = parent->d_parent;
++      }
++      
++      name = kmalloc(len + extra + 1, GFP_KERNEL);
++      if(name == NULL) return(NULL);
++
++      name[len] = '\0';
++      parent = dentry;
++      while(parent->d_parent != parent){
++              len -= parent->d_name.len + 1;
++              name[len] = '/';
++              strncpy(&name[len + 1], parent->d_name.name, 
++                      parent->d_name.len);
++              parent = parent->d_parent;
++      }
++
++      return(name);
++}
++
++char *inode_name(struct inode *ino, int extra)
++{
++      struct dentry *dentry;
++
++      dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
++      return(dentry_name(dentry, extra));
++}
++
++char *inode_name_prefix(struct inode *inode, char *prefix)
++{
++      int len;
++      char *name;
++
++      len = strlen(prefix);
++      name = inode_name(inode, len);
++      if(name == NULL)
++              return(name);
++
++      memmove(&name[len], name, strlen(name) + 1);
++      memcpy(name, prefix, strlen(prefix));
++      return(name);
++}
++
++static int read_name(struct inode *ino, char *name)
++{
++      struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
++      /* The non-int inode fields are copied into ints by stat_file and
++       * then copied into the inode because passing the actual pointers
++       * in and having them treated as int * breaks on big-endian machines
++       */
++      int err;
++      int i_dev, i_mode, i_nlink, i_blksize;
++      unsigned long long i_size;
++      unsigned long long i_ino;
++      unsigned long long i_blocks;
++
++      err = (*ops->stat_file)(name, ino->i_sb->u.generic_sbp, 
++                              (dev_t *) &i_dev, &i_ino, &i_mode, &i_nlink,
++                              &ino->i_uid, &ino->i_gid, &i_size, 
++                              &ino->i_atime, &ino->i_mtime, &ino->i_ctime, 
++                              &i_blksize, &i_blocks);
++      if(err) return(err);
++      ino->i_ino = i_ino;
++      ino->i_dev = i_dev;
++      ino->i_mode = i_mode;
++      ino->i_nlink = i_nlink;
++      ino->i_size = i_size;
++      ino->i_blksize = i_blksize;
++      ino->i_blocks = i_blocks;
++      return(0);
++}
++
++static char *follow_link(char *link, 
++                       int (*do_read_link)(char *path, int uid, int gid,
++                                           char *buf, int size, 
++                                           struct externfs_data *ed),
++                       int uid, int gid, struct externfs_data *ed)
++{
++      int len, n;
++      char *name, *resolved, *end;
++
++      len = 64;
++      while(1){
++              n = -ENOMEM;
++              name = kmalloc(len, GFP_KERNEL);
++              if(name == NULL)
++                      goto out;
++
++              n = (*do_read_link)(link, uid, gid, name, len, ed);
++              if(n < len)
++                      break;
++              len *= 2;
++              kfree(name);
++      }
++      if(n < 0)
++              goto out_free;
++
++      if(*name == '/')
++              return(name);
++
++      end = strrchr(link, '/');
++      if(end == NULL)
++              return(name);
++
++      *(end + 1) = '\0';
++      len = strlen(link) + strlen(name) + 1;
++
++      resolved = kmalloc(len, GFP_KERNEL);
++      if(resolved == NULL){
++              n = -ENOMEM;
++              goto out_free;
++      }
++
++      sprintf(resolved, "%s%s", link, name);
++      kfree(name);
++      return(resolved);
++
++ out_free:
++      kfree(name);
++ out:
++      return(ERR_PTR(n));
++}
++
++static int read_inode(struct inode *ino)
++{
++      struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
++      struct externfs_data *ed = ino->i_sb->u.generic_sbp;
++      char *name, *new;
++      int err, type;
++
++      err = -ENOMEM;
++      name = inode_name(ino, 0);
++      if(name == NULL) 
++              goto out;
++
++      type = (*ops->file_type)(name, NULL, ed);
++      if(type < 0){
++              err = type;
++              goto out_free;
++      }
++
++      if(type == OS_TYPE_SYMLINK){
++              new = follow_link(name, ops->read_link, current->fsuid,
++                                current->fsgid, ed);
++              if(IS_ERR(new)){
++                      err = PTR_ERR(new);
++                      goto out_free;
++              }
++              kfree(name);
++              name = new;
++      }
++      
++      err = read_name(ino, name);
++ out_free:
++      kfree(name);
++ out:
++      return(err);
++}
++
++void externfs_delete_inode(struct inode *ino)
++{
++      struct externfs_inode *ext = EXTERNFS_I(ino);
++      struct externfs_file_ops *ops = ext->ops;
++
++      (*ops->close_file)(ext, ino->i_size);
++
++      clear_inode(ino);
++}
++
++int externfs_statfs(struct super_block *sb, struct statfs *sf)
++{
++      /* do_statfs uses struct statfs64 internally, but the linux kernel
++       * struct statfs still has 32-bit versions for most of these fields,
++       * so we convert them here
++       */
++      int err;
++      long long f_blocks;
++      long long f_bfree;
++      long long f_bavail;
++      long long f_files;
++      long long f_ffree;
++      struct externfs_data *ed = sb->u.generic_sbp;
++      
++      err = (*ed->file_ops->statfs)(&sf->f_bsize, &f_blocks, &f_bfree, 
++                                    &f_bavail, &f_files, &f_ffree, 
++                                    &sf->f_fsid, sizeof(sf->f_fsid), 
++                                    &sf->f_namelen, sf->f_spare, ed);
++      if(err)
++              return(err);
++
++      sf->f_blocks = f_blocks;
++      sf->f_bfree = f_bfree;
++      sf->f_bavail = f_bavail;
++      sf->f_files = f_files;
++      sf->f_ffree = f_ffree;
++      sf->f_type = EXTERNFS_SUPER_MAGIC;
++      return(0);
++}
++
++static struct super_operations externfs_sbops = { 
++      .delete_inode   = externfs_delete_inode,
++      .statfs         = externfs_statfs,
++};
++
++int externfs_readdir(struct file *file, void *ent, filldir_t filldir)
++{
++      void *dir;
++      char *name;
++      unsigned long long next, ino;
++      int error, len;
++      struct externfs_file_ops *ops = file_externfs_i(file)->ops;
++      struct externfs_data *ed = 
++              file->f_dentry->d_inode->i_sb->u.generic_sbp;
++
++      name = dentry_name(file->f_dentry, 0);
++      if(name == NULL) 
++              return(-ENOMEM);
++
++      dir = (*ops->open_dir)(name, current->fsuid, current->fsgid, ed);
++      kfree(name);
++      if(IS_ERR(dir)) 
++              return(PTR_ERR(dir));
++
++      next = file->f_pos;
++      while((name = (*ops->read_dir)(dir, &next, &ino, &len, ed)) != NULL){
++              error = (*filldir)(ent, name, len, file->f_pos, ino, 
++                                 DT_UNKNOWN);
++              if(error) 
++                      break;
++              file->f_pos = next;
++      }
++      (*ops->close_dir)(dir, ed);
++      return(0);
++}
++
++int externfs_file_open(struct inode *ino, struct file *file)
++{
++      ino->i_nlink++;
++      return(0);
++}
++
++int externfs_dir_open(struct inode *ino, struct file *file)
++{
++      return(0);      
++}
++
++int externfs_dir_release(struct inode *ino, struct file *file)
++{
++      return(0);
++}
++
++int externfs_fsync(struct file *file, struct dentry *dentry, int datasync)
++{
++      struct externfs_file_ops *ops = file_externfs_i(file)->ops;
++      struct inode *inode = dentry->d_inode;
++      struct externfs_data *ed = inode->i_sb->u.generic_sbp;
++
++      return((*ops->truncate_file)(EXTERNFS_I(inode), inode->i_size, ed));
++}
++
++static struct file_operations externfs_file_fops = {
++      .owner          = NULL,
++      .read           = generic_file_read,
++      .write          = generic_file_write,
++      .mmap           = generic_file_mmap,
++      .open           = externfs_file_open,
++      .release        = NULL,
++      .fsync          = externfs_fsync,
++};
++
++static struct file_operations externfs_dir_fops = {
++      .owner          = NULL,
++      .readdir        = externfs_readdir,
++      .open           = externfs_dir_open,
++      .release        = externfs_dir_release,
++      .fsync          = externfs_fsync,
++};
++
++struct wp_info {
++      struct page *page;
++      int count;
++      unsigned long long start;
++      unsigned long long size;
++      int (*truncate)(struct externfs_inode *ei, __u64 size, 
++                      struct externfs_data *ed);
++      struct externfs_inode *ei;
++      struct externfs_data *ed;
++};
++
++static void externfs_finish_writepage(char *buffer, int res, void *arg)
++{
++      struct wp_info *wp = arg;
++
++      if(res == wp->count){
++              ClearPageError(wp->page);
++              if(wp->start + res > wp->size)
++                      (*wp->truncate)(wp->ei, wp->size, wp->ed);
++      }
++      else {
++              SetPageError(wp->page);
++              ClearPageUptodate(wp->page);
++      }               
++
++      kunmap(wp->page);
++      unlock_page(wp->page);
++      kfree(wp);
++}
++
++static int externfs_writepage(struct page *page)
++{
++      struct address_space *mapping = page->mapping;
++      struct inode *inode = mapping->host;
++      struct externfs_file_ops *ops = EXTERNFS_I(inode)->ops;
++      struct wp_info *wp;
++      struct externfs_data *ed = inode->i_sb->u.generic_sbp;
++      char *buffer;
++      unsigned long long base;
++      int count = PAGE_CACHE_SIZE;
++      int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
++      int err, offset;
++
++      base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
++
++      /* If we are entirely outside the file, then return an error */
++      err = -EIO;
++      offset = inode->i_size & (PAGE_CACHE_SIZE-1);
++      if (page->index > end_index || 
++          ((page->index == end_index) && !offset))
++              goto out_unlock;
++
++      err = -ENOMEM;
++      wp = kmalloc(sizeof(*wp), GFP_KERNEL);
++      if(wp == NULL)
++              goto out_unlock;
++
++      *wp = ((struct wp_info) { .page         = page,
++                                .count        = count,
++                                .start        = base,
++                                .size         = inode->i_size,
++                                .truncate     = ops->truncate_file,
++                                .ei           = EXTERNFS_I(inode),
++                                .ed           = ed });
++
++      buffer = kmap(page);
++      err = (*ops->write_file)(EXTERNFS_I(inode), base, buffer, 0, 
++                               count, externfs_finish_writepage, wp, ed);
++
++      return err;
++
++ out_unlock:
++      unlock_page(page);
++      return(err);
++}
++
++static void externfs_finish_readpage(char *buffer, int res, void *arg)
++{
++      struct page *page = arg;
++      struct inode *inode;
++
++      if(res < 0){
++              SetPageError(page);
++              goto out;
++      }
++
++      inode = page->mapping->host;
++      if(inode->i_size >> PAGE_CACHE_SHIFT == page->index)
++              res = inode->i_size % PAGE_CACHE_SIZE;
++
++      memset(&buffer[res], 0, PAGE_CACHE_SIZE - res);
++
++      flush_dcache_page(page);
++      SetPageUptodate(page);
++      if (PageError(page)) 
++              ClearPageError(page);
++ out:
++      kunmap(page);
++      unlock_page(page);
++}
++
++static int externfs_readpage(struct file *file, struct page *page)
++{
++      struct inode *ino = page->mapping->host;
++      struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
++      struct externfs_data *ed = ino->i_sb->u.generic_sbp;
++      char *buffer;
++      long long start;
++      int err = 0;
++
++      start = (long long) page->index << PAGE_CACHE_SHIFT;
++      buffer = kmap(page);
++
++      if(ops->map_file_page != NULL){
++              /* XXX What happens when PAGE_SIZE != PAGE_CACHE_SIZE? */
++              err = (*ops->map_file_page)(file_externfs_i(file), start, 
++                                          buffer, file->f_mode & FMODE_WRITE,
++                                          ed);
++              if(!err)
++                      err = PAGE_CACHE_SIZE;
++      }
++      else err = (*ops->read_file)(file_externfs_i(file), start, buffer,
++                                   PAGE_CACHE_SIZE, 0, 0, 
++                                   externfs_finish_readpage, page, ed);
++
++      if(err > 0)
++              err = 0;
++      return(err);
++}
++
++struct writepage_info {
++      struct semaphore sem;
++      int res;
++};
++
++static void externfs_finish_prepare(char *buffer, int res, void *arg)
++{
++      struct writepage_info *wp = arg;
++
++      wp->res = res;
++      up(&wp->sem);
++}
++
++int externfs_prepare_write(struct file *file, struct page *page, 
++                       unsigned int from, unsigned int to)
++{
++      struct address_space *mapping = page->mapping;
++      struct inode *inode = mapping->host;
++      struct externfs_file_ops *ops = EXTERNFS_I(inode)->ops;
++      struct externfs_data *ed = inode->i_sb->u.generic_sbp;
++      char *buffer;
++      long long start;
++      int err;
++      struct writepage_info wp;
++
++      if(Page_Uptodate(page))
++              return(0);
++
++      start = (long long) page->index << PAGE_CACHE_SHIFT;
++      buffer = kmap(page);
++
++      if(ops->map_file_page != NULL){
++              err = (*ops->map_file_page)(file_externfs_i(file), start, 
++                                          buffer, file->f_mode & FMODE_WRITE,
++                                          ed);
++              goto out;
++      }
++
++      init_MUTEX_LOCKED(&wp.sem);
++      err = (*ops->read_file)(file_externfs_i(file), start, buffer,
++                              PAGE_CACHE_SIZE, from, to, 
++                              externfs_finish_prepare, &wp, ed);
++      down(&wp.sem);
++      if(err < 0) 
++              goto out;
++
++      err = wp.res;
++      if(err < 0)
++              goto out;
++
++      if(from > 0)
++              memset(buffer, 0, from);
++      if(to < PAGE_CACHE_SIZE)
++              memset(buffer + to, 0, PAGE_CACHE_SIZE - to);
++
++      SetPageUptodate(page);
++      err = 0;
++ out:
++      kunmap(page);
++      return(err);
++}
++
++static int externfs_commit_write(struct file *file, struct page *page, 
++                             unsigned from, unsigned to)
++{
++      struct address_space *mapping = page->mapping;
++      struct inode *inode = mapping->host;
++      struct externfs_file_ops *ops = EXTERNFS_I(inode)->ops;
++      unsigned long long size;
++      long long start;
++      int err;
++
++      start = (long long) (page->index << PAGE_CACHE_SHIFT);
++
++      if(ops->map_file_page != NULL)
++              err = to - from;
++      else {
++              size = start + to;
++              if(size > inode->i_size){
++                      inode->i_size = size;
++                      mark_inode_dirty(inode);
++              }
++      }
++
++      set_page_dirty(page);
++      return(to - from);
++}
++
++static void externfs_removepage(struct page *page)
++{
++      physmem_remove_mapping(page_address(page));
++}
++
++static struct address_space_operations externfs_aops = {
++      .writepage      = externfs_writepage,
++      .readpage       = externfs_readpage,
++      .removepage     = externfs_removepage,
++/*    .set_page_dirty = __set_page_dirty_nobuffers, */
++      .prepare_write  = externfs_prepare_write,
++      .commit_write   = externfs_commit_write
++};
++
++static struct inode *get_inode(struct super_block *sb, struct dentry *dentry,
++                             int need_fh)
++{
++      struct inode *inode;
++      struct externfs_data *ed = sb->u.generic_sbp;
++      struct externfs_mount_ops *ops = ed->mount_ops;
++      char *name = NULL;
++      int type, err = -ENOMEM, rdev;
++
++      if(dentry){
++              name = dentry_name(dentry, 0);
++              if(name == NULL)
++                      goto out;
++              type = (*ed->file_ops->file_type)(name, &rdev, ed);
++      }
++      else type = OS_TYPE_DIR;
++
++      inode = new_inode(sb);
++      if(inode == NULL)
++              goto out_free;
++
++      insert_inode_hash(inode);
++
++      if(type == OS_TYPE_SYMLINK)
++              inode->i_op = &page_symlink_inode_operations;
++      else if(type == OS_TYPE_DIR)
++              inode->i_op = &externfs_dir_iops;
++      else inode->i_op = &externfs_iops;
++
++      if(type == OS_TYPE_DIR) inode->i_fop = &externfs_dir_fops;
++      else inode->i_fop = &externfs_file_fops;
++
++      if(type == OS_TYPE_SYMLINK) 
++              inode->i_mapping->a_ops = &externfs_link_aops;
++      else inode->i_mapping->a_ops = &externfs_aops;
++
++      switch (type) {
++      case OS_TYPE_CHARDEV:
++              init_special_inode(inode, S_IFCHR, rdev);
++              break;
++      case OS_TYPE_BLOCKDEV:
++              init_special_inode(inode, S_IFBLK, rdev);
++              break;
++      case OS_TYPE_FIFO:
++              init_special_inode(inode, S_IFIFO, 0);
++              break;
++      case OS_TYPE_SOCK:
++              init_special_inode(inode, S_IFSOCK, 0);
++              break;
++      case OS_TYPE_SYMLINK:
++              inode->i_mode = S_IFLNK | S_IRWXUGO;
++      }
++      
++      if(need_fh){
++              struct externfs_inode *ei;
++
++              err = -ENOMEM;
++              ei = (*ops->init_file)(ed);
++              if(ei == NULL)
++                      goto out_put;
++
++              *ei = ((struct externfs_inode) { .ops   = ed->file_ops });
++              inode->u.generic_ip = ei;
++
++              err = (*ed->file_ops->open_file)(ei, name, current->fsuid, 
++                                               current->fsgid, inode, ed);
++              if(err && ((err != -ENOENT) && (err != -EISDIR)))
++                      goto out_put;
++      }
++
++      return(inode);
++
++ out_put:
++      iput(inode);
++ out_free:
++      kfree(name);
++ out:
++      return(ERR_PTR(err));
++}
++
++int externfs_create(struct inode *dir, struct dentry *dentry, int mode)
++{
++      struct externfs_file_ops *ops = EXTERNFS_I(dir)->ops;
++      struct inode *inode;
++      struct externfs_data *ed = dir->i_sb->u.generic_sbp;
++      struct externfs_inode *ei;
++      char *name;
++      int err = -ENOMEM;
++
++      name = dentry_name(dentry, 0);
++      if(name == NULL)
++              goto out;
++
++      inode = get_inode(dir->i_sb, dentry, 0);
++      if(IS_ERR(inode)){
++              err = PTR_ERR(inode);
++              goto out_free;
++      }
++
++      ei = (*ed->mount_ops->init_file)(ed);
++      if(ei == NULL)
++              /* XXX need a free_file() */
++              goto out_put;
++
++      *ei = ((struct externfs_inode) { .ops   = ed->file_ops });
++      inode->u.generic_ip = ei;
++
++      err = (*ops->create_file)(ei, name, mode, current->fsuid, 
++                                current->fsuid, inode, ed);
++      if(err)
++              goto out_put;
++
++      err = read_name(inode, name);
++      if(err)
++              goto out_rm;
++
++      inode->i_nlink++;
++      d_instantiate(dentry, inode);
++ out_free:
++      kfree(name);
++ out:
++      return(err);
++
++ out_rm:
++      (*ops->unlink_file)(name, ed);
++ out_put:
++      inode->i_nlink = 0;
++      iput(inode);
++      goto out_free;
++}
++ 
++struct dentry *externfs_lookup(struct inode *ino, struct dentry *dentry)
++{
++      struct inode *inode;
++      char *name;
++      int err;
++
++      inode = get_inode(ino->i_sb, dentry, 1);
++      if(IS_ERR(inode)){
++              err = PTR_ERR(inode);
++              goto out;
++      }
++
++      err = -ENOMEM;
++      name = dentry_name(dentry, 0);
++      if(name == NULL)
++              goto out_put;
++
++      err = read_name(inode, name);
++      kfree(name);
++      if(err){
++              if(err != -ENOENT)
++                      goto out_put;
++
++              inode->i_nlink = 0;
++              iput(inode);
++              inode = NULL;
++      }
++      d_add(dentry, inode);
++      dentry->d_op = &externfs_dentry_ops;
++      return(NULL);
++
++ out_put:
++      inode->i_nlink = 0;
++      iput(inode);
++ out:
++      return(ERR_PTR(err));
++}
++
++static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
++{
++        char *file;
++      int len;
++
++      file = inode_name(ino, dentry->d_name.len + 1);
++      if(file == NULL) return(NULL);
++        strcat(file, "/");
++      len = strlen(file);
++        strncat(file, dentry->d_name.name, dentry->d_name.len);
++      file[len + dentry->d_name.len] = '\0';
++        return(file);
++}
++
++int externfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
++{
++      struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
++      struct externfs_data *ed = ino->i_sb->u.generic_sbp;
++        char *from_name, *to_name;
++        int err = -ENOMEM;
++
++        from_name = inode_dentry_name(ino, from); 
++        if(from_name == NULL) 
++              goto out;
++
++        to_name = dentry_name(to, 0);
++      if(to_name == NULL)
++              goto out_free_from;
++
++        err = (*ops->link_file)(to_name, from_name, current->fsuid, 
++                              current->fsgid, ed);
++      if(err)
++              goto out_free_to;
++
++      d_instantiate(from, to->d_inode);
++      to->d_inode->i_nlink++;
++      atomic_inc(&to->d_inode->i_count);
++
++ out_free_to:
++        kfree(to_name);
++ out_free_from:
++        kfree(from_name);
++ out:
++        return(err);
++}
++
++int externfs_unlink(struct inode *ino, struct dentry *dentry)
++{
++      struct inode *inode;
++      struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
++      struct externfs_data *ed = ino->i_sb->u.generic_sbp;
++      char *file;
++      int err;
++
++      file = inode_dentry_name(ino, dentry);
++      if(file == NULL) 
++              return(-ENOMEM);
++
++      inode = dentry->d_inode;
++      if((inode->i_nlink == 1) && (ops->invisible != NULL))
++              (*ops->invisible)(EXTERNFS_I(inode));
++
++      err = (*ops->unlink_file)(file, ed);
++      kfree(file);
++
++      inode->i_nlink--;
++
++      return(err);
++}
++
++int externfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
++{
++      struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
++      struct externfs_data *ed = ino->i_sb->u.generic_sbp;
++      struct inode *inode;
++      char *file;
++      int err;
++
++      file = inode_dentry_name(ino, dentry);
++      if(file == NULL) 
++              return(-ENOMEM);
++      err = (*ops->make_symlink)(file, to, current->fsuid, current->fsgid,
++                                 ed);
++      kfree(file);
++
++      inode = get_inode(ino->i_sb, dentry, 1);
++      if(IS_ERR(inode)){
++              err = PTR_ERR(inode);
++              goto out;
++      }
++
++      d_instantiate(dentry, inode);
++      inode->i_nlink++;
++      iput(inode);
++ out:
++      return(err);
++}
++
++int externfs_make_dir(struct inode *ino, struct dentry *dentry, int mode)
++{
++      struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
++      struct externfs_data *ed = ino->i_sb->u.generic_sbp;
++      struct inode *inode;
++      char *file;
++      int err;
++
++      file = inode_dentry_name(ino, dentry);
++      if(file == NULL) 
++              return(-ENOMEM);
++      err = (*ops->make_dir)(file, mode, current->fsuid, current->fsgid, ed);
++
++      inode = get_inode(ino->i_sb, dentry, 1);
++      if(IS_ERR(inode)){
++              err = PTR_ERR(inode);
++              goto out_free;
++      }
++
++      err = read_name(inode, file);
++      kfree(file);
++      if(err)
++              goto out_put;
++
++      d_instantiate(dentry, inode);
++      inode->i_nlink = 2;
++      inode->i_mode = S_IFDIR | mode;
++      iput(inode);
++
++      ino->i_nlink++;
++ out:
++      return(err);
++ out_free:
++      kfree(file);
++ out_put:
++      inode->i_nlink = 0;
++      iput(inode);
++      goto out;       
++}
++
++int externfs_remove_dir(struct inode *ino, struct dentry *dentry)
++{
++      struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
++      void *mount = ino->i_sb->u.generic_sbp;
++      char *file;
++      int err;
++
++      file = inode_dentry_name(ino, dentry);
++      if(file == NULL) 
++              return(-ENOMEM);
++      err = (*ops->remove_dir)(file, current->fsuid, current->fsgid, mount);
++      kfree(file);
++
++      dentry->d_inode->i_nlink = 0;
++      ino->i_nlink--;
++      return(err);
++}
++
++int externfs_make_node(struct inode *dir, struct dentry *dentry, int mode, 
++                   int dev)
++{
++      struct externfs_file_ops *ops = EXTERNFS_I(dir)->ops;
++      struct externfs_data *ed = dir->i_sb->u.generic_sbp;
++      struct inode *inode;
++      char *name;
++      int err = -ENOMEM;
++ 
++      name = dentry_name(dentry, 0);
++      if(name == NULL)
++              goto out;
++
++      inode = get_inode(dir->i_sb, dentry, 1);
++      if(IS_ERR(inode)){
++              err = PTR_ERR(inode);
++              goto out_free;
++      }
++
++      init_special_inode(inode, mode, dev);
++      err = (*ops->make_node)(name, mode & S_IRWXUGO, current->fsuid, 
++                              current->fsgid, mode & S_IFMT, major(dev), 
++                              minor(dev), ed);
++      if(err)
++              goto out_put;
++      
++      err = read_name(inode, name);
++      if(err)
++              goto out_rm;
++
++      d_instantiate(dentry, inode);
++ out_free:
++      kfree(name);
++ out:
++      return(err);
++
++ out_rm:
++      (*ops->unlink_file)(name, ed);
++ out_put:
++      inode->i_nlink = 0;
++      iput(inode);
++      goto out_free;
++}
++
++int externfs_rename(struct inode *from_ino, struct dentry *from,
++                struct inode *to_ino, struct dentry *to)
++{
++      struct externfs_file_ops *ops = EXTERNFS_I(from_ino)->ops;
++      struct externfs_data *ed = from_ino->i_sb->u.generic_sbp;
++      char *from_name, *to_name;
++      int err;
++
++      from_name = inode_dentry_name(from_ino, from);
++      if(from_name == NULL)
++              return(-ENOMEM);
++      to_name = inode_dentry_name(to_ino, to);
++      if(to_name == NULL){
++              kfree(from_name);
++              return(-ENOMEM);
++      }
++      err = (*ops->rename_file)(from_name, to_name, ed);
++      kfree(from_name);
++      kfree(to_name);
++
++      from_ino->i_nlink--;
++      to_ino->i_nlink++;
++      return(err);
++}
++
++void externfs_truncate(struct inode *ino)
++{
++      struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
++      struct externfs_data *ed = ino->i_sb->u.generic_sbp;
++
++      (*ops->truncate_file)(EXTERNFS_I(ino), ino->i_size, ed);
++}
++
++int externfs_permission(struct inode *ino, int desired)
++{
++      struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
++      struct externfs_data *ed = ino->i_sb->u.generic_sbp;
++      char *name;
++      int r = 0, w = 0, x = 0, err;
++
++      if(ops->access_file == NULL)
++              return(vfs_permission(ino, desired));
++
++      if(desired & MAY_READ) r = 1;
++      if(desired & MAY_WRITE) w = 1;
++      if(desired & MAY_EXEC) x = 1;
++      name = inode_name(ino, 0);
++      if(name == NULL) 
++              return(-ENOMEM);
++
++      err = (*ops->access_file)(name, r, w, x, current->fsuid, 
++                                current->fsgid, ed);
++      kfree(name);
++
++      if(!err) 
++              err = vfs_permission(ino, desired);
++      return(err);
++}
++
++int externfs_setattr(struct dentry *dentry, struct iattr *attr)
++{
++      struct externfs_file_ops *ops = EXTERNFS_I(dentry->d_inode)->ops;
++      struct externfs_data *ed = dentry->d_inode->i_sb->u.generic_sbp;
++      struct externfs_iattr attrs;
++      char *name;
++      int err;
++      
++      attrs.ia_valid = 0;
++      if(attr->ia_valid & ATTR_MODE){
++              attrs.ia_valid |= EXTERNFS_ATTR_MODE;
++              attrs.ia_mode = attr->ia_mode;
++      }
++      if(attr->ia_valid & ATTR_UID){
++              attrs.ia_valid |= EXTERNFS_ATTR_UID;
++              attrs.ia_uid = attr->ia_uid;
++      }
++      if(attr->ia_valid & ATTR_GID){
++              attrs.ia_valid |= EXTERNFS_ATTR_GID;
++              attrs.ia_gid = attr->ia_gid;
++      }
++      if(attr->ia_valid & ATTR_SIZE){
++              attrs.ia_valid |= EXTERNFS_ATTR_SIZE;
++              attrs.ia_size = attr->ia_size;
++      }
++      if(attr->ia_valid & ATTR_ATIME){
++              attrs.ia_valid |= EXTERNFS_ATTR_ATIME;
++              attrs.ia_atime = attr->ia_atime;
++      }
++      if(attr->ia_valid & ATTR_MTIME){
++              attrs.ia_valid |= EXTERNFS_ATTR_MTIME;
++              attrs.ia_mtime = attr->ia_mtime;
++      }
++      if(attr->ia_valid & ATTR_CTIME){
++              attrs.ia_valid |= EXTERNFS_ATTR_CTIME;
++              attrs.ia_ctime = attr->ia_ctime;
++      }
++      if(attr->ia_valid & ATTR_ATIME_SET){
++              attrs.ia_valid |= EXTERNFS_ATTR_ATIME_SET;
++      }
++      if(attr->ia_valid & ATTR_MTIME_SET){
++              attrs.ia_valid |= EXTERNFS_ATTR_MTIME_SET;
++      }
++      name = dentry_name(dentry, 0);
++      if(name == NULL) 
++              return(-ENOMEM);
++      err = (*ops->set_attr)(name, &attrs, ed);
++      kfree(name);
++      if(err)
++              return(err);
++
++      return(inode_setattr(dentry->d_inode, attr));
++}
++
++int externfs_getattr(struct dentry *dentry, struct iattr *attr)
++{
++      not_implemented();
++      return(-EINVAL);
++}
++
++static struct inode_operations externfs_iops = {
++      .create         = externfs_create,
++      .link           = externfs_link,
++      .unlink         = externfs_unlink,
++      .symlink        = externfs_symlink,
++      .mkdir          = externfs_make_dir,
++      .rmdir          = externfs_remove_dir,
++      .mknod          = externfs_make_node,
++      .rename         = externfs_rename,
++      .truncate       = externfs_truncate,
++      .permission     = externfs_permission,
++      .setattr        = externfs_setattr,
++      .getattr        = externfs_getattr,
++};
++
++static struct inode_operations externfs_dir_iops = {
++      .create         = externfs_create,
++      .lookup         = externfs_lookup,
++      .link           = externfs_link,
++      .unlink         = externfs_unlink,
++      .symlink        = externfs_symlink,
++      .mkdir          = externfs_make_dir,
++      .rmdir          = externfs_remove_dir,
++      .mknod          = externfs_make_node,
++      .rename         = externfs_rename,
++      .truncate       = externfs_truncate,
++      .permission     = externfs_permission,
++      .setattr        = externfs_setattr,
++      .getattr        = externfs_getattr,
++};
++
++int externfs_link_readpage(struct file *file, struct page *page)
++{
++      struct inode *ino = page->mapping->host;
++      struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
++      struct externfs_data *ed = ino->i_sb->u.generic_sbp;
++      char *buffer, *name;
++      long long start;
++      int err;
++
++      start = page->index << PAGE_CACHE_SHIFT;
++      buffer = kmap(page);
++      name = inode_name(ino, 0);
++      if(name == NULL) 
++              return(-ENOMEM);
++
++      err = (*ops->read_link)(name, current->fsuid, current->fsgid, buffer, 
++                              PAGE_CACHE_SIZE, ed);
++
++      kfree(name);
++      if(err == PAGE_CACHE_SIZE)
++              err = -E2BIG;
++      else if(err > 0){
++              flush_dcache_page(page);
++              SetPageUptodate(page);
++              if (PageError(page)) ClearPageError(page);
++              err = 0;
++      }
++      kunmap(page);
++      UnlockPage(page);
++      return(err);
++}
++
++static int externfs_flushpage(struct page *page, unsigned long offset)
++{
++      return(externfs_writepage(page));
++}
++
++struct externfs_data *inode_externfs_info(struct inode *inode)
++{
++      return(inode->i_sb->u.generic_sbp);
++}
++
++static struct address_space_operations externfs_link_aops = {
++      .readpage       = externfs_link_readpage,
++      .removepage     = externfs_removepage,
++      .flushpage      = externfs_flushpage,
++};
++
++DECLARE_MUTEX(externfs_sem);
++struct list_head externfses = LIST_HEAD_INIT(externfses);
++
++static struct externfs *find_externfs(struct file_system_type *type)
++{
++      struct list_head *ele;
++      struct externfs *fs;
++
++      down(&externfs_sem);
++      list_for_each(ele, &externfses){
++              fs = list_entry(ele, struct externfs, list);
++              if(&fs->type == type)
++                      goto out;
++      }
++      fs = NULL;
++ out:
++      up(&externfs_sem);
++      return(fs);
++}
++
++#define DEFAULT_ROOT "/"
++
++char *host_root_filename(char *mount_arg)
++{
++      char *root = DEFAULT_ROOT;
++
++      if((mount_arg != NULL) && (*mount_arg != '\0'))
++              root = mount_arg;
++
++      return(uml_strdup(root));
++}
++
++struct super_block *externfs_read_super(struct super_block *sb, void *data, 
++                                      int silent)
++{
++      struct externfs *fs;
++      struct inode *root_inode;
++      struct externfs_data *sb_data;
++      int err = -EINVAL;
++
++      sb->s_blocksize = 1024;
++      sb->s_blocksize_bits = 10;
++      sb->s_magic = EXTERNFS_SUPER_MAGIC;
++      sb->s_op = &externfs_sbops;
++
++      fs = find_externfs(sb->s_type);
++      if(fs == NULL){
++              printk("Couldn't find externfs for filesystem '%s'\n",
++                     sb->s_type->name);
++              goto out;
++      }
++
++      sb_data = (*fs->mount_ops->mount)(data);
++      if(IS_ERR(sb_data)){
++              err = PTR_ERR(sb_data);
++              goto out;
++      }
++
++      sb->u.generic_sbp = sb_data;
++      sb_data->mount_ops = fs->mount_ops;
++
++      root_inode = get_inode(sb, NULL, 1);
++      if(IS_ERR(root_inode))
++              goto out;
++
++      sb->s_root = d_alloc_root(root_inode);
++      if(sb->s_root == NULL)
++              goto out_put;
++
++      if(read_inode(root_inode))
++              goto out_dput;
++      return(sb);
++
++ out_dput:
++      /* dput frees the inode */
++      dput(sb->s_root);
++      return(NULL);
++ out_put:
++      root_inode->i_nlink = 0;
++      make_bad_inode(root_inode);
++      iput(root_inode);
++ out:
++      return(NULL);
++}
++
++void init_externfs(struct externfs_data *ed, struct externfs_file_ops *ops)
++{
++      ed->file_ops = ops;
++}
++
++int register_externfs(char *name, struct externfs_mount_ops *mount_ops)
++{
++      struct externfs *new;
++      int err = -ENOMEM;
++
++      new = kmalloc(sizeof(*new), GFP_KERNEL);
++      if(new == NULL)
++              goto out;
++
++      memset(new, 0, sizeof(*new));
++      *new = ((struct externfs) { .list       = LIST_HEAD_INIT(new->list),
++                                  .mount_ops  = mount_ops,
++                                  .type = { .name     = name,
++                                            .read_super = externfs_read_super,
++                                            .fs_flags = 0,
++                                            .owner    = THIS_MODULE } });
++      list_add(&new->list, &externfses);
++
++      err = register_filesystem(&new->type);
++      if(err)
++              goto out_del;
++      return(0);
++
++ out_del:
++      list_del(&new->list);
++      kfree(new);
++ out:
++      return(err);
++}
++
++void unregister_externfs(char *name)
++{
++      struct list_head *ele;
++      struct externfs *fs;
++
++      down(&externfs_sem);
++      list_for_each(ele, &externfses){
++              fs = list_entry(ele, struct externfs, list);
++              if(!strcmp(fs->type.name, name)){
++                      list_del(ele);
++                      up(&externfs_sem);
++                      return;
++              }
++      }
++      up(&externfs_sem);
++      printk("Unregister_externfs - filesystem '%s' not found\n", name);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/fs/hostfs/host_file.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/fs/hostfs/host_file.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/fs/hostfs/host_file.c 2005-05-03 22:28:14.271440624 +0300
+@@ -0,0 +1,441 @@
++/* 
++ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/string.h"
++#include "linux/errno.h"
++#include "linux/types.h"
++#include "linux/slab.h"
++#include "linux/blkdev.h"
++#include "asm/fcntl.h"
++#include "hostfs.h"
++
++extern int append;
++
++char *get_path(const char *path[], char *buf, int size)
++{
++      const char **s;
++      char *p;
++      int new = 1;
++
++      for(s = path; *s != NULL; s++){
++              new += strlen(*s);
++              if((*(s + 1) != NULL) && (strlen(*s) > 0) && 
++                 ((*s)[strlen(*s) - 1] != '/'))
++                      new++;
++      }
++
++      if(new > size){
++              buf = kmalloc(new, GFP_KERNEL);
++              if(buf == NULL)
++                      return(NULL);
++      }
++
++      p = buf;
++      for(s = path; *s != NULL; s++){
++              strcpy(p, *s);
++              p += strlen(*s);
++              if((*(s + 1) != NULL) && (strlen(*s) > 0) && 
++                 ((*s)[strlen(*s) - 1] != '/'))
++                      strcpy(p++, "/");
++      }
++              
++      return(buf);
++}
++
++void free_path(const char *buf, char *tmp)
++{
++      if((buf != tmp) && (buf != NULL))
++              kfree((char *) buf);
++}
++
++int host_open_file(const char *path[], int r, int w, struct file_handle *fh)
++{
++      char tmp[HOSTFS_BUFSIZE], *file;
++      int mode = 0, err;
++      struct openflags flags = OPENFLAGS();
++
++      if (r)
++              flags = of_read(flags);
++      if (w)
++              flags = of_write(flags);
++      if(append)
++              flags = of_append(flags);
++
++      err = -ENOMEM;
++      file = get_path(path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++      
++      err = open_filehandle(file, flags, mode, fh);
++ out:
++      free_path(file, tmp);
++      return(err);
++}
++
++void *host_open_dir(const char *path[])
++{
++      char tmp[HOSTFS_BUFSIZE], *file;
++      void *dir = ERR_PTR(-ENOMEM);
++
++      file = get_path(path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++      
++      dir = open_dir(file);
++ out:
++      free_path(file, tmp);
++      return(dir);
++}
++
++char *host_read_dir(void *stream, unsigned long long *pos, 
++                  unsigned long long *ino_out, int *len_out)
++{
++      int err;
++      char *name;
++
++      err = os_seek_dir(stream, *pos);
++      if(err)
++              return(ERR_PTR(err));
++
++      err = os_read_dir(stream, ino_out, &name);
++      if(err)
++              return(ERR_PTR(err));
++
++      if(name == NULL)
++              return(NULL);
++
++      *len_out = strlen(name);
++      *pos = os_tell_dir(stream);
++      return(name);
++}
++
++int host_file_type(const char *path[], int *rdev)
++{
++      char tmp[HOSTFS_BUFSIZE], *file;
++      struct uml_stat buf;
++      int ret;
++
++      ret = -ENOMEM;
++      file = get_path(path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      if(rdev != NULL){
++              ret = os_lstat_file(file, &buf);
++              if(ret)
++                      goto out;
++              *rdev = MKDEV(buf.ust_rmajor, buf.ust_rminor);
++      }
++
++      ret = os_file_type(file);
++ out:
++      free_path(file, tmp);
++      return(ret);
++}
++
++int host_create_file(const char *path[], int mode, struct file_handle *fh)
++{
++      char tmp[HOSTFS_BUFSIZE], *file;
++      int err = -ENOMEM;
++
++      file = get_path(path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      err = open_filehandle(file, of_create(of_rdwr(OPENFLAGS())), mode, fh);
++ out:
++      free_path(file, tmp);
++      return(err);
++}
++
++static int do_stat_file(const char *path, dev_t *dev_out, 
++                      unsigned long long *inode_out, int *mode_out, 
++                      int *nlink_out, int *uid_out, int *gid_out, 
++                      unsigned long long *size_out, unsigned long *atime_out,
++                      unsigned long *mtime_out, unsigned long *ctime_out,
++                      int *blksize_out, unsigned long long *blocks_out)
++{
++      struct uml_stat buf;
++      int err;
++
++      err = os_lstat_file(path, &buf);
++      if(err < 0)
++              return(err);
++
++      if(dev_out != NULL) *dev_out = MKDEV(buf.ust_major, buf.ust_minor);
++      if(inode_out != NULL) *inode_out = buf.ust_ino;
++      if(mode_out != NULL) *mode_out = buf.ust_mode;
++      if(nlink_out != NULL) *nlink_out = buf.ust_nlink;
++      if(uid_out != NULL) *uid_out = buf.ust_uid;
++      if(gid_out != NULL) *gid_out = buf.ust_gid;
++      if(size_out != NULL) *size_out = buf.ust_size;
++      if(atime_out != NULL) *atime_out = buf.ust_atime;
++      if(mtime_out != NULL) *mtime_out = buf.ust_mtime;
++      if(ctime_out != NULL) *ctime_out = buf.ust_ctime;
++      if(blksize_out != NULL) *blksize_out = buf.ust_blksize;
++      if(blocks_out != NULL) *blocks_out = buf.ust_blocks;
++
++      return(0);
++}
++
++int host_stat_file(const char *path[], dev_t *dev_out, 
++                 unsigned long long *inode_out, int *mode_out, 
++                 int *nlink_out, int *uid_out, int *gid_out, 
++                 unsigned long long *size_out, unsigned long *atime_out,
++                 unsigned long *mtime_out, unsigned long *ctime_out,
++                 int *blksize_out, unsigned long long *blocks_out)
++{
++      char tmp[HOSTFS_BUFSIZE], *file;
++      int err;
++
++      err = -ENOMEM;
++      file = get_path(path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      err = do_stat_file(file, dev_out, inode_out, mode_out, nlink_out,
++                         uid_out, gid_out, size_out, atime_out, mtime_out,
++                         ctime_out, blksize_out, blocks_out);
++ out:
++      free_path(file, tmp);
++      return(err);
++}
++
++int host_set_attr(const char *path[], struct externfs_iattr *attrs)
++{
++      char tmp[HOSTFS_BUFSIZE], *file;
++      unsigned long time;
++      int err = 0, ma;
++
++      if(append && (attrs->ia_valid & EXTERNFS_ATTR_SIZE))
++              return(-EPERM);
++
++      err = -ENOMEM;
++      file = get_path(path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      if(attrs->ia_valid & EXTERNFS_ATTR_MODE){
++              err = os_set_file_perms(file, attrs->ia_mode);
++              if(err < 0)
++                      goto out;
++      }
++      if(attrs->ia_valid & EXTERNFS_ATTR_UID){
++              err = os_set_file_owner(file, attrs->ia_uid, -1);
++              if(err < 0)
++                      goto out;
++      }
++      if(attrs->ia_valid & EXTERNFS_ATTR_GID){
++              err = os_set_file_owner(file, -1, attrs->ia_gid);
++              if(err < 0)
++                      goto out;
++      }
++      if(attrs->ia_valid & EXTERNFS_ATTR_SIZE){
++              err = os_truncate_file(file, attrs->ia_size);
++              if(err < 0)
++                      goto out;
++      }
++      ma = EXTERNFS_ATTR_ATIME_SET | EXTERNFS_ATTR_MTIME_SET;
++      if((attrs->ia_valid & ma) == ma){
++              err = os_set_file_time(file, attrs->ia_atime, attrs->ia_mtime);
++              if(err)
++                      goto out;
++      }
++      else {
++              if(attrs->ia_valid & EXTERNFS_ATTR_ATIME_SET){
++                      err = do_stat_file(file, NULL, NULL, NULL, NULL, NULL, 
++                                         NULL, NULL, NULL, &time, 
++                                         NULL, NULL, NULL);
++                      if(err != 0)
++                              goto out;
++
++                      err = os_set_file_time(file, attrs->ia_atime, time);
++                      if(err)
++                              goto out;
++              }
++              if(attrs->ia_valid & EXTERNFS_ATTR_MTIME_SET){
++                      err = do_stat_file(file, NULL, NULL, NULL, NULL, NULL, 
++                                         NULL, NULL, &time, NULL, 
++                                         NULL, NULL, NULL);
++                      if(err != 0)
++                              goto out;
++
++                      err = os_set_file_time(file, time, attrs->ia_mtime);
++                      if(err)
++                              goto out;
++              }
++      }
++      if(attrs->ia_valid & EXTERNFS_ATTR_CTIME) ;
++      if(attrs->ia_valid & (EXTERNFS_ATTR_ATIME | EXTERNFS_ATTR_MTIME)){
++              err = do_stat_file(file, NULL, NULL, NULL, NULL, NULL, 
++                                 NULL, NULL, &attrs->ia_atime, 
++                                 &attrs->ia_mtime, NULL, NULL, NULL);
++              if(err != 0)
++                      goto out;
++      }
++
++      err = 0;
++ out:
++      free_path(file, tmp);
++      return(err);
++}
++
++int host_make_symlink(const char *from[], const char *to)
++{
++      char tmp[HOSTFS_BUFSIZE], *file;
++      int err = -ENOMEM;
++
++      file = get_path(from, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++      
++      err = os_make_symlink(to, file);
++ out:
++      free_path(file, tmp);
++      return(err);
++}
++
++int host_unlink_file(const char *path[])
++{
++      char tmp[HOSTFS_BUFSIZE], *file;
++      int err = -ENOMEM;
++
++      if(append)
++              return(-EPERM);
++
++      file = get_path(path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      err = os_remove_file(file);
++ out:
++      free_path(file, tmp);
++      return(err);
++}
++
++int host_make_dir(const char *path[], int mode)
++{
++      char tmp[HOSTFS_BUFSIZE], *file;
++      int err = -ENOMEM;
++
++      file = get_path(path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      err = os_make_dir(file, mode);
++ out:
++      free_path(file, tmp);
++      return(err);
++}
++
++int host_remove_dir(const char *path[])
++{
++      char tmp[HOSTFS_BUFSIZE], *file;
++      int err = -ENOMEM;
++
++      file = get_path(path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      err = os_remove_dir(file);
++ out:
++      free_path(file, tmp);
++      return(err);
++}
++
++int host_link_file(const char *to[], const char *from[])
++{
++      char from_tmp[HOSTFS_BUFSIZE], *f, to_tmp[HOSTFS_BUFSIZE], *t;
++      int err = -ENOMEM;
++
++      f = get_path(from, from_tmp, sizeof(from_tmp));
++      t = get_path(to, to_tmp, sizeof(to_tmp));
++      if((f == NULL) || (t == NULL))
++              goto out;
++
++      err = os_link_file(t, f);
++ out:
++      free_path(f, from_tmp);
++      free_path(t, to_tmp);
++      return(err);
++}
++
++int host_read_link(const char *path[], char *buf, int size)
++{
++      char tmp[HOSTFS_BUFSIZE], *file;
++      int n = -ENOMEM;
++
++      file = get_path(path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      n = os_read_symlink(file, buf, size);
++      if(n < size) 
++              buf[n] = '\0';
++ out:
++      free_path(file, tmp);
++      return(n);
++}
++
++int host_rename_file(const char *from[], const char *to[])
++{
++      char from_tmp[HOSTFS_BUFSIZE], *f, to_tmp[HOSTFS_BUFSIZE], *t;
++      int err = -ENOMEM;
++
++      f = get_path(from, from_tmp, sizeof(from_tmp));
++      t = get_path(to, to_tmp, sizeof(to_tmp));
++      if((f == NULL) || (t == NULL))
++              goto out;
++
++      err = os_move_file(f, t);
++ out:
++      free_path(f, from_tmp);
++      free_path(t, to_tmp);
++      return(err);
++}
++
++int host_stat_fs(const char *path[], long *bsize_out, long long *blocks_out, 
++               long long *bfree_out, long long *bavail_out, 
++               long long *files_out, long long *ffree_out, void *fsid_out, 
++               int fsid_size, long *namelen_out, long *spare_out)
++{
++      char tmp[HOSTFS_BUFSIZE], *file;
++      int err = -ENOMEM;
++
++      file = get_path(path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      err = os_stat_filesystem(file, bsize_out, blocks_out, bfree_out, 
++                               bavail_out, files_out, ffree_out, fsid_out, 
++                               fsid_size, namelen_out, spare_out);
++ out:
++      free_path(file, tmp);
++      return(err);
++}
++
++char *generic_host_read_dir(void *stream, unsigned long long *pos, 
++                          unsigned long long *ino_out, int *len_out, 
++                          void *mount)
++{
++      return(host_read_dir(stream, pos, ino_out, len_out));
++}
++
++int generic_host_truncate_file(struct file_handle *fh, __u64 size, void *m)
++{
++      return(truncate_file(fh, size));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/fs/hostfs/host_fs.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/fs/hostfs/host_fs.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/fs/hostfs/host_fs.c   2005-05-03 22:28:14.273440320 +0300
+@@ -0,0 +1,465 @@
++/* 
++ * Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/string.h"
++#include "linux/types.h"
++#include "linux/errno.h"
++#include "linux/slab.h"
++#include "linux/init.h"
++#include "linux/fs.h"
++#include "linux/stat.h"
++#include "hostfs.h"
++#include "kern.h"
++#include "init.h"
++#include "kern_util.h"
++#include "filehandle.h"
++#include "os.h"
++
++/* Changed in hostfs_args before the kernel starts running */
++static char *jail_dir = "/";
++int append = 0;
++
++static int __init hostfs_args(char *options, int *add)
++{
++      char *ptr;
++
++      ptr = strchr(options, ',');
++      if(ptr != NULL)
++              *ptr++ = '\0';
++      if(*options != '\0')
++              jail_dir = options;
++
++      options = ptr;
++      while(options){
++              ptr = strchr(options, ',');
++              if(ptr != NULL)
++                      *ptr++ = '\0';
++              if(*options != '\0'){
++                      if(!strcmp(options, "append"))
++                              append = 1;
++                      else printf("hostfs_args - unsupported option - %s\n",
++                                  options);
++              }
++              options = ptr;
++      }
++      return(0);
++}
++
++__uml_setup("hostfs=", hostfs_args,
++"hostfs=<root dir>,<flags>,...\n"
++"    This is used to set hostfs parameters.  The root directory argument\n"
++"    is used to confine all hostfs mounts to within the specified directory\n"
++"    tree on the host.  If this isn't specified, then a user inside UML can\n"
++"    mount anything on the host that's accessible to the user that's running\n"
++"    it.\n"
++"    The only flag currently supported is 'append', which specifies that all\n"
++"    files opened by hostfs will be opened in append mode.\n\n"
++);
++
++struct hostfs_data {
++      struct externfs_data ext;
++      char *mount;
++};
++
++struct hostfs_file {
++      struct externfs_inode ext;
++      struct file_handle fh;
++};
++
++static int hostfs_access_file(char *file, int r, int w, int x, int uid, 
++                            int gid, struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, file, NULL };
++      char tmp[HOSTFS_BUFSIZE];
++      int err, mode = 0;
++
++      if(r) mode = OS_ACC_R_OK;
++      if(w) mode |= OS_ACC_W_OK;
++      if(x) mode |= OS_ACC_X_OK;
++      
++      err = -ENOMEM;
++      file = get_path(path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      err = os_access(file, mode);
++      free_path(file, tmp);
++ out:
++      return(err);
++}
++
++static int hostfs_make_node(const char *file, int mode, int uid, int gid, 
++                          int type, int major, int minor, 
++                          struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, file, NULL };
++      char tmp[HOSTFS_BUFSIZE];
++      int err = -ENOMEM;
++
++      file = get_path(path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      /* XXX Pass type in an OS-independent way */
++      mode |= type;
++
++      err = os_make_dev(file, mode, major, minor);
++      free_path(file, tmp);
++ out:
++      return(err);
++}
++
++static int hostfs_stat_file(const char *file, struct externfs_data *ed, 
++                          dev_t *dev_out, unsigned long long *inode_out, 
++                          int *mode_out, int *nlink_out, int *uid_out, 
++                          int *gid_out, unsigned long long *size_out, 
++                          unsigned long *atime_out, unsigned long *mtime_out,
++                          unsigned long *ctime_out, int *blksize_out, 
++                          unsigned long long *blocks_out)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, file, NULL };
++
++      /* XXX Why pretend everything is owned by root? */
++      *uid_out = 0;
++      *gid_out = 0;
++      return(host_stat_file(path, dev_out, inode_out, mode_out, nlink_out, 
++                            NULL, NULL, size_out, atime_out, mtime_out, 
++                            ctime_out, blksize_out, blocks_out));
++}
++
++static int hostfs_file_type(const char *file, int *rdev, 
++                           struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, file, NULL };
++
++      return(host_file_type(path, rdev));
++}
++
++static char *hostfs_name(struct inode *inode)
++{
++      struct externfs_data *ed = inode_externfs_info(inode);
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++
++      return(inode_name_prefix(inode, mount));        
++}
++
++static struct externfs_inode *hostfs_init_file(struct externfs_data *ed)
++{
++      struct hostfs_file *hf;
++
++      hf = kmalloc(sizeof(*hf), GFP_KERNEL);
++      if(hf == NULL)
++              return(NULL);
++
++      hf->fh.fd = -1;
++      return(&hf->ext);
++}
++
++static int hostfs_open_file(struct externfs_inode *ext, char *file, 
++                          int uid, int gid, struct inode *inode, 
++                          struct externfs_data *ed)
++{
++      struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext);
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, file, NULL };
++      int err;
++
++      err = host_open_file(path, 1, 1, &hf->fh);
++      if(err == -EISDIR)
++              goto out;
++
++      if(err == -EACCES)
++              err = host_open_file(path, 1, 0, &hf->fh);
++
++      if(err)
++              goto out;
++
++      is_reclaimable(&hf->fh, hostfs_name, inode);
++ out:
++      return(err);
++}
++
++static void *hostfs_open_dir(char *file, int uid, int gid, 
++                           struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, file, NULL };
++
++      return(host_open_dir(path));
++}
++
++static void hostfs_close_dir(void *stream, struct externfs_data *ed)
++{
++      os_close_dir(stream);
++}
++
++static char *hostfs_read_dir(void *stream, unsigned long long *pos, 
++                           unsigned long long *ino_out, int *len_out, 
++                           struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++
++      return(generic_host_read_dir(stream, pos, ino_out, len_out, mount));
++}
++
++static int hostfs_read_file(struct externfs_inode *ext, 
++                          unsigned long long offset, char *buf, int len, 
++                          int ignore_start, int ignore_end,
++                          void (*completion)(char *, int, void *), void *arg,
++                          struct externfs_data *ed)
++{
++      struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext);
++      int err = 0;
++
++      if(ignore_start != 0){
++              err = read_file(&hf->fh, offset, buf, ignore_start);
++              if(err < 0)
++                      goto out;
++      }
++
++      if(ignore_end != len)
++              err = read_file(&hf->fh, offset + ignore_end, buf + ignore_end,
++                              len - ignore_end);
++
++ out:
++
++      (*completion)(buf, err, arg);
++      if (err > 0)
++              err = 0;
++      return(err);
++}
++
++static int hostfs_write_file(struct externfs_inode *ext,
++                           unsigned long long offset, const char *buf, 
++                           int start, int len, 
++                           void (*completion)(char *, int, void *), 
++                           void *arg, struct externfs_data *ed)
++{
++      struct file_handle *fh;
++      int err;
++
++      fh = &container_of(ext, struct hostfs_file, ext)->fh;
++      err = write_file(fh, offset + start, buf + start, len);
++
++      (*completion)((char *) buf, err, arg);
++      if (err > 0)
++              err = 0;
++
++      return(err);
++}
++
++static int hostfs_create_file(struct externfs_inode *ext, char *file, int mode,
++                            int uid, int gid, struct inode *inode, 
++                            struct externfs_data *ed)
++{
++      struct hostfs_file *hf = container_of(ext, struct hostfs_file, 
++                                            ext);
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, file, NULL };
++      int err = -ENOMEM;
++
++      err = host_create_file(path, mode, &hf->fh);
++      if(err)
++              goto out;
++
++      is_reclaimable(&hf->fh, hostfs_name, inode);
++ out:
++      return(err);
++}
++
++static int hostfs_set_attr(const char *file, struct externfs_iattr *attrs, 
++                         struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, file, NULL };
++
++      return(host_set_attr(path, attrs));
++}
++
++static int hostfs_make_symlink(const char *from, const char *to, int uid, 
++                             int gid, struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, from, NULL };
++
++      return(host_make_symlink(path, to));
++}
++
++static int hostfs_link_file(const char *to, const char *from, int uid, int gid,
++                          struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *to_path[] = { jail_dir, mount, to, NULL };
++      const char *from_path[] = { jail_dir, mount, from, NULL };
++
++      return(host_link_file(to_path, from_path));
++}
++
++static int hostfs_unlink_file(const char *file, struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, file, NULL };
++
++      return(host_unlink_file(path));
++}
++
++static int hostfs_make_dir(const char *file, int mode, int uid, int gid, 
++                          struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, file, NULL };
++
++      return(host_make_dir(path, mode));
++}
++
++static int hostfs_remove_dir(const char *file, int uid, int gid, 
++                           struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, file, NULL };
++
++      return(host_remove_dir(path));
++}
++
++static int hostfs_read_link(char *file, int uid, int gid, char *buf, int size, 
++                          struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, file, NULL };
++
++      return(host_read_link(path, buf, size));
++}
++
++static int hostfs_rename_file(char *from, char *to, struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *to_path[] = { jail_dir, mount, to, NULL };
++      const char *from_path[] = { jail_dir, mount, from, NULL };
++
++      return(host_rename_file(from_path, to_path));
++}
++
++static int hostfs_stat_fs(long *bsize_out, long long *blocks_out, 
++                        long long *bfree_out, long long *bavail_out, 
++                        long long *files_out, long long *ffree_out,
++                        void *fsid_out, int fsid_size, long *namelen_out, 
++                        long *spare_out, struct externfs_data *ed)
++{
++      char *mount = container_of(ed, struct hostfs_data, ext)->mount;
++      const char *path[] = { jail_dir, mount, NULL };
++
++      return(host_stat_fs(path, bsize_out, blocks_out, bfree_out, bavail_out,
++                          files_out, ffree_out, fsid_out, fsid_size, 
++                          namelen_out, spare_out));
++}
++
++static void hostfs_close_file(struct externfs_inode *ext,
++                            unsigned long long size)
++{
++      struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext);
++
++      if(hf->fh.fd == -1)
++              return;
++
++      truncate_file(&hf->fh, size);
++      close_file(&hf->fh);
++}
++
++static int hostfs_truncate_file(struct externfs_inode *ext, __u64 size, 
++                              struct externfs_data *ed)
++{
++      struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext);
++
++      return(truncate_file(&hf->fh, size));
++}
++
++static struct externfs_file_ops hostfs_file_ops = {
++      .stat_file              = hostfs_stat_file,
++      .file_type              = hostfs_file_type,
++      .access_file            = hostfs_access_file,
++      .open_file              = hostfs_open_file,
++      .open_dir               = hostfs_open_dir,
++      .read_dir               = hostfs_read_dir,
++      .read_file              = hostfs_read_file,
++      .write_file             = hostfs_write_file,
++      .map_file_page          = NULL,
++      .close_file             = hostfs_close_file,
++      .close_dir              = hostfs_close_dir,
++      .invisible              = NULL,
++      .create_file            = hostfs_create_file,
++      .set_attr               = hostfs_set_attr,
++      .make_symlink           = hostfs_make_symlink,
++      .unlink_file            = hostfs_unlink_file,
++      .make_dir               = hostfs_make_dir,
++      .remove_dir             = hostfs_remove_dir,
++      .make_node              = hostfs_make_node,
++      .link_file              = hostfs_link_file,
++      .read_link              = hostfs_read_link,
++      .rename_file            = hostfs_rename_file,
++      .statfs                 = hostfs_stat_fs,
++      .truncate_file          = hostfs_truncate_file
++};
++
++static struct externfs_data *mount_fs(char *mount_arg)
++{
++      struct hostfs_data *hd;
++      int err = -ENOMEM;
++
++      hd = kmalloc(sizeof(*hd), GFP_KERNEL);
++      if(hd == NULL)
++              goto out;
++
++      hd->mount = host_root_filename(mount_arg);
++      if(hd->mount == NULL)
++              goto out_free;
++
++      init_externfs(&hd->ext, &hostfs_file_ops);
++
++      return(&hd->ext);
++ out_free:
++      kfree(hd);
++ out:
++      return(ERR_PTR(err));
++}
++
++static struct externfs_mount_ops hostfs_mount_ops = {
++      .init_file              = hostfs_init_file,
++      .mount                  = mount_fs,
++};
++
++static int __init init_hostfs(void)
++{
++      return(register_externfs("hostfs", &hostfs_mount_ops));
++}
++
++static void __exit exit_hostfs(void)
++{
++      unregister_externfs("hostfs");
++}
++
++__initcall(init_hostfs);
++__exitcall(exit_hostfs);
++
++#if 0
++module_init(init_hostfs)
++module_exit(exit_hostfs)
++MODULE_LICENSE("GPL");
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/fs/hostfs/hostfs.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/fs/hostfs/hostfs.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/fs/hostfs/hostfs.h    2005-05-03 23:46:13.801043992 +0300
+@@ -0,0 +1,200 @@
++/* 
++ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_FS_HOSTFS
++#define __UM_FS_HOSTFS
++
++#include "linux/fs.h"
++#include "linux/blkdev.h"
++#include "filehandle.h"
++#include "os.h"
++
++/* These are exactly the same definitions as in fs.h, but the names are 
++ * changed so that this file can be included in both kernel and user files.
++ */
++
++#define EXTERNFS_ATTR_MODE    1
++#define EXTERNFS_ATTR_UID     2
++#define EXTERNFS_ATTR_GID     4
++#define EXTERNFS_ATTR_SIZE    8
++#define EXTERNFS_ATTR_ATIME   16
++#define EXTERNFS_ATTR_MTIME   32
++#define EXTERNFS_ATTR_CTIME   64
++#define EXTERNFS_ATTR_ATIME_SET       128
++#define EXTERNFS_ATTR_MTIME_SET       256
++#define EXTERNFS_ATTR_FORCE   512     /* Not a change, but a change it */
++#define EXTERNFS_ATTR_ATTR_FLAG       1024
++
++/**
++ * container_of - cast a member of a structure out to the containing structure
++ *
++ * @ptr:        the pointer to the member.
++ * @type:       the type of the container struct this is embedded in.
++ * @member:     the name of the member within the struct.
++ *
++ */
++#define container_of(ptr, type, member) ({                      \
++        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
++        (type *)( (char *)__mptr - offsetof(type,member) );})
++
++struct externfs_iattr {
++      unsigned int    ia_valid;
++      mode_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;
++};
++
++struct externfs_data {
++      struct externfs_file_ops *file_ops;
++      struct externfs_mount_ops *mount_ops;
++};
++
++struct externfs_inode {
++      struct externfs_file_ops *ops;
++};
++
++struct externfs_mount_ops {
++      struct externfs_data *(*mount)(char *mount_arg);
++      struct externfs_inode *(*init_file)(struct externfs_data *ed);
++};
++
++struct externfs_file_ops {
++      int (*stat_file)(const char *path, struct externfs_data *ed, 
++                       dev_t *dev_out, unsigned long long *inode_out, 
++                       int *mode_out, int *nlink_out, int *uid_out, 
++                       int *gid_out, unsigned long long *size_out, 
++                       unsigned long *atime_out, unsigned long *mtime_out,
++                       unsigned long *ctime_out, int *blksize_out, 
++                       unsigned long long *blocks_out);
++      int (*file_type)(const char *path, int *rdev, 
++                       struct externfs_data *ed);
++      int (*access_file)(char *path, int r, int w, int x, int uid, int gid, 
++                         struct externfs_data *ed);
++      int (*open_file)(struct externfs_inode *ext, char *file, 
++                       int uid, int gid, struct inode *inode, 
++                       struct externfs_data *ed);
++      void (*close_file)(struct externfs_inode *ext, 
++                         unsigned long long size);
++      void *(*open_dir)(char *path, int uid, int gid, 
++                        struct externfs_data *ed);
++      char *(*read_dir)(void *stream, unsigned long long *pos, 
++                        unsigned long long *ino_out, int *len_out, 
++                        struct externfs_data *ed);
++      int (*read_file)(struct externfs_inode *ext, 
++                       unsigned long long offset, char *buf, int len, 
++                       int ignore_start, int ignore_end,
++                       void (*completion)(char *, int, void *), void *arg, 
++                       struct externfs_data *ed);
++      int (*write_file)(struct externfs_inode *ext, 
++                        unsigned long long offset, const char *buf, 
++                        int start, int len, 
++                        void (*completion)(char *, int, void *), void *arg, 
++                        struct externfs_data *ed);
++      int (*map_file_page)(struct externfs_inode *ext, 
++                           unsigned long long offset, char *buf, int w, 
++                           struct externfs_data *ed);
++      void (*close_dir)(void *stream, struct externfs_data *ed);
++      void (*invisible)(struct externfs_inode *ext);
++      int (*create_file)(struct externfs_inode *ext, char *path, 
++                         int mode, int uid, int gid, struct inode *inode, 
++                         struct externfs_data *ed);
++      int (*set_attr)(const char *path, struct externfs_iattr *attrs, 
++                      struct externfs_data *ed);
++      int (*make_symlink)(const char *from, const char *to, int uid, int gid,
++                          struct externfs_data *ed);
++      int (*unlink_file)(const char *path, struct externfs_data *ed);
++      int (*make_dir)(const char *path, int mode, int uid, int gid, 
++                      struct externfs_data *ed);
++      int (*remove_dir)(const char *path, int uid, int gid, 
++                        struct externfs_data *ed);
++      int (*make_node)(const char *path, int mode, int uid, int gid, 
++                       int type, int maj, int min, struct externfs_data *ed);
++      int (*link_file)(const char *to, const char *from, int uid, int gid, 
++                       struct externfs_data *ed);
++      int (*read_link)(char *path, int uid, int gid, char *buf, int size, 
++                       struct externfs_data *ed);
++      int (*rename_file)(char *from, char *to, struct externfs_data *ed);
++      int (*statfs)(long *bsize_out, long long *blocks_out, 
++                    long long *bfree_out, long long *bavail_out, 
++                    long long *files_out, long long *ffree_out,
++                    void *fsid_out, int fsid_size, long *namelen_out, 
++                    long *spare_out, struct externfs_data *ed);
++      int (*truncate_file)(struct externfs_inode *ext, __u64 size, 
++                           struct externfs_data *ed);
++};
++
++#define HOSTFS_BUFSIZE 64
++
++extern int register_externfs(char *name, struct externfs_mount_ops *mount_ops);
++extern void unregister_externfs(char *name);
++extern void init_externfs(struct externfs_data *ed, 
++                        struct externfs_file_ops *ops);
++struct externfs_data *inode_externfs_info(struct inode *inode);
++
++extern char *generic_root_filename(char *mount_arg);
++extern void host_close_file(void *stream);
++extern int host_read_file(int fd, unsigned long long offset, char *buf, 
++                        int len);
++extern int host_open_file(const char *path[], int r, int w,
++                        struct file_handle *fh);
++extern void *host_open_dir(const char *path[]);
++extern char *host_read_dir(void *stream, unsigned long long *pos, 
++                         unsigned long long *ino_out, int *len_out);
++extern int host_file_type(const char *path[], int *rdev);
++extern char *host_root_filename(char *mount_arg);
++extern char *get_path(const char *path[], char *buf, int size);
++extern void free_path(const char *buf, char *tmp);
++extern int host_create_file(const char *path[], int mode, 
++                          struct file_handle *fh);
++extern int host_set_attr(const char *path[], struct externfs_iattr *attrs);
++extern int host_make_symlink(const char *from[], const char *to);
++extern int host_unlink_file(const char *path[]);
++extern int host_make_dir(const char *path[], int mode);
++extern int host_remove_dir(const char *path[]);
++extern int host_link_file(const char *to[], const char *from[]);
++extern int host_read_link(const char *path[], char *buf, int size);
++extern int host_rename_file(const char *from[], const char *to[]);
++extern int host_stat_fs(const char *path[], long *bsize_out, 
++                      long long *blocks_out, long long *bfree_out, 
++                      long long *bavail_out, long long *files_out, 
++                      long long *ffree_out, void *fsid_out, int fsid_size, 
++                      long *namelen_out, long *spare_out);
++extern int host_stat_file(const char *path[], dev_t *dev_out, 
++                        unsigned long long *inode_out, int *mode_out, 
++                        int *nlink_out, int *uid_out, int *gid_out, 
++                        unsigned long long *size_out, 
++                        unsigned long *atime_out, unsigned long *mtime_out,
++                        unsigned long *ctime_out, int *blksize_out,
++                        unsigned long long *blocks_out);
++
++extern char *generic_host_read_dir(void *stream, unsigned long long *pos, 
++                            unsigned long long *ino_out, int *len_out, 
++                            void *mount);
++extern int generic_host_read_file(int fd, unsigned long long offset, char *buf,
++                           int len, void *mount);
++extern void generic_host_close_file(void *stream, unsigned long long size,
++                                  void *mount);
++extern int generic_host_truncate_file(struct file_handle *fh, __u64 size, 
++                                    void *m);
++
++extern char *inode_name_prefix(struct inode *inode, char *prefix);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/fs/hostfs/humfs.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/fs/hostfs/humfs.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/fs/hostfs/humfs.c     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,1024 @@
++/* 
++ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/stat.h>
++#include <linux/tqueue.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/kdev_t.h>
++#include <asm/irq.h>
++#include "hostfs.h"
++#include "mem.h"
++#include "os.h"
++#include "mode.h"
++#include "aio.h"
++#include "irq_user.h"
++#include "irq_kern.h"
++#include "filehandle.h"
++#include "metadata.h"
++
++#define HUMFS_VERSION 2
++
++static int humfs_stat_file(const char *path, struct externfs_data *ed, 
++                         dev_t *dev_out, unsigned long long *inode_out, 
++                         int *mode_out, int *nlink_out, int *uid_out, 
++                         int *gid_out, unsigned long long *size_out, 
++                         unsigned long *atime_out, unsigned long *mtime_out, 
++                         unsigned long *ctime_out, int *blksize_out, 
++                         unsigned long long *blocks_out)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      const char *data_path[3] = { mount->data, path, NULL };
++      int err, mode, perms, major, minor;
++      char type;
++
++      err = host_stat_file(data_path, dev_out, inode_out, mode_out, 
++                           nlink_out, NULL, NULL, size_out, atime_out, 
++                           mtime_out, ctime_out, blksize_out, blocks_out);
++      if(err)
++              return(err);
++
++      err = (*mount->meta->ownerships)(path, &perms, uid_out, gid_out, 
++                                       &type, &major, &minor, mount);
++      if(err)
++              return(err);
++
++      *mode_out = (*mode_out & ~S_IRWXUGO) | perms;
++
++      mode = 0;
++      switch(type){
++      case 'c':
++              mode = S_IFCHR;
++              break;
++      case 'b':
++              mode = S_IFBLK;
++              break;
++      case 's':
++              mode = S_IFSOCK;
++              break;
++      default:
++              break;
++      }
++
++      if(mode != 0)
++              *mode_out = (*mode_out & ~S_IFMT) | mode;
++
++      return(0);
++}
++
++static int meta_type(const char *path, int *dev_out, void *m)
++{
++      struct humfs *mount = m;
++      int err, type, maj, min;
++      char c;
++
++      err = (*mount->meta->ownerships)(path, NULL, NULL, NULL, &c, &maj, 
++                                       &min, mount);
++      if(err)
++              return(err);
++
++      if(c == 0)
++              return(0);
++
++      if(dev_out)
++              *dev_out = MKDEV(maj, min);
++
++      switch(c){
++      case 'c':
++              type = OS_TYPE_CHARDEV;
++              break;
++      case 'b':
++              type = OS_TYPE_BLOCKDEV;
++              break;
++      case 'p':
++              type = OS_TYPE_FIFO;
++              break;
++      case 's':
++              type = OS_TYPE_SOCK;
++              break;
++      default:
++              type = -EINVAL;
++              break;
++      }
++
++      return(type);
++}
++
++static int humfs_file_type(const char *path, int *dev_out, 
++                         struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      const char *data_path[3] = { mount->data, path, NULL };
++      int type;
++
++      type = meta_type(path, dev_out, mount);
++      if(type != 0)
++              return(type);
++
++      return(host_file_type(data_path, dev_out));
++}
++
++static char *humfs_data_name(struct inode *inode)
++{
++      struct externfs_data *ed = inode_externfs_info(inode);
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++
++      return(inode_name_prefix(inode, mount->data));
++}
++
++static struct externfs_inode *humfs_init_file(struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      struct humfs_file *hf;
++
++      hf = (*mount->meta->init_file)();
++      if(IS_ERR(hf))
++              return((struct externfs_inode *) hf);
++
++      hf->data.fd = -1;
++      return(&hf->ext);
++}
++
++static int humfs_open_file(struct externfs_inode *ext, char *path, int uid, 
++                         int gid, struct inode *inode, 
++                         struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
++      const char *data_path[3] = { mount->data, path, NULL };
++      struct openflags flags;
++      char tmp[HOSTFS_BUFSIZE], *file;
++      int err = -ENOMEM;
++
++      file = get_path(data_path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      flags = of_rdwr(OPENFLAGS());
++      if(mount->direct)
++              flags = of_direct(flags);
++
++      if(path == NULL)
++              path = "";
++      err = (*mount->meta->open_file)(hf, path, inode, mount);
++      if(err)
++              goto out_free;
++
++      err = open_filehandle(file, flags, 0, &hf->data);
++      if(err == -EISDIR)
++              goto out;
++      else if(err == -EPERM){
++              flags = of_set_rw(flags, 1, 0);
++              err = open_filehandle(file, flags, 0, &hf->data);
++      }
++      
++      if(err)
++              goto out_close;
++
++      hf->mount = mount;
++      is_reclaimable(&hf->data, humfs_data_name, inode);
++
++ out_free:
++      free_path(file, tmp);
++ out: 
++      return(err);
++
++ out_close:
++      (*mount->meta->close_file)(hf);
++      goto out_free;
++}
++
++static void *humfs_open_dir(char *path, int uid, int gid, 
++                          struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      const char *data_path[3] = { mount->data, path, NULL };
++
++      return(host_open_dir(data_path));
++}
++
++static void humfs_close_dir(void *stream, struct externfs_data *ed)
++{
++      os_close_dir(stream);
++}
++
++static char *humfs_read_dir(void *stream, unsigned long long *pos, 
++                          unsigned long long *ino_out, int *len_out, 
++                          struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++
++      return(generic_host_read_dir(stream, pos, ino_out, len_out, mount));
++}
++
++LIST_HEAD(humfs_replies);
++
++struct humfs_aio {
++      struct aio_context aio;
++      struct list_head list;
++      void (*completion)(char *, int, void *);
++      char *buf;
++      int real_len;
++      int err;
++      void *data;
++};
++
++static int humfs_reply_fd = -1;
++
++struct humfs_aio last_task_aio, last_intr_aio;
++struct humfs_aio *last_task_aio_ptr, *last_intr_aio_ptr;
++
++void humfs_task_proc(void *unused)
++{
++      struct humfs_aio *aio;
++      unsigned long flags;
++
++      while(!list_empty(&humfs_replies)){
++              local_irq_save(flags);
++              aio = list_entry(humfs_replies.next, struct humfs_aio, list);
++
++              last_task_aio = *aio;
++              last_task_aio_ptr = aio;
++
++              list_del(&aio->list);
++              local_irq_restore(flags);
++
++              if(aio->err >= 0)
++                      aio->err = aio->real_len;
++              (*aio->completion)(aio->buf, aio->err, aio->data);
++              kfree(aio);
++      }
++}
++
++struct tq_struct humfs_task = {
++      .routine        = humfs_task_proc,
++      .data           = NULL
++};
++
++static void humfs_interrupt(int irq, void *dev_id, struct pt_regs *unused)
++{
++      struct aio_thread_reply reply;
++      struct humfs_aio *aio;
++      int err, fd = (int) dev_id;
++
++      while(1){
++              err = os_read_file(fd, &reply, sizeof(reply));
++              if(err < 0){
++                      if(err == -EAGAIN)
++                              break;
++                      printk("humfs_interrupt - read returned err %d\n", 
++                             -err);
++                      return;
++              }
++              aio = reply.data;
++              aio->err = reply.err;
++              list_add(&aio->list, &humfs_replies);
++              last_intr_aio = *aio;
++              last_intr_aio_ptr = aio;
++      }
++
++      if(!list_empty(&humfs_replies))
++              schedule_task(&humfs_task);
++      reactivate_fd(fd, HUMFS_IRQ);
++}
++
++static int init_humfs_aio(void)
++{
++      int fds[2], err;
++
++      err = os_pipe(fds, 1, 1);
++      if(err){
++              printk("init_humfs_aio - pipe failed, err = %d\n", -err);
++              goto out;
++      }
++
++      err = um_request_irq(HUMFS_IRQ, fds[0], IRQ_READ, humfs_interrupt,
++                           SA_INTERRUPT | SA_SAMPLE_RANDOM, "humfs", 
++                           (void *) fds[0]);
++      if(err){
++              printk("init_humfs_aio - : um_request_irq failed, err = %d\n",
++                     err);
++              goto out_close;
++      }
++
++      humfs_reply_fd = fds[1];
++      goto out;
++      
++ out_close:
++      os_close_file(fds[0]);
++      os_close_file(fds[1]);
++ out:
++      return(0);
++}
++
++__initcall(init_humfs_aio);
++
++static int humfs_aio(enum aio_type type, int fd, unsigned long long offset,
++                   char *buf, int len, int real_len,
++                   void (*completion)(char *, int, void *), void *arg)
++{
++      struct humfs_aio *aio;
++      int err = -ENOMEM;
++
++      aio = kmalloc(sizeof(*aio), GFP_KERNEL);
++      if(aio == NULL)
++              goto out;
++      *aio = ((struct humfs_aio) { .aio       = INIT_AIO_CONTEXT,
++                                   .list      = LIST_HEAD_INIT(aio->list),
++                                   .completion= completion,
++                                   .buf       = buf,
++                                   .err       = 0,
++                                   .real_len  = real_len,
++                                   .data      = arg });
++
++      err = submit_aio(type, fd, buf, len, offset, humfs_reply_fd, aio);
++      if(err)
++              (*completion)(buf, err, arg);
++
++ out:
++      return(err);
++}
++
++static int humfs_read_file(struct externfs_inode *ext,
++                         unsigned long long offset, char *buf, int len, 
++                         int ignore_start, int ignore_end,
++                         void (*completion)(char *, int, void *), void *arg, 
++                         struct externfs_data *ed)
++{
++      struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
++      int fd = filehandle_fd(&hf->data);
++
++      if(fd < 0){
++              (*completion)(buf, fd, arg);
++              return(fd);
++      }
++
++      return(humfs_aio(AIO_READ, fd, offset, buf, len, len, completion, 
++                       arg));
++}
++
++static int humfs_write_file(struct externfs_inode *ext,
++                          unsigned long long offset, const char *buf, 
++                          int start, int len, 
++                          void (*completion)(char *, int, void *), void *arg,
++                          struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
++      int err, orig_len = len, fd = filehandle_fd(&hf->data);
++
++      if(fd < 0){
++              (*completion)((char *) buf, fd, arg);
++              return(fd);
++      }
++
++      if(mount->direct)
++              len = PAGE_SIZE;
++      else {
++              offset += start;
++              buf += start;
++      }
++
++      err = humfs_aio(AIO_WRITE, fd, offset, (char *) buf, len, orig_len, 
++                      completion, arg);
++
++      if(err < 0)
++              return(err);
++
++      if(mount->direct)
++              err = orig_len;
++
++      return(err);
++}
++
++static int humfs_map_file_page(struct externfs_inode *ext, 
++                             unsigned long long offset, char *buf, int w, 
++                             struct externfs_data *ed)
++{
++      struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
++      unsigned long long size, need;
++      int err, fd = filehandle_fd(&hf->data);
++
++      if(fd < 0)
++              return(fd);
++
++      err = os_fd_size(fd, &size);
++      if(err)
++              return(err);
++
++      need = offset + PAGE_SIZE;
++      if(size < need){
++              err = os_truncate_fd(fd, need);
++              if(err)
++                      return(err);
++      }
++      
++      return(physmem_subst_mapping(buf, fd, offset, w));
++}
++
++static void humfs_close_file(struct externfs_inode *ext,
++                           unsigned long long size)
++{
++      struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
++      int fd;
++
++      if(hf->data.fd == -1)
++              return;
++
++      fd = filehandle_fd(&hf->data);
++      physmem_forget_descriptor(fd);
++      truncate_file(&hf->data, size);
++      close_file(&hf->data);
++
++      (*hf->mount->meta->close_file)(hf);
++}
++
++/* XXX Assumes that you can't make a normal file */
++
++static int humfs_make_node(const char *path, int mode, int uid, int gid, 
++                         int type, int major, int minor, 
++                         struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      struct file_handle fh;
++      const char *data_path[3] = { mount->data, path, NULL };
++      int err;
++      char t;
++
++      err = host_create_file(data_path, S_IRWXUGO, &fh);
++      if(err)
++              goto out;
++
++      close_file(&fh);
++
++      switch(type){
++      case S_IFCHR:
++              t = 'c';
++              break;
++      case S_IFBLK:
++              t = 'b';
++              break;
++      case S_IFIFO:
++              t = 'p';
++              break;
++      case S_IFSOCK:
++              t = 's';
++              break;
++      default:
++              err = -EINVAL;
++              printk("humfs_make_node - bad node type : %d\n", type);
++              goto out_rm;
++      }
++
++      err = (*mount->meta->make_node)(path, mode, uid, gid, t, major, minor, 
++                                      mount);
++      if(err)
++              goto out_rm;
++
++ out:
++      return(err);
++
++ out_rm:
++      host_unlink_file(data_path);
++      goto out;
++}
++              
++static int humfs_create_file(struct externfs_inode *ext, char *path, int mode, 
++                           int uid, int gid, struct inode *inode, 
++                           struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
++      const char *data_path[3] = { mount->data, path, NULL };
++      int err;
++
++      err = (*mount->meta->create_file)(hf, path, mode, uid, gid, inode, 
++                                        mount);
++      if(err)
++              goto out;
++
++      err = host_create_file(data_path, S_IRWXUGO, &hf->data);
++      if(err)
++              goto out_rm;
++
++      
++      is_reclaimable(&hf->data, humfs_data_name, inode);
++
++      return(0);
++
++ out_rm:
++      (*mount->meta->remove_file)(path, mount);
++      (*mount->meta->close_file)(hf);
++ out:
++      return(err);
++}
++
++static int humfs_set_attr(const char *path, struct externfs_iattr *attrs, 
++                        struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      const char *data_path[3] = { mount->data, path, NULL };
++      int (*chown)(const char *, int, int, int, struct humfs *);
++      int err;
++
++      chown = mount->meta->change_ownerships;
++      if(attrs->ia_valid & EXTERNFS_ATTR_MODE){
++              err = (*chown)(path, attrs->ia_mode, -1, -1, mount);
++              if(err)
++                      return(err);
++      }
++      if(attrs->ia_valid & EXTERNFS_ATTR_UID){
++              err = (*chown)(path, -1, attrs->ia_uid, -1, mount);
++              if(err)
++                      return(err);
++      }
++      if(attrs->ia_valid & EXTERNFS_ATTR_GID){
++              err = (*chown)(path, -1, -1, attrs->ia_gid, mount);
++              if(err)
++                      return(err);
++      }
++
++      attrs->ia_valid &= ~(EXTERNFS_ATTR_MODE | EXTERNFS_ATTR_UID | 
++                           EXTERNFS_ATTR_GID);
++
++      return(host_set_attr(data_path, attrs));
++}
++
++static int humfs_make_symlink(const char *from, const char *to, int uid, 
++                            int gid, struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      struct humfs_file *hf;
++      const char *data_path[3] = { mount->data, from, NULL };
++      int err = -ENOMEM;
++
++      hf = (*mount->meta->init_file)();
++      if(hf == NULL)
++              goto out;
++
++      err = (*mount->meta->create_file)(hf, from, S_IRWXUGO, uid, gid, NULL, 
++                                        mount);
++      if(err)
++              goto out_close;
++
++      err = host_make_symlink(data_path, to);
++      if(err)
++              (*mount->meta->remove_file)(from, mount);
++
++ out_close:
++      (*mount->meta->close_file)(hf);
++ out:
++      return(err);
++}
++
++static int humfs_link_file(const char *to, const char *from, int uid, int gid, 
++                         struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      const char *data_path_from[3] = { mount->data, from, NULL };
++      const char *data_path_to[3] = { mount->data, to, NULL };
++      int err;
++
++      err = (*mount->meta->create_link)(to, from, mount);
++      if(err)
++              return(err);
++
++      err = host_link_file(data_path_to, data_path_from);
++      if(err)
++              (*mount->meta->remove_file)(from, mount);
++      
++      return(err);
++}
++
++static int humfs_unlink_file(const char *path, struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      const char *data_path[3] = { mount->data, path, NULL };
++      int err;
++
++      err = (*mount->meta->remove_file)(path, mount);
++      if (err)
++              return err;
++
++      (*mount->meta->remove_file)(path, mount);
++      return(host_unlink_file(data_path));
++}
++
++static void humfs_invisible(struct externfs_inode *ext)
++{
++      struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
++      struct humfs *mount = hf->mount;
++      
++      (*mount->meta->invisible)(hf);
++      not_reclaimable(&hf->data);
++}
++
++static int humfs_make_dir(const char *path, int mode, int uid, int gid, 
++                        struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      const char *data_path[3] = { mount->data, path, NULL };
++      int err;
++
++      err = (*mount->meta->create_dir)(path, mode, uid, gid, mount);
++      if(err)
++              return(err);
++      
++      err = host_make_dir(data_path, S_IRWXUGO);
++      if(err)
++              (*mount->meta->remove_dir)(path, mount);
++
++      return(err);
++}
++
++static int humfs_remove_dir(const char *path, int uid, int gid, 
++                          struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      const char *data_path[3] = { mount->data, path, NULL };
++      int err;
++
++      err = host_remove_dir(data_path);
++      if (err)
++              return err;
++
++      (*mount->meta->remove_dir)(path, mount);
++
++      return(err);
++}
++
++static int humfs_read_link(char *file, int uid, int gid, char *buf, int size, 
++                         struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      const char *data_path[3] = { mount->data, file, NULL };
++
++      return(host_read_link(data_path, buf, size));
++}
++
++struct humfs *inode_humfs_info(struct inode *inode)
++{
++      return(container_of(inode_externfs_info(inode), struct humfs, ext));
++}
++
++static int humfs_rename_file(char *from, char *to, struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      const char *data_path_from[3] = { mount->data, from, NULL };
++      const char *data_path_to[3] = { mount->data, to, NULL };
++      int err;
++
++      err = (*mount->meta->rename_file)(from, to, mount);
++      if(err)
++              return(err);
++      
++      err = host_rename_file(data_path_from, data_path_to);
++      if(err)
++              (*mount->meta->rename_file)(to, from, mount);
++
++      return(err);
++}
++
++static int humfs_stat_fs(long *bsize_out, long long *blocks_out, 
++                       long long *bfree_out, long long *bavail_out, 
++                       long long *files_out, long long *ffree_out, 
++                       void *fsid_out, int fsid_size, long *namelen_out, 
++                       long *spare_out, struct externfs_data *ed)
++{
++      struct humfs *mount = container_of(ed, struct humfs, ext);
++      const char *data_path[3] = { mount->data, NULL };
++      int err;
++
++      /* XXX Needs to maintain this info as metadata */
++      err = host_stat_fs(data_path, bsize_out, blocks_out, bfree_out, 
++                         bavail_out, files_out, ffree_out, fsid_out, 
++                         fsid_size, namelen_out, spare_out);
++      if(err)
++              return(err);
++
++      *blocks_out = mount->total / *bsize_out;
++      *bfree_out = (mount->total - mount->used) / *bsize_out;
++      *bavail_out = (mount->total - mount->used) / *bsize_out;
++      return(0);
++}
++
++int humfs_truncate_file(struct externfs_inode *ext, __u64 size, 
++                      struct externfs_data *ed)
++{
++      struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
++
++      return(truncate_file(&hf->data, size));
++}
++
++char *humfs_path(char *dir, char *file)
++{
++      int need_slash, len = strlen(dir) + strlen(file);
++      char *new;
++
++      need_slash = (dir[strlen(dir) - 1] != '/');
++      if(need_slash)
++              len++;
++
++      new = kmalloc(len + 1, GFP_KERNEL);
++      if(new == NULL)
++              return(NULL);
++
++      strcpy(new, dir);
++      if(need_slash)
++              strcat(new, "/");
++      strcat(new, file);
++
++      return(new);
++}
++
++DECLARE_MUTEX(meta_sem);
++struct list_head metas = LIST_HEAD_INIT(metas);
++
++static struct humfs_meta_ops *find_meta(const char *name)
++{
++      struct list_head *ele;
++      struct humfs_meta_ops *m;
++ 
++      down(&meta_sem);
++      list_for_each(ele, &metas){
++              m = list_entry(ele, struct humfs_meta_ops, list);
++              if(!strcmp(m->name, name))
++                      goto out;
++      }
++      m = NULL;
++ out:
++      up(&meta_sem);
++      return(m);
++}
++
++void register_meta(struct humfs_meta_ops *ops)
++{
++      down(&meta_sem);
++      list_add(&ops->list, &metas);
++      up(&meta_sem);
++}
++ 
++void unregister_meta(struct humfs_meta_ops *ops)
++{
++      down(&meta_sem);
++      list_del(&ops->list);
++      up(&meta_sem);
++}
++ 
++static struct humfs *read_superblock(char *root)
++{
++      struct humfs *mount;
++      struct humfs_meta_ops *meta = NULL;
++      struct file_handle *fh;
++      const char *path[] = { root, "superblock", NULL };
++      u64 used, total;
++      char meta_buf[33], line[HOSTFS_BUFSIZE], *newline;
++      unsigned long long pos;
++      int version, i, n, err;
++
++      fh = kmalloc(sizeof(*fh), GFP_KERNEL);
++      if(fh == NULL)
++              return(ERR_PTR(-ENOMEM));
++
++      err = host_open_file(path, 1, 0, fh);
++      if(err){
++              printk("Failed to open %s/%s, errno = %d\n", path[0],
++                     path[1], err);
++              return(ERR_PTR(err));
++      }
++
++      used = 0;
++      total = 0;
++      pos = 0;
++      i = 0;
++      while(1){
++              n = read_file(fh, pos, &line[i], sizeof(line) - i - 1);
++              if((n == 0) && (i == 0))
++                      break;
++              if(n < 0)
++                      return(ERR_PTR(n));
++
++              pos += n;
++              if(n > 0)
++                      line[n + i] = '\0';
++
++              newline = strchr(line, '\n');
++              if(newline == NULL){
++                      printk("read_superblock - line too long : '%s'\n", 
++                             line);
++                      return(ERR_PTR(-EINVAL));
++              }
++              newline++;
++
++              if(sscanf(line, "version %d\n", &version) == 1){
++                      if(version != HUMFS_VERSION){
++                              printk("humfs version mismatch - want version "
++                                     "%d, got version %d.\n", HUMFS_VERSION,
++                                     version);
++                              return(ERR_PTR(-EINVAL));
++                      }
++              }
++              else if(sscanf(line, "used %Lu\n", &used) == 1) ;
++              else if(sscanf(line, "total %Lu\n", &total) == 1) ;
++              else if(sscanf(line, "metadata %32s\n", meta_buf) == 1){
++                      meta = find_meta(meta_buf);
++                      if(meta == NULL){
++                              printk("read_superblock - meta api \"%s\" not "
++                                     "registered\n", meta_buf);
++                              return(ERR_PTR(-EINVAL));
++                      }
++              }
++              
++              else {
++                      printk("read_superblock - bogus line : '%s'\n", line);
++                      return(ERR_PTR(-EINVAL));
++              }
++
++              i = newline - line;
++              memmove(line, newline, sizeof(line) - i);
++              i = strlen(line);
++      }
++
++      if(used == 0){
++              printk("read_superblock - used not specified or set to "
++                     "zero\n");
++              return(ERR_PTR(-EINVAL));
++      }
++      if(total == 0){
++              printk("read_superblock - total not specified or set to "
++                     "zero\n");
++              return(ERR_PTR(-EINVAL));
++      }
++      if(used > total){
++              printk("read_superblock - used is greater than total\n");
++              return(ERR_PTR(-EINVAL));
++      }
++
++      if(meta == NULL){
++              meta = find_meta("shadow_fs");
++      }
++
++      if(meta == NULL){
++              printk("read_superblock - valid meta api was not specified\n");
++              return(ERR_PTR(-EINVAL));
++      }
++
++      mount = (*meta->init_mount)(root);
++      if(IS_ERR(mount))
++              return(mount);
++
++      *mount = ((struct humfs) { .total       = total,
++                                 .used        = used,
++                                 .meta        = meta });
++      return(mount);
++}
++
++struct externfs_file_ops humfs_no_mmap_file_ops = {
++      .stat_file              = humfs_stat_file,
++      .file_type              = humfs_file_type,
++      .access_file            = NULL,
++      .open_file              = humfs_open_file,
++      .open_dir               = humfs_open_dir,
++      .read_dir               = humfs_read_dir,
++      .read_file              = humfs_read_file,
++      .write_file             = humfs_write_file,
++      .map_file_page          = NULL,
++      .close_file             = humfs_close_file,
++      .close_dir              = humfs_close_dir,
++      .invisible              = humfs_invisible,
++      .create_file            = humfs_create_file,
++      .set_attr               = humfs_set_attr,
++      .make_symlink           = humfs_make_symlink,
++      .unlink_file            = humfs_unlink_file,
++      .make_dir               = humfs_make_dir,
++      .remove_dir             = humfs_remove_dir,
++      .make_node              = humfs_make_node,
++      .link_file              = humfs_link_file,
++      .read_link              = humfs_read_link,
++      .rename_file            = humfs_rename_file,
++      .statfs                 = humfs_stat_fs,
++      .truncate_file          = humfs_truncate_file
++};
++
++struct externfs_file_ops humfs_mmap_file_ops = {
++      .stat_file              = humfs_stat_file,
++      .file_type              = humfs_file_type,
++      .access_file            = NULL,
++      .open_file              = humfs_open_file,
++      .open_dir               = humfs_open_dir,
++      .read_dir               = humfs_read_dir,
++      .read_file              = humfs_read_file,
++      .write_file             = humfs_write_file,
++      .map_file_page          = humfs_map_file_page,
++      .close_file             = humfs_close_file,
++      .close_dir              = humfs_close_dir,
++      .invisible              = humfs_invisible,
++      .create_file            = humfs_create_file,
++      .set_attr               = humfs_set_attr,
++      .make_symlink           = humfs_make_symlink,
++      .unlink_file            = humfs_unlink_file,
++      .make_dir               = humfs_make_dir,
++      .remove_dir             = humfs_remove_dir,
++      .make_node              = humfs_make_node,
++      .link_file              = humfs_link_file,
++      .read_link              = humfs_read_link,
++      .rename_file            = humfs_rename_file,
++      .statfs                 = humfs_stat_fs,
++      .truncate_file          = humfs_truncate_file
++};
++
++static struct externfs_data *mount_fs(char *mount_arg)
++{
++      char *root, *data, *flags;
++      struct humfs *mount;
++      struct externfs_file_ops *file_ops;
++      int err, do_mmap = 0;
++
++      if(mount_arg == NULL){
++              printk("humfs - no host directory specified\n");
++              return(NULL);
++      }
++
++      flags = strchr((char *) mount_arg, ',');
++      if(flags != NULL){
++              do {
++                      *flags++ = '\0';
++
++                      if(!strcmp(flags, "mmap"))
++                              do_mmap = 1;
++
++                      flags = strchr(flags, ',');
++              } while(flags != NULL);
++      }
++
++      err = -ENOMEM;
++      root = host_root_filename(mount_arg);
++      if(root == NULL)
++              goto err;
++
++      mount = read_superblock(root);
++      if(IS_ERR(mount)){
++              err = PTR_ERR(mount);
++              goto err_free_root;
++      }
++
++      data = humfs_path(root, "data/");
++      if(data == NULL)
++              goto err_free_mount;
++
++      if(CHOOSE_MODE(do_mmap, 0)){
++              printk("humfs doesn't support mmap in tt mode\n");
++              do_mmap = 0;
++      }
++
++      mount->data = data;
++      mount->mmap = do_mmap;
++
++      file_ops = do_mmap ? &humfs_mmap_file_ops : &humfs_no_mmap_file_ops;
++      init_externfs(&mount->ext, file_ops);
++
++      return(&mount->ext);
++
++ err_free_mount:
++      kfree(mount);
++ err_free_root:
++      kfree(root);
++ err:
++      return(NULL);
++}
++
++struct externfs_mount_ops humfs_mount_ops = {
++      .init_file              = humfs_init_file,
++      .mount                  = mount_fs,
++};
++
++static int __init init_humfs(void)
++{
++      return(register_externfs("humfs", &humfs_mount_ops));
++}
++
++static void __exit exit_humfs(void)
++{
++      unregister_externfs("humfs");
++}
++
++__initcall(init_humfs);
++__exitcall(exit_humfs);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/fs/hostfs/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/fs/hostfs/Makefile       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/fs/hostfs/Makefile    2005-05-03 22:28:14.284438648 +0300
+@@ -0,0 +1,14 @@
++# 
++# Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com)
++# Licensed under the GPL
++#
++
++O_TARGET := hostfs.o
++
++obj-$(CONFIG_EXTERNFS) += externfs.o
++obj-$(CONFIG_HOSTFS) += host_fs.o host_file.o
++obj-$(CONFIG_HUMFS) += humfs.o host_file.o meta_fs.o
++
++obj-m = $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
+Index: linux-2.4.29/arch/um/fs/hostfs/metadata.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/fs/hostfs/metadata.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/fs/hostfs/metadata.h  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,84 @@
++/* 
++ * Copyright (C) 2004 Piotr Neuman (sikkh@wp.pl) and 
++ * Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_FS_METADATA
++#define __UM_FS_METADATA
++
++#include "linux/fs.h"
++#include "linux/list.h"
++#include "os.h"
++#include "hostfs.h"
++#include "filehandle.h"
++
++#define container_of(ptr, type, member) ({                      \
++        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
++        (type *)( (char *)__mptr - offsetof(type,member) );})
++
++struct humfs {
++      struct externfs_data ext;
++      __u64 used;
++      __u64 total;
++      char *data;
++      int mmap;
++      int direct;
++      struct humfs_meta_ops *meta;
++};
++
++struct humfs_file {
++      struct humfs *mount;
++      struct file_handle data;
++      struct externfs_inode ext;
++};
++
++struct humfs_meta_ops {
++      struct list_head list;
++      char *name;
++      struct humfs_file *(*init_file)(void);
++      int (*open_file)(struct humfs_file *hf, const char *path, 
++                       struct inode *inode, struct humfs *humfs);
++      int (*create_file)(struct humfs_file *hf, const char *path, int mode, 
++                         int uid, int gid, struct inode *inode, 
++                         struct humfs *humfs);
++      void (*close_file)(struct humfs_file *humfs);
++      int (*ownerships)(const char *path, int *mode_out, int *uid_out, 
++                        int *gid_out, char *type_out, int *maj_out, 
++                        int *min_out, struct humfs *humfs);
++      int (*make_node)(const char *path, int mode, int uid, int gid,
++                       int type, int major, int minor, struct humfs *humfs);
++      int (*create_link)(const char *to, const char *from, 
++                         struct humfs *humfs);
++      int (*remove_file)(const char *path, struct humfs *humfs);
++      int (*create_dir)(const char *path, int mode, int uid, int gid, 
++                        struct humfs *humfs);
++      int (*remove_dir)(const char *path, struct humfs *humfs);
++      int (*change_ownerships)(const char *path, int mode, int uid, int gid,
++                               struct humfs *humfs);
++      int (*rename_file)(const char *from, const char *to, 
++                         struct humfs *humfs);
++      void (*invisible)(struct humfs_file *hf);
++      struct humfs *(*init_mount)(char *root);
++      void (*free_mount)(struct humfs *humfs);
++};
++
++void register_meta(struct humfs_meta_ops *ops);
++void unregister_meta(struct humfs_meta_ops *ops);
++
++char *humfs_path(char *dir, char *file);
++char *humfs_name(struct inode *inode, char *prefix);
++extern struct humfs *inode_humfs_info(struct inode *inode);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/fs/hostfs/meta_fs.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/fs/hostfs/meta_fs.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/fs/hostfs/meta_fs.c   2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,519 @@
++/* 
++ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/slab.h>
++#include "hostfs.h"
++#include "metadata.h"
++#include "kern_util.h"
++
++#define METADATA_FILE_PATH(meta) (meta)->root, "file_metadata"
++#define METADATA_DIR_PATH(meta) (meta)->root, "dir_metadata"
++
++struct meta_fs {
++      struct humfs humfs;
++      char *root;
++};
++
++struct meta_file {
++      struct humfs_file humfs;
++      struct file_handle fh;
++};
++
++static int meta_file_path(const char *path, struct meta_fs *meta, 
++                        const char *path_out[])
++{
++      const char *data_path[] = { meta->root, "data", path, NULL };
++      char data_tmp[HOSTFS_BUFSIZE];
++      char *data_file = get_path(data_path, data_tmp, sizeof(data_tmp));
++
++      if(data_file == NULL)
++              return(-ENOMEM);
++
++      path_out[0] = meta->root;
++      path_out[2] = path;
++      if(os_file_type(data_file) == OS_TYPE_DIR){
++              path_out[1] = "dir_metadata";
++              path_out[3] = "metadata";
++              path_out[4] = NULL;
++      }
++      else {
++              path_out[1] = "file_metadata";
++              path_out[3] = NULL;
++      }
++
++      return(0);
++}
++
++static int open_meta_file(const char *path, struct humfs *humfs,
++                        struct file_handle *fh)
++{
++      struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
++      const char *meta_path[5];
++      char meta_tmp[HOSTFS_BUFSIZE];
++      char *meta_file;
++      int err;
++
++      err = meta_file_path(path, meta, meta_path);
++      if(err)
++              goto out;
++
++      meta_file = get_path(meta_path, meta_tmp, sizeof(meta_tmp));
++      if(meta_file == NULL)
++              goto out;
++      
++      err = open_filehandle(meta_file, of_rdwr(OPENFLAGS()), 0, fh);
++
++ out:
++      return(err);
++}
++
++static char *meta_fs_name(struct inode *inode)
++{
++      struct humfs *mount = inode->i_sb->u.generic_sbp;
++      struct meta_fs *meta = container_of(mount, struct meta_fs, humfs);
++      const char *metadata_path[5];
++      char tmp[HOSTFS_BUFSIZE], *name, *file;
++
++      if(meta_file_path("", meta, metadata_path))
++              return(NULL);
++
++      file = get_path(metadata_path, tmp, sizeof(tmp));
++      if(file == NULL)
++              return(NULL);
++
++      name = inode_name_prefix(inode, file);
++
++      free_path(file, tmp);
++      return(name);
++}
++
++static void metafs_invisible(struct humfs_file *hf)
++{
++      struct meta_file *mf = container_of(hf, struct meta_file, humfs);
++
++      not_reclaimable(&mf->fh);
++}
++
++static struct humfs_file *metafs_init_file(void)
++{
++      struct meta_file *mf;
++      int err = -ENOMEM;
++
++      mf = kmalloc(sizeof(*mf), GFP_KERNEL);
++      if(mf == NULL)
++              return(ERR_PTR(err));
++
++      return(&mf->humfs);
++}
++
++static int metafs_open_file(struct humfs_file *hf, const char *path, 
++                          struct inode *inode, struct humfs *humfs)
++{
++      struct meta_file *mf = container_of(hf, struct meta_file, humfs);
++      int err;
++
++      err = open_meta_file(path, humfs, &mf->fh);
++      if(err)
++              return(err);
++
++      is_reclaimable(&mf->fh, meta_fs_name, inode);
++
++      return(0);
++}
++
++static void metafs_close_file(struct humfs_file *hf)
++{
++      struct meta_file *meta = container_of(hf, struct meta_file, humfs);
++
++      close_file(&meta->fh);
++      kfree(meta);
++}
++
++static int metafs_create_file(struct humfs_file *hf, const char *path, 
++                            int mode, int uid, int gid, struct inode *inode, 
++                            struct humfs *humfs)
++{
++      struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
++      struct meta_file *mf = container_of(hf, struct meta_file, humfs);
++      char tmp[HOSTFS_BUFSIZE];
++      const char *metadata_path[] = { METADATA_FILE_PATH(meta), path, NULL };
++      char *file = get_path(metadata_path, tmp, sizeof(tmp));
++      char buf[sizeof("mmmm uuuuuuuuuu gggggggggg")];
++      int err = -ENOMEM;
++
++      if(file == NULL)
++              goto out;
++
++      err = open_filehandle(file, of_write(of_create(OPENFLAGS())), 0644, 
++                            &mf->fh);
++      if(err)
++              goto out_free_path;
++
++      if(inode != NULL)
++              is_reclaimable(&mf->fh, meta_fs_name, inode);
++
++      sprintf(buf, "%d %d %d\n", mode  & S_IRWXUGO, uid, gid);
++      err = write_file(&mf->fh, 0, buf, strlen(buf));
++      if(err < 0)
++              goto out_rm;
++
++      free_path(file, tmp);
++      return(0);
++
++ out_rm:
++      close_file(&mf->fh);
++      os_remove_file(file);
++ out_free_path:
++      free_path(file, tmp);
++ out:
++      return(err);
++}
++
++static int metafs_create_link(const char *to, const char *from, 
++                            struct humfs *humfs)
++{
++      struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
++      const char *path_to[] = { METADATA_FILE_PATH(meta), to,  NULL };
++      const char *path_from[] = { METADATA_FILE_PATH(meta), from, NULL };
++
++      return(host_link_file(path_to, path_from));
++}
++
++static int metafs_remove_file(const char *path, struct humfs *humfs)
++{
++      struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
++      char tmp[HOSTFS_BUFSIZE];
++      const char *metadata_path[] = { METADATA_FILE_PATH(meta), path, NULL };
++      char *file = get_path(metadata_path, tmp, sizeof(tmp));
++      int err = -ENOMEM;
++
++      if(file == NULL)
++              goto out;
++
++      err = os_remove_file(file);
++
++ out:
++      free_path(file, tmp);
++      return(err);
++}
++
++static int metafs_create_directory(const char *path, int mode, int uid, 
++                                 int gid, struct humfs *humfs)
++{
++      struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
++      char tmp[HOSTFS_BUFSIZE];
++      const char *dir_path[] = { METADATA_DIR_PATH(meta), path, NULL, NULL };
++      const char *file_path[] = { METADATA_FILE_PATH(meta), path, NULL, 
++                                  NULL };
++      char *file, dir_meta[sizeof("mmmm uuuuuuuuuu gggggggggg\n")];
++      int err, fd;
++
++      err = host_make_dir(dir_path, 0755);
++      if(err)
++              goto out;
++
++      err = host_make_dir(file_path, 0755);
++      if(err)
++              goto out_rm;
++
++      /* This to make the index independent of the number of elements in
++       * METADATA_DIR_PATH().
++       */
++      dir_path[sizeof(dir_path) / sizeof(dir_path[0]) - 2] = "metadata";
++
++      err = -ENOMEM;
++      file = get_path(dir_path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      fd = os_open_file(file, of_create(of_rdwr(OPENFLAGS())), 0644);
++      if(fd < 0){
++              err = fd;
++              goto out_free;
++      }
++
++      sprintf(dir_meta, "%d %d %d\n", mode & S_IRWXUGO, uid, gid);
++      err = os_write_file(fd, dir_meta, strlen(dir_meta));
++      if(err > 0)
++              err = 0;
++
++      os_close_file(fd);
++
++ out_free:
++      free_path(file, tmp);
++ out_rm:
++      host_remove_dir(dir_path);
++ out:
++      return(err);
++}
++
++static int metafs_remove_directory(const char *path, struct humfs *humfs)
++{
++      struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
++      char tmp[HOSTFS_BUFSIZE], *file;
++      const char *dir_path[] = { METADATA_DIR_PATH(meta), path, "metadata", 
++                                 NULL };
++      const char *file_path[] = { METADATA_FILE_PATH(meta), path, NULL };
++      char *slash;
++      int err;
++
++      err = -ENOMEM;
++      file = get_path(dir_path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      err = os_remove_file(file);
++      if(err)
++              goto out_free;
++
++      slash = strrchr(file, '/');
++      if(slash == NULL){
++              printk("remove_shadow_directory failed to find last slash\n");
++              goto out_free;
++      }
++      *slash = '\0';
++      err = os_remove_dir(file);
++      free_path(file, tmp);
++
++      file = get_path(file_path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      err = os_remove_dir(file);
++      if(err)
++              goto out_free;
++
++ out:
++      return(err);
++ out_free:
++      free_path(file, tmp);
++      goto out;
++}
++
++static int metafs_make_node(const char *path, int mode, int uid, int gid, 
++                          int type, int maj, int min, struct humfs *humfs)
++{
++      struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
++      struct file_handle fh;
++      char tmp[HOSTFS_BUFSIZE];
++      const char *metadata_path[] = { METADATA_FILE_PATH(meta), path, NULL };
++      int err;
++      char buf[sizeof("mmmm uuuuuuuuuu gggggggggg x nnn mmm\n")], *file;
++
++      sprintf(buf, "%d %d %d %c %d %d\n", mode & S_IRWXUGO, uid, gid, type, 
++              maj, min);
++
++      err = -ENOMEM;
++      file = get_path(metadata_path, tmp, sizeof(tmp));
++      if(file == NULL)
++              goto out;
++
++      err = open_filehandle(file, 
++                            of_create(of_rdwr(OPENFLAGS())), 0644, &fh);
++      if(err)
++              goto out_free;
++
++      err = write_file(&fh, 0, buf, strlen(buf));
++      if(err > 0)
++              err = 0;
++
++      close_file(&fh);
++
++ out_free:
++      free_path(file, tmp);
++ out:
++      return(err);
++}
++
++static int metafs_ownerships(const char *path, int *mode_out, int *uid_out, 
++                           int *gid_out, char *type_out, int *maj_out, 
++                           int *min_out, struct humfs *humfs)
++{
++      struct file_handle fh;
++      char buf[sizeof("mmmm uuuuuuuuuu gggggggggg x nnn mmm\n")];
++      int err, n, mode, uid, gid, maj, min;
++      char type;
++
++      err = open_meta_file(path, humfs, &fh);
++      if(err)
++              goto out;
++
++      err = os_read_file(fh.fd, buf, sizeof(buf) - 1);
++      if(err < 0)
++              goto out_close;
++
++      buf[err] = '\0';
++      err = 0;
++
++      n = sscanf(buf, "%d %d %d %c %d %d", &mode, &uid, &gid, &type, &maj, 
++                 &min);
++      if(n == 3){
++              maj = -1;
++              min = -1;
++              type = 0;
++              err = 0;
++      }
++      else if(n != 6)
++              err = -EINVAL;
++
++      if(mode_out != NULL)
++              *mode_out = mode;
++      if(uid_out != NULL)
++              *uid_out = uid;
++      if(gid_out != NULL)
++              *gid_out = uid;
++      if(type_out != NULL)
++              *type_out = type;
++      if(maj_out != NULL)
++              *maj_out = maj;
++      if(min_out != NULL)
++              *min_out = min;
++
++ out_close:
++      close_file(&fh);
++ out:
++      return(err);
++}
++
++static int metafs_change_ownerships(const char *path, int mode, int uid, 
++                                  int gid, struct humfs *humfs)
++{
++      struct file_handle fh;
++      char type;
++      char buf[sizeof("mmmm uuuuuuuuuu gggggggggg x nnn mmm\n")];
++      int err = -ENOMEM, old_mode, old_uid, old_gid, n, maj, min;
++
++      err = open_meta_file(path, humfs, &fh);
++      if(err)
++              goto out;
++
++      err = read_file(&fh, 0, buf, sizeof(buf) - 1);
++      if(err < 0)
++              goto out_close;
++
++      buf[err] = '\0';
++
++      n = sscanf(buf, "%d %d %d %c %d %d\n", &old_mode, &old_uid, &old_gid,
++                 &type, &maj, &min);
++      if((n != 3) && (n != 6)){
++              err = -EINVAL;
++              goto out_close;
++      }
++
++      if(mode == -1)
++                mode = old_mode;
++      if(uid == -1)
++              uid = old_uid;
++      if(gid == -1)
++              gid = old_gid;
++
++      if(n == 3)
++              sprintf(buf, "%d %d %d\n", mode & S_IRWXUGO, uid, gid);
++      else
++              sprintf(buf, "%d %d %d %c %d %d\n", mode & S_IRWXUGO, uid, gid,
++                      type, maj, min);
++
++      err = write_file(&fh, 0, buf, strlen(buf));
++      if(err > 0)
++              err = 0;
++
++      err = truncate_file(&fh, strlen(buf));
++
++ out_close:
++      close_file(&fh);
++ out:
++      return(err);
++}
++
++static int metafs_rename_file(const char *from, const char *to, 
++                            struct humfs *humfs)
++{
++      struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
++      const char *metadata_path_from[5], *metadata_path_to[5];
++      int err;
++
++      err = meta_file_path(from, meta, metadata_path_from);
++      if(err)
++              return(err);
++
++      err = meta_file_path(to, meta, metadata_path_to);
++      if(err)
++              return(err);
++
++      return(host_rename_file(metadata_path_from, metadata_path_to));
++}
++
++static struct humfs *metafs_init_mount(char *root)
++{
++      struct meta_fs *meta;
++      int err = -ENOMEM;
++
++      meta = kmalloc(sizeof(*meta), GFP_KERNEL);
++      if(meta == NULL)
++              goto out;
++
++      meta->root = uml_strdup(root);
++      if(meta->root == NULL)
++              goto out_free_meta;
++
++      return(&meta->humfs);
++
++ out_free_meta:
++      kfree(meta);
++ out:
++      return(ERR_PTR(err));
++}
++
++static void metafs_free_mount(struct humfs *humfs)
++{
++      struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
++      
++      kfree(meta);
++}
++
++struct humfs_meta_ops hum_fs_meta_fs_ops = {
++      .list                   = LIST_HEAD_INIT(hum_fs_meta_fs_ops.list),
++      .name                   = "shadow_fs",
++      .init_file              = metafs_init_file,
++      .open_file              = metafs_open_file,
++      .close_file             = metafs_close_file,
++      .ownerships             = metafs_ownerships,
++      .make_node              = metafs_make_node,
++      .create_file            = metafs_create_file,
++      .create_link            = metafs_create_link,
++      .remove_file            = metafs_remove_file,
++      .create_dir             = metafs_create_directory,
++      .remove_dir             = metafs_remove_directory,
++      .change_ownerships      = metafs_change_ownerships,
++      .rename_file            = metafs_rename_file,
++      .invisible              = metafs_invisible,
++      .init_mount             = metafs_init_mount,
++      .free_mount             = metafs_free_mount,
++};
++
++static int __init init_meta_fs(void)
++{
++      register_meta(&hum_fs_meta_fs_ops);
++      return(0);
++}
++
++static void __exit exit_meta_fs(void)
++{
++      unregister_meta(&hum_fs_meta_fs_ops);
++}
++
++__initcall(init_meta_fs);
++__exitcall(exit_meta_fs);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/fs/hppfs/hppfs_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/fs/hppfs/hppfs_kern.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/fs/hppfs/hppfs_kern.c 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,737 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/fs.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/list.h>
++#include <linux/kernel.h>
++#include <linux/ctype.h>
++#include <asm/uaccess.h>
++#include "os.h"
++
++struct hppfs_data {
++      struct list_head list;
++      char contents[PAGE_SIZE - sizeof(struct list_head)];
++};
++
++struct hppfs_private {
++      struct file proc_file;
++      int host_fd;
++      loff_t len;
++      struct hppfs_data *contents;
++};
++
++#define HPPFS_SUPER_MAGIC 0xb00000ee
++
++static struct super_operations hppfs_sbops;
++
++static struct inode *get_inode(struct super_block *sb, struct dentry *dentry,
++                             int *error);
++
++static int is_pid(struct dentry *dentry)
++{
++      struct super_block *sb;
++      int i;
++
++      sb = dentry->d_sb;
++      if((sb->s_op != &hppfs_sbops) || (dentry->d_parent != sb->s_root))
++              return(0);
++
++      for(i = 0; i < dentry->d_name.len; i++){
++              if(!isdigit(dentry->d_name.name[i]))
++                      return(0);
++      }
++      return(1);
++}
++
++static char *dentry_name(struct dentry *dentry, int extra)
++{
++      struct dentry *parent;
++      char *root, *name;
++      const char *seg_name;
++      int len, seg_len;
++
++      len = 0;
++      parent = dentry;
++      while(parent->d_parent != parent){
++              if(is_pid(parent))
++                      len += strlen("pid") + 1;
++              else len += parent->d_name.len + 1;
++              parent = parent->d_parent;
++      }
++      
++      root = "proc";
++      len += strlen(root);
++      name = kmalloc(len + extra + 1, GFP_KERNEL);
++      if(name == NULL) return(NULL);
++
++      name[len] = '\0';
++      parent = dentry;
++      while(parent->d_parent != parent){
++              if(is_pid(parent)){
++                      seg_name = "pid";
++                      seg_len = strlen("pid");
++              }
++              else {
++                      seg_name = parent->d_name.name;
++                      seg_len = parent->d_name.len;
++              }
++
++              len -= seg_len + 1;
++              name[len] = '/';
++              strncpy(&name[len + 1], seg_name, seg_len);
++              parent = parent->d_parent;
++      }
++      strncpy(name, root, strlen(root));
++      return(name);
++}
++
++struct dentry_operations hppfs_dentry_ops = {
++};
++
++static int file_removed(struct dentry *dentry, const char *file)
++{
++      char *host_file;
++      int extra, fd;
++
++      extra = 0;
++      if(file != NULL) extra += strlen(file) + 1;
++
++      host_file = dentry_name(dentry, extra + strlen("/remove"));
++      if(host_file == NULL){
++              printk("file_removed : allocation failed\n");
++              return(-ENOMEM);
++      }
++
++      if(file != NULL){
++              strcat(host_file, "/");
++              strcat(host_file, file);
++      }
++      strcat(host_file, "/remove");
++
++      fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
++      kfree(host_file);
++      if(fd >= 0){
++              os_close_file(fd);
++              return(1);
++      }
++      return(0);
++}
++
++static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry)
++{
++      struct dentry *proc_dentry;
++      struct inode *inode;
++      int err, deleted;
++
++      deleted = file_removed(dentry, NULL);
++      if(deleted < 0)
++              return(ERR_PTR(deleted));
++      else if(deleted)
++              return(ERR_PTR(-ENOENT));
++
++      proc_dentry = lookup_hash(&dentry->d_name, ino->u.hppfs_i.proc_dentry);
++      if(IS_ERR(proc_dentry))
++              return(proc_dentry);
++
++      inode = get_inode(ino->i_sb, proc_dentry, &err);
++      if(err != 0) 
++              return(ERR_PTR(err));
++
++      d_add(dentry, inode);
++      dentry->d_op = &hppfs_dentry_ops;
++      return(NULL);
++}
++
++static struct inode_operations hppfs_file_iops = {
++};
++
++static struct inode_operations hppfs_dir_iops = {
++      .lookup         = hppfs_lookup,
++};
++
++static ssize_t read_proc(struct file *file, char *buf, ssize_t count, 
++                       loff_t *ppos, int is_user)
++{
++      ssize_t (*read)(struct file *, char *, size_t, loff_t *);
++      ssize_t n;
++
++      read = file->f_dentry->d_inode->i_fop->read;
++      if(read == NULL)
++              return(-EOPNOTSUPP);
++
++      if(!is_user)
++              set_fs(KERNEL_DS);
++              
++      n = (*read)(file, buf, count, &file->f_pos);
++
++      if(!is_user)
++              set_fs(USER_DS);
++
++      if(ppos) *ppos = file->f_pos;
++      return(n);
++}
++
++static ssize_t hppfs_read_file(int fd, char *buf, ssize_t count)
++{
++      ssize_t n;
++      int cur, err;
++      char *new_buf;
++
++      n = -ENOMEM;
++      new_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
++      if(new_buf == NULL){
++              printk("hppfs_read_file : kmalloc failed\n");
++              goto out;
++      }
++      n = 0;
++      while(count > 0){
++              cur = min_t(ssize_t, count, PAGE_SIZE);
++              err = os_read_file(fd, new_buf, cur);
++              if(err < 0){
++                      printk("hppfs_read : read failed, err = %d\n", -err);
++                      n = err;
++                      goto out_free;
++              }
++              else if(err == 0)
++                      break;
++
++              if(copy_to_user(buf, new_buf, err)){
++                      n = -EFAULT;
++                      goto out_free;
++              }
++              n += err;
++              count -= err;
++      }
++ out_free:
++      kfree(new_buf);
++ out:
++      return(n);
++}
++
++static ssize_t hppfs_read(struct file *file, char *buf, size_t count, 
++                        loff_t *ppos)
++{
++      struct hppfs_private *hppfs = file->private_data;
++      struct hppfs_data *data;
++      loff_t off;
++      int err;
++
++      if(hppfs->contents != NULL){
++              if(*ppos >= hppfs->len) return(0);
++
++              data = hppfs->contents;
++              off = *ppos;
++              while(off >= sizeof(data->contents)){
++                      data = list_entry(data->list.next, struct hppfs_data,
++                                        list);
++                      off -= sizeof(data->contents);
++              }
++
++              if(off + count > hppfs->len)
++                      count = hppfs->len - off;
++              copy_to_user(buf, &data->contents[off], count);
++              *ppos += count;
++      }
++      else if(hppfs->host_fd != -1){
++              err = os_seek_file(hppfs->host_fd, *ppos);
++              if(err < 0){
++                      printk("hppfs_read : seek failed, err = %d\n", -err);
++                      return(err);
++              }
++              count = hppfs_read_file(hppfs->host_fd, buf, count);
++              if(count > 0)
++                      *ppos += count;
++      }
++      else count = read_proc(&hppfs->proc_file, buf, count, ppos, 1);
++
++      return(count);
++}
++
++static ssize_t hppfs_write(struct file *file, const char *buf, size_t len, 
++                         loff_t *ppos)
++{
++      struct hppfs_private *data = file->private_data;
++      struct file *proc_file = &data->proc_file;
++      ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
++      int err;
++
++      write = proc_file->f_dentry->d_inode->i_fop->write;
++      if(write == NULL)
++              return(-EOPNOTSUPP);
++
++      proc_file->f_pos = file->f_pos;
++      err = (*write)(proc_file, buf, len, &proc_file->f_pos);
++      file->f_pos = proc_file->f_pos;
++
++      return(err);
++}
++
++static int open_host_sock(char *host_file, int *filter_out)
++{
++      char *end;
++      int fd;
++
++      end = &host_file[strlen(host_file)];
++      strcpy(end, "/rw");
++      *filter_out = 1;
++      fd = os_connect_socket(host_file);
++      if(fd >= 0)
++              return(fd);
++
++      strcpy(end, "/r");
++      *filter_out = 0;
++      fd = os_connect_socket(host_file);
++      return(fd);
++}
++
++static void free_contents(struct hppfs_data *head)
++{
++      struct hppfs_data *data;
++      struct list_head *ele, *next;
++
++      if(head == NULL) return;
++
++      list_for_each_safe(ele, next, &head->list){
++              data = list_entry(ele, struct hppfs_data, list);
++              kfree(data);
++      }
++      kfree(head);
++}
++
++static struct hppfs_data *hppfs_get_data(int fd, int filter, 
++                                       struct file *proc_file, 
++                                       struct file *hppfs_file, 
++                                       loff_t *size_out)
++{
++      struct hppfs_data *data, *new, *head;
++      int n, err;
++
++      err = -ENOMEM;
++      data = kmalloc(sizeof(*data), GFP_KERNEL);
++      if(data == NULL){
++              printk("hppfs_get_data : head allocation failed\n");
++              goto failed;
++      }
++
++      INIT_LIST_HEAD(&data->list);
++
++      head = data;
++      *size_out = 0;
++
++      if(filter){
++              while((n = read_proc(proc_file, data->contents,
++                                   sizeof(data->contents), NULL, 0)) > 0) {
++                      err = os_write_file(fd, data->contents, n);
++                      if(err != n)
++                              printk("hppfs_get_data : failed to write out "
++                                     "%d bytes, err = %d\n", n, -err);
++              }
++              err = os_shutdown_socket(fd, 0, 1);
++              if(err < 0){
++                      printk("hppfs_get_data : failed to shut down "
++                             "socket\n");
++                      goto failed_free;
++              }
++      }
++      while(1){
++              n = os_read_file(fd, data->contents, sizeof(data->contents));
++              if(n < 0){
++                      err = n;
++                      printk("hppfs_get_data : read failed, err = %d\n", -n);
++                      goto failed_free;
++              }
++              else if(n == 0)
++                      break;
++
++              *size_out += n;
++
++              if(n < sizeof(data->contents))
++                      break;
++
++              new = kmalloc(sizeof(*data), GFP_KERNEL);
++              if(new == 0){
++                      printk("hppfs_get_data : data allocation failed\n");
++                      err = -ENOMEM;
++                      goto failed_free;
++              }
++      
++              INIT_LIST_HEAD(&new->list);
++              list_add(&new->list, &data->list);
++              data = new;
++      }
++      return(head);
++
++ failed_free:
++      free_contents(head);
++ failed:              
++      return(ERR_PTR(err));
++}
++
++static struct hppfs_private *hppfs_data(void)
++{
++      struct hppfs_private *data;
++
++      data = kmalloc(sizeof(*data), GFP_KERNEL);
++      if(data == NULL)
++              return(data);
++
++      *data = ((struct hppfs_private ) { .host_fd             = -1,
++                                         .len                 = -1,
++                                         .contents            = NULL } );
++      return(data);
++}
++
++static int hppfs_open(struct inode *inode, struct file *file)
++{
++      struct hppfs_private *data;
++      struct dentry *proc_dentry;
++      char *host_file;
++      int err, fd, type, filter;
++
++      err = -ENOMEM;
++      data = hppfs_data();
++      if(data == NULL)
++              goto out;
++
++      host_file = dentry_name(file->f_dentry, strlen("/rw"));
++      if(host_file == NULL)
++              goto out_free2;
++
++      proc_dentry = inode->u.hppfs_i.proc_dentry;
++      err = init_private_file(&data->proc_file, proc_dentry, file->f_mode);
++      if(err)
++              goto out_free1;
++
++      type = os_file_type(host_file);
++      if(type == OS_TYPE_FILE){
++              fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
++              if(fd >= 0) 
++                      data->host_fd = fd;
++              else printk("hppfs_open : failed to open '%s', err = %d\n",
++                          host_file, -fd);
++
++              data->contents = NULL;
++      }
++      else if(type == OS_TYPE_DIR){
++              fd = open_host_sock(host_file, &filter);
++              if(fd >= 0){
++                      data->contents = hppfs_get_data(fd, filter, 
++                                                      &data->proc_file, 
++                                                      file, &data->len);
++                      if(!IS_ERR(data->contents))
++                              data->host_fd = fd;
++              }
++              else printk("hppfs_open : failed to open a socket in "
++                          "'%s', err = %d\n", host_file, -fd);
++      }
++      kfree(host_file);
++
++      file->private_data = data;
++      return(0);
++
++ out_free1:
++      kfree(host_file);
++ out_free2:
++      free_contents(data->contents);
++      kfree(data);
++ out:
++      return(err);
++}
++
++static int hppfs_dir_open(struct inode *inode, struct file *file)
++{
++      struct hppfs_private *data;
++      struct dentry *proc_dentry;
++      int err;
++
++      err = -ENOMEM;
++      data = hppfs_data();
++      if(data == NULL)
++              goto out;
++
++      proc_dentry = inode->u.hppfs_i.proc_dentry;
++      err = init_private_file(&data->proc_file, proc_dentry, file->f_mode);
++      if(err)
++              goto out_free;
++
++      file->private_data = data;
++      return(0);
++
++ out_free:
++      kfree(data);
++ out:
++      return(err);
++}
++
++static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
++{
++      struct hppfs_private *data = file->private_data;
++      struct file *proc_file = &data->proc_file;
++      loff_t (*llseek)(struct file *, loff_t, int);
++      loff_t ret;
++
++      llseek = proc_file->f_dentry->d_inode->i_fop->llseek;
++      if(llseek != NULL){
++              ret = (*llseek)(proc_file, off, where);
++              if(ret < 0)
++                      return(ret);
++      }
++
++      return(default_llseek(file, off, where));
++}
++
++struct hppfs_dirent {
++      void *vfs_dirent;
++      filldir_t filldir;
++      struct dentry *dentry;
++};
++
++static int hppfs_filldir(void *d, const char *name, int size, 
++                       loff_t offset, ino_t inode, unsigned int type)
++{
++      struct hppfs_dirent *dirent = d;
++
++      if(file_removed(dirent->dentry, name))
++              return(0);
++
++      return((*dirent->filldir)(dirent->vfs_dirent, name, size, offset, 
++                                inode, type));
++}
++
++static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
++{
++      struct hppfs_private *data = file->private_data;
++      struct file *proc_file = &data->proc_file;
++      int (*readdir)(struct file *, void *, filldir_t);
++      struct hppfs_dirent dirent = ((struct hppfs_dirent)
++                                    { .vfs_dirent     = ent,
++                                      .filldir        = filldir,
++                                      .dentry         = file->f_dentry } );
++      int err;
++
++      readdir = proc_file->f_dentry->d_inode->i_fop->readdir;
++      if(readdir == NULL)
++              return(-EOPNOTSUPP);
++
++      proc_file->f_pos = file->f_pos;
++      err = (*readdir)(proc_file, &dirent, hppfs_filldir);
++      file->f_pos = proc_file->f_pos;
++
++      return(err);
++}
++
++static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync)
++{
++      return(0);
++}
++
++static struct file_operations hppfs_file_fops = {
++      .owner          = NULL,
++      .llseek         = hppfs_llseek,
++      .read           = hppfs_read,
++      .write          = hppfs_write,
++      .open           = hppfs_open,
++};
++
++static struct file_operations hppfs_dir_fops = {
++      .owner          = NULL,
++      .readdir        = hppfs_readdir,
++      .open           = hppfs_dir_open,
++      .fsync          = hppfs_fsync,
++};
++
++static int hppfs_statfs(struct super_block *sb, struct statfs *sf)
++{
++      sf->f_blocks = 0;
++      sf->f_bfree = 0;
++      sf->f_bavail = 0;
++      sf->f_files = 0;
++      sf->f_ffree = 0;
++      sf->f_type = HPPFS_SUPER_MAGIC;
++      return(0);
++}
++
++static struct super_operations hppfs_sbops = { 
++      .put_inode      = force_delete,
++      .delete_inode   = NULL,
++      .statfs         = hppfs_statfs,
++};
++
++static int hppfs_readlink(struct dentry *dentry, char *buffer, int buflen)
++{
++      struct file proc_file;
++      struct dentry *proc_dentry;
++      int (*readlink)(struct dentry *, char *, int);
++      int err, n;
++
++      proc_dentry = dentry->d_inode->u.hppfs_i.proc_dentry;
++      err = init_private_file(&proc_file, proc_dentry, FMODE_READ);
++      if(err) 
++              return(err);
++
++      readlink = proc_dentry->d_inode->i_op->readlink;
++      if(readlink == NULL)
++              return(-EOPNOTSUPP);
++      n = (*readlink)(proc_dentry, buffer, buflen);
++
++      if(proc_file.f_op->release)
++              (*proc_file.f_op->release)(proc_dentry->d_inode, &proc_file);
++      
++      return(n);
++}
++
++static int hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++      struct file proc_file;
++      struct dentry *proc_dentry;
++      int (*follow_link)(struct dentry *, struct nameidata *);
++      int err, n;
++
++      proc_dentry = dentry->d_inode->u.hppfs_i.proc_dentry;
++      err = init_private_file(&proc_file, proc_dentry, FMODE_READ);
++      if(err) 
++              return(err);
++
++      follow_link = proc_dentry->d_inode->i_op->follow_link;
++      if(follow_link == NULL)
++              return(-EOPNOTSUPP);
++      n = (*follow_link)(proc_dentry, nd);
++
++      if(proc_file.f_op->release)
++              (*proc_file.f_op->release)(proc_dentry->d_inode, &proc_file);
++      
++      return(n);
++}
++
++static struct inode_operations hppfs_link_iops = {
++      .readlink       = hppfs_readlink,
++      .follow_link    = hppfs_follow_link,
++};
++
++static void read_inode(struct inode *ino)
++{
++      struct inode *proc_ino;
++
++      proc_ino = ino->u.hppfs_i.proc_dentry->d_inode;
++      ino->i_uid = proc_ino->i_uid;
++      ino->i_gid = proc_ino->i_gid;
++      ino->i_atime = proc_ino->i_atime;
++      ino->i_mtime = proc_ino->i_mtime;
++      ino->i_ctime = proc_ino->i_ctime;
++      ino->i_ino = proc_ino->i_ino;
++      ino->i_dev = proc_ino->i_dev;
++      ino->i_mode = proc_ino->i_mode;
++      ino->i_nlink = proc_ino->i_nlink;
++      ino->i_size = proc_ino->i_size;
++      ino->i_blksize = proc_ino->i_blksize;
++      ino->i_blocks = proc_ino->i_blocks;
++}
++
++static struct inode *get_inode(struct super_block *sb, struct dentry *dentry,
++                             int *error)
++{
++      struct inode *inode;
++      int err = -ENOMEM;
++
++      inode = new_inode(sb);
++      if(inode == NULL) 
++              goto out;
++
++      insert_inode_hash(inode);
++      if(S_ISDIR(dentry->d_inode->i_mode)){
++              inode->i_op = &hppfs_dir_iops;
++              inode->i_fop = &hppfs_dir_fops;
++      }
++      else if(S_ISLNK(dentry->d_inode->i_mode)){
++              inode->i_op = &hppfs_link_iops;
++              inode->i_fop = &hppfs_file_fops;
++      }
++      else {
++              inode->i_op = &hppfs_file_iops;
++              inode->i_fop = &hppfs_file_fops;
++      }
++
++      inode->i_sb = sb;
++      inode->u.hppfs_i.proc_dentry = dentry;
++
++      read_inode(inode);
++      err = 0;
++
++      if(error) *error = err;
++      return(inode);
++ out:
++      if(error) *error = err;
++      return(NULL);
++}
++
++static struct super_block *hppfs_read_super(struct super_block *sb, void *d, 
++                                          int silent)
++{
++      struct inode *root_inode;
++      struct file_system_type *procfs;
++      struct super_block *proc_sb;
++
++      procfs = get_fs_type("proc");
++      if(procfs == NULL) 
++              goto out;
++
++      if(list_empty(&procfs->fs_supers))
++              goto out;
++
++      proc_sb = list_entry(procfs->fs_supers.next, struct super_block,
++                           s_instances);
++      
++      sb->s_blocksize = 1024;
++      sb->s_blocksize_bits = 10;
++      sb->s_magic = HPPFS_SUPER_MAGIC;
++      sb->s_op = &hppfs_sbops;
++
++      dget(proc_sb->s_root);
++      root_inode = get_inode(sb, proc_sb->s_root, NULL);
++      if(root_inode == NULL)
++              goto out_dput;
++
++      sb->s_root = d_alloc_root(root_inode);
++      if(sb->s_root == NULL)
++              goto out_put;
++
++      return(sb);
++
++ out_put:
++      iput(root_inode);
++ out_dput:
++      dput(proc_sb->s_root);
++ out:
++      return(NULL);
++}
++
++DECLARE_FSTYPE(hppfs_type, "hppfs", hppfs_read_super, 0);
++
++static int __init init_hppfs(void)
++{
++      return(register_filesystem(&hppfs_type));
++}
++
++static void __exit exit_hppfs(void)
++{
++      unregister_filesystem(&hppfs_type);
++}
++
++module_init(init_hppfs)
++module_exit(exit_hppfs)
++MODULE_LICENSE("GPL");
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/fs/hppfs/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/fs/hppfs/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/fs/hppfs/Makefile     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,10 @@
++O_TARGET := hppfs.o
++obj-y = hppfs_kern.o #hppfs_user.o
++obj-m = $(O_TARGET)
++
++CFLAGS_hppfs_kern.o := $(CFLAGS)
++#CFLAGS_hppfs_user.o := $(USER_CFLAGS)
++
++override CFLAGS =  
++
++include $(TOPDIR)/Rules.make
+Index: linux-2.4.29/arch/um/fs/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/fs/Makefile      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/fs/Makefile   2005-05-03 22:28:14.291437584 +0300
+@@ -0,0 +1,23 @@
++# 
++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET := built-in.o
++
++subdir-y =
++subdir-m =
++
++subdir-$(CONFIG_HOSTFS) += hostfs
++subdir-$(CONFIG_HPPFS) += hppfs
++
++obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
++obj-m += $(join $(subdir-m),$(subdir-m:%=/%.o))
++
++include $(TOPDIR)/Rules.make
++
++dep:
++
++clean:
++
++archmrproper:
+Index: linux-2.4.29/arch/um/include/2_5compat.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/2_5compat.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/2_5compat.h   2005-05-03 22:28:14.292437432 +0300
+@@ -0,0 +1,33 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __2_5_COMPAT_H__
++#define __2_5_COMPAT_H__
++
++#include "linux/version.h"
++
++#define INIT_ELV(queue, elv) elevator_init(elv, ELV_NOOP)
++
++#define ELV_NOOP ELEVATOR_NOOP
++
++#define INIT_HARDSECT(arr, maj, sizes) arr[maj] = sizes
++
++#define IS_WRITE(req) ((req)->cmd == WRITE)
++
++#define SET_PRI(task) \
++      do { (task)->nice = 20; (task)->counter = -100; } while(0);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/aio.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/aio.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/aio.h 2005-05-03 22:28:14.293437280 +0300
+@@ -0,0 +1,36 @@
++/* 
++ * Copyright (C) 2004 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef AIO_H__
++#define AIO_H__
++
++enum aio_type { AIO_READ, AIO_WRITE, AIO_MMAP };
++
++struct aio_thread_reply {
++      void *data;
++      int err;
++};
++
++struct aio_context {
++      int reply_fd;
++};
++
++#define INIT_AIO_CONTEXT { .reply_fd  = -1 }
++
++extern int submit_aio(enum aio_type type, int fd, char *buf, int len, 
++                    unsigned long long offset, int reply_fd, void *data);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/chan_kern.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/chan_kern.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/chan_kern.h   2005-05-03 22:28:14.294437128 +0300
+@@ -0,0 +1,56 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __CHAN_KERN_H__
++#define __CHAN_KERN_H__
++
++#include "linux/tty.h"
++#include "linux/list.h"
++#include "chan_user.h"
++
++struct chan {
++      struct list_head list;
++      char *dev;
++      unsigned int primary:1;
++      unsigned int input:1;
++      unsigned int output:1;
++      unsigned int opened:1;
++      int fd;
++      enum chan_init_pri pri;
++      struct chan_ops *ops;
++      void *data;
++};
++
++extern void chan_interrupt(struct list_head *chans, struct tq_struct *task,
++                         struct tty_struct *tty, int irq, void *dev);
++extern int parse_chan_pair(char *str, struct list_head *chans, int pri, 
++                         int device, struct chan_opts *opts);
++extern int open_chan(struct list_head *chans);
++extern int write_chan(struct list_head *chans, const char *buf, int len,
++                           int write_irq);
++extern int console_write_chan(struct list_head *chans, const char *buf, 
++                            int len);
++extern void close_chan(struct list_head *chans);
++extern void chan_enable_winch(struct list_head *chans, void *line);
++extern void enable_chan(struct list_head *chans, void *data);
++extern int chan_window_size(struct list_head *chans, 
++                           unsigned short *rows_out, 
++                           unsigned short *cols_out);
++extern int chan_out_fd(struct list_head *chans);
++extern int chan_config_string(struct list_head *chans, char *str, int size,
++                            char **error_out);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/chan_user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/chan_user.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/chan_user.h   2005-05-03 22:28:14.295436976 +0300
+@@ -0,0 +1,66 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __CHAN_USER_H__
++#define __CHAN_USER_H__
++
++#include "init.h"
++
++struct chan_opts {
++      void (*announce)(char *dev_name, int dev);
++      char *xterm_title;
++      int raw;
++      unsigned long tramp_stack;
++      int in_kernel;
++};
++
++enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
++
++struct chan_ops {
++      char *type;
++      void *(*init)(char *, int, struct chan_opts *);
++      int (*open)(int, int, int, void *, char **);
++      void (*close)(int, void *);
++      int (*read)(int, char *, void *);
++      int (*write)(int, const char *, int, void *);
++      int (*console_write)(int, const char *, int, void *);
++      int (*window_size)(int, void *, unsigned short *, unsigned short *);
++      void (*free)(void *);
++      int winch;
++};
++
++extern struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops,
++      xterm_ops;
++
++extern void generic_close(int fd, void *unused);
++extern int generic_read(int fd, char *c_out, void *unused);
++extern int generic_write(int fd, const char *buf, int n, void *unused);
++extern int generic_console_write(int fd, const char *buf, int n, void *state);
++extern int generic_window_size(int fd, void *unused, unsigned short *rows_out,
++                             unsigned short *cols_out);
++extern void generic_free(void *data);
++
++extern void register_winch(int fd, void *device_data);
++extern void register_winch_irq(int fd, int tty_fd, int pid, void *line);
++
++#define __channel_help(fn, prefix) \
++__uml_help(fn, prefix "[0-9]*=<channel description>\n" \
++"    Attach a console or serial line to a host channel.  See\n" \
++"    http://user-mode-linux.sourceforge.net/input.html for a complete\n" \
++"    description of this switch.\n\n" \
++);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/choose-mode.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/choose-mode.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/choose-mode.h 2005-05-03 22:28:14.295436976 +0300
+@@ -0,0 +1,35 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __CHOOSE_MODE_H__
++#define __CHOOSE_MODE_H__
++
++#include "uml-config.h"
++
++#if defined(UML_CONFIG_MODE_TT) && defined(UML_CONFIG_MODE_SKAS)
++#define CHOOSE_MODE(tt, skas) (mode_tt ? (tt) : (skas))
++
++#elif defined(UML_CONFIG_MODE_SKAS)
++#define CHOOSE_MODE(tt, skas) (skas)
++
++#elif defined(UML_CONFIG_MODE_TT)
++#define CHOOSE_MODE(tt, skas) (tt)
++#endif
++
++#define CHOOSE_MODE_PROC(tt, skas, args...) \
++      CHOOSE_MODE(tt(args), skas(args))
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/filehandle.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/filehandle.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/filehandle.h  2005-05-03 22:28:14.296436824 +0300
+@@ -0,0 +1,51 @@
++/* 
++ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FILEHANDLE_H__
++#define __FILEHANDLE_H__
++
++#include "linux/list.h"
++#include "linux/fs.h"
++#include "os.h"
++
++struct file_handle {
++      struct list_head list;
++      int fd;
++      char *(*get_name)(struct inode *);
++      struct inode *inode;
++      struct openflags flags;
++};
++
++extern struct file_handle bad_filehandle;
++
++extern int open_file(char *name, struct openflags flags, int mode);
++extern void *open_dir(char *file);
++extern int open_filehandle(char *name, struct openflags flags, int mode, 
++                         struct file_handle *fh);
++extern int read_file(struct file_handle *fh, unsigned long long offset, 
++                   char *buf, int len);
++extern int write_file(struct file_handle *fh, unsigned long long offset, 
++                    const char *buf, int len);
++extern int truncate_file(struct file_handle *fh, unsigned long long size);
++extern int close_file(struct file_handle *fh);
++extern void not_reclaimable(struct file_handle *fh);
++extern void is_reclaimable(struct file_handle *fh, 
++                         char *(name_proc)(struct inode *),
++                         struct inode *inode);
++extern int filehandle_fd(struct file_handle *fh);
++extern int make_pipe(struct file_handle *fhs);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/frame.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/frame.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/frame.h       2005-05-03 22:28:14.297436672 +0300
+@@ -0,0 +1,53 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FRAME_H_
++#define __FRAME_H_
++
++#include "sysdep/frame.h"
++
++struct frame_common {
++      void *data;
++      int len;
++      int sig_index;
++      int sr_index;
++      int sr_relative;
++      int sp_index;
++      struct arch_frame_data arch;
++};
++
++struct sc_frame {
++      struct frame_common common;
++      int sc_index;
++};
++
++extern struct sc_frame signal_frame_sc;
++
++extern struct sc_frame signal_frame_sc_sr;
++
++struct si_frame {
++      struct frame_common common;
++      int sip_index;
++      int si_index;
++      int ucp_index;
++      int uc_index;
++};
++
++extern struct si_frame signal_frame_si;
++
++extern void capture_signal_stack(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/frame_kern.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/frame_kern.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/frame_kern.h  2005-05-03 22:28:14.298436520 +0300
+@@ -0,0 +1,34 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FRAME_KERN_H_
++#define __FRAME_KERN_H_
++
++#include "frame.h"
++#include "sysdep/frame_kern.h"
++
++extern int setup_signal_stack_sc(unsigned long stack_top, int sig, 
++                               unsigned long handler,
++                               void (*restorer)(void), 
++                               struct pt_regs *regs, 
++                               sigset_t *mask);
++extern int setup_signal_stack_si(unsigned long stack_top, int sig, 
++                               unsigned long handler, 
++                               void (*restorer)(void), 
++                               struct pt_regs *regs, siginfo_t *info, 
++                               sigset_t *mask);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/frame_user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/frame_user.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/frame_user.h  2005-05-03 22:28:14.299436368 +0300
+@@ -0,0 +1,23 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FRAME_USER_H_
++#define __FRAME_USER_H_
++
++#include "sysdep/frame_user.h"
++#include "frame.h"
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/helper.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/helper.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/helper.h      2005-05-03 22:28:14.300436216 +0300
+@@ -0,0 +1,27 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __HELPER_H__
++#define __HELPER_H__
++
++extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
++                    unsigned long *stack_out);
++extern int run_helper_thread(int (*proc)(void *), void *arg, 
++                           unsigned int flags, unsigned long *stack_out,
++                           int stack_order);
++extern int helper_wait(int pid);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/init.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/init.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/init.h        2005-05-03 22:28:14.301436064 +0300
+@@ -0,0 +1,124 @@
++#ifndef _LINUX_UML_INIT_H
++#define _LINUX_UML_INIT_H
++
++/* These macros are used to mark some functions or
++ * initialized data (doesn't apply to uninitialized data)
++ * as `initialization' functions. The kernel can take this
++ * as hint that the function is used only during the initialization
++ * phase and free up used memory resources after
++ *
++ * Usage:
++ * For functions:
++ *
++ * You should add __init immediately before the function name, like:
++ *
++ * static void __init initme(int x, int y)
++ * {
++ *    extern int z; z = x * y;
++ * }
++ *
++ * If the function has a prototype somewhere, you can also add
++ * __init between closing brace of the prototype and semicolon:
++ *
++ * extern int initialize_foobar_device(int, int, int) __init;
++ *
++ * For initialized data:
++ * You should insert __initdata between the variable name and equal
++ * sign followed by value, e.g.:
++ *
++ * static int init_variable __initdata = 0;
++ * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
++ *
++ * Don't forget to initialize data not at file scope, i.e. within a function,
++ * as gcc otherwise puts the data into the bss section and not into the init
++ * section.
++ *
++ * Also note, that this data cannot be "const".
++ */
++
++#ifndef _LINUX_INIT_H
++typedef int (*initcall_t)(void);
++typedef void (*exitcall_t)(void);
++
++#define __init          __attribute__ ((__section__ (".text.init")))
++#define __exit          __attribute__ ((unused, __section__(".text.exit")))
++#define __initdata      __attribute__ ((__section__ (".data.init")))
++
++#endif
++
++#ifndef MODULE
++struct uml_param {
++        const char *str;
++        int (*setup_func)(char *, int *);
++};
++
++extern initcall_t __uml_initcall_start, __uml_initcall_end;
++extern initcall_t __uml_postsetup_start, __uml_postsetup_end;
++extern const char *__uml_help_start, *__uml_help_end;
++#endif
++
++#define __uml_initcall(fn)                                            \
++      static initcall_t __uml_initcall_##fn __uml_init_call = fn
++
++#define __uml_exitcall(fn)                                            \
++      static exitcall_t __uml_exitcall_##fn __uml_exit_call = fn
++
++extern struct uml_param __uml_setup_start, __uml_setup_end;
++
++#define __uml_postsetup(fn)                                           \
++      static initcall_t __uml_postsetup_##fn __uml_postsetup_call = fn
++
++#define __non_empty_string(dummyname,string)                          \
++      struct __uml_non_empty_string_struct_##dummyname                \
++      {                                                               \
++              char _string[sizeof(string)-2];                         \
++      }
++
++#ifndef MODULE
++#define __uml_setup(str, fn, help...)                                 \
++      __non_empty_string(fn ##_setup, str);                           \
++      __uml_help(fn, help);                                           \
++      static char __uml_setup_str_##fn[] __initdata = str;            \
++      static struct uml_param __uml_setup_##fn __uml_init_setup = { __uml_setup_str_##fn, fn }
++#else
++#define __uml_setup(str, fn, help...)                                 \
++
++#endif
++
++#define __uml_help(fn, help...)                                               \
++      __non_empty_string(fn ##__help, help);                          \
++      static char __uml_help_str_##fn[] __initdata = help;            \
++      static const char *__uml_help_##fn __uml_setup_help = __uml_help_str_##fn
++
++/*
++ * Mark functions and data as being only used at initialization
++ * or exit time.
++ */
++#define __uml_init_setup      __attribute__ ((unused,__section__ (".uml.setup.init")))
++#define __uml_setup_help      __attribute__ ((unused,__section__ (".uml.help.init")))
++#define __uml_init_call               __attribute__ ((unused,__section__ (".uml.initcall.init")))
++#define __uml_postsetup_call  __attribute__ ((unused,__section__ (".uml.postsetup.init")))
++#define __uml_exit_call               __attribute__ ((unused,__section__ (".uml.exitcall.exit")))
++
++#ifndef __KERNEL__
++
++#define __initcall(fn) static initcall_t __initcall_##fn __init_call = fn
++#define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn
++
++#define __init_call __attribute__ ((unused,__section__ (".initcall.init")))
++#define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit")))
++
++#endif
++
++#endif /* _LINUX_UML_INIT_H */
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/initrd.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/initrd.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/initrd.h      2005-05-03 22:28:14.301436064 +0300
+@@ -0,0 +1,22 @@
++/*
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __INITRD_USER_H__
++#define __INITRD_USER_H__
++
++extern int load_initrd(char *filename, void *buf, int size);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/irq_kern.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/irq_kern.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/irq_kern.h    2005-05-03 22:28:14.303435760 +0300
+@@ -0,0 +1,27 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __IRQ_KERN_H__
++#define __IRQ_KERN_H__
++
++#include "linux/interrupt.h"
++
++extern int um_request_irq(unsigned int irq, int fd, int type,
++                        void (*handler)(int, void *, struct pt_regs *),
++                        unsigned long irqflags,  const char * devname,
++                        void *dev_id);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/irq_user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/irq_user.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/irq_user.h    2005-05-03 22:28:14.304435608 +0300
+@@ -0,0 +1,36 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __IRQ_USER_H__
++#define __IRQ_USER_H__
++
++enum { IRQ_READ, IRQ_WRITE };
++
++extern void sigio_handler(int sig, union uml_pt_regs *regs);
++extern int activate_fd(int irq, int fd, int type, void *dev_id);
++extern void free_irq_by_irq_and_dev(int irq, void *dev_id);
++extern void free_irq_by_fd(int fd);
++extern void reactivate_fd(int fd, int irqnum);
++extern void deactivate_fd(int fd, int irqnum);
++extern int deactivate_all_fds(void);
++extern void forward_interrupts(int pid);
++extern void init_irq_signals(int on_sigstack);
++extern void forward_ipi(int fd, int pid);
++extern void free_irq_later(int irq, void *dev_id);
++extern int activate_ipi(int fd, int pid);
++extern unsigned long irq_lock(void);
++extern void irq_unlock(unsigned long flags);
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/kern.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/kern.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/kern.h        2005-05-03 22:28:14.304435608 +0300
+@@ -0,0 +1,48 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __KERN_H__
++#define __KERN_H__
++
++/* These are all user-mode things which are convenient to call directly
++ * from kernel code and for which writing a wrapper is too much of a pain.
++ * The regular include files can't be included because this file is included
++ * only into kernel code, and user-space includes conflict with kernel
++ * includes.
++ */
++
++extern int errno;
++
++extern int clone(int (*proc)(void *), void *sp, int flags, void *data);
++extern int sleep(int);
++extern int printf(char *fmt, ...);
++extern char *strerror(int errnum);
++extern char *ptsname(int __fd);
++extern int munmap(void *, int);
++extern void *sbrk(int increment);
++extern void *malloc(int size);
++extern void perror(char *err);
++extern int kill(int pid, int sig);
++extern int getuid(void);
++extern int pause(void);
++extern int write(int, const void *, int);
++extern int exit(int);
++extern int close(int);
++extern int read(unsigned int, char *, int);
++extern int pipe(int *);
++extern int sched_yield(void);
++extern int ptrace(int op, int pid, long addr, long data);
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/kern_util.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/kern_util.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/kern_util.h   2005-05-03 22:28:14.306435304 +0300
+@@ -0,0 +1,123 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __KERN_UTIL_H__
++#define __KERN_UTIL_H__
++
++#include "sysdep/ptrace.h"
++
++extern int ncpus;
++extern char *linux_prog;
++extern char *gdb_init;
++extern int kmalloc_ok;
++extern int timer_irq_inited;
++extern int jail;
++extern int nsyscalls;
++
++#define UML_ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK))
++#define UML_ROUND_UP(addr) \
++      UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
++
++extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg);
++extern unsigned long stack_sp(unsigned long page);
++extern int kernel_thread_proc(void *data);
++extern void syscall_segv(int sig);
++extern int current_pid(void);
++extern unsigned long alloc_stack(int order, int atomic);
++extern int do_signal(int error);
++extern int is_stack_fault(unsigned long sp);
++extern unsigned long segv(unsigned long address, unsigned long ip, 
++                        int is_write, int is_user, void *sc);
++extern unsigned long handle_page_fault(unsigned long address, unsigned long ip,
++                                     int is_write, int is_user, 
++                                     int *code_out);
++extern void syscall_ready(void);
++extern int segv_syscall(void);
++extern void kern_finish_exec(void *task, int new_pid, unsigned long stack);
++extern int page_size(void);
++extern int page_mask(void);
++extern int need_finish_fork(void);
++extern void free_stack(unsigned long stack, int order);
++extern void add_input_request(int op, void (*proc)(int), void *arg);
++extern int sys_execve(char *file, char **argv, char **env);
++extern char *current_cmd(void);
++extern void timer_handler(int sig, union uml_pt_regs *regs);
++extern int set_signals(int enable);
++extern void force_sigbus(void);
++extern int pid_to_processor_id(int pid);
++extern void block_signals(void);
++extern void unblock_signals(void);
++extern void deliver_signals(void *t);
++extern int next_syscall_index(int max);
++extern int next_trap_index(int max);
++extern void cpu_idle(void);
++extern void finish_fork(void);
++extern void paging_init(void);
++extern void init_flush_vm(void);
++extern void *syscall_sp(void *t);
++extern void syscall_trace(void);
++extern int hz(void);
++extern void idle_timer(void);
++extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs);
++extern int external_pid(void *t);
++extern void boot_timer_handler(int sig);
++extern void interrupt_end(void);
++extern void initial_thread_cb(void (*proc)(void *), void *arg);
++extern int debugger_signal(int status, int pid);
++extern void debugger_parent_signal(int status, int pid);
++extern void child_signal(int pid, int status);
++extern int init_ptrace_proxy(int idle_pid, int startup, int stop);
++extern int init_parent_proxy(int pid);
++extern void check_stack_overflow(void *ptr);
++extern void relay_signal(int sig, union uml_pt_regs *regs);
++extern void not_implemented(void);
++extern int user_context(unsigned long sp);
++extern void timer_irq(union uml_pt_regs *regs);
++extern void unprotect_stack(unsigned long stack);
++extern void do_uml_exitcalls(void);
++extern int attach_debugger(int idle_pid, int pid, int stop);
++extern void bad_segv(unsigned long address, unsigned long ip, int is_write);
++extern int config_gdb(char *str);
++extern int remove_gdb(void);
++extern char *uml_strdup(char *string);
++extern void unprotect_kernel_mem(void);
++extern void protect_kernel_mem(void);
++extern void set_kmem_end(unsigned long);
++extern void uml_cleanup(void);
++extern void set_current(void *t);
++extern void lock_signalled_task(void *t);
++extern void IPI_handler(int cpu);
++extern int jail_setup(char *line, int *add);
++extern void *get_init_task(void);
++extern int clear_user_proc(void *buf, int size);
++extern int copy_to_user_proc(void *to, void *from, int size);
++extern int copy_from_user_proc(void *to, void *from, int size);
++extern int strlen_user_proc(char *str);
++extern void bus_handler(int sig, union uml_pt_regs *regs);
++extern void winch(int sig, union uml_pt_regs *regs);
++extern long execute_syscall(void *r);
++extern int smp_sigio_handler(void);
++extern void *get_current(void);
++extern struct task_struct *get_task(int pid, int require);
++extern void machine_halt(void);
++extern int is_syscall(unsigned long addr);
++extern void arch_switch(void);
++extern void free_irq(unsigned int, void *);
++extern int um_in_interrupt(void);
++extern int cpu(void);
++extern unsigned long long time_stamp(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/line.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/line.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/line.h        2005-05-03 22:28:14.307435152 +0300
+@@ -0,0 +1,103 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __LINE_H__
++#define __LINE_H__
++
++#include "linux/list.h"
++#include "linux/tqueue.h"
++#include "linux/tty.h"
++#include "asm/semaphore.h"
++#include "chan_user.h"
++#include "mconsole_kern.h"
++
++struct line_driver {
++      char *name;
++      char *devfs_name;
++      short major;
++      short minor_start;
++      short type;
++      short subtype;
++      int read_irq;
++      char *read_irq_name;
++      int write_irq;
++      char *write_irq_name;
++      char *symlink_from;
++      char *symlink_to;
++      struct mc_device mc;
++};
++
++struct line {
++      char *init_str;
++      int init_pri;
++      struct list_head chan_list;
++      int valid;
++      int count;
++      struct tty_struct *tty;
++      struct semaphore sem;
++      char *buffer;
++      char *head;
++      char *tail;
++      int sigio;
++      struct tq_struct task;
++      struct line_driver *driver;
++      int have_irq;
++};
++
++#define LINE_INIT(str, d) \
++      { init_str :    str, \
++        init_pri :    INIT_STATIC, \
++        chan_list :   { }, \
++        valid :       1, \
++        count :       0, \
++        tty :         NULL, \
++        sem :         { }, \
++        buffer :      NULL, \
++        head :        NULL, \
++        tail :        NULL, \
++        sigio :       0, \
++        driver :      d, \
++          have_irq :  0 }
++
++struct lines {
++      int num;
++};
++
++#define LINES_INIT(n) {  num :                n }
++
++extern void line_close(struct line *lines, struct tty_struct *tty);
++extern int line_open(struct line *lines, struct tty_struct *tty, 
++                   struct chan_opts *opts);
++extern int line_setup(struct line *lines, int num, char *init, 
++                    int all_allowed);
++extern int line_write(struct line *line, struct tty_struct *tty, int from_user,
++                    const char *buf, int len);
++extern char *add_xterm_umid(char *base);
++extern int line_setup_irq(int fd, int input, int output, void *data);
++extern void line_close_chan(struct line *line);
++extern void line_disable(struct line *line, int current_irq);
++extern void line_register_devfs(struct lines *set, 
++                              struct line_driver *line_driver, 
++                              struct tty_driver *driver, struct line *lines,
++                              int nlines);
++extern void lines_init(struct line *lines, int nlines);
++extern void close_lines(struct line *lines, int nlines);
++extern int line_config(struct line *lines, int num, char *str);
++extern int line_remove(struct line *lines, int num, char *str);
++extern int line_get_config(char *dev, struct line *lines, int num, char *str, 
++                         int size, char **error_out);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/Makefile 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/Makefile      2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,7 @@
++all : sc.h
++
++sc.h : ../util/mk_sc
++      ../util/mk_sc > $@
++
++../util/mk_sc :
++      $(MAKE) -C ../util mk_sc
+Index: linux-2.4.29/arch/um/include/mconsole.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/mconsole.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/mconsole.h    2005-05-03 22:28:14.309434848 +0300
+@@ -0,0 +1,103 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MCONSOLE_H__
++#define __MCONSOLE_H__
++
++#ifndef __KERNEL__
++#include <stdint.h>
++#define u32 uint32_t
++#endif
++
++#define MCONSOLE_MAGIC (0xcafebabe)
++#define MCONSOLE_MAX_DATA (512)
++#define MCONSOLE_VERSION 2
++
++struct mconsole_request {
++      u32 magic;
++      u32 version;
++      u32 len;
++      char data[MCONSOLE_MAX_DATA];
++};
++
++struct mconsole_reply {
++      u32 err;
++      u32 more;
++      u32 len;
++      char data[MCONSOLE_MAX_DATA];
++};
++
++struct mconsole_notify {
++      u32 magic;
++      u32 version;    
++      enum { MCONSOLE_SOCKET, MCONSOLE_PANIC, MCONSOLE_HANG,
++             MCONSOLE_USER_NOTIFY } type;
++      u32 len;
++      char data[MCONSOLE_MAX_DATA];
++};
++
++struct mc_request;
++
++enum mc_context { MCONSOLE_INTR, MCONSOLE_PROC };
++
++struct mconsole_command
++{
++      char *command;
++      void (*handler)(struct mc_request *req);
++      enum mc_context context;
++};
++
++struct mc_request
++{
++      int len;
++      int as_interrupt;
++
++      int originating_fd;
++      int originlen;
++      unsigned char origin[128];                      /* sockaddr_un */
++
++      struct mconsole_request request;
++      struct mconsole_command *cmd;
++};
++
++extern char mconsole_socket_name[];
++
++extern int mconsole_unlink_socket(void);
++extern int mconsole_reply(struct mc_request *req, char *reply, int err,
++                        int more);
++
++extern void mconsole_version(struct mc_request *req);
++extern void mconsole_help(struct mc_request *req);
++extern void mconsole_halt(struct mc_request *req);
++extern void mconsole_reboot(struct mc_request *req);
++extern void mconsole_config(struct mc_request *req);
++extern void mconsole_remove(struct mc_request *req);
++extern void mconsole_sysrq(struct mc_request *req);
++extern void mconsole_cad(struct mc_request *req);
++extern void mconsole_stop(struct mc_request *req);
++extern void mconsole_go(struct mc_request *req);
++extern void mconsole_log(struct mc_request *req);
++extern void mconsole_proc(struct mc_request *req);
++
++extern int mconsole_get_request(int fd, struct mc_request *req);
++extern int mconsole_notify(char *sock_name, int type, const void *data, 
++                         int len);
++extern char *mconsole_notify_socket(void);
++extern void lock_notify(void);
++extern void unlock_notify(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/mconsole_kern.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/mconsole_kern.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/mconsole_kern.h       2005-05-03 22:28:14.310434696 +0300
+@@ -0,0 +1,62 @@
++/*
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MCONSOLE_KERN_H__
++#define __MCONSOLE_KERN_H__
++
++#include "linux/config.h"
++#include "linux/list.h"
++#include "mconsole.h"
++
++struct mconsole_entry {
++      struct list_head list;
++      struct mc_request request;
++};
++
++struct mc_device {
++      struct list_head list;
++      char *name;
++      int (*config)(char *);
++      int (*get_config)(char *, char *, int, char **);
++      int (*remove)(char *);
++};
++
++#define CONFIG_CHUNK(str, size, current, chunk, end) \
++do { \
++      current += strlen(chunk); \
++      if(current >= size) \
++              str = NULL; \
++      if(str != NULL){ \
++              strcpy(str, chunk); \
++              str += strlen(chunk); \
++      } \
++      if(end) \
++              current++; \
++} while(0)
++
++#ifdef CONFIG_MCONSOLE
++
++extern void mconsole_register_dev(struct mc_device *new);
++
++#else
++
++static inline void mconsole_register_dev(struct mc_device *new)
++{
++}
++
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/mem.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/mem.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/mem.h 2005-05-03 22:28:14.310434696 +0300
+@@ -0,0 +1,29 @@
++/* 
++ * Copyright (C) 2002, 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MEM_H__
++#define __MEM_H__
++
++#include "linux/types.h"
++
++extern void set_kmem_end(unsigned long new);
++extern int phys_mapping(unsigned long phys, __u64 *offset_out);
++extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w);
++extern int is_remapped(const void *virt, int fd, __u64 offset);
++extern int physmem_remove_mapping(void *virt);
++extern void physmem_forget_descriptor(int fd);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/mem_kern.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/mem_kern.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/mem_kern.h    2005-05-03 22:28:14.311434544 +0300
+@@ -0,0 +1,30 @@
++/* 
++ * Copyright (C) 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MEM_KERN_H__
++#define __MEM_KERN_H__
++
++#include "linux/list.h"
++#include "linux/types.h"
++
++struct remapper {
++      struct list_head list;
++      int (*proc)(int, unsigned long, int, __u64, int);
++};
++
++extern void register_remapper(struct remapper *info);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/mem_user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/mem_user.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/mem_user.h    2005-05-03 22:28:14.313434240 +0300
+@@ -0,0 +1,82 @@
++/*
++ * arch/um/include/mem_user.h
++ *
++ * BRIEF MODULE DESCRIPTION
++ * user side memory interface for support IO memory inside user mode linux
++ *
++ * Copyright (C) 2001 RidgeRun, Inc.
++ * Author: RidgeRun, Inc.
++ *         Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
++ *
++ *  This program is free software; you can redistribute  it and/or modify it
++ *  under  the terms of  the GNU General  Public License as published by the
++ *  Free Software Foundation;  either version 2 of the  License, or (at your
++ *  option) any later version.
++ *
++ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
++ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
++ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
++ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
++ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
++ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
++ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ *  You should have received a copy of the  GNU General Public License along
++ *  with this program; if not, write  to the Free Software Foundation, Inc.,
++ *  675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef _MEM_USER_H
++#define _MEM_USER_H
++
++struct iomem_region {
++      struct iomem_region *next;
++      char *driver;
++      int fd;
++      int size;
++      unsigned long phys;
++      unsigned long virt;
++};
++
++extern struct iomem_region *iomem_regions;
++extern int iomem_size;
++
++#define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1))
++
++extern unsigned long host_task_size;
++extern unsigned long task_size;
++
++extern int init_mem_user(void);
++extern int create_mem_file(unsigned long len);
++extern void setup_memory(void *entry);
++extern unsigned long find_iomem(char *driver, unsigned long *len_out);
++extern int init_maps(unsigned long physmem, unsigned long iomem, 
++                   unsigned long highmem);
++extern unsigned long get_vm(unsigned long len);
++extern void setup_physmem(unsigned long start, unsigned long usable,
++                        unsigned long len, unsigned long highmem);
++extern void add_iomem(char *name, int fd, unsigned long size);
++extern unsigned long phys_offset(unsigned long phys);
++extern void unmap_physmem(void);
++extern void map_memory(unsigned long virt, unsigned long phys, 
++                     unsigned long len, int r, int w, int x);
++extern int protect_memory(unsigned long addr, unsigned long len, 
++                        int r, int w, int x, int must_succeed);
++extern unsigned long get_kmem_end(void);
++extern void check_tmpexec(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/mode.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/mode.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/mode.h        2005-05-03 22:28:14.313434240 +0300
+@@ -0,0 +1,30 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MODE_H__
++#define __MODE_H__
++
++#include "uml-config.h"
++
++#ifdef UML_CONFIG_MODE_TT
++#include "../kernel/tt/include/mode.h"
++#endif
++
++#ifdef UML_CONFIG_MODE_SKAS
++#include "../kernel/skas/include/mode.h"
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/mode_kern.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/mode_kern.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/mode_kern.h   2005-05-03 22:28:14.314434088 +0300
+@@ -0,0 +1,30 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MODE_KERN_H__
++#define __MODE_KERN_H__
++
++#include "linux/config.h"
++
++#ifdef CONFIG_MODE_TT
++#include "../kernel/tt/include/mode_kern.h"
++#endif
++
++#ifdef CONFIG_MODE_SKAS
++#include "../kernel/skas/include/mode_kern.h"
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/net_kern.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/net_kern.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/net_kern.h    2005-05-03 22:28:14.315433936 +0300
+@@ -0,0 +1,81 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_NET_KERN_H
++#define __UM_NET_KERN_H
++
++#include "linux/netdevice.h"
++#include "linux/skbuff.h"
++#include "linux/socket.h"
++#include "linux/list.h"
++
++struct uml_net {
++      struct list_head list;
++      struct net_device *dev;
++      int index;
++      unsigned char mac[ETH_ALEN];
++      int have_mac;
++};
++
++struct uml_net_private {
++      struct list_head list;
++      spinlock_t lock;
++      struct net_device *dev;
++      struct timer_list tl;
++      struct net_device_stats stats;
++      int fd;
++      unsigned char mac[ETH_ALEN];
++      int have_mac;
++      unsigned short (*protocol)(struct sk_buff *);
++      int (*open)(void *);
++      void (*close)(int, void *);
++      void (*remove)(void *);
++      int (*read)(int, struct sk_buff **skb, struct uml_net_private *);
++      int (*write)(int, struct sk_buff **skb, struct uml_net_private *);
++      
++      void (*add_address)(unsigned char *, unsigned char *, void *);
++      void (*delete_address)(unsigned char *, unsigned char *, void *);
++      int (*set_mtu)(int mtu, void *);
++      int user[1];
++};
++
++struct net_kern_info {
++      void (*init)(struct net_device *, void *);
++      unsigned short (*protocol)(struct sk_buff *);
++      int (*read)(int, struct sk_buff **skb, struct uml_net_private *);
++      int (*write)(int, struct sk_buff **skb, struct uml_net_private *);
++};
++
++struct transport {
++      struct list_head list;
++      char *name;
++      int (*setup)(char *, char **, void *);
++      struct net_user_info *user;
++      struct net_kern_info *kern;
++      int private_size;
++      int setup_size;
++};
++
++extern struct net_device *ether_init(int);
++extern unsigned short ether_protocol(struct sk_buff *);
++extern int setup_etheraddr(char *str, unsigned char *addr);
++extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra);
++extern int tap_setup_common(char *str, char *type, char **dev_name, 
++                          char **mac_out, char **gate_addr);
++extern void register_transport(struct transport *new);
++extern unsigned short eth_protocol(struct sk_buff *skb);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/net_user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/net_user.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/net_user.h    2005-05-03 22:28:14.316433784 +0300
+@@ -0,0 +1,66 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_NET_USER_H__
++#define __UM_NET_USER_H__
++
++#define ETH_ADDR_LEN (6)
++#define ETH_HEADER_ETHERTAP (16)
++#define ETH_HEADER_OTHER (14)
++#define ETH_MAX_PACKET (1500)
++
++#define UML_NET_VERSION (4)
++
++struct net_user_info {
++      void (*init)(void *, void *);
++      int (*open)(void *);
++      void (*close)(int, void *);
++      void (*remove)(void *);
++      int (*set_mtu)(int mtu, void *);
++      void (*add_address)(unsigned char *, unsigned char *, void *);
++      void (*delete_address)(unsigned char *, unsigned char *, void *);
++      int max_packet;
++};
++
++extern void ether_user_init(void *data, void *dev);
++extern void dev_ip_addr(void *d, char *buf, char *bin_buf);
++extern void set_ether_mac(void *d, unsigned char *addr);
++extern void iter_addresses(void *d, void (*cb)(unsigned char *, 
++                                             unsigned char *, void *), 
++                         void *arg);
++
++extern void *get_output_buffer(int *len_out);
++extern void free_output_buffer(void *buffer);
++
++extern int tap_open_common(void *dev, char *gate_addr);
++extern void tap_check_ips(char *gate_addr, char *eth_addr);
++
++extern void read_output(int fd, char *output_out, int len);
++
++extern int net_read(int fd, void *buf, int len);
++extern int net_recvfrom(int fd, void *buf, int len);
++extern int net_write(int fd, void *buf, int len);
++extern int net_send(int fd, void *buf, int len);
++extern int net_sendto(int fd, void *buf, int len, void *to, int sock_len);
++
++extern void open_addr(unsigned char *addr, unsigned char *netmask, void *arg);
++extern void close_addr(unsigned char *addr, unsigned char *netmask, void *arg);
++
++extern char *split_if_spec(char *str, ...);
++
++extern int dev_netmask(void *d, void *m);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/os.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/os.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/os.h  2005-05-03 22:28:14.318433480 +0300
+@@ -0,0 +1,221 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __OS_H__
++#define __OS_H__
++
++#include "asm/types.h"
++#include "../os/include/file.h"
++
++#define OS_TYPE_FILE 1 
++#define OS_TYPE_DIR 2 
++#define OS_TYPE_SYMLINK 3 
++#define OS_TYPE_CHARDEV 4
++#define OS_TYPE_BLOCKDEV 5
++#define OS_TYPE_FIFO 6
++#define OS_TYPE_SOCK 7
++
++/* os_access() flags */
++#define OS_ACC_F_OK    0       /* Test for existence.  */
++#define OS_ACC_X_OK    1       /* Test for execute permission.  */
++#define OS_ACC_W_OK    2       /* Test for write permission.  */
++#define OS_ACC_R_OK    4       /* Test for read permission.  */
++#define OS_ACC_RW_OK   (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */
++
++/*
++ * types taken from stat_file() in hostfs_user.c
++ * (if they are wrong here, they are wrong there...).
++ */
++struct uml_stat {
++      int                ust_major;      /* device */
++      int                ust_minor;
++      unsigned long long ust_ino;        /* inode */
++      int                ust_mode;       /* protection */
++      int                ust_nlink;      /* number of hard links */
++      int                ust_uid;        /* user ID of owner */
++      int                ust_gid;        /* group ID of owner */
++      unsigned long long ust_size;       /* total size, in bytes */
++      int                ust_blksize;    /* blocksize for filesystem I/O */
++      unsigned long long ust_blocks;     /* number of blocks allocated */
++      unsigned long      ust_atime;      /* time of last access */
++      unsigned long      ust_mtime;      /* time of last modification */
++      unsigned long      ust_ctime;      /* time of last change */
++      int                ust_rmajor;
++      int                ust_rminor;
++};
++
++struct openflags {
++      unsigned int r : 1;
++      unsigned int w : 1;
++      unsigned int s : 1;     /* O_SYNC */
++      unsigned int c : 1;     /* O_CREAT */
++      unsigned int t : 1;     /* O_TRUNC */
++      unsigned int a : 1;     /* O_APPEND */
++      unsigned int e : 1;     /* O_EXCL */
++      unsigned int cl : 1;    /* FD_CLOEXEC */
++      unsigned int d : 1;     /* O_DIRECT */
++};
++
++#define OPENFLAGS() ((struct openflags) { .r = 0, .w = 0, .s = 0, .c = 0, \
++                                        .t = 0, .a = 0, .e = 0, .cl = 0, \
++                                        .d = 0 })
++
++static inline struct openflags of_read(struct openflags flags)
++{
++      flags.r = 1; 
++      return(flags);
++}
++
++static inline struct openflags of_write(struct openflags flags)
++{
++      flags.w = 1; 
++      return(flags); 
++}
++
++static inline struct openflags of_rdwr(struct openflags flags)
++{
++      return(of_read(of_write(flags)));
++}
++
++static inline struct openflags of_set_rw(struct openflags flags, int r, int w)
++{
++      flags.r = r;
++      flags.w = w;
++      return(flags);
++}
++
++static inline struct openflags of_sync(struct openflags flags)
++{ 
++      flags.s = 1; 
++      return(flags); 
++}
++
++static inline struct openflags of_create(struct openflags flags)
++{ 
++      flags.c = 1; 
++      return(flags); 
++}
++ 
++static inline struct openflags of_trunc(struct openflags flags)
++{ 
++      flags.t = 1; 
++      return(flags); 
++}
++ 
++static inline struct openflags of_append(struct openflags flags)
++{ 
++      flags.a = 1; 
++      return(flags); 
++}
++ 
++static inline struct openflags of_excl(struct openflags flags)
++{ 
++      flags.e = 1; 
++      return(flags); 
++}
++
++static inline struct openflags of_cloexec(struct openflags flags)
++{ 
++      flags.cl = 1; 
++      return(flags); 
++}
++ 
++static inline struct openflags of_direct(struct openflags flags)
++{ 
++      flags.d = 1; 
++      return(flags); 
++}
++ 
++extern int os_stat_file(const char *file_name, struct uml_stat *buf);
++extern int os_lstat_file(const char *file_name, struct uml_stat *ubuf);
++extern int os_stat_fd(const int fd, struct uml_stat *buf);
++extern int os_access(const char *file, int mode);
++extern int os_set_file_time(const char *file, unsigned long access, 
++                          unsigned long mod);
++extern int os_set_file_perms(const char *file, int mode);
++extern int os_set_file_owner(const char *file, int owner, int group);
++extern void os_print_error(int error, const char* str);
++extern int os_get_exec_close(int fd, int *close_on_exec);
++extern int os_set_exec_close(int fd, int close_on_exec);
++extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg);
++extern int os_window_size(int fd, int *rows, int *cols);
++extern int os_new_tty_pgrp(int fd, int pid);
++extern int os_get_ifname(int fd, char *namebuf);
++extern int os_set_slip(int fd);
++extern int os_set_owner(int fd, int pid);
++extern int os_sigio_async(int master, int slave);
++extern int os_mode_fd(int fd, int mode);
++
++extern int os_seek_file(int fd, __u64 offset);
++extern int os_open_file(char *file, struct openflags flags, int mode);
++extern void *os_open_dir(char *dir, int *err_out);
++extern int os_seek_dir(void *stream, unsigned long long pos);
++extern int os_read_dir(void *stream, unsigned long long *ino_out, 
++                     char **name_out);
++extern int os_tell_dir(void *stream);
++extern int os_close_dir(void *stream);
++extern int os_remove_file(const char *file);
++extern int os_move_file(const char *from, const char *to);
++extern int os_truncate_file(const char *file, unsigned long long len);
++extern int os_truncate_fd(int fd, unsigned long long len);
++extern int os_read_file(int fd, void *buf, int len);
++extern int os_write_file(int fd, const void *buf, int count);
++extern int os_file_size(char *file, long long *size_out);
++extern int os_fd_size(int fd, long long *size_out);
++extern int os_file_modtime(char *file, unsigned long *modtime);
++extern int os_pipe(int *fd, int stream, int close_on_exec);
++extern int os_set_fd_async(int fd, int owner);
++extern int os_clear_fd_async(int fd);
++extern int os_set_fd_block(int fd, int blocking);
++extern int os_accept_connection(int fd);
++extern int os_create_unix_socket(char *file, int len, int close_on_exec);
++extern int os_make_symlink(const char *to, const char *from);
++extern int os_read_symlink(const char *file, char *buf, int size);
++extern int os_link_file(const char *to, const char *from);
++extern int os_make_dir(const char *dir, int mode);
++extern int os_remove_dir(const char *dir);
++extern int os_make_dev(const char *name, int mode, int major, int minor);
++extern int os_shutdown_socket(int fd, int r, int w);
++extern void os_close_file(int fd);
++extern int os_rcv_fd(int fd, int *helper_pid_out);
++extern int create_unix_socket(char *file, int len, int close_on_exec);
++extern int os_connect_socket(char *name);
++extern int os_file_type(char *file);
++extern int os_file_mode(char *file, struct openflags *mode_out);
++extern int os_lock_file(int fd, int excl);
++
++extern unsigned long os_process_pc(int pid);
++extern int os_process_parent(int pid);
++extern void os_stop_process(int pid);
++extern void os_kill_process(int pid, int reap_child);
++extern void os_usr1_process(int pid);
++extern int os_getpid(void);
++
++extern int os_map_memory(void *virt, int fd, unsigned long long off, 
++                       unsigned long len, int r, int w, int x);
++extern int os_protect_memory(void *addr, unsigned long len, 
++                           int r, int w, int x);
++extern int os_unmap_memory(void *addr, int len);
++extern void os_flush_stdout(void);
++extern int os_stat_filesystem(char *path, long *bsize_out, 
++                            long long *blocks_out, long long *bfree_out,
++                            long long *bavail_out, long long *files_out,
++                            long long *ffree_out, void *fsid_out, 
++                            int fsid_size, long *namelen_out, 
++                            long *spare_out);
++extern unsigned long long os_usecs(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/process.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/process.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/process.h     2005-05-03 22:28:14.319433328 +0300
+@@ -0,0 +1,25 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROCESS_H__
++#define __PROCESS_H__
++
++#include <asm/sigcontext.h>
++
++extern void sig_handler(int sig, struct sigcontext sc);
++extern void alarm_handler(int sig, struct sigcontext sc);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/ptrace_user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/ptrace_user.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/ptrace_user.h 2005-05-03 22:28:14.319433328 +0300
+@@ -0,0 +1,25 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PTRACE_USER_H__
++#define __PTRACE_USER_H__
++
++#include "sysdep/ptrace_user.h"
++
++/* syscall emulation path in ptrace */
++#ifndef PTRACE_SYSEMU
++#define PTRACE_SYSEMU 31
++#endif
++
++extern int use_sysemu;
++
++extern int ptrace_getregs(long pid, unsigned long *regs_out);
++extern int ptrace_setregs(long pid, unsigned long *regs_in);
++extern int ptrace_getfpregs(long pid, unsigned long *regs_out);
++extern void arch_enter_kernel(void *task, int pid);
++extern void arch_leave_kernel(void *task, int pid);
++extern void ptrace_pokeuser(unsigned long addr, unsigned long data);
++
++#endif
+Index: linux-2.4.29/arch/um/include/sigcontext.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sigcontext.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sigcontext.h  2005-05-03 22:28:14.320433176 +0300
+@@ -0,0 +1,25 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UML_SIGCONTEXT_H__
++#define __UML_SIGCONTEXT_H__
++
++#include "sysdep/sigcontext.h"
++
++extern int sc_size(void *data);
++extern void sc_to_sc(void *to_ptr, void *from_ptr);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sigio.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sigio.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sigio.h       2005-05-03 22:28:14.321433024 +0300
+@@ -0,0 +1,28 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SIGIO_H__
++#define __SIGIO_H__
++
++extern int write_sigio_irq(int fd);
++extern int register_sigio_fd(int fd);
++extern int read_sigio_fd(int fd);
++extern int add_sigio_fd(int fd, int read);
++extern int ignore_sigio_fd(int fd);
++extern void sigio_lock(void);
++extern void sigio_unlock(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/signal_kern.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/signal_kern.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/signal_kern.h 2005-05-03 22:28:14.322432872 +0300
+@@ -0,0 +1,22 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SIGNAL_KERN_H__
++#define __SIGNAL_KERN_H__
++
++extern int have_signals(void *t);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/signal_user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/signal_user.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/signal_user.h 2005-05-03 22:28:14.323432720 +0300
+@@ -0,0 +1,26 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SIGNAL_USER_H__
++#define __SIGNAL_USER_H__
++
++extern int signal_stack_size;
++
++extern int change_sig(int signal, int on);
++extern void set_sigstack(void *stack, int size);
++extern void set_handler(int sig, void (*handler)(int), int flags, ...);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/skas_ptrace.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/skas_ptrace.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/skas_ptrace.h 2005-05-03 22:28:14.323432720 +0300
+@@ -0,0 +1,36 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SKAS_PTRACE_H
++#define __SKAS_PTRACE_H
++
++struct ptrace_faultinfo {
++      int is_write;
++      unsigned long addr;
++};
++
++struct ptrace_ldt {
++      int func;
++      void *ptr;
++      unsigned long bytecount;
++};
++
++#define PTRACE_FAULTINFO 52
++#define PTRACE_SIGPENDING 53
++#define PTRACE_LDT 54
++#define PTRACE_SWITCH_MM 55
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/syscall_user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/syscall_user.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/syscall_user.h        2005-05-03 22:28:14.324432568 +0300
+@@ -0,0 +1,23 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSCALL_USER_H
++#define __SYSCALL_USER_H
++
++extern int record_syscall_start(int syscall);
++extern void record_syscall_end(int index, int result);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysdep-i386/checksum.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-i386/checksum.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-i386/checksum.h        2005-05-03 22:28:14.326432264 +0300
+@@ -0,0 +1,218 @@
++/* 
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_SYSDEP_CHECKSUM_H
++#define __UM_SYSDEP_CHECKSUM_H
++
++#include "linux/string.h"
++#include "asm/uaccess.h"
++
++/*
++ * computes the checksum of a memory block at buff, length len,
++ * and adds in "sum" (32-bit)
++ *
++ * returns a 32-bit number suitable for feeding into itself
++ * or csum_tcpudp_magic
++ *
++ * this function must be called with even lengths, except
++ * for the last fragment, which may be odd
++ *
++ * it's best to have buff aligned on a 32-bit boundary
++ */
++unsigned int csum_partial(const unsigned char * buff, int len, 
++                        unsigned int sum);
++
++/*
++ * the same as csum_partial, but copies from src while it
++ * checksums, and handles user-space pointer exceptions correctly, when needed.
++ *
++ * here even more important to align src and dst on a 32-bit (or even
++ * better 64-bit) boundary
++ */
++
++unsigned int csum_partial_copy_to(const char *src, char *dst, int len, 
++                                int sum, int *err_ptr);
++unsigned int csum_partial_copy_from(const char *src, char *dst, int len, 
++                                  int sum, int *err_ptr);
++
++/*
++ *    Note: when you get a NULL pointer exception here this means someone
++ *    passed in an incorrect kernel address to one of these functions.
++ *
++ *    If you use these functions directly please don't forget the
++ *    verify_area().
++ */
++
++static __inline__
++unsigned int csum_partial_copy_nocheck(const char *src, char *dst,
++                                     int len, int sum)
++{
++      memcpy(dst, src, len);
++      return(csum_partial(dst, len, sum));
++}
++
++static __inline__
++unsigned int csum_partial_copy_from_user(const char *src, char *dst,
++                                       int len, int sum, int *err_ptr)
++{
++      return csum_partial_copy_from(src, dst, len, sum, err_ptr);
++}
++
++/*
++ * These are the old (and unsafe) way of doing checksums, a warning message 
++ * will be printed if they are used and an exception occurs.
++ *
++ * these functions should go away after some time.
++ */
++
++#define csum_partial_copy_fromuser csum_partial_copy_from_user
++unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
++
++/*
++ *    This is a version of ip_compute_csum() optimized for IP headers,
++ *    which always checksum on 4 octet boundaries.
++ *
++ *    By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
++ *    Arnt Gulbrandsen.
++ */
++static inline unsigned short ip_fast_csum(unsigned char * iph,
++                                        unsigned int ihl)
++{
++      unsigned int sum;
++
++      __asm__ __volatile__(
++          "movl (%1), %0      ;\n"
++          "subl $4, %2        ;\n"
++          "jbe 2f             ;\n"
++          "addl 4(%1), %0     ;\n"
++          "adcl 8(%1), %0     ;\n"
++          "adcl 12(%1), %0    ;\n"
++"1:       adcl 16(%1), %0     ;\n"
++          "lea 4(%1), %1      ;\n"
++          "decl %2            ;\n"
++          "jne 1b             ;\n"
++          "adcl $0, %0        ;\n"
++          "movl %0, %2        ;\n"
++          "shrl $16, %0       ;\n"
++          "addw %w2, %w0      ;\n"
++          "adcl $0, %0        ;\n"
++          "notl %0            ;\n"
++"2:                           ;\n"
++      /* Since the input registers which are loaded with iph and ipl
++         are modified, we must also specify them as outputs, or gcc
++         will assume they contain their original values. */
++      : "=r" (sum), "=r" (iph), "=r" (ihl)
++      : "1" (iph), "2" (ihl));
++      return(sum);
++}
++
++/*
++ *    Fold a partial checksum
++ */
++
++static inline unsigned int csum_fold(unsigned int sum)
++{
++      __asm__(
++              "addl %1, %0            ;\n"
++              "adcl $0xffff, %0       ;\n"
++              : "=r" (sum)
++              : "r" (sum << 16), "0" (sum & 0xffff0000)
++      );
++      return (~sum) >> 16;
++}
++
++static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
++                                                 unsigned long daddr,
++                                                 unsigned short len,
++                                                 unsigned short proto,
++                                                 unsigned int sum)
++{
++    __asm__(
++      "addl %1, %0    ;\n"
++      "adcl %2, %0    ;\n"
++      "adcl %3, %0    ;\n"
++      "adcl $0, %0    ;\n"
++      : "=r" (sum)
++      : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum));
++    return sum;
++}
++
++/*
++ * computes the checksum of the TCP/UDP pseudo-header
++ * returns a 16-bit checksum, already complemented
++ */
++static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
++                                                 unsigned long daddr,
++                                                 unsigned short len,
++                                                 unsigned short proto,
++                                                 unsigned int sum)
++{
++      return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
++}
++
++/*
++ * this routine is used for miscellaneous IP-like checksums, mainly
++ * in icmp.c
++ */
++
++static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
++{
++    return csum_fold (csum_partial(buff, len, 0));
++}
++
++#define _HAVE_ARCH_IPV6_CSUM
++static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
++                                                   struct in6_addr *daddr,
++                                                   __u32 len,
++                                                   unsigned short proto,
++                                                   unsigned int sum)
++{
++      __asm__(
++              "addl 0(%1), %0         ;\n"
++              "adcl 4(%1), %0         ;\n"
++              "adcl 8(%1), %0         ;\n"
++              "adcl 12(%1), %0        ;\n"
++              "adcl 0(%2), %0         ;\n"
++              "adcl 4(%2), %0         ;\n"
++              "adcl 8(%2), %0         ;\n"
++              "adcl 12(%2), %0        ;\n"
++              "adcl %3, %0            ;\n"
++              "adcl %4, %0            ;\n"
++              "adcl $0, %0            ;\n"
++              : "=&r" (sum)
++              : "r" (saddr), "r" (daddr),
++                "r"(htonl(len)), "r"(htonl(proto)), "0"(sum));
++
++      return csum_fold(sum);
++}
++
++/*
++ *    Copy and checksum to user
++ */
++#define HAVE_CSUM_COPY_USER
++static __inline__ unsigned int csum_and_copy_to_user(const char *src, 
++                                                   char *dst, int len,
++                                                   int sum, int *err_ptr)
++{
++      if (access_ok(VERIFY_WRITE, dst, len))
++              return(csum_partial_copy_to(src, dst, len, sum, err_ptr));
++
++      if (len)
++              *err_ptr = -EFAULT;
++
++      return -1; /* invalid checksum */
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysdep-i386/frame.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-i386/frame.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-i386/frame.h   2005-05-03 22:28:14.351428464 +0300
+@@ -0,0 +1,29 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FRAME_I386_H
++#define __FRAME_I386_H
++
++struct arch_frame_data_raw {
++      unsigned long fp_start;
++      unsigned long sr;
++};
++
++struct arch_frame_data {
++      int fpstate_size;
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysdep-i386/frame_kern.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-i386/frame_kern.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-i386/frame_kern.h      2005-05-03 22:28:14.352428312 +0300
+@@ -0,0 +1,69 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FRAME_KERN_I386_H
++#define __FRAME_KERN_I386_H
++
++/* This is called from sys_sigreturn.  It takes the sp at the point of the
++ * sigreturn system call and returns the address of the sigcontext struct
++ * on the stack.
++ */
++
++static inline void *sp_to_sc(unsigned long sp)
++{
++      return((void *) sp);
++}
++
++static inline void *sp_to_uc(unsigned long sp)
++{
++      unsigned long uc;
++
++      uc = sp + signal_frame_si.uc_index - 
++              signal_frame_si.common.sp_index - 4;
++      return((void *) uc);
++}
++
++static inline void *sp_to_rt_sc(unsigned long sp)
++{
++      unsigned long sc;
++
++      sc = sp - signal_frame_si.common.sp_index + 
++              signal_frame_si.common.len - 4;
++      return((void *) sc);
++}
++
++static inline void *sp_to_mask(unsigned long sp)
++{
++      unsigned long mask;
++
++      mask = sp - signal_frame_sc.common.sp_index + 
++              signal_frame_sc.common.len - 8;
++      return((void *) mask);
++}
++
++extern int sc_size(void *data);
++
++static inline void *sp_to_rt_mask(unsigned long sp)
++{
++      unsigned long mask;
++
++      mask = sp - signal_frame_si.common.sp_index + 
++              signal_frame_si.common.len + 
++              sc_size(&signal_frame_si.common.arch) - 4;
++      return((void *) mask);
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysdep-i386/frame_user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-i386/frame_user.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-i386/frame_user.h      2005-05-03 22:28:14.353428160 +0300
+@@ -0,0 +1,91 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __FRAME_USER_I386_H
++#define __FRAME_USER_I386_H
++
++#include <asm/page.h>
++#include "sysdep/frame.h"
++
++/* This stuff is to calculate the size of the fp state struct at runtime
++ * because it has changed between 2.2 and 2.4 and it would be good for a
++ * UML compiled on one to work on the other.
++ * So, setup_arch_frame_raw fills in the arch struct with the raw data, which
++ * just contains the address of the end of the sigcontext.  This is invoked
++ * from the signal handler.
++ * setup_arch_frame uses that data to figure out what 
++ * arch_frame_data.fpstate_size should be.  It really has no idea, since it's
++ * not allowed to do sizeof(struct fpstate) but it's safe to consider that it's
++ * everything from the end of the sigcontext up to the top of the stack.  So,
++ * it masks off the page number to get the offset within the page and subtracts
++ * that from the page size, and that's how big the fpstate struct will be
++ * considered to be.
++ */
++
++static inline void setup_arch_frame_raw(struct arch_frame_data_raw *data,
++                                      void *end, unsigned long srp)
++{
++      unsigned long sr = *((unsigned long *) srp);
++
++      data->fp_start = (unsigned long) end;
++      if((sr & PAGE_MASK) == ((unsigned long) end & PAGE_MASK))
++              data->sr = sr;
++      else data->sr = 0;
++}
++
++static inline void setup_arch_frame(struct arch_frame_data_raw *in, 
++                                  struct arch_frame_data *out)
++{
++      unsigned long fpstate_start = in->fp_start;
++
++      if(in->sr == 0){
++              fpstate_start &= ~PAGE_MASK;
++              out->fpstate_size = PAGE_SIZE - fpstate_start;
++      }
++      else {
++              out->fpstate_size = in->sr - fpstate_start;
++      }
++}
++
++/* This figures out where on the stack the SA_RESTORER function address
++ * is stored.  For i386, it's the signal handler return address, so it's
++ * located next to the frame pointer.
++ * This is inlined, so __builtin_frame_address(0) is correct.  Otherwise,
++ * it would have to be __builtin_frame_address(1).
++ */
++
++#define frame_restorer() \
++({ \
++      unsigned long *fp; \
++\
++      fp = __builtin_frame_address(0); \
++      ((unsigned long) (fp + 1)); \
++})
++
++/* Similarly, this returns the value of sp when the handler was first
++ * entered.  This is used to calculate the proper sp when delivering
++ * signals.
++ */
++
++#define frame_sp() \
++({ \
++      unsigned long *fp; \
++\
++      fp = __builtin_frame_address(0); \
++      ((unsigned long) (fp + 1)); \
++})
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysdep-i386/ptrace.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-i386/ptrace.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-i386/ptrace.h  2005-05-03 22:28:14.355427856 +0300
+@@ -0,0 +1,193 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSDEP_I386_PTRACE_H
++#define __SYSDEP_I386_PTRACE_H
++
++#include "uml-config.h"
++
++#ifdef UML_CONFIG_MODE_TT
++#include "ptrace-tt.h"
++#endif
++
++#ifdef UML_CONFIG_MODE_SKAS
++#include "ptrace-skas.h"
++#endif
++
++#include "choose-mode.h"
++
++union uml_pt_regs {
++#ifdef UML_CONFIG_MODE_TT
++      struct tt_regs {
++              long syscall;
++              void *sc;
++      } tt;
++#endif
++#ifdef UML_CONFIG_MODE_SKAS
++      struct skas_regs {
++              unsigned long regs[HOST_FRAME_SIZE];
++              unsigned long fp[HOST_FP_SIZE];
++              unsigned long xfp[HOST_XFP_SIZE];
++              unsigned long fault_addr;
++              unsigned long fault_type;
++              unsigned long trap_type;
++              long syscall;
++              int is_user;
++      } skas;
++#endif
++};
++
++#define EMPTY_UML_PT_REGS { }
++
++extern int mode_tt;
++
++#define UPT_SC(r) ((r)->tt.sc)
++#define UPT_IP(r) \
++      CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
++#define UPT_SP(r) \
++      CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs))
++#define UPT_EFLAGS(r) \
++      CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs))
++#define UPT_EAX(r) \
++      CHOOSE_MODE(SC_EAX(UPT_SC(r)), REGS_EAX((r)->skas.regs))
++#define UPT_EBX(r) \
++      CHOOSE_MODE(SC_EBX(UPT_SC(r)), REGS_EBX((r)->skas.regs))
++#define UPT_ECX(r) \
++      CHOOSE_MODE(SC_ECX(UPT_SC(r)), REGS_ECX((r)->skas.regs))
++#define UPT_EDX(r) \
++      CHOOSE_MODE(SC_EDX(UPT_SC(r)), REGS_EDX((r)->skas.regs))
++#define UPT_ESI(r) \
++      CHOOSE_MODE(SC_ESI(UPT_SC(r)), REGS_ESI((r)->skas.regs))
++#define UPT_EDI(r) \
++      CHOOSE_MODE(SC_EDI(UPT_SC(r)), REGS_EDI((r)->skas.regs))
++#define UPT_EBP(r) \
++      CHOOSE_MODE(SC_EBP(UPT_SC(r)), REGS_EBP((r)->skas.regs))
++#define UPT_ORIG_EAX(r) \
++      CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall)
++#define UPT_CS(r) \
++      CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
++#define UPT_SS(r) \
++      CHOOSE_MODE(SC_SS(UPT_SC(r)), REGS_SS((r)->skas.regs))
++#define UPT_DS(r) \
++      CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
++#define UPT_ES(r) \
++      CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
++#define UPT_FS(r) \
++      CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
++#define UPT_GS(r) \
++      CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
++
++#define UPT_SYSCALL_ARG1(r) UPT_EBX(r)
++#define UPT_SYSCALL_ARG2(r) UPT_ECX(r)
++#define UPT_SYSCALL_ARG3(r) UPT_EDX(r)
++#define UPT_SYSCALL_ARG4(r) UPT_ESI(r)
++#define UPT_SYSCALL_ARG5(r) UPT_EDI(r)
++#define UPT_SYSCALL_ARG6(r) UPT_EBP(r)
++
++extern int user_context(unsigned long sp);
++
++#define UPT_IS_USER(r) \
++      CHOOSE_MODE(user_context(UPT_SP(r)), (r)->skas.is_user)
++
++struct syscall_args {
++      unsigned long args[6];
++};
++
++#define SYSCALL_ARGS(r) ((struct syscall_args) \
++                        { .args = { UPT_SYSCALL_ARG1(r), \
++                                    UPT_SYSCALL_ARG2(r), \
++                                  UPT_SYSCALL_ARG3(r), \
++                                    UPT_SYSCALL_ARG4(r), \
++                                  UPT_SYSCALL_ARG5(r), \
++                                    UPT_SYSCALL_ARG6(r) } } )
++
++#define UPT_REG(regs, reg) \
++      ({      unsigned long val; \
++              switch(reg){ \
++              case EIP: val = UPT_IP(regs); break; \
++              case UESP: val = UPT_SP(regs); break; \
++              case EAX: val = UPT_EAX(regs); break; \
++              case EBX: val = UPT_EBX(regs); break; \
++              case ECX: val = UPT_ECX(regs); break; \
++              case EDX: val = UPT_EDX(regs); break; \
++              case ESI: val = UPT_ESI(regs); break; \
++              case EDI: val = UPT_EDI(regs); break; \
++              case EBP: val = UPT_EBP(regs); break; \
++              case ORIG_EAX: val = UPT_ORIG_EAX(regs); break; \
++              case CS: val = UPT_CS(regs); break; \
++              case SS: val = UPT_SS(regs); break; \
++              case DS: val = UPT_DS(regs); break; \
++              case ES: val = UPT_ES(regs); break; \
++              case FS: val = UPT_FS(regs); break; \
++              case GS: val = UPT_GS(regs); break; \
++              case EFL: val = UPT_EFLAGS(regs); break; \
++              default :  \
++                      panic("Bad register in UPT_REG : %d\n", reg);  \
++                      val = -1; \
++              } \
++              val; \
++      })
++      
++
++#define UPT_SET(regs, reg, val) \
++      do { \
++              switch(reg){ \
++              case EIP: UPT_IP(regs) = val; break; \
++              case UESP: UPT_SP(regs) = val; break; \
++              case EAX: UPT_EAX(regs) = val; break; \
++              case EBX: UPT_EBX(regs) = val; break; \
++              case ECX: UPT_ECX(regs) = val; break; \
++              case EDX: UPT_EDX(regs) = val; break; \
++              case ESI: UPT_ESI(regs) = val; break; \
++              case EDI: UPT_EDI(regs) = val; break; \
++              case EBP: UPT_EBP(regs) = val; break; \
++              case ORIG_EAX: UPT_ORIG_EAX(regs) = val; break; \
++              case CS: UPT_CS(regs) = val; break; \
++              case SS: UPT_SS(regs) = val; break; \
++              case DS: UPT_DS(regs) = val; break; \
++              case ES: UPT_ES(regs) = val; break; \
++              case FS: UPT_FS(regs) = val; break; \
++              case GS: UPT_GS(regs) = val; break; \
++              case EFL: UPT_EFLAGS(regs) = val; break; \
++              default :  \
++                      panic("Bad register in UPT_SET : %d\n", reg);  \
++                      break; \
++              } \
++      } while (0)
++
++#define UPT_SET_SYSCALL_RETURN(r, res) \
++      CHOOSE_MODE(SC_SET_SYSCALL_RETURN(UPT_SC(r), (res)), \
++                    REGS_SET_SYSCALL_RETURN((r)->skas.regs, (res)))
++
++#define UPT_RESTART_SYSCALL(r) \
++      CHOOSE_MODE(SC_RESTART_SYSCALL(UPT_SC(r)), \
++                  REGS_RESTART_SYSCALL((r)->skas.regs))
++
++#define UPT_ORIG_SYSCALL(r) UPT_EAX(r)
++#define UPT_SYSCALL_NR(r) UPT_ORIG_EAX(r)
++#define UPT_SYSCALL_RET(r) UPT_EAX(r)
++
++#define UPT_SEGV_IS_FIXABLE(r) \
++      CHOOSE_MODE(SC_SEGV_IS_FIXABLE(UPT_SC(r)), \
++                    REGS_SEGV_IS_FIXABLE(&r->skas))
++
++#define UPT_FAULT_ADDR(r) \
++      CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas))
++
++#define UPT_FAULT_WRITE(r) \
++      CHOOSE_MODE(SC_FAULT_WRITE(UPT_SC(r)), REGS_FAULT_WRITE(&r->skas))
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysdep-i386/ptrace_user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-i386/ptrace_user.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-i386/ptrace_user.h     2005-05-03 22:28:14.356427704 +0300
+@@ -0,0 +1,62 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSDEP_I386_PTRACE_USER_H__
++#define __SYSDEP_I386_PTRACE_USER_H__
++
++#include <asm/ptrace.h>
++
++#define PT_OFFSET(r) ((r) * sizeof(long))
++
++#define PT_SYSCALL_NR(regs) ((regs)[ORIG_EAX])
++#define PT_SYSCALL_NR_OFFSET PT_OFFSET(ORIG_EAX)
++
++#define PT_SYSCALL_ARG1_OFFSET PT_OFFSET(EBX)
++#define PT_SYSCALL_ARG2_OFFSET PT_OFFSET(ECX)
++#define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX)
++#define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI)
++#define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI)
++
++#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX)
++
++#define PT_IP_OFFSET PT_OFFSET(EIP)
++#define PT_IP(regs) ((regs)[EIP])
++#define PT_SP(regs) ((regs)[UESP])
++
++#ifndef FRAME_SIZE
++#define FRAME_SIZE (17)
++#endif
++#define FRAME_SIZE_OFFSET (FRAME_SIZE * sizeof(unsigned long))
++
++#define FP_FRAME_SIZE (27)
++#define FPX_FRAME_SIZE (128)
++
++#ifdef PTRACE_GETREGS
++#define UM_HAVE_GETREGS
++#endif
++
++#ifdef PTRACE_SETREGS
++#define UM_HAVE_SETREGS
++#endif
++
++#ifdef PTRACE_GETFPREGS
++#define UM_HAVE_GETFPREGS
++#endif
++
++#ifdef PTRACE_SETFPREGS
++#define UM_HAVE_SETFPREGS
++#endif
++
++#ifdef PTRACE_GETFPXREGS
++#define UM_HAVE_GETFPXREGS
++#endif
++
++#ifdef PTRACE_SETFPXREGS
++#define UM_HAVE_SETFPXREGS
++#endif
++
++extern void update_debugregs(int seq);
++
++#endif
+Index: linux-2.4.29/arch/um/include/sysdep-i386/sigcontext.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-i386/sigcontext.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-i386/sigcontext.h      2005-05-03 22:28:14.357427552 +0300
+@@ -0,0 +1,49 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYS_SIGCONTEXT_I386_H
++#define __SYS_SIGCONTEXT_I386_H
++
++#include "sc.h"
++
++#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
++
++#define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc))
++#define SC_SET_SYSCALL_RETURN(sc, result) SC_EAX(sc) = (result)
++
++#define SC_FAULT_ADDR(sc) SC_CR2(sc)
++#define SC_FAULT_TYPE(sc) SC_ERR(sc)
++
++#define FAULT_WRITE(err) (err & 2)
++#define TO_SC_ERR(is_write) ((is_write) ? 2 : 0)
++
++#define SC_FAULT_WRITE(sc) (FAULT_WRITE(SC_ERR(sc)))
++
++#define SC_TRAP_TYPE(sc) SC_TRAPNO(sc)
++
++/* ptrace expects that, at the start of a system call, %eax contains
++ * -ENOSYS, so this makes it so.
++ */
++#define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0)
++
++/* This is Page Fault */
++#define SEGV_IS_FIXABLE(trap) (trap == 14)
++
++#define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc)))
++
++extern unsigned long *sc_sigmask(void *sc_ptr);
++extern int sc_get_fpregs(unsigned long buf, void *sc_ptr);
++
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysdep-i386/syscalls.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-i386/syscalls.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-i386/syscalls.h        2005-05-03 22:28:14.358427400 +0300
+@@ -0,0 +1,61 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "asm/unistd.h"
++#include "sysdep/ptrace.h"
++
++typedef long syscall_handler_t(struct pt_regs);
++
++#define EXECUTE_SYSCALL(syscall, regs) \
++      ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(&regs->regs))
++
++extern syscall_handler_t sys_modify_ldt;
++extern syscall_handler_t old_mmap_i386;
++extern syscall_handler_t old_select;
++extern syscall_handler_t sys_ni_syscall;
++
++#define ARCH_SYSCALLS \
++      [ __NR_mmap ] = old_mmap_i386, \
++      [ __NR_select ] = old_select, \
++      [ __NR_vm86old ] = sys_ni_syscall, \
++        [ __NR_modify_ldt ] = sys_modify_ldt, \
++      [ __NR_lchown32 ] = sys_lchown, \
++      [ __NR_getuid32 ] = sys_getuid, \
++      [ __NR_getgid32 ] = sys_getgid, \
++      [ __NR_geteuid32 ] = sys_geteuid, \
++      [ __NR_getegid32 ] = sys_getegid, \
++      [ __NR_setreuid32 ] = sys_setreuid, \
++      [ __NR_setregid32 ] = sys_setregid, \
++      [ __NR_getgroups32 ] = sys_getgroups, \
++      [ __NR_setgroups32 ] = sys_setgroups, \
++      [ __NR_fchown32 ] = sys_fchown, \
++      [ __NR_setresuid32 ] = sys_setresuid, \
++      [ __NR_getresuid32 ] = sys_getresuid, \
++      [ __NR_setresgid32 ] = sys_setresgid, \
++      [ __NR_getresgid32 ] = sys_getresgid, \
++      [ __NR_chown32 ] = sys_chown, \
++      [ __NR_setuid32 ] = sys_setuid, \
++      [ __NR_setgid32 ] = sys_setgid, \
++      [ __NR_setfsuid32 ] = sys_setfsuid, \
++      [ __NR_setfsgid32 ] = sys_setfsgid, \
++      [ __NR_pivot_root ] = sys_pivot_root, \
++      [ __NR_mincore ] = sys_mincore, \
++      [ __NR_madvise ] = sys_madvise, \
++        [ 222 ] = sys_ni_syscall, 
++        
++/* 222 doesn't yet have a name in include/asm-i386/unistd.h */
++
++#define LAST_ARCH_SYSCALL 222
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysdep-ia64/ptrace.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-ia64/ptrace.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-ia64/ptrace.h  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,26 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSDEP_IA64_PTRACE_H
++#define __SYSDEP_IA64_PTRACE_H
++
++struct sys_pt_regs {
++  int foo;
++};
++
++#define EMPTY_REGS { 0 }
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysdep-ia64/sigcontext.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-ia64/sigcontext.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-ia64/sigcontext.h      2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,20 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSDEP_IA64_SIGCONTEXT_H
++#define __SYSDEP_IA64_SIGCONTEXT_H
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysdep-ia64/syscalls.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-ia64/syscalls.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-ia64/syscalls.h        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,20 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYSDEP_IA64_SYSCALLS_H
++#define __SYSDEP_IA64_SYSCALLS_H
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysdep-ppc/ptrace.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-ppc/ptrace.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-ppc/ptrace.h   2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,104 @@
++/* 
++ * Licensed under the GPL
++ */
++
++#ifndef __SYS_PTRACE_PPC_H
++#define __SYS_PTRACE_PPC_H
++
++#include "linux/config.h"
++#include "linux/types.h"
++
++/* the following taken from <asm-ppc/ptrace.h> */
++
++#ifdef CONFIG_PPC64
++#define PPC_REG unsigned long /*long*/
++#else
++#define PPC_REG unsigned long
++#endif
++struct sys_pt_regs_s {
++      PPC_REG gpr[32];
++      PPC_REG nip;
++      PPC_REG msr;
++      PPC_REG orig_gpr3;      /* Used for restarting system calls */
++      PPC_REG ctr;
++      PPC_REG link;
++      PPC_REG xer;
++      PPC_REG ccr;
++      PPC_REG mq;             /* 601 only (not used at present) */
++                              /* Used on APUS to hold IPL value. */
++      PPC_REG trap;           /* Reason for being here */
++      PPC_REG dar;            /* Fault registers */
++      PPC_REG dsisr;
++      PPC_REG result;         /* Result of a system call */
++};
++
++#define NUM_REGS (sizeof(struct sys_pt_regs_s) / sizeof(PPC_REG))
++
++struct sys_pt_regs {
++    PPC_REG regs[sizeof(struct sys_pt_regs_s) / sizeof(PPC_REG)];
++};
++
++#define UM_MAX_REG (PT_FPR0)
++#define UM_MAX_REG_OFFSET (UM_MAX_REG * sizeof(PPC_REG))
++
++#define EMPTY_REGS { { [ 0 ... NUM_REGS - 1] = 0 } }
++
++#define UM_REG(r, n) ((r)->regs[n])
++
++#define UM_SYSCALL_RET(r) UM_REG(r, PT_R3)
++#define UM_SP(r) UM_REG(r, PT_R1)
++#define UM_IP(r) UM_REG(r, PT_NIP)
++#define UM_ELF_ZERO(r) UM_REG(r, PT_FPSCR)
++#define UM_SYSCALL_NR(r) UM_REG(r, PT_R0)
++#define UM_SYSCALL_ARG1(r) UM_REG(r, PT_ORIG_R3)
++#define UM_SYSCALL_ARG2(r) UM_REG(r, PT_R4)
++#define UM_SYSCALL_ARG3(r) UM_REG(r, PT_R5)
++#define UM_SYSCALL_ARG4(r) UM_REG(r, PT_R6)
++#define UM_SYSCALL_ARG5(r) UM_REG(r, PT_R7)
++#define UM_SYSCALL_ARG6(r) UM_REG(r, PT_R8)
++
++#define UM_SYSCALL_NR_OFFSET (PT_R0 * sizeof(PPC_REG))
++#define UM_SYSCALL_RET_OFFSET (PT_R3 * sizeof(PPC_REG))
++#define UM_SYSCALL_ARG1_OFFSET (PT_R3 * sizeof(PPC_REG))
++#define UM_SYSCALL_ARG2_OFFSET (PT_R4 * sizeof(PPC_REG))
++#define UM_SYSCALL_ARG3_OFFSET (PT_R5 * sizeof(PPC_REG))
++#define UM_SYSCALL_ARG4_OFFSET (PT_R6 * sizeof(PPC_REG))
++#define UM_SYSCALL_ARG5_OFFSET (PT_R7 * sizeof(PPC_REG))
++#define UM_SYSCALL_ARG6_OFFSET (PT_R8 * sizeof(PPC_REG))
++#define UM_SP_OFFSET (PT_R1 * sizeof(PPC_REG))
++#define UM_IP_OFFSET (PT_NIP * sizeof(PPC_REG))
++#define UM_ELF_ZERO_OFFSET (PT_R3 * sizeof(PPC_REG))
++
++#define UM_SET_SYSCALL_RETURN(_regs, result)          \
++do {                                                    \
++        if (result < 0) {                             \
++              (_regs)->regs[PT_CCR] |= 0x10000000;    \
++              UM_SYSCALL_RET((_regs)) = -result;      \
++        } else {                                      \
++              UM_SYSCALL_RET((_regs)) = result;       \
++        }                                               \
++} while(0)
++
++extern void shove_aux_table(unsigned long sp);
++#define UM_FIX_EXEC_STACK(sp) shove_aux_table(sp);
++
++/* These aren't actually defined.  The undefs are just to make sure
++ * everyone's clear on the concept.
++ */
++#undef UML_HAVE_GETREGS
++#undef UML_HAVE_GETFPREGS
++#undef UML_HAVE_SETREGS
++#undef UML_HAVE_SETFPREGS
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysdep-ppc/sigcontext.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-ppc/sigcontext.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-ppc/sigcontext.h       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,62 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SYS_SIGCONTEXT_PPC_H
++#define __SYS_SIGCONTEXT_PPC_H
++
++#define DSISR_WRITE 0x02000000
++
++#define SC_FAULT_ADDR(sc) ({ \
++              struct sigcontext *_sc = (sc); \
++              long retval = -1; \
++              switch (_sc->regs->trap) { \
++              case 0x300: \
++                      /* data exception */ \
++                      retval = _sc->regs->dar; \
++                      break; \
++              case 0x400: \
++                      /* instruction exception */ \
++                      retval = _sc->regs->nip; \
++                      break; \
++              default: \
++                      panic("SC_FAULT_ADDR: unhandled trap type\n"); \
++              } \
++              retval; \
++      })
++
++#define SC_FAULT_WRITE(sc) ({ \
++              struct sigcontext *_sc = (sc); \
++              long retval = -1; \
++              switch (_sc->regs->trap) { \
++              case 0x300: \
++                      /* data exception */ \
++                      retval = !!(_sc->regs->dsisr & DSISR_WRITE); \
++                      break; \
++              case 0x400: \
++                      /* instruction exception: not a write */ \
++                      retval = 0; \
++                      break; \
++              default: \
++                      panic("SC_FAULT_ADDR: unhandled trap type\n"); \
++              } \
++              retval; \
++      })
++
++#define SC_IP(sc) ((sc)->regs->nip)
++#define SC_SP(sc) ((sc)->regs->gpr[1])
++#define SEGV_IS_FIXABLE(sc) (1)
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysdep-ppc/syscalls.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysdep-ppc/syscalls.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysdep-ppc/syscalls.h 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,50 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++typedef long syscall_handler_t(unsigned long arg1, unsigned long arg2,
++                             unsigned long arg3, unsigned long arg4,
++                             unsigned long arg5, unsigned long arg6);
++
++#define EXECUTE_SYSCALL(syscall, regs) \
++        (*sys_call_table[syscall])(UM_SYSCALL_ARG1(&regs), \
++                                 UM_SYSCALL_ARG2(&regs), \
++                                 UM_SYSCALL_ARG3(&regs), \
++                                 UM_SYSCALL_ARG4(&regs), \
++                                 UM_SYSCALL_ARG5(&regs), \
++                                 UM_SYSCALL_ARG6(&regs))
++
++extern syscall_handler_t sys_mincore;
++extern syscall_handler_t sys_madvise;
++
++/* old_mmap needs the correct prototype since syscall_kern.c includes
++ * this file.
++ */
++int old_mmap(unsigned long addr, unsigned long len,
++           unsigned long prot, unsigned long flags,
++           unsigned long fd, unsigned long offset);
++
++#define ARCH_SYSCALLS \
++      [ __NR_modify_ldt ] = sys_ni_syscall, \
++      [ __NR_pciconfig_read ] = sys_ni_syscall, \
++      [ __NR_pciconfig_write ] = sys_ni_syscall, \
++      [ __NR_pciconfig_iobase ] = sys_ni_syscall, \
++      [ __NR_pivot_root ] = sys_ni_syscall, \
++      [ __NR_multiplexer ] = sys_ni_syscall, \
++      [ __NR_mmap ] = old_mmap, \
++      [ __NR_madvise ] = sys_madvise, \
++      [ __NR_mincore ] = sys_mincore, 
++
++#define LAST_ARCH_SYSCALL __NR_mincore
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/sysrq.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/sysrq.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/sysrq.h       2005-05-03 22:28:14.364426488 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_SYSRQ_H
++#define __UM_SYSRQ_H
++
++extern void show_trace(unsigned long *stack);
++
++#endif
+Index: linux-2.4.29/arch/um/include/tempfile.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/tempfile.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/tempfile.h    2005-05-03 22:28:14.365426336 +0300
+@@ -0,0 +1,21 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TEMPFILE_H__
++#define __TEMPFILE_H__
++
++extern int make_tempfile(const char *template, char **tempname, int do_unlink);
++
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/time_user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/time_user.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/time_user.h   2005-05-03 22:28:14.366426184 +0300
+@@ -0,0 +1,18 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TIME_USER_H__
++#define __TIME_USER_H__
++
++extern void timer(void);
++extern void switch_timers(int to_real);
++extern void set_interval(int timer_type);
++extern void idle_sleep(int secs);
++extern void enable_timer(void);
++extern void disable_timer(void);
++extern unsigned long time_lock(void);
++extern void time_unlock(unsigned long);
++
++#endif
+Index: linux-2.4.29/arch/um/include/tlb.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/tlb.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/tlb.h 2005-05-03 22:28:14.367426032 +0300
+@@ -0,0 +1,23 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TLB_H__
++#define __TLB_H__
++
++extern void mprotect_kernel_vm(int w);
++extern void force_flush_all(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/ubd_user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/ubd_user.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/ubd_user.h    2005-05-03 22:28:14.368425880 +0300
+@@ -0,0 +1,79 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2001 RidgeRun, Inc (glonnon@ridgerun.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_UBD_USER_H
++#define __UM_UBD_USER_H
++
++#include "os.h"
++
++enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP };
++
++struct io_thread_req {
++      enum ubd_req op;
++      int fds[2];
++      unsigned long offsets[2];
++      unsigned long long offset;
++      unsigned long length;
++      char *buffer;
++      int sectorsize;
++      unsigned long sector_mask;
++      unsigned long long cow_offset;
++      unsigned long bitmap_words[2];
++      int map_fd;
++      unsigned long long map_offset;
++      int error;
++};
++
++extern int open_ubd_file(char *file, struct openflags *openflags, 
++                       char **backing_file_out, int *bitmap_offset_out, 
++                       unsigned long *bitmap_len_out, int *data_offset_out,
++                       int *create_cow_out);
++extern int create_cow_file(char *cow_file, char *backing_file, 
++                         struct openflags flags, int sectorsize, 
++                         int alignment, int *bitmap_offset_out, 
++                         unsigned long *bitmap_len_out,
++                         int *data_offset_out);
++extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
++extern int read_ubd_fs(int fd, void *buffer, int len);
++extern int write_ubd_fs(int fd, char *buffer, int len);
++extern int start_io_thread(unsigned long sp, int *fds_out);
++extern void do_io(struct io_thread_req *req);
++
++static inline int ubd_test_bit(__u64 bit, unsigned char *data)
++{
++      __u64 n;
++      int bits, off;
++
++      bits = sizeof(data[0]) * 8;
++      n = bit / bits;
++      off = bit % bits;
++      return((data[n] & (1 << off)) != 0);
++}
++
++static inline void ubd_set_bit(__u64 bit, unsigned char *data)
++{
++      __u64 n;
++      int bits, off;
++
++      bits = sizeof(data[0]) * 8;
++      n = bit / bits;
++      off = bit % bits;
++      data[n] |= (1 << off);
++}
++
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/umid.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/umid.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/umid.h        2005-05-03 22:28:14.368425880 +0300
+@@ -0,0 +1,22 @@
++/*
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UMID_H__
++#define __UMID_H__
++
++extern int umid_file_name(char *name, char *buf, int len);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/uml_uaccess.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/uml_uaccess.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/uml_uaccess.h 2005-05-03 22:28:14.369425728 +0300
+@@ -0,0 +1,28 @@
++/*
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UML_UACCESS_H__
++#define __UML_UACCESS_H__
++
++extern int __do_copy_to_user(void *to, const void *from, int n,
++                                void **fault_addr, void **fault_catcher);
++extern unsigned long __do_user_copy(void *to, const void *from, int n,
++                                  void **fault_addr, void **fault_catcher,
++                                  void (*op)(void *to, const void *from,
++                                             int n), int *faulted_out);
++void __do_copy(void *to, const void *from, int n);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/um_mmu.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/um_mmu.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/um_mmu.h      2005-05-03 22:28:14.370425576 +0300
+@@ -0,0 +1,40 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __ARCH_UM_MMU_H
++#define __ARCH_UM_MMU_H
++
++#include "linux/config.h"
++#include "choose-mode.h"
++
++#ifdef CONFIG_MODE_TT
++#include "../kernel/tt/include/mmu.h"
++#endif
++
++#ifdef CONFIG_MODE_SKAS
++#include "../kernel/skas/include/mmu.h"
++#endif
++
++typedef union {
++#ifdef CONFIG_MODE_TT
++      struct mmu_context_tt tt;
++#endif
++#ifdef CONFIG_MODE_SKAS
++      struct mmu_context_skas skas;
++#endif
++} mm_context_t;
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/umn.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/umn.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/umn.h 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,27 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UMN_H
++#define __UMN_H
++
++extern int open_umn_tty(int *slave_out, int *slipno_out);
++extern void close_umn_tty(int master, int slave);
++extern int umn_send_packet(int fd, void *data, int len);
++extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
++extern void slip_unesc(unsigned char s);
++extern void umn_read(int fd);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/um_uaccess.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/um_uaccess.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/um_uaccess.h  2005-05-03 22:28:14.372425272 +0300
+@@ -0,0 +1,124 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __ARCH_UM_UACCESS_H
++#define __ARCH_UM_UACCESS_H
++
++#include "linux/config.h"
++#include "choose-mode.h"
++
++#ifdef CONFIG_MODE_TT
++#include "../kernel/tt/include/uaccess.h"
++#endif
++
++#ifdef CONFIG_MODE_SKAS
++#include "../kernel/skas/include/uaccess.h"
++#endif
++
++#define access_ok(type, addr, size) \
++      CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)
++
++static inline int verify_area(int type, const void * addr, unsigned long size)
++{
++      return(CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr,
++                              size));
++}
++
++static inline int copy_from_user(void *to, const void *from, int n)
++{
++      return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to,
++                              from, n));
++}
++
++static inline int copy_to_user(void *to, const void *from, int n)
++{
++      return(CHOOSE_MODE_PROC(copy_to_user_tt, copy_to_user_skas, to, 
++                              from, n));
++}
++
++/*
++ * strncpy_from_user: - Copy a NUL terminated string from userspace.
++ * @dst:   Destination address, in kernel space.  This buffer must be at
++ *         least @count bytes long.
++ * @src:   Source address, in user space.
++ * @count: Maximum number of bytes to copy, including the trailing NUL.
++ * 
++ * Copies a NUL-terminated string from userspace to kernel space.
++ *
++ * On success, returns the length of the string (not including the trailing
++ * NUL).
++ *
++ * If access to userspace fails, returns -EFAULT (some data may have been
++ * copied).
++ *
++ * If @count is smaller than the length of the string, copies @count bytes
++ * and returns @count.
++ */
++
++static inline int strncpy_from_user(char *dst, const char *src, int count)
++{
++      return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas,
++                              dst, src, count));
++}
++
++/*
++ * __clear_user: - Zero a block of memory in user space, with less checking.
++ * @to:   Destination address, in user space.
++ * @n:    Number of bytes to zero.
++ *
++ * Zero a block of memory in user space.  Caller must check
++ * the specified block with access_ok() before calling this function.
++ *
++ * Returns number of bytes that could not be cleared.
++ * On success, this will be zero.
++ */
++static inline int __clear_user(void *mem, int len)
++{
++      return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len));
++}
++
++/*
++ * clear_user: - Zero a block of memory in user space.
++ * @to:   Destination address, in user space.
++ * @n:    Number of bytes to zero.
++ *
++ * Zero a block of memory in user space.
++ *
++ * Returns number of bytes that could not be cleared.
++ * On success, this will be zero.
++ */
++static inline int clear_user(void *mem, int len)
++{
++      return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len));
++}
++
++/*
++ * strlen_user: - Get the size of a string in user space.
++ * @str: The string to measure.
++ * @n:   The maximum valid length
++ *
++ * Get the size of a NUL-terminated string in user space.
++ *
++ * Returns the size of the string INCLUDING the terminating NUL.
++ * On exception, returns 0.
++ * If the string is too long, returns a value greater than @n.
++ */
++static inline int strnlen_user(const void *str, int len)
++{
++      return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len));
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/user.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/user.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/user.h        2005-05-03 22:28:14.373425120 +0300
+@@ -0,0 +1,31 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __USER_H__
++#define __USER_H__
++
++extern void panic(const char *fmt, ...);
++extern int printk(const char *fmt, ...);
++extern void schedule(void);
++extern void *um_kmalloc(int size);
++extern void *um_kmalloc_atomic(int size);
++extern void kfree(void *ptr);
++extern int in_aton(char *str);
++extern int open_gdb_chan(void);
++extern void *um_vmalloc(int size);
++extern void vfree(void *ptr);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/include/user_util.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/include/user_util.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/include/user_util.h   2005-05-03 22:28:14.374424968 +0300
+@@ -0,0 +1,105 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __USER_UTIL_H__
++#define __USER_UTIL_H__
++
++#include "sysdep/ptrace.h"
++
++#define CATCH_EINTR(expr) while (((expr) < 0) && (errno == EINTR))
++
++extern int mode_tt;
++
++extern int grantpt(int __fd);
++extern int unlockpt(int __fd);
++extern char *ptsname(int __fd);
++
++struct cpu_task {
++      int pid;
++      void *task;
++};
++
++extern struct cpu_task cpu_tasks[];
++
++struct signal_info {
++      void (*handler)(int, union uml_pt_regs *);
++      int is_irq;
++};
++
++extern struct signal_info sig_info[];
++
++extern unsigned long low_physmem;
++extern unsigned long high_physmem;
++extern unsigned long uml_physmem;
++extern unsigned long uml_reserved;
++extern unsigned long end_vm;
++extern unsigned long start_vm;
++extern unsigned long highmem;
++
++extern char host_info[];
++
++extern char saved_command_line[];
++extern char command_line[];
++
++extern char *tempdir;
++
++extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end;
++extern unsigned long _unprotected_end;
++extern unsigned long brk_start;
++
++extern int pty_output_sigio;
++extern int pty_close_sigio;
++
++extern void stop(void);
++extern void stack_protections(unsigned long address);
++extern void task_protections(unsigned long address);
++extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
++extern void *add_signal_handler(int sig, void (*handler)(int));
++extern int start_fork_tramp(void *arg, unsigned long temp_stack, 
++                          int clone_flags, int (*tramp)(void *));
++extern int linux_main(int argc, char **argv);
++extern void set_cmdline(char *cmd);
++extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
++extern int get_pty(void);
++extern void *um_kmalloc(int size);
++extern int switcheroo(int fd, int prot, void *from, void *to, int size);
++extern void setup_machinename(char *machine_out);
++extern void setup_hostinfo(void);
++extern void add_arg(char *cmd_line, char *arg);
++extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
++extern void init_new_thread_signals(int altstack);
++extern void do_exec(int old_pid, int new_pid);
++extern void tracer_panic(char *msg, ...);
++extern char *get_umid(int only_if_set);
++extern void do_longjmp(void *p, int val);
++extern int detach(int pid, int sig);
++extern int attach(int pid);
++extern void kill_child_dead(int pid);
++extern int cont(int pid);
++extern void check_ptrace(void);
++extern void check_sigio(void);
++extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
++extern void write_sigio_workaround(void);
++extern void arch_check_bugs(void);
++extern int cpu_feature(char *what, char *buf, int len);
++extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
++extern int arch_fixup(unsigned long address, void *sc_ptr);
++extern int can_do_skas(void);
++extern void arch_init_thread(void);
++extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
++extern int raw(int fd);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/checksum.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/checksum.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/checksum.c     2005-05-03 22:28:14.375424816 +0300
+@@ -0,0 +1,42 @@
++#include "asm/uaccess.h"
++#include "linux/errno.h"
++
++extern unsigned int arch_csum_partial(const char *buff, int len, int sum);
++
++extern unsigned int csum_partial(char *buff, int len, int sum)
++{
++      return(arch_csum_partial(buff, len, sum));
++}
++
++unsigned int csum_partial_copy_to(const char *src, char *dst, int len, 
++                                int sum, int *err_ptr)
++{
++      if(copy_to_user(dst, src, len)){
++              *err_ptr = -EFAULT;
++              return(-1);
++      }
++
++      return(arch_csum_partial(src, len, sum));
++}
++
++unsigned int csum_partial_copy_from(const char *src, char *dst, int len, 
++                                  int sum, int *err_ptr)
++{
++      if(copy_from_user(dst, src, len)){
++              *err_ptr = -EFAULT;
++              return(-1);
++      }
++
++      return(arch_csum_partial(dst, len, sum));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/common.ld.in
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/common.ld.in      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/common.ld.in   2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,53 @@
++  .kstrtab : { *(.kstrtab) }
++
++  . = ALIGN(16);              /* Exception table */
++  __start___ex_table = .;
++  __ex_table : { *(__ex_table) }
++  __stop___ex_table = .;
++
++  __start___ksymtab = .;      /* Kernel symbol table */
++  __ksymtab : { *(__ksymtab) }
++  __stop___ksymtab = .;
++
++  .unprotected : { *(.unprotected) }
++  . = ALIGN(4096);
++  PROVIDE (_unprotected_end = .);
++
++  . = ALIGN(4096);
++  __uml_setup_start = .;
++  .uml.setup.init : { *(.uml.setup.init) }
++  __uml_setup_end = .;
++  __uml_help_start = .;
++  .uml.help.init : { *(.uml.help.init) }
++  __uml_help_end = .;
++  __uml_postsetup_start = .;
++  .uml.postsetup.init : { *(.uml.postsetup.init) }
++  __uml_postsetup_end = .;
++  __setup_start = .;
++  .setup.init : { *(.setup.init) }
++  __setup_end = .;
++  __initcall_start = .;
++  .initcall.init : { *(.initcall.init) }
++  __initcall_end = .;
++  __uml_initcall_start = .;
++  .uml.initcall.init : { *(.uml.initcall.init) }
++  __uml_initcall_end = .;
++  __init_end = .;
++  __exitcall_begin = .;
++  .exitcall : { *(.exitcall.exit) }
++  __exitcall_end = .;
++  __uml_exitcall_begin = .;
++  .uml.exitcall : { *(.uml.exitcall.exit) }
++  __uml_exitcall_end = .;
++
++  __preinit_array_start = .;
++  .preinit_array : { *(.preinit_array) }
++  __preinit_array_end = .;
++  __init_array_start = .;
++  .init_array : { *(.init_array) }
++  __init_array_end = .;
++  __fini_array_start = .;
++  .fini_array : { *(.fini_array) }
++  __fini_array_end = .;
++
++  .data.init : { *(.data.init) }
+Index: linux-2.4.29/arch/um/kernel/config.c.in
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/config.c.in       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/config.c.in    2005-05-03 22:28:14.406420104 +0300
+@@ -0,0 +1,32 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "init.h"
++
++static __initdata char *config = "CONFIG";
++
++static int __init print_config(char *line, int *add)
++{
++      printf("%s", config);
++      exit(0);
++}
++
++__uml_setup("--showconfig", print_config,
++"--showconfig\n"
++"    Prints the config file that this UML binary was generated from.\n\n"
++);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/dyn_link.ld.in
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/dyn_link.ld.in    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/dyn_link.ld.in 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,169 @@
++OUTPUT_FORMAT("ELF_FORMAT")
++OUTPUT_ARCH(ELF_ARCH)
++ENTRY(_start)
++
++SECTIONS
++{
++  . = START() + SIZEOF_HEADERS;
++  .interp         : { *(.interp) }
++  __binary_start = .;
++  . = ALIGN(4096);            /* Init code and data */
++  _stext = .;
++  __init_begin = .;
++  .text.init : { *(.text.init) }
++
++  . = ALIGN(4096);
++
++  /* Read-only sections, merged into text segment: */
++  .hash           : { *(.hash) }
++  .dynsym         : { *(.dynsym) }
++  .dynstr         : { *(.dynstr) }
++  .gnu.version    : { *(.gnu.version) }
++  .gnu.version_d  : { *(.gnu.version_d) }
++  .gnu.version_r  : { *(.gnu.version_r) }
++  .rel.init       : { *(.rel.init) }
++  .rela.init      : { *(.rela.init) }
++  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
++  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
++  .rel.fini       : { *(.rel.fini) }
++  .rela.fini      : { *(.rela.fini) }
++  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
++  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
++  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
++  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
++  .rel.tdata    : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
++  .rela.tdata   : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
++  .rel.tbss     : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
++  .rela.tbss    : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
++  .rel.ctors      : { *(.rel.ctors) }
++  .rela.ctors     : { *(.rela.ctors) }
++  .rel.dtors      : { *(.rel.dtors) }
++  .rela.dtors     : { *(.rela.dtors) }
++  .rel.got        : { *(.rel.got) }
++  .rela.got       : { *(.rela.got) }
++  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
++  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
++  .rel.plt        : { *(.rel.plt) }
++  .rela.plt       : { *(.rela.plt) }
++  .init           : {
++    KEEP (*(.init))
++  } =0x90909090
++  .plt            : { *(.plt) }
++  .text           : {
++    *(.text .stub .text.* .gnu.linkonce.t.*)
++    /* .gnu.warning sections are handled specially by elf32.em.  */
++    *(.gnu.warning)
++  } =0x90909090
++  .fini           : {
++    KEEP (*(.fini))
++  } =0x90909090
++
++  PROVIDE (__etext = .);
++  PROVIDE (_etext = .);
++  PROVIDE (etext = .);
++  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
++  .rodata1        : { *(.rodata1) }
++  .eh_frame_hdr : { *(.eh_frame_hdr) }
++
++
++  . = ALIGN(4096);
++  PROVIDE (_sdata = .);
++
++include(`arch/um/kernel/common.ld.in')
++
++  /* Ensure the __preinit_array_start label is properly aligned.  We
++     could instead move the label definition inside the section, but
++     the linker would then create the section even if it turns out to
++     be empty, which isn't pretty.  */
++  . = ALIGN(32 / 8);
++  .preinit_array     : { *(.preinit_array) }
++  .init_array     : { *(.init_array) }
++  .fini_array     : { *(.fini_array) }
++  .data           : {
++    . = ALIGN(KERNEL_STACK_SIZE);             /* init_task */
++    *(.data.init_task)
++    *(.data .data.* .gnu.linkonce.d.*)
++    SORT(CONSTRUCTORS)
++  }
++  .data1          : { *(.data1) }
++  .tdata        : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
++  .tbss                 : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
++  .eh_frame       : { KEEP (*(.eh_frame)) }
++  .gcc_except_table   : { *(.gcc_except_table) }
++  .dynamic        : { *(.dynamic) }
++  .ctors          : {
++    /* gcc uses crtbegin.o to find the start of
++       the constructors, so we make sure it is
++       first.  Because this is a wildcard, it
++       doesn't matter if the user does not
++       actually link against crtbegin.o; the
++       linker won't look for a file to match a
++       wildcard.  The wildcard also means that it
++       doesn't matter which directory crtbegin.o
++       is in.  */
++    KEEP (*crtbegin.o(.ctors))
++    /* We don't want to include the .ctor section from
++       from the crtend.o file until after the sorted ctors.
++       The .ctor section from the crtend file contains the
++       end of ctors marker and it must be last */
++    KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
++    KEEP (*(SORT(.ctors.*)))
++    KEEP (*(.ctors))
++  }
++  .dtors          : {
++    KEEP (*crtbegin.o(.dtors))
++    KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
++    KEEP (*(SORT(.dtors.*)))
++    KEEP (*(.dtors))
++  }
++  .jcr            : { KEEP (*(.jcr)) }
++  .got            : { *(.got.plt) *(.got) }
++  _edata = .;
++  PROVIDE (edata = .);
++  __bss_start = .;
++  .bss            : {
++   *(.dynbss)
++   *(.bss .bss.* .gnu.linkonce.b.*)
++   *(COMMON)
++   /* Align here to ensure that the .bss section occupies space up to
++      _end.  Align after .bss to ensure correct alignment even if the
++      .bss section disappears because there are no input sections.  */
++   . = ALIGN(32 / 8);
++  . = ALIGN(32 / 8);
++  }
++  _end = .;
++  PROVIDE (end = .);
++   /* Stabs debugging sections.  */
++  .stab          0 : { *(.stab) }
++  .stabstr       0 : { *(.stabstr) }
++  .stab.excl     0 : { *(.stab.excl) }
++  .stab.exclstr  0 : { *(.stab.exclstr) }
++  .stab.index    0 : { *(.stab.index) }
++  .stab.indexstr 0 : { *(.stab.indexstr) }
++  .comment       0 : { *(.comment) }
++  /* DWARF debug sections.
++     Symbols in the DWARF debugging sections are relative to the beginning
++     of the section so we begin them at 0.  */
++  /* DWARF 1 */
++  .debug          0 : { *(.debug) }
++  .line           0 : { *(.line) }
++  /* GNU DWARF 1 extensions */
++  .debug_srcinfo  0 : { *(.debug_srcinfo) }
++  .debug_sfnames  0 : { *(.debug_sfnames) }
++  /* DWARF 1.1 and DWARF 2 */
++  .debug_aranges  0 : { *(.debug_aranges) }
++  .debug_pubnames 0 : { *(.debug_pubnames) }
++  /* DWARF 2 */
++  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
++  .debug_abbrev   0 : { *(.debug_abbrev) }
++  .debug_line     0 : { *(.debug_line) }
++  .debug_frame    0 : { *(.debug_frame) }
++  .debug_str      0 : { *(.debug_str) }
++  .debug_loc      0 : { *(.debug_loc) }
++  .debug_macinfo  0 : { *(.debug_macinfo) }
++  /* SGI/MIPS DWARF 2 extensions */
++  .debug_weaknames 0 : { *(.debug_weaknames) }
++  .debug_funcnames 0 : { *(.debug_funcnames) }
++  .debug_typenames 0 : { *(.debug_typenames) }
++  .debug_varnames  0 : { *(.debug_varnames) }
++}
+Index: linux-2.4.29/arch/um/kernel/exec_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/exec_kern.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/exec_kern.c    2005-05-03 22:28:14.408419800 +0300
+@@ -0,0 +1,86 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/slab.h"
++#include "linux/smp_lock.h"
++#include "asm/ptrace.h"
++#include "asm/pgtable.h"
++#include "asm/pgalloc.h"
++#include "asm/uaccess.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "mem_user.h"
++#include "kern.h"
++#include "irq_user.h"
++#include "tlb.h"
++#include "2_5compat.h"
++#include "os.h"
++#include "time_user.h"
++#include "choose-mode.h"
++#include "mode_kern.h"
++
++void flush_thread(void)
++{
++      CHOOSE_MODE(flush_thread_tt(), flush_thread_skas());
++}
++
++void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
++{
++      CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp);
++}
++
++extern void log_exec(char **argv, void *tty);
++
++static int execve1(char *file, char **argv, char **env)
++{
++        int error;
++
++#ifdef CONFIG_TTY_LOG
++      log_exec(argv, current->tty);
++#endif
++        error = do_execve(file, argv, env, &current->thread.regs);
++        if (error == 0){
++                current->ptrace &= ~PT_DTRACE;
++                set_cmdline(current_cmd());
++        }
++        return(error);
++}
++
++int um_execve(char *file, char **argv, char **env)
++{
++      int err;
++
++      err = execve1(file, argv, env);
++      if(!err) 
++              do_longjmp(current->thread.exec_buf, 1);
++      return(err);
++}
++
++int sys_execve(char *file, char **argv, char **env)
++{
++      int error;
++      char *filename;
++
++      lock_kernel();
++      filename = getname((char *) file);
++      error = PTR_ERR(filename);
++      if (IS_ERR(filename)) goto out;
++      error = execve1(filename, argv, env);
++      putname(filename);
++ out:
++      unlock_kernel();
++      return(error);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/exitcode.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/exitcode.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/exitcode.c     2005-05-03 22:28:14.409419648 +0300
+@@ -0,0 +1,73 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/init.h"
++#include "linux/ctype.h"
++#include "linux/proc_fs.h"
++#include "asm/uaccess.h"
++
++/* If read and write race, the read will still atomically read a valid
++ * value.
++ */
++int uml_exitcode = 0;
++
++static int read_proc_exitcode(char *page, char **start, off_t off,
++                            int count, int *eof, void *data)
++{
++      int len;
++
++      len = sprintf(page, "%d\n", uml_exitcode);
++      len -= off;
++      if(len <= off+count) *eof = 1;
++      *start = page + off;
++      if(len > count) len = count;
++      if(len < 0) len = 0;
++      return(len);
++}
++
++static int write_proc_exitcode(struct file *file, const char *buffer,
++                             unsigned long count, void *data)
++{
++      char *end, buf[sizeof("nnnnn\0")];
++      int tmp;
++
++      if(copy_from_user(buf, buffer, count))
++              return(-EFAULT);
++      tmp = simple_strtol(buf, &end, 0);
++      if((*end != '\0') && !isspace(*end))
++              return(-EINVAL);
++      uml_exitcode = tmp;
++      return(count);
++}
++
++static int make_proc_exitcode(void)
++{
++      struct proc_dir_entry *ent;
++
++      ent = create_proc_entry("exitcode", 0600, &proc_root);
++      if(ent == NULL){
++              printk("make_proc_exitcode : Failed to register "
++                     "/proc/exitcode\n");
++              return(0);
++      }
++
++      ent->read_proc = read_proc_exitcode;
++      ent->write_proc = write_proc_exitcode;
++      
++      return(0);
++}
++
++__initcall(make_proc_exitcode);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/filehandle.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/filehandle.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/filehandle.c   2005-05-03 22:28:14.410419496 +0300
+@@ -0,0 +1,250 @@
++/* 
++ * Copyright (C) 2004 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/slab.h"
++#include "linux/list.h"
++#include "linux/spinlock.h"
++#include "linux/fs.h"
++#include "linux/errno.h"
++#include "filehandle.h"
++#include "os.h"
++#include "kern_util.h"
++
++static spinlock_t open_files_lock = SPIN_LOCK_UNLOCKED;
++static struct list_head open_files = LIST_HEAD_INIT(open_files);
++
++#define NUM_RECLAIM 128
++
++static void reclaim_fds(void)
++{
++      struct file_handle *victim;
++      int closed = NUM_RECLAIM;
++
++      spin_lock(&open_files_lock);
++      while(!list_empty(&open_files) && closed--){
++              victim = list_entry(open_files.prev, struct file_handle, list);
++              os_close_file(victim->fd);
++              victim->fd = -1;
++              list_del_init(&victim->list);
++      }
++      spin_unlock(&open_files_lock);
++}
++
++int open_file(char *name, struct openflags flags, int mode)
++{
++      int fd;
++
++      fd = os_open_file(name, flags, mode);
++      if(fd != -EMFILE)
++              return(fd);
++
++      reclaim_fds();
++      fd = os_open_file(name, flags, mode);
++
++      return(fd);
++}
++
++void *open_dir(char *file)
++{
++      void *dir;
++      int err;
++
++      dir = os_open_dir(file, &err);
++      if(dir != NULL)
++              return(dir);
++      if(err != -EMFILE)
++              return(ERR_PTR(err));
++
++      reclaim_fds();
++
++      dir = os_open_dir(file, &err);
++      if(dir == NULL)
++              dir = ERR_PTR(err);
++
++      return(dir);
++}
++
++void not_reclaimable(struct file_handle *fh)
++{
++      char *name;
++
++      if(fh->get_name == NULL)
++              return;
++
++      if(list_empty(&fh->list)){
++              name = (*fh->get_name)(fh->inode);
++              if(name != NULL){
++                      fh->fd = open_file(name, fh->flags, 0);
++                      kfree(name);
++              }
++              else printk("File descriptor %d has no name\n", fh->fd);
++      }
++      else {
++              spin_lock(&open_files_lock);
++              list_del_init(&fh->list);
++              spin_unlock(&open_files_lock);
++      }
++}
++
++void is_reclaimable(struct file_handle *fh, char *(name_proc)(struct inode *),
++                  struct inode *inode)
++{
++      fh->get_name = name_proc;
++      fh->inode = inode;
++
++      spin_lock(&open_files_lock);
++      list_add(&fh->list, &open_files);
++      spin_unlock(&open_files_lock);
++}
++
++static int active_handle(struct file_handle *fh)
++{
++      int fd;
++      char *name;
++
++      if(!list_empty(&fh->list))
++              list_move(&fh->list, &open_files);
++
++      if(fh->fd != -1)
++              return(0);
++
++      if(fh->inode == NULL)
++              return(-ENOENT);
++
++      name = (*fh->get_name)(fh->inode);
++      if(name == NULL)
++              return(-ENOMEM);
++
++      fd = open_file(name, fh->flags, 0);
++      kfree(name);
++      if(fd < 0)
++              return(fd);
++
++      fh->fd = fd;
++      is_reclaimable(fh, fh->get_name, fh->inode);
++
++      return(0);
++}
++
++int filehandle_fd(struct file_handle *fh)
++{
++      int err;
++
++      err = active_handle(fh);
++      if(err)
++              return(err);
++
++      return(fh->fd);
++}
++
++static void init_fh(struct file_handle *fh, int fd, struct openflags flags)
++{
++      flags.c = 0;
++      *fh = ((struct file_handle) { .list     = LIST_HEAD_INIT(fh->list),
++                                    .fd       = fd,
++                                    .get_name = NULL,
++                                    .inode    = NULL,
++                                    .flags    = flags });
++}
++
++int open_filehandle(char *name, struct openflags flags, int mode, 
++                  struct file_handle *fh)
++{
++      int fd;
++
++      fd = open_file(name, flags, mode);
++      if(fd < 0)
++              return(fd);
++
++      init_fh(fh, fd, flags);
++      return(0);
++}
++
++int close_file(struct file_handle *fh)
++{
++      spin_lock(&open_files_lock);
++      list_del(&fh->list);
++      spin_unlock(&open_files_lock);
++
++      os_close_file(fh->fd);
++
++      fh->fd = -1;
++      return(0);
++}
++
++int read_file(struct file_handle *fh, unsigned long long offset, char *buf,
++            int len)
++{
++      int err;
++
++      err = active_handle(fh);
++      if(err)
++              return(err);
++
++      err = os_seek_file(fh->fd, offset);
++      if(err)
++              return(err);
++
++      return(os_read_file(fh->fd, buf, len));
++}
++
++int write_file(struct file_handle *fh, unsigned long long offset, 
++             const char *buf, int len)
++{
++      int err;
++
++      err = active_handle(fh);
++      if(err)
++              return(err);
++
++      if(offset != -1)
++              err = os_seek_file(fh->fd, offset);
++      if(err)
++              return(err);
++
++      return(os_write_file(fh->fd, buf, len));
++}
++
++int truncate_file(struct file_handle *fh, unsigned long long size)
++{
++      int err;
++
++      err = active_handle(fh);
++      if(err)
++              return(err);
++
++      return(os_truncate_fd(fh->fd, size));
++}
++
++int make_pipe(struct file_handle *fhs)
++{
++      int fds[2], err;
++
++      err = os_pipe(fds, 1, 1);
++      if(err && (err != -EMFILE))
++              return(err);
++
++      if(err){
++              reclaim_fds();
++              err = os_pipe(fds, 1, 1);
++      }
++      if(err)
++              return(err);
++
++      init_fh(&fhs[0], fds[0], OPENFLAGS());
++      init_fh(&fhs[1], fds[1], OPENFLAGS());
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/frame.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/frame.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/frame.c        2005-05-03 22:28:14.412419192 +0300
+@@ -0,0 +1,343 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <signal.h>
++#include <wait.h>
++#include <sched.h>
++#include <errno.h>
++#include <sys/ptrace.h>
++#include <sys/syscall.h>
++#include <sys/mman.h>
++#include <asm/page.h>
++#include <asm/ptrace.h>
++#include <asm/sigcontext.h>
++#include "sysdep/ptrace.h"
++#include "sysdep/sigcontext.h"
++#include "frame_user.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "ptrace_user.h"
++#include "os.h"
++
++static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
++                       unsigned long top, void **data_out)
++{
++      unsigned long regs[FRAME_SIZE];
++      int pid, status, n, len;
++
++      /* Start the child as a thread */
++      pid = clone(child, sp, CLONE_VM | SIGCHLD, arg);
++      if(pid < 0){
++              printf("capture_stack : clone failed - errno = %d\n", errno);
++              exit(1);
++      }
++
++      /* Wait for it to stop itself and continue it with a SIGUSR1 to force 
++       * it into the signal handler.
++       */
++      CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
++      if(n < 0){
++              printf("capture_stack : waitpid failed - errno = %d\n", errno);
++              exit(1);
++      }
++      if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
++              fprintf(stderr, "capture_stack : Expected SIGSTOP, "
++                      "got status = 0x%x\n", status);
++              exit(1);
++      }
++      if(ptrace(PTRACE_CONT, pid, 0, SIGUSR1) < 0){
++              printf("capture_stack : PTRACE_CONT failed - errno = %d\n", 
++                     errno);
++              exit(1);
++      }
++
++      /* Wait for it to stop itself again and grab its registers again.  
++       * At this point, the handler has stuffed the addresses of
++       * sig, sc, and SA_RESTORER in raw.
++       */
++      CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
++      if(n < 0){
++              printf("capture_stack : waitpid failed - errno = %d\n", errno);
++              exit(1);
++      }
++      if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
++              fprintf(stderr, "capture_stack : Expected SIGSTOP, "
++                      "got status = 0x%x\n", status);
++              exit(1);
++      }
++      if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0){
++              printf("capture_stack : PTRACE_GETREGS failed - errno = %d\n", 
++                     errno);
++              exit(1);
++      }
++
++      /* It has outlived its usefulness, so continue it so it can exit */
++      if(ptrace(PTRACE_CONT, pid, 0, 0) < 0){
++              printf("capture_stack : PTRACE_CONT failed - errno = %d\n", 
++                     errno);
++              exit(1);
++      }
++      CATCH_EINTR(n = waitpid(pid, &status, 0));
++      if(n < 0){
++              printf("capture_stack : waitpid failed - errno = %d\n", errno);
++              exit(1);
++      }
++      if(!WIFSIGNALED(status) || (WTERMSIG(status) != 9)){
++              printf("capture_stack : Expected exit signal 9, "
++                     "got status = 0x%x\n", status);
++              exit(1);
++      }
++
++      /* The frame that we want is the top of the signal stack */
++
++      len = top - PT_SP(regs);
++      *data_out = malloc(len);
++      if(*data_out == NULL){
++              printf("capture_stack : malloc failed - errno = %d\n", errno);
++              exit(1);
++      }
++      memcpy(*data_out, (void *) PT_SP(regs), len);
++
++      return(len);
++}
++
++struct common_raw {
++      void *stack;
++      int size;
++      unsigned long sig;
++      unsigned long sr;
++      unsigned long sp;       
++      struct arch_frame_data_raw arch;
++};
++
++#define SA_RESTORER (0x04000000)
++
++typedef unsigned long old_sigset_t;
++
++struct old_sigaction {
++      __sighandler_t handler;
++      old_sigset_t sa_mask;
++      unsigned long sa_flags;
++      void (*sa_restorer)(void);
++};
++
++static void child_common(struct common_raw *common, sighandler_t handler,
++                       int restorer, int flags)
++{
++      stack_t ss = ((stack_t) { .ss_sp        = common->stack,
++                                .ss_flags     = 0,
++                                .ss_size      = common->size });
++      int err;
++
++      if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
++              printf("PTRACE_TRACEME failed, errno = %d\n", errno);
++      }
++      if(sigaltstack(&ss, NULL) < 0){
++              printf("sigaltstack failed - errno = %d\n", errno);
++              kill(getpid(), SIGKILL);
++      }
++
++      if(restorer){
++              struct sigaction sa;
++
++              sa.sa_handler = handler;
++              sigemptyset(&sa.sa_mask);
++              sa.sa_flags = SA_ONSTACK | flags;
++              err = sigaction(SIGUSR1, &sa, NULL);
++      }
++      else {
++              struct old_sigaction sa;
++
++              sa.handler = handler;
++              sa.sa_mask = 0;
++              sa.sa_flags = (SA_ONSTACK | flags) & ~SA_RESTORER;
++              err = syscall(__NR_sigaction, SIGUSR1, &sa, NULL);
++      }
++      
++      if(err < 0){
++              printf("sigaction failed - errno = %d\n", errno);
++              kill(getpid(), SIGKILL);
++      }
++
++      os_stop_process(os_getpid());
++}
++
++/* Changed only during early boot */
++struct sc_frame signal_frame_sc;
++
++struct sc_frame signal_frame_sc_sr;
++
++struct sc_frame_raw {
++      struct common_raw common;
++      unsigned long sc;
++      int restorer;
++};
++
++/* Changed only during early boot */
++static struct sc_frame_raw *raw_sc = NULL;
++
++static void sc_handler(int sig, struct sigcontext sc)
++{
++      raw_sc->common.sig = (unsigned long) &sig;
++      raw_sc->common.sr = frame_restorer();
++      raw_sc->common.sp = frame_sp();
++      raw_sc->sc = (unsigned long) &sc;
++      setup_arch_frame_raw(&raw_sc->common.arch, &sc + 1, raw_sc->common.sr);
++
++      os_stop_process(os_getpid());
++      kill(getpid(), SIGKILL);
++}
++
++static int sc_child(void *arg)
++{
++      raw_sc = arg;
++      child_common(&raw_sc->common, (sighandler_t) sc_handler, 
++                   raw_sc->restorer, 0);
++      return(-1);
++}
++
++/* Changed only during early boot */
++struct si_frame signal_frame_si;
++
++struct si_frame_raw {
++      struct common_raw common;
++      unsigned long sip;
++      unsigned long si;
++      unsigned long ucp;
++      unsigned long uc;
++};
++
++/* Changed only during early boot */
++static struct si_frame_raw *raw_si = NULL;
++
++static void si_handler(int sig, siginfo_t *si, struct ucontext *ucontext)
++{
++      raw_si->common.sig = (unsigned long) &sig;
++      raw_si->common.sr = frame_restorer();
++      raw_si->common.sp = frame_sp();
++      raw_si->sip = (unsigned long) &si;
++      raw_si->si = (unsigned long) si;
++      raw_si->ucp = (unsigned long) &ucontext;
++      raw_si->uc = (unsigned long) ucontext;
++      setup_arch_frame_raw(&raw_si->common.arch, 
++                           ucontext->uc_mcontext.fpregs, raw_si->common.sr);
++      
++      os_stop_process(os_getpid());
++      kill(getpid(), SIGKILL);
++}
++
++static int si_child(void *arg)
++{
++      raw_si = arg;
++      child_common(&raw_si->common, (sighandler_t) si_handler, 1, 
++                   SA_SIGINFO);
++      return(-1);
++}
++
++static int relative_sr(unsigned long sr, int sr_index, void *stack, 
++                     void *framep)
++{
++      unsigned long *srp = (unsigned long *) sr;
++      unsigned long frame = (unsigned long) framep;
++
++      if((*srp & PAGE_MASK) == (unsigned long) stack){
++              *srp -= sr;
++              *((unsigned long *) (frame + sr_index)) = *srp;
++              return(1);
++      }
++      else return(0);
++}
++
++static unsigned long capture_stack_common(int (*proc)(void *), void *arg, 
++                                        struct common_raw *common_in, 
++                                        void *top, void *sigstack, 
++                                        int stack_len, 
++                                        struct frame_common *common_out)
++{
++      unsigned long sig_top = (unsigned long) sigstack + stack_len, base;
++
++      common_in->stack = (void *) sigstack;
++      common_in->size = stack_len;
++      common_out->len = capture_stack(proc, arg, top, sig_top, 
++                                      &common_out->data);
++      base = sig_top - common_out->len;
++      common_out->sig_index = common_in->sig - base;
++      common_out->sp_index = common_in->sp - base;
++      common_out->sr_index = common_in->sr - base;
++      common_out->sr_relative = relative_sr(common_in->sr, 
++                                            common_out->sr_index, sigstack, 
++                                            common_out->data);
++      return(base);
++}
++
++void capture_signal_stack(void)
++{
++      struct sc_frame_raw raw_sc;
++      struct si_frame_raw raw_si;
++      void *stack, *sigstack;
++      unsigned long top, base;
++
++      stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
++                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
++      sigstack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
++                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
++      if((stack == MAP_FAILED) || (sigstack == MAP_FAILED)){
++              printf("capture_signal_stack : mmap failed - errno = %d\n", 
++                     errno);
++              exit(1);
++      }
++
++      top = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
++
++      /* Get the sigcontext, no sigrestorer layout */
++      raw_sc.restorer = 0;
++      base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common, 
++                                  (void *) top, sigstack, PAGE_SIZE, 
++                                  &signal_frame_sc.common);
++
++      signal_frame_sc.sc_index = raw_sc.sc - base;
++      setup_arch_frame(&raw_sc.common.arch, &signal_frame_sc.common.arch);
++
++      /* Ditto for the sigcontext, sigrestorer layout */
++      raw_sc.restorer = 1;
++      base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common, 
++                                  (void *) top, sigstack, PAGE_SIZE, 
++                                  &signal_frame_sc_sr.common);
++      signal_frame_sc_sr.sc_index = raw_sc.sc - base;
++      setup_arch_frame(&raw_sc.common.arch, &signal_frame_sc_sr.common.arch);
++
++      /* And the siginfo layout */
++
++      base = capture_stack_common(si_child, &raw_si, &raw_si.common, 
++                                  (void *) top, sigstack, PAGE_SIZE, 
++                                  &signal_frame_si.common);
++      signal_frame_si.sip_index = raw_si.sip - base;
++      signal_frame_si.si_index = raw_si.si - base;
++      signal_frame_si.ucp_index = raw_si.ucp - base;
++      signal_frame_si.uc_index = raw_si.uc - base;
++      setup_arch_frame(&raw_si.common.arch, &signal_frame_si.common.arch);
++
++      if((munmap(stack, PAGE_SIZE) < 0) || 
++         (munmap(sigstack, PAGE_SIZE) < 0)){
++              printf("capture_signal_stack : munmap failed - errno = %d\n", 
++                     errno);
++              exit(1);
++      }
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/frame_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/frame_kern.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/frame_kern.c   2005-05-03 22:28:14.413419040 +0300
+@@ -0,0 +1,173 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++#include "asm/signal.h"
++#include "asm/ucontext.h"
++#include "frame_kern.h"
++#include "sigcontext.h"
++#include "sysdep/ptrace.h"
++#include "choose-mode.h"
++#include "mode.h"
++
++int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
++{
++      if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
++              return -EFAULT;
++      if (from->si_code < 0)
++              return __copy_to_user(to, from, sizeof(siginfo_t));
++      else {
++              int err;
++
++              /* If you change siginfo_t structure, please be sure
++                 this code is fixed accordingly.
++                 It should never copy any pad contained in the structure
++                 to avoid security leaks, but must copy the generic
++                 3 ints plus the relevant union member.  */
++              err = __put_user(from->si_signo, &to->si_signo);
++              err |= __put_user(from->si_errno, &to->si_errno);
++              err |= __put_user((short)from->si_code, &to->si_code);
++              /* First 32bits of unions are always present.  */
++              err |= __put_user(from->si_pid, &to->si_pid);
++              switch (from->si_code >> 16) {
++              case __SI_FAULT >> 16:
++                      break;
++              case __SI_CHLD >> 16:
++                      err |= __put_user(from->si_utime, &to->si_utime);
++                      err |= __put_user(from->si_stime, &to->si_stime);
++                      err |= __put_user(from->si_status, &to->si_status);
++              default:
++                      err |= __put_user(from->si_uid, &to->si_uid);
++                      break;
++              }
++              return err;
++      }
++}
++
++static int copy_restorer(void (*restorer)(void), unsigned long start, 
++                       unsigned long sr_index, int sr_relative)
++{
++      unsigned long sr;
++
++      if(sr_relative){
++              sr = (unsigned long) restorer;
++              sr += start + sr_index;
++              restorer = (void (*)(void)) sr;
++      }
++
++      return(copy_to_user((void *) (start + sr_index), &restorer, 
++                          sizeof(restorer)));
++}
++
++extern int userspace_pid[];
++
++static int copy_sc_to_user(void *to, void *fp, struct pt_regs *from, 
++                         struct arch_frame_data *arch)
++{
++      return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), 
++                                            arch),
++                         copy_sc_to_user_skas(userspace_pid[0], to, fp, 
++                                              &from->regs,
++                                              current->thread.cr2,
++                                              current->thread.err)));
++}
++
++static int copy_ucontext_to_user(struct ucontext *uc, void *fp, sigset_t *set,
++                               unsigned long sp)
++{
++      int err = 0;
++
++      err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp);
++      err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags);
++      err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
++      err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs,
++                             &signal_frame_si.common.arch);
++      err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
++      return(err);
++}
++
++int setup_signal_stack_si(unsigned long stack_top, int sig, 
++                        unsigned long handler, void (*restorer)(void), 
++                        struct pt_regs *regs, siginfo_t *info, 
++                        sigset_t *mask)
++{
++      unsigned long start;
++      void *sip, *ucp, *fp;
++
++      start = stack_top - signal_frame_si.common.len;
++      sip = (void *) (start + signal_frame_si.si_index);
++      ucp = (void *) (start + signal_frame_si.uc_index);
++      fp = (void *) (((unsigned long) ucp) + sizeof(struct ucontext));
++
++      if(restorer == NULL)
++              panic("setup_signal_stack_si - no restorer");
++
++      if(copy_to_user((void *) start, signal_frame_si.common.data,
++                      signal_frame_si.common.len) ||
++         copy_to_user((void *) (start + signal_frame_si.common.sig_index), 
++                      &sig, sizeof(sig)) ||
++         copy_siginfo_to_user(sip, info) ||
++         copy_to_user((void *) (start + signal_frame_si.sip_index), &sip,
++                      sizeof(sip)) ||
++         copy_ucontext_to_user(ucp, fp, mask, PT_REGS_SP(regs)) ||
++         copy_to_user((void *) (start + signal_frame_si.ucp_index), &ucp,
++                      sizeof(ucp)) ||
++         copy_restorer(restorer, start, signal_frame_si.common.sr_index,
++                       signal_frame_si.common.sr_relative))
++              return(1);
++      
++      PT_REGS_IP(regs) = handler;
++      PT_REGS_SP(regs) = start + signal_frame_si.common.sp_index;
++      return(0);
++}
++
++int setup_signal_stack_sc(unsigned long stack_top, int sig, 
++                        unsigned long handler, void (*restorer)(void), 
++                        struct pt_regs *regs, sigset_t *mask)
++{
++      struct frame_common *frame = &signal_frame_sc_sr.common;
++      void *user_sc;
++      int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
++      unsigned long sigs, sr;
++      unsigned long start = stack_top - frame->len - sig_size;
++
++      user_sc = (void *) (start + signal_frame_sc_sr.sc_index);
++      if(restorer == NULL){
++              frame = &signal_frame_sc.common;
++              user_sc = (void *) (start + signal_frame_sc.sc_index);
++              sr = (unsigned long) frame->data;
++              sr += frame->sr_index;
++              sr = *((unsigned long *) sr);
++              restorer = ((void (*)(void)) sr);
++      }
++
++      sigs = start + frame->len;
++      if(copy_to_user((void *) start, frame->data, frame->len) ||
++         copy_to_user((void *) (start + frame->sig_index), &sig, 
++                      sizeof(sig)) ||
++         copy_sc_to_user(user_sc, NULL, regs, 
++                         &signal_frame_sc.common.arch) ||
++         copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) ||
++         copy_to_user((void *) sigs, &mask->sig[1], sig_size) ||
++         copy_restorer(restorer, start, frame->sr_index, frame->sr_relative))
++              return(1);
++
++      PT_REGS_IP(regs) = handler;
++      PT_REGS_SP(regs) = start + frame->sp_index;
++
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/gmon_syms.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/gmon_syms.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/gmon_syms.c    2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,20 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/module.h"
++
++extern void __bb_init_func(void *);
++EXPORT_SYMBOL(__bb_init_func);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/gprof_syms.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/gprof_syms.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/gprof_syms.c   2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,20 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/module.h"
++
++extern void mcount(void);
++EXPORT_SYMBOL(mcount);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/helper.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/helper.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/helper.c       2005-05-03 22:28:14.416418584 +0300
+@@ -0,0 +1,167 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <sched.h>
++#include <sys/signal.h>
++#include <sys/wait.h>
++#include "user.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "os.h"
++
++struct helper_data {
++      void (*pre_exec)(void*);
++      void *pre_data;
++      char **argv;
++      int fd;
++};
++
++/* Debugging aid, changed only from gdb */
++int helper_pause = 0;
++
++static void helper_hup(int sig)
++{
++}
++
++static int helper_child(void *arg)
++{
++      struct helper_data *data = arg;
++      char **argv = data->argv;
++      int errval;
++
++      if(helper_pause){
++              signal(SIGHUP, helper_hup);
++              pause();
++      }
++      if(data->pre_exec != NULL)
++              (*data->pre_exec)(data->pre_data);
++      execvp(argv[0], argv);
++      errval = errno;
++      printk("execvp of '%s' failed - errno = %d\n", argv[0], errno);
++      os_write_file(data->fd, &errval, sizeof(errval));
++      os_kill_process(os_getpid(), 0);
++      return(0);
++}
++
++/* XXX The alloc_stack here breaks if this is called in the tracing thread */
++
++int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
++             unsigned long *stack_out)
++{
++      struct helper_data data;
++      unsigned long stack, sp;
++      int pid, fds[2], err, n;
++
++      if((stack_out != NULL) && (*stack_out != 0))
++              stack = *stack_out;
++      else stack = alloc_stack(0, um_in_interrupt());
++      if(stack == 0) 
++              return(-ENOMEM);
++
++      err = os_pipe(fds, 1, 0);
++      if(err < 0){
++              printk("run_helper : pipe failed, err = %d\n", -err);
++              goto out_free;
++      }
++
++      err = os_set_exec_close(fds[1], 1);
++      if(err < 0){
++              printk("run_helper : setting FD_CLOEXEC failed, err = %d\n",
++                     -err);
++              goto out_close;
++      }
++
++      sp = stack + page_size() - sizeof(void *);
++      data.pre_exec = pre_exec;
++      data.pre_data = pre_data;
++      data.argv = argv;
++      data.fd = fds[1];
++      pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data);
++      if(pid < 0){
++              printk("run_helper : clone failed, errno = %d\n", errno);
++              err = -errno;
++              goto out_close;
++      }
++
++      os_close_file(fds[1]);
++      n = os_read_file(fds[0], &err, sizeof(err));
++      if(n < 0){
++              printk("run_helper : read on pipe failed, err = %d\n", -n);
++              err = n;
++              os_kill_process(pid, 1);
++      }
++      else if(n != 0){
++              CATCH_EINTR(n = waitpid(pid, NULL, 0));
++              pid = -errno;
++      }
++      err = pid;
++
++ out_close:
++      os_close_file(fds[0]);
++ out_free:
++      if(stack_out == NULL) 
++              free_stack(stack, 0);
++        else *stack_out = stack;
++      return(err);
++}
++
++int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, 
++                    unsigned long *stack_out, int stack_order)
++{
++      unsigned long stack, sp;
++      int pid, status;
++
++      stack = alloc_stack(stack_order, um_in_interrupt());
++      if(stack == 0) return(-ENOMEM);
++
++      sp = stack + (page_size() << stack_order) - sizeof(void *);
++      pid = clone(proc, (void *) sp, flags | SIGCHLD, arg);
++      if(pid < 0){
++              printk("run_helper_thread : clone failed, errno = %d\n", 
++                     errno);
++              return(-errno);
++      }
++      if(stack_out == NULL){
++              CATCH_EINTR(pid = waitpid(pid, &status, 0));
++              if(pid < 0){
++                      printk("run_helper_thread - wait failed, errno = %d\n",
++                             errno);
++                      pid = -errno;
++              }
++              if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
++                      printk("run_helper_thread - thread returned status "
++                             "0x%x\n", status);
++              free_stack(stack, stack_order);
++      }
++        else *stack_out = stack;
++      return(pid);
++}
++
++int helper_wait(int pid, int block)
++{
++      int ret;
++
++      CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG));
++      if(ret < 0){
++              printk("helper_wait : waitpid failed, errno = %d\n", errno);
++              return(-errno);
++      }
++      return(ret);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/initrd_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/initrd_kern.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/initrd_kern.c  2005-05-03 22:28:14.417418432 +0300
+@@ -0,0 +1,59 @@
++/*
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/init.h"
++#include "linux/bootmem.h"
++#include "linux/blk.h"
++#include "asm/types.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "initrd.h"
++#include "init.h"
++#include "os.h"
++
++/* Changed by uml_initrd_setup, which is a setup */
++static char *initrd __initdata = NULL;
++
++static int __init read_initrd(void)
++{
++      void *area;
++      long long size;
++      int err;
++
++      if(initrd == NULL) return 0;
++      err = os_file_size(initrd, &size);
++      if(err) return 0;
++      area = alloc_bootmem(size);
++      if(area == NULL) return 0;
++      if(load_initrd(initrd, area, size) == -1) return 0;
++      initrd_start = (unsigned long) area;
++      initrd_end = initrd_start + size;
++      return 0;
++}
++
++__uml_postsetup(read_initrd);
++
++static int __init uml_initrd_setup(char *line, int *add)
++{
++      initrd = line;
++      return 0;
++}
++
++__uml_setup("initrd=", uml_initrd_setup, 
++"initrd=<initrd image>\n"
++"    This is used to boot UML from an initrd image.  The argument is the\n"
++"    name of the file containing the image.\n\n"
++);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/initrd_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/initrd_user.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/initrd_user.c  2005-05-03 22:28:14.418418280 +0300
+@@ -0,0 +1,44 @@
++/*
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <errno.h>
++
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "initrd.h"
++#include "os.h"
++
++int load_initrd(char *filename, void *buf, int size)
++{
++      int fd, n;
++
++      fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
++      if(fd < 0){
++              printk("Opening '%s' failed - err = %d\n", filename, -fd);
++              return(-1);
++      }
++      n = os_read_file(fd, buf, size);
++      if(n != size){
++              printk("Read of %d bytes from '%s' failed, err = %d\n", size, 
++                     filename, -n);
++              return(-1);
++      }
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/init_task.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/init_task.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/init_task.c    2005-05-03 22:28:14.419418128 +0300
+@@ -0,0 +1,61 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/mm.h"
++#include "linux/sched.h"
++#include "linux/version.h"
++#include "asm/uaccess.h"
++#include "asm/pgtable.h"
++#include "user_util.h"
++#include "mem_user.h"
++
++static struct fs_struct init_fs = INIT_FS;
++static struct files_struct init_files = INIT_FILES;
++static struct signal_struct init_signals = INIT_SIGNALS;
++struct mm_struct init_mm = INIT_MM(init_mm);
++
++/*
++ * Initial task structure.
++ *
++ * We need to make sure that this is 16384-byte aligned due to the
++ * way process stacks are handled. This is done by having a special
++ * "init_task" linker map entry..
++ */
++
++union task_union init_task_union 
++__attribute__((__section__(".data.init_task"))) = 
++{ INIT_TASK(init_task_union.task) };
++
++struct task_struct *alloc_task_struct(void)
++{
++      return((struct task_struct *) 
++             __get_free_pages(GFP_KERNEL, CONFIG_KERNEL_STACK_ORDER));
++}
++
++void unprotect_stack(unsigned long stack)
++{
++      protect_memory(stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE, 
++                     1, 1, 0, 1);
++}
++
++void free_task_struct(struct task_struct *task)
++{
++      /* free_pages decrements the page counter and only actually frees
++       * the pages if they are now not accessed by anything.
++       */
++      free_pages((unsigned long) task, CONFIG_KERNEL_STACK_ORDER);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/irq.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/irq.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/irq.c  2005-05-03 22:28:14.422417672 +0300
+@@ -0,0 +1,840 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
++ *    Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
++ */
++
++#include "linux/config.h"
++#include "linux/kernel.h"
++#include "linux/smp.h"
++#include "linux/irq.h"
++#include "linux/kernel_stat.h"
++#include "linux/interrupt.h"
++#include "linux/random.h"
++#include "linux/slab.h"
++#include "linux/file.h"
++#include "linux/proc_fs.h"
++#include "linux/init.h"
++#include "linux/seq_file.h"
++#include "asm/irq.h"
++#include "asm/hw_irq.h"
++#include "asm/hardirq.h"
++#include "asm/atomic.h"
++#include "asm/signal.h"
++#include "asm/system.h"
++#include "asm/errno.h"
++#include "asm/uaccess.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "irq_user.h"
++#include "irq_kern.h"
++
++static void register_irq_proc (unsigned int irq);
++
++irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
++        { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
++
++/*
++ * Generic no controller code
++ */
++
++static void enable_none(unsigned int irq) { }
++static unsigned int startup_none(unsigned int irq) { return 0; }
++static void disable_none(unsigned int irq) { }
++static void ack_none(unsigned int irq)
++{
++/*
++ * 'what should we do if we get a hw irq event on an illegal vector'.
++ * each architecture has to answer this themselves, it doesnt deserve
++ * a generic callback i think.
++ */
++#if CONFIG_X86
++      printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq);
++#ifdef CONFIG_X86_LOCAL_APIC
++      /*
++       * Currently unexpected vectors happen only on SMP and APIC.
++       * We _must_ ack these because every local APIC has only N
++       * irq slots per priority level, and a 'hanging, unacked' IRQ
++       * holds up an irq slot - in excessive cases (when multiple
++       * unexpected vectors occur) that might lock up the APIC
++       * completely.
++       */
++      ack_APIC_irq();
++#endif
++#endif
++}
++
++/* startup is the same as "enable", shutdown is same as "disable" */
++#define shutdown_none disable_none
++#define end_none      enable_none
++
++struct hw_interrupt_type no_irq_type = {
++      "none",
++      startup_none,
++      shutdown_none,
++      enable_none,
++      disable_none,
++      ack_none,
++      end_none
++};
++
++/*
++ * Generic, controller-independent functions:
++ */
++
++int get_irq_list(char *buf)
++{
++      int i, j;
++      unsigned long flags;
++      struct irqaction * action;
++      char *p = buf;
++
++      p += sprintf(p, "           ");
++      for (j=0; j<smp_num_cpus; j++)
++              p += sprintf(p, "CPU%d       ",j);
++      *p++ = '\n';
++
++      for (i = 0 ; i < NR_IRQS ; i++) {
++              spin_lock_irqsave(&irq_desc[i].lock, flags);
++              action = irq_desc[i].action;
++              if (!action) 
++                      goto end;
++              p += sprintf(p, "%3d: ",i);
++#ifndef CONFIG_SMP
++              p += sprintf(p, "%10u ", kstat_irqs(i));
++#else
++              for (j = 0; j < smp_num_cpus; j++)
++                      p += sprintf(p, "%10u ",
++                              kstat.irqs[cpu_logical_map(j)][i]);
++#endif
++              p += sprintf(p, " %14s", irq_desc[i].handler->typename);
++              p += sprintf(p, "  %s", action->name);
++
++              for (action=action->next; action; action = action->next)
++                      p += sprintf(p, ", %s", action->name);
++              *p++ = '\n';
++      end:
++              spin_unlock_irqrestore(&irq_desc[i].lock, flags);
++      }
++      p += sprintf(p, "\n");
++#ifdef notdef
++#if CONFIG_SMP
++      p += sprintf(p, "LOC: ");
++      for (j = 0; j < smp_num_cpus; j++)
++              p += sprintf(p, "%10u ",
++                      apic_timer_irqs[cpu_logical_map(j)]);
++      p += sprintf(p, "\n");
++#endif
++#endif
++      p += sprintf(p, "ERR: %10lu\n", 0L);
++      return p - buf;
++}
++
++/*
++ * This should really return information about whether
++ * we should do bottom half handling etc. Right now we
++ * end up _always_ checking the bottom half, which is a
++ * waste of time and is not what some drivers would
++ * prefer.
++ */
++int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, 
++                   struct irqaction * action)
++{
++      int status;
++      int cpu = smp_processor_id();
++
++      irq_enter(cpu, irq);
++
++      status = 1;     /* Force the "do bottom halves" bit */
++
++      if (!(action->flags & SA_INTERRUPT))
++              __sti();
++
++      do {
++              status |= action->flags;
++              action->handler(irq, action->dev_id, regs);
++              action = action->next;
++      } while (action);
++      if (status & SA_SAMPLE_RANDOM)
++              add_interrupt_randomness(irq);
++      __cli();
++
++      irq_exit(cpu, irq);
++
++      return status;
++}
++
++/*
++ * Generic enable/disable code: this just calls
++ * down into the PIC-specific version for the actual
++ * hardware disable after having gotten the irq
++ * controller lock. 
++ */
++ 
++/**
++ *    disable_irq_nosync - disable an irq without waiting
++ *    @irq: Interrupt to disable
++ *
++ *    Disable the selected interrupt line. Disables of an interrupt
++ *    stack. Unlike disable_irq(), this function does not ensure existing
++ *    instances of the IRQ handler have completed before returning.
++ *
++ *    This function may be called from IRQ context.
++ */
++ 
++void inline disable_irq_nosync(unsigned int irq)
++{
++      irq_desc_t *desc = irq_desc + irq;
++      unsigned long flags;
++
++      spin_lock_irqsave(&desc->lock, flags);
++      if (!desc->depth++) {
++              desc->status |= IRQ_DISABLED;
++              desc->handler->disable(irq);
++      }
++      spin_unlock_irqrestore(&desc->lock, flags);
++}
++
++/**
++ *    disable_irq - disable an irq and wait for completion
++ *    @irq: Interrupt to disable
++ *
++ *    Disable the selected interrupt line. Disables of an interrupt
++ *    stack. That is for two disables you need two enables. This
++ *    function waits for any pending IRQ handlers for this interrupt
++ *    to complete before returning. If you use this function while
++ *    holding a resource the IRQ handler may need you will deadlock.
++ *
++ *    This function may be called - with care - from IRQ context.
++ */
++ 
++void disable_irq(unsigned int irq)
++{
++      disable_irq_nosync(irq);
++
++      if (!local_irq_count(smp_processor_id())) {
++              do {
++                      barrier();
++              } while (irq_desc[irq].status & IRQ_INPROGRESS);
++      }
++}
++
++/**
++ *    enable_irq - enable interrupt handling on an irq
++ *    @irq: Interrupt to enable
++ *
++ *    Re-enables the processing of interrupts on this IRQ line
++ *    providing no disable_irq calls are now in effect.
++ *
++ *    This function may be called from IRQ context.
++ */
++ 
++void enable_irq(unsigned int irq)
++{
++      irq_desc_t *desc = irq_desc + irq;
++      unsigned long flags;
++
++      spin_lock_irqsave(&desc->lock, flags);
++      switch (desc->depth) {
++      case 1: {
++              unsigned int status = desc->status & ~IRQ_DISABLED;
++              desc->status = status;
++              if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
++                      desc->status = status | IRQ_REPLAY;
++                      hw_resend_irq(desc->handler,irq);
++              }
++              desc->handler->enable(irq);
++              /* fall-through */
++      }
++      default:
++              desc->depth--;
++              break;
++      case 0:
++              printk(KERN_ERR "enable_irq() unbalanced from %p\n",
++                     __builtin_return_address(0));
++      }
++      spin_unlock_irqrestore(&desc->lock, flags);
++}
++
++/*
++ * do_IRQ handles all normal device IRQ's (the special
++ * SMP cross-CPU interrupts have their own specific
++ * handlers).
++ */
++unsigned int do_IRQ(int irq, union uml_pt_regs *regs)
++{     
++      /* 
++       * 0 return value means that this irq is already being
++       * handled by some other CPU. (or is disabled)
++       */
++      int cpu = smp_processor_id();
++      irq_desc_t *desc = irq_desc + irq;
++      struct irqaction * action;
++      unsigned int status;
++
++      kstat.irqs[cpu][irq]++;
++      spin_lock(&desc->lock);
++      desc->handler->ack(irq);
++      /*
++         REPLAY is when Linux resends an IRQ that was dropped earlier
++         WAITING is used by probe to mark irqs that are being tested
++         */
++      status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
++      status |= IRQ_PENDING; /* we _want_ to handle it */
++
++      /*
++       * If the IRQ is disabled for whatever reason, we cannot
++       * use the action we have.
++       */
++      action = NULL;
++      if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
++              action = desc->action;
++              status &= ~IRQ_PENDING; /* we commit to handling */
++              status |= IRQ_INPROGRESS; /* we are handling it */
++      }
++      desc->status = status;
++
++      /*
++       * If there is no IRQ handler or it was disabled, exit early.
++         Since we set PENDING, if another processor is handling
++         a different instance of this same irq, the other processor
++         will take care of it.
++       */
++      if (!action)
++              goto out;
++
++      /*
++       * Edge triggered interrupts need to remember
++       * pending events.
++       * This applies to any hw interrupts that allow a second
++       * instance of the same irq to arrive while we are in do_IRQ
++       * or in the handler. But the code here only handles the _second_
++       * instance of the irq, not the third or fourth. So it is mostly
++       * useful for irq hardware that does not mask cleanly in an
++       * SMP environment.
++       */
++      for (;;) {
++              spin_unlock(&desc->lock);
++              handle_IRQ_event(irq, (struct pt_regs *) regs, action);
++              spin_lock(&desc->lock);
++              
++              if (!(desc->status & IRQ_PENDING))
++                      break;
++              desc->status &= ~IRQ_PENDING;
++      }
++      desc->status &= ~IRQ_INPROGRESS;
++out:
++      /*
++       * The ->end() handler has to deal with interrupts which got
++       * disabled while the handler was running.
++       */
++      desc->handler->end(irq);
++      spin_unlock(&desc->lock);
++
++      if (softirq_pending(cpu))
++              do_softirq();
++      return 1;
++}
++
++/**
++ *    request_irq - allocate an interrupt line
++ *    @irq: Interrupt line to allocate
++ *    @handler: Function to be called when the IRQ occurs
++ *    @irqflags: Interrupt type flags
++ *    @devname: An ascii name for the claiming device
++ *    @dev_id: A cookie passed back to the handler function
++ *
++ *    This call allocates interrupt resources and enables the
++ *    interrupt line and IRQ handling. From the point this
++ *    call is made your handler function may be invoked. Since
++ *    your handler function must clear any interrupt the board 
++ *    raises, you must take care both to initialise your hardware
++ *    and to set up the interrupt handler in the right order.
++ *
++ *    Dev_id must be globally unique. Normally the address of the
++ *    device data structure is used as the cookie. Since the handler
++ *    receives this value it makes sense to use it.
++ *
++ *    If your interrupt is shared you must pass a non NULL dev_id
++ *    as this is required when freeing the interrupt.
++ *
++ *    Flags:
++ *
++ *    SA_SHIRQ                Interrupt is shared
++ *
++ *    SA_INTERRUPT            Disable local interrupts while processing
++ *
++ *    SA_SAMPLE_RANDOM        The interrupt can be used for entropy
++ *
++ */
++ 
++int request_irq(unsigned int irq,
++              void (*handler)(int, void *, struct pt_regs *),
++              unsigned long irqflags, 
++              const char * devname,
++              void *dev_id)
++{
++      int retval;
++      struct irqaction * action;
++
++#if 1
++      /*
++       * Sanity-check: shared interrupts should REALLY pass in
++       * a real dev-ID, otherwise we'll have trouble later trying
++       * to figure out which interrupt is which (messes up the
++       * interrupt freeing logic etc).
++       */
++      if (irqflags & SA_SHIRQ) {
++              if (!dev_id)
++                      printk(KERN_ERR "Bad boy: %s (at 0x%x) called us "
++                             "without a dev_id!\n", devname, (&irq)[-1]);
++      }
++#endif
++
++      if (irq >= NR_IRQS)
++              return -EINVAL;
++      if (!handler)
++              return -EINVAL;
++
++      action = (struct irqaction *)
++                      kmalloc(sizeof(struct irqaction), GFP_KERNEL);
++      if (!action)
++              return -ENOMEM;
++
++      action->handler = handler;
++      action->flags = irqflags;
++      action->mask = 0;
++      action->name = devname;
++      action->next = NULL;
++      action->dev_id = dev_id;
++
++      retval = setup_irq(irq, action);
++      if (retval)
++              kfree(action);
++      return retval;
++}
++
++int um_request_irq(unsigned int irq, int fd, int type,
++                 void (*handler)(int, void *, struct pt_regs *),
++                 unsigned long irqflags, const char * devname,
++                 void *dev_id)
++{
++      int err;
++
++      err = request_irq(irq, handler, irqflags, devname, dev_id);
++      if(err) 
++              return(err);
++
++      if(fd != -1)
++              err = activate_fd(irq, fd, type, dev_id);
++      return(err);
++}
++
++/* this was setup_x86_irq but it seems pretty generic */
++int setup_irq(unsigned int irq, struct irqaction * new)
++{
++      int shared = 0;
++      unsigned long flags;
++      struct irqaction *old, **p;
++      irq_desc_t *desc = irq_desc + irq;
++
++      /*
++       * Some drivers like serial.c use request_irq() heavily,
++       * so we have to be careful not to interfere with a
++       * running system.
++       */
++      if (new->flags & SA_SAMPLE_RANDOM) {
++              /*
++               * This function might sleep, we want to call it first,
++               * outside of the atomic block.
++               * Yes, this might clear the entropy pool if the wrong
++               * driver is attempted to be loaded, without actually
++               * installing a new handler, but is this really a problem,
++               * only the sysadmin is able to do this.
++               */
++              rand_initialize_irq(irq);
++      }
++
++      /*
++       * The following block of code has to be executed atomically
++       */
++      spin_lock_irqsave(&desc->lock,flags);
++      p = &desc->action;
++      old = *p;
++      if (old != NULL) {
++              /* Can't share interrupts unless both agree to */
++              if (!(old->flags & new->flags & SA_SHIRQ)) {
++                      spin_unlock_irqrestore(&desc->lock,flags);
++                      return -EBUSY;
++              }
++
++              /* add new interrupt at end of irq queue */
++              do {
++                      p = &old->next;
++                      old = *p;
++              } while (old);
++              shared = 1;
++      }
++
++      *p = new;
++
++      if (!shared) {
++              desc->depth = 0;
++              desc->status &= ~IRQ_DISABLED;
++              desc->handler->startup(irq);
++      }
++      spin_unlock_irqrestore(&desc->lock,flags);
++
++      register_irq_proc(irq);
++      return 0;
++}
++
++/**
++ *    free_irq - free an interrupt
++ *    @irq: Interrupt line to free
++ *    @dev_id: Device identity to free
++ *
++ *    Remove an interrupt handler. The handler is removed and if the
++ *    interrupt line is no longer in use by any driver it is disabled.
++ *    On a shared IRQ the caller must ensure the interrupt is disabled
++ *    on the card it drives before calling this function. The function
++ *    does not return until any executing interrupts for this IRQ
++ *    have completed.
++ *
++ *    This function may be called from interrupt context. 
++ *
++ *    Bugs: Attempting to free an irq in a handler for the same irq hangs
++ *          the machine.
++ */
++ 
++void free_irq(unsigned int irq, void *dev_id)
++{
++      irq_desc_t *desc;
++      struct irqaction **p;
++      unsigned long flags;
++
++      if (irq >= NR_IRQS)
++              return;
++
++      desc = irq_desc + irq;
++      spin_lock_irqsave(&desc->lock,flags);
++      p = &desc->action;
++      for (;;) {
++              struct irqaction * action = *p;
++              if (action) {
++                      struct irqaction **pp = p;
++                      p = &action->next;
++                      if (action->dev_id != dev_id)
++                              continue;
++
++                      /* Found it - now remove it from the list of entries */
++                      *pp = action->next;
++                      if (!desc->action) {
++                              desc->status |= IRQ_DISABLED;
++                              desc->handler->shutdown(irq);
++                      }
++                      free_irq_by_irq_and_dev(irq, dev_id);
++                      spin_unlock_irqrestore(&desc->lock,flags);
++
++#ifdef CONFIG_SMP
++                      /* Wait to make sure it's not being used on another CPU */
++                      while (desc->status & IRQ_INPROGRESS)
++                              barrier();
++#endif
++                      kfree(action);
++                      return;
++              }
++              printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
++              spin_unlock_irqrestore(&desc->lock,flags);
++              return;
++      }
++}
++
++/* These are initialized by sysctl_init, which is called from init/main.c */
++static struct proc_dir_entry * root_irq_dir;
++static struct proc_dir_entry * irq_dir [NR_IRQS];
++static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
++
++/* These are read and written as longs, so a read won't see a partial write
++ * even during a race.
++ */
++static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
++
++#define HEX_DIGITS 8
++
++static int irq_affinity_read_proc (char *page, char **start, off_t off,
++                      int count, int *eof, void *data)
++{
++      if (count < HEX_DIGITS+1)
++              return -EINVAL;
++      return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
++}
++
++static unsigned int parse_hex_value (const char *buffer,
++              unsigned long count, unsigned long *ret)
++{
++      unsigned char hexnum [HEX_DIGITS];
++      unsigned long value;
++      int i;
++
++      if (!count)
++              return -EINVAL;
++      if (count > HEX_DIGITS)
++              count = HEX_DIGITS;
++      if (copy_from_user(hexnum, buffer, count))
++              return -EFAULT;
++
++      /*
++       * Parse the first HEX_DIGITS characters as a hex string, any non-hex
++       * char is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
++       */
++      value = 0;
++
++      for (i = 0; i < count; i++) {
++              unsigned int c = hexnum[i];
++
++              switch (c) {
++                      case '0' ... '9': c -= '0'; break;
++                      case 'a' ... 'f': c -= 'a'-10; break;
++                      case 'A' ... 'F': c -= 'A'-10; break;
++              default:
++                      goto out;
++              }
++              value = (value << 4) | c;
++      }
++out:
++      *ret = value;
++      return 0;
++}
++
++static int irq_affinity_write_proc (struct file *file, const char *buffer,
++                                      unsigned long count, void *data)
++{
++      int irq = (long) data, full_count = count, err;
++      unsigned long new_value;
++
++      if (!irq_desc[irq].handler->set_affinity)
++              return -EIO;
++
++      err = parse_hex_value(buffer, count, &new_value);
++
++#if CONFIG_SMP
++      /*
++       * Do not allow disabling IRQs completely - it's a too easy
++       * way to make the system unusable accidentally :-) At least
++       * one online CPU still has to be targeted.
++       */
++      if (!(new_value & cpu_online_map))
++              return -EINVAL;
++#endif
++
++      irq_affinity[irq] = new_value;
++      irq_desc[irq].handler->set_affinity(irq, new_value);
++
++      return full_count;
++}
++
++static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
++                      int count, int *eof, void *data)
++{
++      unsigned long *mask = (unsigned long *) data;
++      if (count < HEX_DIGITS+1)
++              return -EINVAL;
++      return sprintf (page, "%08lx\n", *mask);
++}
++
++static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
++                                      unsigned long count, void *data)
++{
++      unsigned long *mask = (unsigned long *) data, full_count = count, err;
++      unsigned long new_value;
++
++      err = parse_hex_value(buffer, count, &new_value);
++      if (err)
++              return err;
++
++      *mask = new_value;
++      return full_count;
++}
++
++#define MAX_NAMELEN 10
++
++static void register_irq_proc (unsigned int irq)
++{
++      struct proc_dir_entry *entry;
++      char name [MAX_NAMELEN];
++
++      if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
++          irq_dir[irq])
++              return;
++
++      memset(name, 0, MAX_NAMELEN);
++      sprintf(name, "%d", irq);
++
++      /* create /proc/irq/1234 */
++      irq_dir[irq] = proc_mkdir(name, root_irq_dir);
++
++      /* create /proc/irq/1234/smp_affinity */
++      entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
++
++      entry->nlink = 1;
++      entry->data = (void *)(long)irq;
++      entry->read_proc = irq_affinity_read_proc;
++      entry->write_proc = irq_affinity_write_proc;
++
++      smp_affinity_entry[irq] = entry;
++}
++
++/* Read and written as a long */
++unsigned long prof_cpu_mask = -1;
++
++void __init init_irq_proc (void)
++{
++      struct proc_dir_entry *entry;
++      int i;
++
++      /* create /proc/irq */
++      root_irq_dir = proc_mkdir("irq", 0);
++
++      /* create /proc/irq/prof_cpu_mask */
++      entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
++
++      entry->nlink = 1;
++      entry->data = (void *)&prof_cpu_mask;
++      entry->read_proc = prof_cpu_mask_read_proc;
++      entry->write_proc = prof_cpu_mask_write_proc;
++
++      /*
++       * Create entries for all existing IRQs.
++       */
++      for (i = 0; i < NR_IRQS; i++)
++              register_irq_proc(i);
++}
++
++static spinlock_t irq_spinlock = SPIN_LOCK_UNLOCKED;
++
++unsigned long irq_lock(void)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&irq_spinlock, flags);
++      return(flags);
++}
++
++void irq_unlock(unsigned long flags)
++{
++      spin_unlock_irqrestore(&irq_spinlock, flags);
++}
++
++unsigned long probe_irq_on(void)
++{
++      return(0);
++}
++
++int probe_irq_off(unsigned long val)
++{
++      return(0);
++}
++
++static unsigned int startup_SIGIO_irq(unsigned int irq)
++{
++      return(0);
++}
++
++static void shutdown_SIGIO_irq(unsigned int irq)
++{
++}
++
++static void enable_SIGIO_irq(unsigned int irq)
++{
++}
++
++static void disable_SIGIO_irq(unsigned int irq)
++{
++}
++
++static void mask_and_ack_SIGIO(unsigned int irq)
++{
++}
++
++static void end_SIGIO_irq(unsigned int irq)
++{
++}
++
++static unsigned int startup_SIGVTALRM_irq(unsigned int irq)
++{
++      return(0);
++}
++
++static void shutdown_SIGVTALRM_irq(unsigned int irq)
++{
++}
++
++static void enable_SIGVTALRM_irq(unsigned int irq)
++{
++}
++
++static void disable_SIGVTALRM_irq(unsigned int irq)
++{
++}
++
++static void mask_and_ack_SIGVTALRM(unsigned int irq)
++{
++}
++
++static void end_SIGVTALRM_irq(unsigned int irq)
++{
++}
++
++static struct hw_interrupt_type SIGIO_irq_type = {
++      "SIGIO",
++      startup_SIGIO_irq,
++      shutdown_SIGIO_irq,
++      enable_SIGIO_irq,
++      disable_SIGIO_irq,
++      mask_and_ack_SIGIO,
++      end_SIGIO_irq,
++      NULL
++};
++
++static struct hw_interrupt_type SIGVTALRM_irq_type = {
++      "SIGVTALRM",
++      startup_SIGVTALRM_irq,
++      shutdown_SIGVTALRM_irq,
++      enable_SIGVTALRM_irq,
++      disable_SIGVTALRM_irq,
++      mask_and_ack_SIGVTALRM,
++      end_SIGVTALRM_irq,
++      NULL
++};
++
++void __init init_IRQ(void)
++{
++      int i;
++
++      irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
++      irq_desc[TIMER_IRQ].action = 0;
++      irq_desc[TIMER_IRQ].depth = 1;
++      irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type;
++      enable_irq(TIMER_IRQ);
++      for(i=1;i<NR_IRQS;i++){
++              irq_desc[i].status = IRQ_DISABLED;
++              irq_desc[i].action = 0;
++              irq_desc[i].depth = 1;
++              irq_desc[i].handler = &SIGIO_irq_type;
++              enable_irq(i);
++      }
++      init_irq_signals(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/irq_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/irq_user.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/irq_user.c     2005-05-03 22:28:14.424417368 +0300
+@@ -0,0 +1,438 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <signal.h>
++#include <string.h>
++#include <sys/poll.h>
++#include <sys/types.h>
++#include <sys/time.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "process.h"
++#include "signal_user.h"
++#include "sigio.h"
++#include "irq_user.h"
++#include "os.h"
++
++struct irq_fd {
++      struct irq_fd *next;
++      void *id;
++      int fd;
++      int type;
++      int irq;
++      int pid;
++      int events;
++      int current_events;
++      int freed;
++};
++
++static struct irq_fd *active_fds = NULL;
++static struct irq_fd **last_irq_ptr = &active_fds;
++
++static struct pollfd *pollfds = NULL;
++static int pollfds_num = 0;
++static int pollfds_size = 0;
++
++extern int io_count, intr_count;
++
++void sigio_handler(int sig, union uml_pt_regs *regs)
++{
++      struct irq_fd *irq_fd, *next;
++      int i, n;
++
++      if(smp_sigio_handler()) return;
++      while(1){
++              n = poll(pollfds, pollfds_num, 0);
++              if(n < 0){
++                      if(errno == EINTR) continue;
++                      printk("sigio_handler : poll returned %d, "
++                             "errno = %d\n", n, errno);
++                      break;
++              }
++              if(n == 0) break;
++
++              irq_fd = active_fds;
++              for(i = 0; i < pollfds_num; i++){
++                      if(pollfds[i].revents != 0){
++                              irq_fd->current_events = pollfds[i].revents;
++                              pollfds[i].fd = -1;
++                      }
++                      irq_fd = irq_fd->next;
++              }
++
++              for(irq_fd = active_fds; irq_fd != NULL; irq_fd = next){
++                      next = irq_fd->next;
++                      if(irq_fd->current_events != 0){
++                              irq_fd->current_events = 0;
++                              do_IRQ(irq_fd->irq, regs);
++
++                              /* This is here because the next irq may be
++                               * freed in the handler.  If a console goes
++                               * away, both the read and write irqs will be
++                               * freed.  After do_IRQ, ->next will point to
++                               * a good IRQ.
++                               * Irqs can't be freed inside their handlers,
++                               * so the next best thing is to have them
++                               * marked as needing freeing, so that they
++                               * can be freed here.
++                               */
++                              next = irq_fd->next;
++                              if(irq_fd->freed)
++                                      free_irq(irq_fd->irq, irq_fd->id);
++                      }
++              }
++      }
++}
++
++int activate_ipi(int fd, int pid)
++{
++      return(os_set_fd_async(fd, pid));
++}
++
++static void maybe_sigio_broken(int fd, int type)
++{
++      if(isatty(fd)){
++              if((type == IRQ_WRITE) && !pty_output_sigio){
++                      write_sigio_workaround();
++                      add_sigio_fd(fd, 0);
++              }
++              else if((type == IRQ_READ) && !pty_close_sigio){
++                      write_sigio_workaround();
++                      add_sigio_fd(fd, 1);                    
++              }
++      }
++}
++
++int activate_fd(int irq, int fd, int type, void *dev_id)
++{
++      struct pollfd *tmp_pfd;
++      struct irq_fd *new_fd, *irq_fd;
++      unsigned long flags;
++      int pid, events, err, n, size;
++
++      pid = os_getpid();
++      err = os_set_fd_async(fd, pid);
++      if(err < 0)
++              goto out;
++
++      new_fd = um_kmalloc(sizeof(*new_fd));
++      err = -ENOMEM;
++      if(new_fd == NULL)
++              goto out;
++
++      if(type == IRQ_READ) events = POLLIN | POLLPRI;
++      else events = POLLOUT;
++      *new_fd = ((struct irq_fd) { .next              = NULL,
++                                   .id                = dev_id,
++                                   .fd                = fd,
++                                   .type              = type,
++                                   .irq               = irq,
++                                   .pid               = pid,
++                                   .events            = events,
++                                   .current_events    = 0,
++                                   .freed             = 0  } );
++
++      /* Critical section - locked by a spinlock because this stuff can
++       * be changed from interrupt handlers.  The stuff above is done 
++       * outside the lock because it allocates memory.
++       */
++
++      /* Actually, it only looks like it can be called from interrupt
++       * context.  The culprit is reactivate_fd, which calls 
++       * maybe_sigio_broken, which calls write_sigio_workaround,
++       * which calls activate_fd.  However, write_sigio_workaround should
++       * only be called once, at boot time.  That would make it clear that
++       * this is called only from process context, and can be locked with
++       * a semaphore.
++       */
++      flags = irq_lock();
++      for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
++              if((irq_fd->fd == fd) && (irq_fd->type == type)){
++                      printk("Registering fd %d twice\n", fd);
++                      printk("Irqs : %d, %d\n", irq_fd->irq, irq);
++                      printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id);
++                      goto out_unlock;
++              }
++      }
++
++      n = pollfds_num;
++      if(n == pollfds_size){
++              while(1){
++                      /* Here we have to drop the lock in order to call 
++                       * kmalloc, which might sleep.  If something else
++                       * came in and changed the pollfds array, we free
++                       * the buffer and try again.
++                       */
++                      irq_unlock(flags);
++                      size = (pollfds_num + 1) * sizeof(pollfds[0]);
++                      tmp_pfd = um_kmalloc(size);
++                      flags = irq_lock();
++                      if(tmp_pfd == NULL)
++                              goto out_unlock;
++                      if(n == pollfds_size)
++                              break;
++                      kfree(tmp_pfd);
++              }
++              if(pollfds != NULL){
++                      memcpy(tmp_pfd, pollfds,
++                             sizeof(pollfds[0]) * pollfds_size);
++                      kfree(pollfds);
++              }
++              pollfds = tmp_pfd;
++              pollfds_size++;
++      }
++
++      if(type == IRQ_WRITE) 
++              fd = -1;
++
++      pollfds[pollfds_num] = ((struct pollfd) { .fd   = fd,
++                                                .events       = events,
++                                                .revents      = 0 });
++      pollfds_num++;
++
++      *last_irq_ptr = new_fd;
++      last_irq_ptr = &new_fd->next;
++
++      irq_unlock(flags);
++
++      /* This calls activate_fd, so it has to be outside the critical
++       * section.
++       */
++      maybe_sigio_broken(fd, type);
++
++      return(0);
++
++ out_unlock:
++      irq_unlock(flags);
++      kfree(new_fd);
++ out:
++      return(err);
++}
++
++static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
++{
++      struct irq_fd **prev;
++      unsigned long flags;
++      int i = 0;
++
++      flags = irq_lock();
++      prev = &active_fds;
++      while(*prev != NULL){
++              if((*test)(*prev, arg)){
++                      struct irq_fd *old_fd = *prev;
++                      if((pollfds[i].fd != -1) && 
++                         (pollfds[i].fd != (*prev)->fd)){
++                              printk("free_irq_by_cb - mismatch between "
++                                     "active_fds and pollfds, fd %d vs %d\n",
++                                     (*prev)->fd, pollfds[i].fd);
++                              goto out;
++                      }
++                      memcpy(&pollfds[i], &pollfds[i + 1],
++                             (pollfds_num - i - 1) * sizeof(pollfds[0]));
++                      pollfds_num--;
++                      if(last_irq_ptr == &old_fd->next) 
++                              last_irq_ptr = prev;
++                      *prev = (*prev)->next;
++                      if(old_fd->type == IRQ_WRITE) 
++                              ignore_sigio_fd(old_fd->fd);
++                      kfree(old_fd);
++                      continue;
++              }
++              prev = &(*prev)->next;
++              i++;
++      }
++ out:
++      irq_unlock(flags);
++}
++
++struct irq_and_dev {
++      int irq;
++      void *dev;
++};
++
++static int same_irq_and_dev(struct irq_fd *irq, void *d)
++{
++      struct irq_and_dev *data = d;
++
++      return((irq->irq == data->irq) && (irq->id == data->dev));
++}
++
++void free_irq_by_irq_and_dev(int irq, void *dev)
++{
++      struct irq_and_dev data = ((struct irq_and_dev) { .irq  = irq,
++                                                        .dev  = dev });
++
++      free_irq_by_cb(same_irq_and_dev, &data);
++}
++
++static int same_fd(struct irq_fd *irq, void *fd)
++{
++      return(irq->fd == *((int *) fd));
++}
++
++void free_irq_by_fd(int fd)
++{
++      free_irq_by_cb(same_fd, &fd);
++}
++
++static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
++{
++      struct irq_fd *irq;
++      int i = 0;
++
++      for(irq=active_fds; irq != NULL; irq = irq->next){
++              if((irq->fd == fd) && (irq->irq == irqnum)) break;
++              i++;
++      }
++      if(irq == NULL){
++              printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
++              goto out;
++      }
++      if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){
++              printk("find_irq_by_fd - mismatch between active_fds and "
++                     "pollfds, fd %d vs %d, need %d\n", irq->fd, 
++                     pollfds[i].fd, fd);
++              irq = NULL;
++              goto out;
++      }
++      *index_out = i;
++ out:
++      return(irq);
++}
++
++void free_irq_later(int irq, void *dev_id)
++{
++      struct irq_fd *irq_fd;
++      unsigned long flags;
++
++      flags = irq_lock();
++      for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
++              if((irq_fd->irq == irq) && (irq_fd->id == dev_id))
++                      break;
++      }
++      if(irq_fd == NULL){
++              printk("free_irq_later found no irq, irq = %d, "
++                     "dev_id = 0x%p\n", irq, dev_id);
++              goto out;
++      }
++      irq_fd->freed = 1;
++ out:
++      irq_unlock(flags);
++}
++
++void reactivate_fd(int fd, int irqnum)
++{
++      struct irq_fd *irq;
++      unsigned long flags;
++      int i;
++
++      flags = irq_lock();
++      irq = find_irq_by_fd(fd, irqnum, &i);
++      if(irq == NULL){
++              irq_unlock(flags);
++              return;
++      }
++
++      pollfds[i].fd = irq->fd;
++
++      irq_unlock(flags);
++
++      /* This calls activate_fd, so it has to be outside the critical
++       * section.
++       */
++      maybe_sigio_broken(fd, irq->type);
++}
++
++void deactivate_fd(int fd, int irqnum)
++{
++      struct irq_fd *irq;
++      unsigned long flags;
++      int i;
++
++      flags = irq_lock();
++      irq = find_irq_by_fd(fd, irqnum, &i);
++      if(irq == NULL)
++              goto out;
++      pollfds[i].fd = -1;
++ out:
++      irq_unlock(flags);
++}
++
++int deactivate_all_fds(void)
++{
++      struct irq_fd *irq;
++      int err;
++
++      for(irq=active_fds;irq != NULL;irq = irq->next){
++              err = os_clear_fd_async(irq->fd);
++              if(err)
++                      return(err);
++      }
++
++      return(0);
++}
++
++void forward_ipi(int fd, int pid)
++{
++      int err;
++
++      err = os_set_owner(fd, pid);
++      if(err < 0)
++              printk("forward_ipi: set_owner failed, fd = %d, me = %d, "
++                     "target = %d, err = %d\n", fd, os_getpid(), pid, -err);
++}
++
++void forward_interrupts(int pid)
++{
++      struct irq_fd *irq;
++      unsigned long flags;
++      int err;
++
++      flags = irq_lock();
++      for(irq=active_fds;irq != NULL;irq = irq->next){
++              err = os_set_owner(irq->fd, pid);
++              if(err < 0){
++                      /* XXX Just remove the irq rather than
++                       * print out an infinite stream of these
++                       */
++                      printk("Failed to forward %d to pid %d, err = %d\n",
++                             irq->fd, pid, -err);
++              }
++
++              irq->pid = pid;
++      }
++      irq_unlock(flags);
++}
++
++void init_irq_signals(int on_sigstack)
++{
++      __sighandler_t h;
++      int flags;
++
++      flags = on_sigstack ? SA_ONSTACK : 0;
++      if(timer_irq_inited) h = (__sighandler_t) alarm_handler;
++      else h = boot_timer_handler;
++
++      set_handler(SIGVTALRM, h, flags | SA_RESTART, 
++                  SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1);
++      set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
++                  SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++      signal(SIGWINCH, SIG_IGN);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/ksyms.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/ksyms.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/ksyms.c        2005-05-03 23:56:02.752509760 +0300
+@@ -0,0 +1,124 @@
++/* 
++ * Copyright (C) 2001 - 2004 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/module.h"
++#include "linux/string.h"
++#include "linux/smp_lock.h"
++#include "linux/spinlock.h"
++#include "asm/current.h"
++#include "asm/delay.h"
++#include "asm/processor.h"
++#include "asm/unistd.h"
++#include "asm/pgalloc.h"
++#include "asm/pgtable.h"
++#include "asm/page.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "mem_user.h"
++#include "os.h"
++#include "helper.h"
++
++EXPORT_SYMBOL(stop);
++EXPORT_SYMBOL(strtok);
++EXPORT_SYMBOL(uml_physmem);
++EXPORT_SYMBOL(set_signals);
++EXPORT_SYMBOL(get_signals);
++EXPORT_SYMBOL(kernel_thread);
++EXPORT_SYMBOL(__const_udelay);
++EXPORT_SYMBOL(__udelay);
++EXPORT_SYMBOL(sys_waitpid);
++EXPORT_SYMBOL(task_size);
++EXPORT_SYMBOL(flush_tlb_range);
++EXPORT_SYMBOL(host_task_size);
++EXPORT_SYMBOL(arch_validate);
++EXPORT_SYMBOL(get_kmem_end);
++
++EXPORT_SYMBOL(high_physmem);
++EXPORT_SYMBOL(empty_zero_page);
++EXPORT_SYMBOL(um_virt_to_phys);
++EXPORT_SYMBOL(__virt_to_page);
++EXPORT_SYMBOL(to_phys);
++EXPORT_SYMBOL(to_virt);
++EXPORT_SYMBOL(mode_tt);
++EXPORT_SYMBOL(handle_page_fault);
++EXPORT_SYMBOL(find_iomem);
++
++#ifdef CONFIG_MODE_TT
++EXPORT_SYMBOL(strncpy_from_user_tt);
++EXPORT_SYMBOL(copy_from_user_tt);
++EXPORT_SYMBOL(copy_to_user_tt);
++#endif
++
++#ifdef CONFIG_MODE_SKAS
++EXPORT_SYMBOL(strncpy_from_user_skas);
++EXPORT_SYMBOL(copy_to_user_skas);
++EXPORT_SYMBOL(copy_from_user_skas);
++#endif
++
++EXPORT_SYMBOL(os_stat_fd);
++EXPORT_SYMBOL(os_stat_file);
++EXPORT_SYMBOL(os_access);
++EXPORT_SYMBOL(os_print_error);
++EXPORT_SYMBOL(os_get_exec_close);
++EXPORT_SYMBOL(os_set_exec_close);
++EXPORT_SYMBOL(os_getpid);
++EXPORT_SYMBOL(os_open_file);
++EXPORT_SYMBOL(os_read_file);
++EXPORT_SYMBOL(os_write_file);
++EXPORT_SYMBOL(os_seek_file);
++EXPORT_SYMBOL(os_lock_file);
++EXPORT_SYMBOL(os_pipe);
++EXPORT_SYMBOL(os_file_type);
++EXPORT_SYMBOL(os_file_mode);
++EXPORT_SYMBOL(os_file_size);
++EXPORT_SYMBOL(os_flush_stdout);
++EXPORT_SYMBOL(os_close_file);
++EXPORT_SYMBOL(os_set_fd_async);
++EXPORT_SYMBOL(os_set_fd_block);
++EXPORT_SYMBOL(helper_wait);
++EXPORT_SYMBOL(os_shutdown_socket);
++EXPORT_SYMBOL(os_create_unix_socket);
++EXPORT_SYMBOL(os_connect_socket);
++EXPORT_SYMBOL(os_accept_connection);
++EXPORT_SYMBOL(os_ioctl_generic);
++EXPORT_SYMBOL(os_rcv_fd);
++EXPORT_SYMBOL(run_helper);
++EXPORT_SYMBOL(start_thread);
++EXPORT_SYMBOL(dump_thread);
++
++/* This is here because UML expands open to sys_open, not to a system
++ * call instruction.
++ */
++EXPORT_SYMBOL(sys_open);
++EXPORT_SYMBOL(sys_lseek);
++EXPORT_SYMBOL(sys_read);
++EXPORT_SYMBOL(sys_wait4);
++
++#ifdef CONFIG_SMP
++
++/* required for SMP */
++
++extern void FASTCALL( __write_lock_failed(rwlock_t *rw));
++EXPORT_SYMBOL_NOVERS(__write_lock_failed);
++
++extern void FASTCALL( __read_lock_failed(rwlock_t *rw));
++EXPORT_SYMBOL_NOVERS(__read_lock_failed);
++
++EXPORT_SYMBOL(kernel_flag_cacheline);
++EXPORT_SYMBOL(smp_num_cpus);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/link.ld
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/link.ld   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/link.ld        2005-05-03 22:43:46.000000000 +0300
+@@ -0,0 +1,147 @@
++OUTPUT_FORMAT("elf32-i386")
++OUTPUT_ARCH(i386)
++ENTRY(_start)
++
++SECTIONS
++{
++  . = 2684354560 + SIZEOF_HEADERS;
++
++  __binary_start = .;
++
++  .thread_private : {
++    __start_thread_private = .;
++    errno = .;
++    . += 4;
++    arch/um/kernel/tt/unmap_fin.o (.data)
++    __end_thread_private = .;
++  }
++  . = ALIGN(4096);
++  .remap : { arch/um/kernel/tt/unmap_fin.o (.text) }
++
++  . = ALIGN(4096);            /* Init code and data */
++  _stext = .;
++  __init_begin = .;
++  .text.init : { *(.text.init) }
++  . = ALIGN(4096);
++  .text      :
++  {
++    *(.text)
++    /* .gnu.warning sections are handled specially by elf32.em.  */
++    *(.gnu.warning)
++    *(.gnu.linkonce.t*)
++  }
++  .fini      : { *(.fini)    } =0x9090
++  .rodata    : { *(.rodata) *(.gnu.linkonce.r*) }
++  .rodata1   : { *(.rodata1) }
++  _etext = .;
++  PROVIDE (etext = .);
++
++  . = ALIGN(4096);
++  PROVIDE (_sdata = .);
++
++  .kstrtab : { *(.kstrtab) }
++
++  . = ALIGN(16);              /* Exception table */
++  __start___ex_table = .;
++  __ex_table : { *(__ex_table) }
++  __stop___ex_table = .;
++
++  __start___ksymtab = .;      /* Kernel symbol table */
++  __ksymtab : { *(__ksymtab) }
++  __stop___ksymtab = .;
++
++  .unprotected : { *(.unprotected) }
++  . = ALIGN(4096);
++  PROVIDE (_unprotected_end = .);
++
++  . = ALIGN(4096);
++  __uml_setup_start = .;
++  .uml.setup.init : { *(.uml.setup.init) }
++  __uml_setup_end = .;
++  __uml_help_start = .;
++  .uml.help.init : { *(.uml.help.init) }
++  __uml_help_end = .;
++  __uml_postsetup_start = .;
++  .uml.postsetup.init : { *(.uml.postsetup.init) }
++  __uml_postsetup_end = .;
++  __setup_start = .;
++  .setup.init : { *(.setup.init) }
++  __setup_end = .;
++  __initcall_start = .;
++  .initcall.init : { *(.initcall.init) }
++  __initcall_end = .;
++  __uml_initcall_start = .;
++  .uml.initcall.init : { *(.uml.initcall.init) }
++  __uml_initcall_end = .;
++  __init_end = .;
++  __exitcall_begin = .;
++  .exitcall : { *(.exitcall.exit) }
++  __exitcall_end = .;
++  __uml_exitcall_begin = .;
++  .uml.exitcall : { *(.uml.exitcall.exit) }
++  __uml_exitcall_end = .;
++
++  __preinit_array_start = .;
++  .preinit_array : { *(.preinit_array) }
++  __preinit_array_end = .;
++  __init_array_start = .;
++  .init_array : { *(.init_array) }
++  __init_array_end = .;
++  __fini_array_start = .;
++  .fini_array : { *(.fini_array) }
++  __fini_array_end = .;
++
++  .data.init : { *(.data.init) }
++
++
++  .data    :
++  {
++    . = ALIGN(32768);         /* init_task */
++    *(.data.init_task)
++    *(.data)
++    *(.gnu.linkonce.d*)
++    CONSTRUCTORS
++  }
++  .data1   : { *(.data1) }
++  .ctors         :
++  {
++    *(.ctors)
++  }
++  .dtors         :
++  {
++    *(.dtors)
++  }
++
++  .got           : { *(.got.plt) *(.got) }
++  .dynamic       : { *(.dynamic) }
++  /* We want the small data sections together, so single-instruction offsets
++     can access them all, and initialized data all before uninitialized, so
++     we can shorten the on-disk segment size.  */
++  .sdata     : { *(.sdata) }
++  _edata  =  .;
++  PROVIDE (edata = .);
++  . = ALIGN(0x1000);
++  .sbss      : 
++  {
++   __bss_start = .;
++   PROVIDE(_bss_start = .);
++   *(.sbss) 
++   *(.scommon) 
++  }
++  .bss       :
++  {
++   *(.dynbss)
++   *(.bss)
++   *(COMMON)
++  }
++  _end = . ;
++  PROVIDE (end = .);
++  /* Stabs debugging sections.  */
++  .stab 0 : { *(.stab) }
++  .stabstr 0 : { *(.stabstr) }
++  .stab.excl 0 : { *(.stab.excl) }
++  .stab.exclstr 0 : { *(.stab.exclstr) }
++  .stab.index 0 : { *(.stab.index) }
++  .stab.indexstr 0 : { *(.stab.indexstr) }
++  .comment 0 : { *(.comment) }
++}
+Index: linux-2.4.29/arch/um/kernel/link.ld.in
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/link.ld.in        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/link.ld.in     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,94 @@
++OUTPUT_FORMAT("ELF_FORMAT")
++OUTPUT_ARCH(ELF_ARCH)
++ENTRY(_start)
++
++SECTIONS
++{
++  . = START() + SIZEOF_HEADERS;
++
++  __binary_start = .;
++ifdef(`MODE_TT', `
++  .thread_private : {
++    __start_thread_private = .;
++    errno = .;
++    . += 4;
++    arch/um/kernel/tt/unmap_fin.o (.data)
++    __end_thread_private = .;
++  }
++  . = ALIGN(4096);
++  .remap : { arch/um/kernel/tt/unmap_fin.o (.text) }
++')
++  . = ALIGN(4096);            /* Init code and data */
++  _stext = .;
++  __init_begin = .;
++  .text.init : { *(.text.init) }
++  . = ALIGN(4096);
++  .text      :
++  {
++    *(.text)
++    /* .gnu.warning sections are handled specially by elf32.em.  */
++    *(.gnu.warning)
++    *(.gnu.linkonce.t*)
++  }
++  .fini      : { *(.fini)    } =0x9090
++  .rodata    : { *(.rodata) *(.gnu.linkonce.r*) }
++  .rodata1   : { *(.rodata1) }
++  _etext = .;
++  PROVIDE (etext = .);
++
++  . = ALIGN(4096);
++  PROVIDE (_sdata = .);
++
++include(`arch/um/kernel/common.ld.in')
++
++  .data    :
++  {
++    . = ALIGN(KERNEL_STACK_SIZE);             /* init_task */
++    *(.data.init_task)
++    *(.data)
++    *(.gnu.linkonce.d*)
++    CONSTRUCTORS
++  }
++  .data1   : { *(.data1) }
++  .ctors         :
++  {
++    *(.ctors)
++  }
++  .dtors         :
++  {
++    *(.dtors)
++  }
++
++  .got           : { *(.got.plt) *(.got) }
++  .dynamic       : { *(.dynamic) }
++  /* We want the small data sections together, so single-instruction offsets
++     can access them all, and initialized data all before uninitialized, so
++     we can shorten the on-disk segment size.  */
++  .sdata     : { *(.sdata) }
++  _edata  =  .;
++  PROVIDE (edata = .);
++  . = ALIGN(0x1000);
++  .sbss      : 
++  {
++   __bss_start = .;
++   PROVIDE(_bss_start = .);
++   *(.sbss) 
++   *(.scommon) 
++  }
++  .bss       :
++  {
++   *(.dynbss)
++   *(.bss)
++   *(COMMON)
++  }
++  _end = . ;
++  PROVIDE (end = .);
++  /* Stabs debugging sections.  */
++  .stab 0 : { *(.stab) }
++  .stabstr 0 : { *(.stabstr) }
++  .stab.excl 0 : { *(.stab.excl) }
++  .stab.exclstr 0 : { *(.stab.exclstr) }
++  .stab.index 0 : { *(.stab.index) }
++  .stab.indexstr 0 : { *(.stab.indexstr) }
++  .comment 0 : { *(.comment) }
++}
+Index: linux-2.4.29/arch/um/kernel/main.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/main.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/main.c 2005-05-03 22:28:14.429416608 +0300
+@@ -0,0 +1,250 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdio.h> 
++#include <stdlib.h>
++#include <string.h>
++#include <signal.h>
++#include <errno.h>
++#include <sys/resource.h>
++#include <sys/mman.h>
++#include <sys/user.h>
++#include <asm/page.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "mem_user.h"
++#include "signal_user.h"
++#include "time_user.h"
++#include "irq_user.h"
++#include "user.h"
++#include "init.h"
++#include "mode.h"
++#include "choose-mode.h"
++#include "uml-config.h"
++
++/* Set in set_stklim, which is called from main and __wrap_malloc.  
++ * __wrap_malloc only calls it if main hasn't started.
++ */
++unsigned long stacksizelim;
++
++/* Set in main */
++char *linux_prog;
++
++#define PGD_BOUND (4 * 1024 * 1024)
++#define STACKSIZE (8 * 1024 * 1024)
++#define THREAD_NAME_LEN (256)
++
++static void set_stklim(void)
++{
++      struct rlimit lim;
++
++      if(getrlimit(RLIMIT_STACK, &lim) < 0){
++              perror("getrlimit");
++              exit(1);
++      }
++      if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){
++              lim.rlim_cur = STACKSIZE;
++              if(setrlimit(RLIMIT_STACK, &lim) < 0){
++                      perror("setrlimit");
++                      exit(1);
++              }
++      }
++      stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1);
++}
++
++static __init void do_uml_initcalls(void)
++{
++      initcall_t *call;
++
++      call = &__uml_initcall_start;
++      while (call < &__uml_initcall_end){;
++              (*call)();
++              call++;
++      }
++}
++
++static void last_ditch_exit(int sig)
++{
++      CHOOSE_MODE(kmalloc_ok = 0, (void) 0);
++      signal(SIGINT, SIG_DFL);
++      signal(SIGTERM, SIG_DFL);
++      signal(SIGHUP, SIG_DFL);
++      uml_cleanup();
++      exit(1);
++}
++
++extern int uml_exitcode;
++
++int main(int argc, char **argv, char **envp)
++{
++      char **new_argv;
++      sigset_t mask;
++      int ret, i;
++
++      /* Enable all signals except SIGIO - in some environments, we can 
++       * enter with some signals blocked
++       */
++
++      sigemptyset(&mask);
++      sigaddset(&mask, SIGIO);
++      if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){
++              perror("sigprocmask");
++              exit(1);
++      }
++
++#ifdef UML_CONFIG_MODE_TT
++      /* Allocate memory for thread command lines */
++      if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
++
++              char padding[THREAD_NAME_LEN] = { 
++                      [ 0 ...  THREAD_NAME_LEN - 2] = ' ', '\0' 
++              };
++
++              new_argv = malloc((argc + 2) * sizeof(char*));
++              if(!new_argv) {
++                      perror("Allocating extended argv");
++                      exit(1);
++              }       
++              
++              new_argv[0] = argv[0];
++              new_argv[1] = padding;
++              
++              for(i = 2; i <= argc; i++)
++                      new_argv[i] = argv[i - 1];
++              new_argv[argc + 1] = NULL;
++              
++              execvp(new_argv[0], new_argv);
++              perror("execing with extended args");
++              exit(1);
++      }       
++#endif
++
++      linux_prog = argv[0];
++
++      set_stklim();
++
++      new_argv = malloc((argc + 1) * sizeof(char *));
++      if(new_argv == NULL){
++              perror("Mallocing argv");
++              exit(1);
++      }
++      for(i=0;i<argc;i++){
++              new_argv[i] = strdup(argv[i]);
++              if(new_argv[i] == NULL){
++                      perror("Mallocing an arg");
++                      exit(1);
++              }
++      }
++      new_argv[argc] = NULL;
++
++      set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
++      set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
++      set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
++
++      do_uml_initcalls();
++      ret = linux_main(argc, argv);
++      
++      /* Reboot */
++      if(ret){
++              int err;
++
++              printf("\n");
++
++              /* Let any pending signals fire, then disable them.  This 
++               * ensures that they won't be delivered after the exec, when 
++               * they are definitely not expected.
++               */
++              unblock_signals();
++              disable_timer();
++              err = deactivate_all_fds();
++              if(err)
++                      printf("deactivate_all_fds failed, errno = %d\n", -err);
++
++              execvp(new_argv[0], new_argv);
++              perror("Failed to exec kernel");
++              ret = 1;
++      }
++      printf("\n");
++      return(uml_exitcode);
++}
++
++#define CAN_KMALLOC() \
++      (kmalloc_ok && CHOOSE_MODE((getpid() != tracing_pid), 1))
++
++extern void *__real_malloc(int);
++
++void *__wrap_malloc(int size)
++{
++      void *ret;
++
++      if(!CAN_KMALLOC())
++              return(__real_malloc(size));
++      else if(size <= PAGE_SIZE) /* finding contiguos pages is hard */
++              ret = um_kmalloc(size);
++      else ret = um_vmalloc(size);
++
++      /* glibc people insist that if malloc fails, errno should be
++       * set by malloc as well. So we do.
++       */
++      if(ret == NULL)
++              errno = ENOMEM;
++
++      return(ret);
++}
++
++void *__wrap_calloc(int n, int size)
++{
++      void *ptr = __wrap_malloc(n * size);
++
++      if(ptr == NULL) return(NULL);
++      memset(ptr, 0, n * size);
++      return(ptr);
++}
++
++extern void __real_free(void *);
++
++extern unsigned long high_physmem;
++
++void __wrap_free(void *ptr)
++{
++      unsigned long addr = (unsigned long) ptr;
++
++      /* We need to know how the allocation happened, so it can be correctly
++       * freed.  This is done by seeing what region of memory the pointer is
++       * in -
++       *      physical memory - kmalloc/kfree
++       *      kernel virtual memory - vmalloc/vfree
++       *      anywhere else - malloc/free
++       * If kmalloc is not yet possible, then the kernel memory regions
++       * may not be set up yet, and the variables not set up.  So,
++       * free is called.
++       *
++       * CAN_KMALLOC is checked because it would be bad to free a buffer
++       * with kmalloc/vmalloc after they have been turned off during 
++       * shutdown.
++       */
++
++      if((addr >= uml_physmem) && (addr < high_physmem)){
++              if(CAN_KMALLOC())
++                      kfree(ptr);
++      }
++      else if((addr >= start_vm) && (addr < end_vm)){
++              if(CAN_KMALLOC())
++                      vfree(ptr);
++      }
++      else __real_free(ptr);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/Makefile  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/Makefile       2005-05-03 22:28:14.430416456 +0300
+@@ -0,0 +1,73 @@
++# 
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET = built-in.o
++
++obj-y = config.o checksum.o exec_kern.o exitcode.o filehandle.o frame_kern.o \
++      frame.o helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o \
++      mem_user.o physmem.o process.o process_kern.o ptrace.o reboot.o \
++      resource.o sigio_user.o sigio_kern.o signal_kern.o signal_user.o \
++      smp.o syscall_kern.o syscall_user.o sysrq.o sys_call_table.o \
++      tempfile.o time.o time_kern.o tlb.o trap_kern.o trap_user.o \
++      uaccess_user.o um_arch.o umid.o user_syms.o user_util.o
++
++obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o
++obj-$(CONFIG_GPROF) += gprof_syms.o
++obj-$(CONFIG_GCOV) += gmon_syms.o
++obj-$(CONFIG_TTY_LOG) += tty_log.o
++
++subdir-$(CONFIG_MODE_TT) += tt
++subdir-$(CONFIG_MODE_SKAS) += skas
++
++user-objs-$(CONFIG_TTY_LOG) += tty_log.o
++
++obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
++
++# user_syms.o not included here because Rules.make has its own ideas about
++# building anything in export-objs
++
++USER_OBJS = $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \
++      main.o process.o tempfile.o time.o umid.o user_util.o 
++
++DMODULES-$(CONFIG_MODULES) = -D__CONFIG_MODULES__
++DMODVERSIONS-$(CONFIG_MODVERSIONS) = -D__CONFIG_MODVERSIONS__
++
++export-objs-$(CONFIG_GPROF) += gprof_syms.o
++export-objs-$(CONFIG_GCOV) += gmon_syms.o
++
++export-objs = ksyms.o process_kern.o signal_kern.o user_syms.o $(export-objs-y)
++
++CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES-y) $(DMODVERSIONS-y) \
++      -I/usr/include -I../include
++
++CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS))
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++# This has to be separate because it needs be compiled with frame pointers
++# regardless of how the rest of the kernel is built.
++
++frame.o: frame.c
++      $(CC) $(CFLAGS_$@) -c -o $@ $<
++
++QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; $$config =~ s/\n/\\n"\n"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
++
++config.c : config.c.in $(TOPDIR)/.config
++      $(PERL) -e $(QUOTE) < config.c.in > $@
++
++clean:
++      $(RM) config.c
++      for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done
++
++modules:
++
++fastdep:
++
++dep:
++
++archmrproper: clean
+Index: linux-2.4.29/arch/um/kernel/mem.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/mem.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/mem.c  2005-05-03 22:28:14.431416304 +0300
+@@ -0,0 +1,336 @@
++/* 
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/kernel.h"
++#include "linux/mm.h"
++#include "linux/bootmem.h"
++#include "linux/highmem.h"
++#include "asm/page.h"
++#include "asm/fixmap.h"
++#include "asm/pgalloc.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "mem_user.h"
++#include "uml_uaccess.h"
++#include "os.h"
++
++extern char __binary_start;
++
++/* Changed during early boot */
++unsigned long *empty_zero_page = NULL;
++unsigned long *empty_bad_page = NULL;
++pgd_t swapper_pg_dir[1024];
++unsigned long highmem;
++int kmalloc_ok = 0;
++
++static unsigned long brk_end;
++static unsigned long totalram_pages = 0;
++
++void unmap_physmem(void)
++{
++      os_unmap_memory((void *) brk_end, uml_reserved - brk_end);
++}
++
++static void map_cb(void *unused)
++{
++      map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
++}
++
++#ifdef CONFIG_HIGHMEM
++static void setup_highmem(unsigned long highmem_start, 
++                        unsigned long highmem_len)
++{
++      struct page *page;
++      unsigned long highmem_pfn;
++      int i;
++
++      highmem_start_page = virt_to_page(highmem_start);
++
++      highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
++      for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
++              page = &mem_map[highmem_pfn + i];
++              ClearPageReserved(page);
++              set_bit(PG_highmem, &page->flags);
++              atomic_set(&page->count, 1);
++              __free_page(page);
++      }
++}
++#endif
++
++void mem_init(void)
++{
++      unsigned long start;
++
++        /* clear the zero-page */
++        memset((void *) empty_zero_page, 0, PAGE_SIZE);
++
++      /* Map in the area just after the brk now that kmalloc is about
++       * to be turned on.
++       */
++      brk_end = (unsigned long) UML_ROUND_UP(sbrk(0));
++      map_cb(NULL);
++      initial_thread_cb(map_cb, NULL);
++      free_bootmem(__pa(brk_end), uml_reserved - brk_end);
++      uml_reserved = brk_end;
++
++      /* Fill in any hole at the start of the binary */
++      start = (unsigned long) &__binary_start;
++      if(uml_physmem != start){
++              map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem,
++                         1, 1, 0);
++      }
++
++      /* this will put all low memory onto the freelists */
++      totalram_pages = free_all_bootmem();
++      totalram_pages += highmem >> PAGE_SHIFT;
++      num_physpages = totalram_pages;
++      printk(KERN_INFO "Memory: %luk available\n", 
++             (unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
++      kmalloc_ok = 1;
++
++#ifdef CONFIG_HIGHMEM
++      setup_highmem(end_iomem, highmem);
++#endif
++}
++
++static void __init fixrange_init(unsigned long start, unsigned long end, 
++                               pgd_t *pgd_base)
++{
++      pgd_t *pgd;
++      pmd_t *pmd;
++      pte_t *pte;
++      int i, j;
++      unsigned long vaddr;
++
++      vaddr = start;
++      i = __pgd_offset(vaddr);
++      j = __pmd_offset(vaddr);
++      pgd = pgd_base + i;
++
++      for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) {
++              pmd = (pmd_t *)pgd;
++              for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
++                      if (pmd_none(*pmd)) {
++                              pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
++                              set_pmd(pmd, __pmd(_KERNPG_TABLE + 
++                                                 (unsigned long) __pa(pte)));
++                              if (pte != pte_offset(pmd, 0))
++                                      BUG();
++                      }
++                      vaddr += PMD_SIZE;
++              }
++              j = 0;
++      }
++}
++
++#ifdef CONFIG_HIGHMEM
++pte_t *kmap_pte;
++pgprot_t kmap_prot;
++
++#define kmap_get_fixmap_pte(vaddr)                                    \
++      pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
++
++void __init kmap_init(void)
++{
++      unsigned long kmap_vstart;
++
++      /* cache the first kmap pte */
++      kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
++      kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
++
++      kmap_prot = PAGE_KERNEL;
++}
++
++static void init_highmem(void)
++{
++      pgd_t *pgd;
++      pmd_t *pmd;
++      pte_t *pte;
++      unsigned long vaddr;
++
++      /*
++       * Permanent kmaps:
++       */
++      vaddr = PKMAP_BASE;
++      fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, swapper_pg_dir);
++
++      pgd = swapper_pg_dir + __pgd_offset(vaddr);
++      pmd = pmd_offset(pgd, vaddr);
++      pte = pte_offset(pmd, vaddr);
++      pkmap_page_table = pte;
++
++      kmap_init();
++}
++
++#endif /* CONFIG_HIGHMEM */
++
++void paging_init(void)
++{
++      unsigned long zones_size[MAX_NR_ZONES], vaddr;
++      int i;
++
++      empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
++      empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
++      for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++) 
++              zones_size[i] = 0;
++      zones_size[0] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT);
++      zones_size[2] = highmem >> PAGE_SHIFT;
++      free_area_init(zones_size);
++
++      /*
++       * Fixed mappings, only the page table structure has to be
++       * created - mappings will be set by set_fixmap():
++       */
++      vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
++      fixrange_init(vaddr, FIXADDR_TOP, swapper_pg_dir);
++
++#if CONFIG_HIGHMEM
++      init_highmem();
++#endif
++}
++
++struct page *arch_validate(struct page *page, int mask, int order)
++{
++      unsigned long addr, zero = 0;
++      int i;
++
++ again:
++      if(page == NULL) return(page);
++      if(PageHighMem(page)) return(page);
++
++      addr = (unsigned long) page_address(page);
++      for(i = 0; i < (1 << order); i++){
++              current->thread.fault_addr = (void *) addr;
++              if(__do_copy_to_user((void *) addr, &zero, 
++                                   sizeof(zero),
++                                   &current->thread.fault_addr,
++                                   &current->thread.fault_catcher)){
++                      if(!(mask & __GFP_WAIT)) return(NULL);
++                      else break;
++              }
++              addr += PAGE_SIZE;
++      }
++      if(i == (1 << order)) return(page);
++      page = _alloc_pages(mask, order);
++      goto again;
++}
++
++/* This can't do anything because nothing in the kernel image can be freed
++ * since it's not in kernel physical memory.
++ */
++
++void free_initmem(void)
++{
++}
++
++#ifdef CONFIG_BLK_DEV_INITRD
++
++void free_initrd_mem(unsigned long start, unsigned long end)
++{
++      if (start < end)
++              printk ("Freeing initrd memory: %ldk freed\n", 
++                      (end - start) >> 10);
++      for (; start < end; start += PAGE_SIZE) {
++              ClearPageReserved(virt_to_page(start));
++              set_page_count(virt_to_page(start), 1);
++              free_page(start);
++              totalram_pages++;
++      }
++}
++      
++#endif
++
++int do_check_pgt_cache(int low, int high)
++{
++        int freed = 0;
++        if(pgtable_cache_size > high) {
++                do {
++                        if (pgd_quicklist) {
++                                free_pgd_slow(get_pgd_fast());
++                                freed++;
++                        }
++                        if (pmd_quicklist) {
++                                pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
++                                freed++;
++                        }
++                        if (pte_quicklist) {
++                                pte_free_slow(pte_alloc_one_fast(NULL, 0));
++                                freed++;
++                        }
++                } while(pgtable_cache_size > low);
++        }
++        return freed;
++}
++
++void show_mem(void)
++{
++        int i, total = 0, reserved = 0;
++        int shared = 0, cached = 0;
++        int highmem = 0;
++
++        printk("Mem-info:\n");
++        show_free_areas();
++        printk("Free swap:       %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
++        i = max_mapnr;
++        while(i-- > 0) {
++                total++;
++                if(PageHighMem(mem_map + i))
++                        highmem++;
++                if(PageReserved(mem_map + i))
++                        reserved++;
++                else if(PageSwapCache(mem_map + i))
++                        cached++;
++                else if(page_count(mem_map + i))
++                        shared += page_count(mem_map + i) - 1;
++        }
++        printk("%d pages of RAM\n", total);
++        printk("%d pages of HIGHMEM\n", highmem);
++        printk("%d reserved pages\n", reserved);
++        printk("%d pages shared\n", shared);
++        printk("%d pages swap cached\n", cached);
++        printk("%ld pages in page table cache\n", pgtable_cache_size);
++        show_buffers();
++}
++
++/* Changed by meminfo_compat, which is a setup */
++static int meminfo_22 = 0;
++
++static int meminfo_compat(char *str)
++{
++      meminfo_22 = 1;
++      return(1);
++}
++
++__setup("22_meminfo", meminfo_compat);
++
++void si_meminfo(struct sysinfo *val)
++{
++      val->totalram = totalram_pages;
++      val->sharedram = 0;
++      val->freeram = nr_free_pages();
++      val->bufferram = atomic_read(&buffermem_pages);
++      val->totalhigh = highmem >> PAGE_SHIFT;
++      val->freehigh = nr_free_highpages();
++      val->mem_unit = PAGE_SIZE;
++      if(meminfo_22){
++              val->freeram <<= PAGE_SHIFT;
++              val->bufferram <<= PAGE_SHIFT;
++              val->totalram <<= PAGE_SHIFT;
++              val->sharedram <<= PAGE_SHIFT;
++      }
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/mem_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/mem_user.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/mem_user.c     2005-05-03 22:28:14.433416000 +0300
+@@ -0,0 +1,271 @@
++/*
++ * arch/um/kernel/mem_user.c
++ *
++ * BRIEF MODULE DESCRIPTION
++ * user side memory routines for supporting IO memory inside user mode linux
++ *
++ * Copyright (C) 2001 RidgeRun, Inc.
++ * Author: RidgeRun, Inc.
++ *         Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
++ *
++ *  This program is free software; you can redistribute  it and/or modify it
++ *  under  the terms of  the GNU General  Public License as published by the
++ *  Free Software Foundation;  either version 2 of the  License, or (at your
++ *  option) any later version.
++ *
++ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
++ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
++ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
++ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
++ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
++ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
++ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ *  You should have received a copy of the  GNU General Public License along
++ *  with this program; if not, write  to the Free Software Foundation, Inc.,
++ *  675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <stdarg.h>
++#include <unistd.h>
++#include <errno.h>
++#include <string.h>
++#include <fcntl.h>
++#include <sys/types.h>
++#include <sys/mman.h>
++#include "kern_util.h"
++#include "user.h"
++#include "user_util.h"
++#include "mem_user.h"
++#include "init.h"
++#include "os.h"
++#include "tempfile.h"
++#include "kern_constants.h"
++
++extern struct mem_region physmem_region;
++
++#define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
++
++static int create_tmp_file(unsigned long len)
++{
++      int fd, err;
++      char zero;
++
++      fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
++      if(fd < 0) {
++              os_print_error(fd, "make_tempfile");
++              exit(1);
++      }
++
++      err = os_mode_fd(fd, 0777);
++      if(err < 0){
++              os_print_error(err, "os_mode_fd");
++              exit(1);
++      }
++      err = os_seek_file(fd, len);
++      if(err < 0){
++              os_print_error(err, "os_seek_file");
++              exit(1);
++      }
++      zero = 0;
++      err = os_write_file(fd, &zero, 1);
++      if(err != 1){
++              os_print_error(err, "os_write_file");
++              exit(1);
++      }
++
++      return(fd);
++}
++
++void check_tmpexec(void)
++{
++      void *addr;
++      int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
++
++      addr = mmap(NULL, UM_KERN_PAGE_SIZE, 
++                  PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
++      printf("Checking PROT_EXEC mmap in /tmp...");
++      fflush(stdout);
++      if(addr == MAP_FAILED){
++              err = errno;
++              perror("failed");
++              if(err == EPERM)
++                      printf("/tmp must be not mounted noexec\n");
++              exit(1);
++      }
++      printf("OK\n");
++      munmap(addr, UM_KERN_PAGE_SIZE);
++}
++
++static int have_devanon(void)
++{
++      int fd;
++
++      printk("Checking for /dev/anon on the host...");
++      fd = open("/dev/anon", O_RDWR);
++      if(fd < 0){
++              printk("Not available (open failed with errno %d)\n", errno);
++              return(0);
++      }
++
++      printk("OK\n");
++      return(1);
++}
++
++static int create_anon_file(unsigned long len)
++{
++      void *addr;
++      int fd;
++
++      fd = open("/dev/anon", O_RDWR);
++      if(fd < 0) {
++              os_print_error(fd, "opening /dev/anon");
++              exit(1);
++      }
++
++      addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
++      if(addr == MAP_FAILED){
++              os_print_error((int) addr, "mapping physmem file");
++              exit(1);
++      }
++      munmap(addr, len);
++
++      return(fd);
++}
++
++int create_mem_file(unsigned long len)
++{
++      int err, fd;
++
++      if(have_devanon())
++              fd = create_anon_file(len);
++      else fd = create_tmp_file(len);
++
++      err = os_set_exec_close(fd, 1);
++      if(err < 0)
++              os_print_error(err, "exec_close");
++      return(fd);
++}
++
++struct iomem_region *iomem_regions = NULL;
++int iomem_size = 0;
++
++static int __init parse_iomem(char *str, int *add)
++{
++      struct iomem_region *new;
++      struct uml_stat buf;
++      char *file, *driver;
++      int fd, err, size;
++
++      driver = str;
++      file = strchr(str,',');
++      if(file == NULL){
++              printf("parse_iomem : failed to parse iomem\n");
++              goto out;
++      }
++      *file = '\0';
++      file++;
++      fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0);
++      if(fd < 0){
++              os_print_error(fd, "parse_iomem - Couldn't open io file");
++              goto out;
++      }
++
++      err = os_stat_fd(fd, &buf);
++      if(err < 0){
++              os_print_error(err, "parse_iomem - cannot stat_fd file");
++              goto out_close;
++      }
++
++      new = malloc(sizeof(*new));
++      if(new == NULL){
++              perror("Couldn't allocate iomem_region struct");
++              goto out_close;
++      }
++
++      size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
++
++      *new = ((struct iomem_region) { .next           = iomem_regions,
++                                      .driver         = driver,
++                                      .fd             = fd,
++                                      .size           = size,
++                                      .phys           = 0,
++                                      .virt           = 0 });
++      iomem_regions = new;
++      iomem_size += new->size + UM_KERN_PAGE_SIZE;
++
++      return(0);
++ out_close:
++      os_close_file(fd);
++ out:
++      return(1);
++}
++
++__uml_setup("iomem=", parse_iomem,
++"iomem=<name>,<file>\n"
++"    Configure <file> as an IO memory region named <name>.\n\n"
++);
++
++int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
++                 int must_succeed)
++{
++      int err;
++
++      err = os_protect_memory((void *) addr, len, r, w, x);
++      if(err < 0){
++                if(must_succeed)
++                        panic("protect failed, err = %d", -err);
++                else return(err);
++      }
++      return(0);
++}
++
++#if 0
++/* Debugging facility for dumping stuff out to the host, avoiding the timing
++ * problems that come with printf and breakpoints.
++ * Enable in case of emergency.
++ */
++
++int logging = 1;
++int logging_fd = -1;
++
++int logging_line = 0;
++char logging_buf[512];
++
++void log(char *fmt, ...)
++{
++        va_list ap;
++        struct timeval tv;
++        struct openflags flags;
++
++        if(logging == 0) return;
++        if(logging_fd < 0){
++                flags = of_create(of_trunc(of_rdwr(OPENFLAGS())));
++                logging_fd = os_open_file("log", flags, 0644);
++        }
++        gettimeofday(&tv, NULL);
++        sprintf(logging_buf, "%d\t %u.%u  ", logging_line++, tv.tv_sec, 
++                tv.tv_usec);
++        va_start(ap, fmt);
++        vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap);
++        va_end(ap);
++        write(logging_fd, logging_buf, strlen(logging_buf));
++}
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/physmem.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/physmem.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/physmem.c      2005-05-03 22:28:14.436415544 +0300
+@@ -0,0 +1,480 @@
++/* 
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "linux/rbtree.h"
++#include "linux/slab.h"
++#include "linux/vmalloc.h"
++#include "linux/bootmem.h"
++#include "asm/types.h"
++#include "asm/pgtable.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "mode_kern.h"
++#include "mem.h"
++#include "mem_user.h"
++#include "os.h"
++#include "kern.h"
++#include "init.h"
++
++struct phys_desc {
++      struct rb_node_s rb;
++      int fd;
++      __u64 offset;
++      void *virt;
++      unsigned long phys;
++      struct list_head list;
++};
++
++static struct rb_root_s phys_mappings = RB_ROOT;
++
++static struct rb_node_s **find_rb(void *virt)
++{
++      struct rb_node_s **n = &phys_mappings.rb_node;
++      struct phys_desc *d;
++
++      while(*n != NULL){
++              d = rb_entry(n, struct phys_desc, rb);
++              if(d->virt == virt)
++                      return(n);
++
++              if(d->virt > virt)
++                      n = &(*n)->rb_left;
++              else
++                      n = &(*n)->rb_right;
++      }
++
++      return(n);
++}
++
++static struct phys_desc *find_phys_mapping(void *virt)
++{
++      struct rb_node_s **n = find_rb(virt);
++
++      if(*n == NULL)
++              return(NULL);
++
++      return(rb_entry(n, struct phys_desc, rb));
++}
++
++static void insert_phys_mapping(struct phys_desc *desc)
++{
++      struct rb_node_s **n = find_rb(desc->virt);
++
++      if(*n != NULL)
++              panic("Physical remapping for %p already present", 
++                    desc->virt);
++
++      rb_link_node(&desc->rb, (*n)->rb_parent, n);
++      rb_insert_color(&desc->rb, &phys_mappings);
++}
++
++LIST_HEAD(descriptor_mappings);
++
++struct desc_mapping {
++      int fd;
++      struct list_head list;
++      struct list_head pages;
++};
++
++static struct desc_mapping *find_mapping(int fd)
++{
++      struct desc_mapping *desc;
++      struct list_head *ele;
++
++      list_for_each(ele, &descriptor_mappings){
++              desc = list_entry(ele, struct desc_mapping, list);
++              if(desc->fd == fd)
++                      return(desc);
++      }
++
++      return(NULL);
++}
++
++static struct desc_mapping *descriptor_mapping(int fd)
++{
++      struct desc_mapping *desc;
++
++      desc = find_mapping(fd);
++      if(desc != NULL)
++              return(desc);
++
++      desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
++      if(desc == NULL)
++              return(NULL);
++
++      *desc = ((struct desc_mapping) 
++              { .fd =         fd,
++                .list =       LIST_HEAD_INIT(desc->list),
++                .pages =      LIST_HEAD_INIT(desc->pages) });
++      list_add(&desc->list, &descriptor_mappings);
++
++      return(desc);
++}
++
++int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w)
++{
++      struct desc_mapping *fd_maps;
++      struct phys_desc *desc;
++      unsigned long phys;
++      int err;
++
++      phys = __pa(virt);
++      desc = find_phys_mapping(virt);
++      if(desc != NULL){
++              if((virt != desc->virt) || (fd != desc->fd) || 
++                 (offset != desc->offset))
++                      panic("Address 0x%p is already substituted\n", virt);
++              return(0);
++      }
++
++      fd_maps = descriptor_mapping(fd);
++      if(fd_maps == NULL)
++              return(-ENOMEM);
++
++      err = -ENOMEM;
++      desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
++      if(desc == NULL)
++              goto out;
++
++      *desc = ((struct phys_desc) 
++              { .fd =                 fd,
++                .offset =             offset,
++                .virt =               virt,
++                .phys =               __pa(virt),
++                .list =               LIST_HEAD_INIT(desc->list) });
++      insert_phys_mapping(desc);
++
++      list_add(&desc->list, &fd_maps->pages);
++
++      virt = (void *) ((unsigned long) virt & PAGE_MASK);
++      err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0);
++      if(!err)
++              goto out;
++
++      rb_erase(&desc->rb, &phys_mappings);
++      kfree(desc);
++ out:
++      return(err);
++}
++
++static int physmem_fd = -1;
++
++static void remove_mapping(struct phys_desc *desc)
++{
++      void *virt = desc->virt;
++      int err;
++
++      rb_erase(&desc->rb, &phys_mappings);
++      list_del(&desc->list);
++      kfree(desc);
++
++      err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0);
++      if(err)
++              panic("Failed to unmap block device page from physical memory, "
++                    "errno = %d", -err);
++}
++
++int physmem_remove_mapping(void *virt)
++{
++      struct phys_desc *desc;
++
++      virt = (void *) ((unsigned long) virt & PAGE_MASK);
++      desc = find_phys_mapping(virt);
++      if(desc == NULL)
++              return(0);
++
++      remove_mapping(desc);
++      return(1);
++}
++
++void physmem_forget_descriptor(int fd)
++{
++      struct desc_mapping *desc;
++      struct phys_desc *page;
++      struct list_head *ele, *next;
++      __u64 offset;
++      void *addr;
++      int err;
++
++      desc = find_mapping(fd);
++      if(desc == NULL)
++              return;
++
++      if(!list_empty(&desc->pages))
++              printk("Still have mapped pages on fd %d\n", fd);
++
++      list_for_each_safe(ele, next, &desc->pages){
++              page = list_entry(ele, struct phys_desc, list);
++              offset = page->offset;
++              addr = page->virt;
++              remove_mapping(page);
++              err = os_seek_file(fd, offset);
++              if(err)
++                      panic("physmem_forget_descriptor - failed to seek "
++                            "to %lld in fd %d, error = %d\n",
++                            offset, fd, -err);
++              err = os_read_file(fd, addr, PAGE_SIZE);
++              if(err < 0)
++                      panic("physmem_forget_descriptor - failed to read "
++                            "from fd %d to 0x%p, error = %d\n",
++                            fd, addr, -err);
++      }
++
++      list_del(&desc->list);
++      kfree(desc);
++}
++
++void arch_free_page(struct page *page, int order)
++{
++      void *virt;
++      int i;
++
++      for(i = 0; i < (1 << order); i++){
++              virt = __va(page_to_phys(page + i));
++              physmem_remove_mapping(virt);
++      }
++}
++
++int is_remapped(const void *virt, int fd, __u64 offset)
++{
++      struct phys_desc *desc;
++
++      desc = find_phys_mapping((void *) virt);
++      if(desc == NULL)
++              return(0);
++      if(offset != desc->offset)
++              printk("offset mismatch\n");
++      return(find_phys_mapping((void *) virt) != NULL);
++}
++
++/* Changed during early boot */
++unsigned long high_physmem;
++
++extern unsigned long physmem_size;
++
++void *to_virt(unsigned long phys)
++{
++      return((void *) uml_physmem + phys);
++}
++
++unsigned long to_phys(void *virt)
++{
++      return(((unsigned long) virt) - uml_physmem);
++}
++
++int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem)
++{
++      struct page *p, *map;
++      unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
++      unsigned long iomem_len, iomem_pages, total_len, total_pages;
++      int i;
++
++      phys_pages = physmem >> PAGE_SHIFT;
++      phys_len = phys_pages * sizeof(struct page);
++
++      iomem_pages = iomem >> PAGE_SHIFT;
++      iomem_len = iomem_pages * sizeof(struct page);
++
++      highmem_pages = highmem >> PAGE_SHIFT;
++      highmem_len = highmem_pages * sizeof(struct page);
++
++      total_pages = phys_pages + iomem_pages + highmem_pages;
++      total_len = phys_len + iomem_pages + highmem_len;
++
++      if(kmalloc_ok){
++              map = kmalloc(total_len, GFP_KERNEL);
++              if(map == NULL) 
++                      map = vmalloc(total_len);
++      }
++      else map = alloc_bootmem_low_pages(total_len);
++
++      if(map == NULL)
++              return(-ENOMEM);
++
++      for(i = 0; i < total_pages; i++){
++              p = &map[i];
++              set_page_count(p, 0);
++              SetPageReserved(p);
++              INIT_LIST_HEAD(&p->list);
++      }
++
++      mem_map = map;
++      max_mapnr = total_pages;
++      return(0);
++}
++
++struct page *phys_to_page(const unsigned long phys)
++{
++      return(&mem_map[phys >> PAGE_SHIFT]);
++}
++
++struct page *__virt_to_page(const unsigned long virt)
++{
++      return(&mem_map[__pa(virt) >> PAGE_SHIFT]);
++}
++
++unsigned long page_to_phys(struct page *page)
++{
++      return((page - mem_map) << PAGE_SHIFT);
++}
++
++pte_t mk_pte(struct page *page, pgprot_t pgprot)
++{
++      pte_t pte;
++
++      pte_val(pte) = page_to_phys(page) + pgprot_val(pgprot);
++      if(pte_present(pte)) pte_mknewprot(pte_mknewpage(pte));
++      return(pte);
++}
++
++/* Changed during early boot */
++static unsigned long kmem_top = 0;
++
++unsigned long get_kmem_end(void)
++{
++      if(kmem_top == 0) 
++              kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
++      return(kmem_top);
++}
++
++void map_memory(unsigned long virt, unsigned long phys, unsigned long len, 
++              int r, int w, int x)
++{
++      __u64 offset;
++      int fd, err;
++
++      fd = phys_mapping(phys, &offset);
++      err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
++      if(err)
++              panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
++                    "err = %d\n", virt, fd, offset, len, r, w, x, err);
++}
++
++#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
++
++void setup_physmem(unsigned long start, unsigned long reserve_end,
++                 unsigned long len, unsigned long highmem)
++{
++      unsigned long reserve = reserve_end - start;
++      int pfn = PFN_UP(__pa(reserve_end));
++      int delta = (len - reserve) >> PAGE_SHIFT;
++      int err, offset, bootmap_size;
++
++      physmem_fd = create_mem_file(len + highmem);
++
++      offset = uml_reserved - uml_physmem;
++      err = os_map_memory((void *) uml_reserved, physmem_fd, offset, 
++                          len - offset, 1, 1, 0);
++      if(err < 0){
++              os_print_error(err, "Mapping memory");
++              exit(1);
++      }
++
++      bootmap_size = init_bootmem(pfn, pfn + delta);
++      free_bootmem(__pa(reserve_end) + bootmap_size,
++                   len - bootmap_size - reserve);
++}
++
++int phys_mapping(unsigned long phys, __u64 *offset_out)
++{
++      struct phys_desc *desc = find_phys_mapping(__va(phys & PAGE_MASK));
++      int fd = -1;
++
++      if(desc != NULL){
++              fd = desc->fd;
++              *offset_out = desc->offset;
++      }
++      else if(phys < physmem_size){
++              fd = physmem_fd;
++              *offset_out = phys;
++      }
++      else if(phys < __pa(end_iomem)){
++              struct iomem_region *region = iomem_regions;
++      
++              while(region != NULL){
++                      if((phys >= region->phys) && 
++                         (phys < region->phys + region->size)){
++                              fd = region->fd;
++                              *offset_out = phys - region->phys;
++                              break;
++                      }
++                      region = region->next;
++              }
++      }
++      else if(phys < __pa(end_iomem) + highmem){
++              fd = physmem_fd;
++              *offset_out = phys - iomem_size;
++      }
++
++      return(fd);
++}
++
++static int __init uml_mem_setup(char *line, int *add)
++{
++      char *retptr;
++      physmem_size = memparse(line,&retptr);
++      return 0;
++}
++__uml_setup("mem=", uml_mem_setup,
++"mem=<Amount of desired ram>\n"
++"    This controls how much \"physical\" memory the kernel allocates\n"
++"    for the system. The size is specified as a number followed by\n"
++"    one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
++"    This is not related to the amount of memory in the host.  It can\n"
++"    be more, and the excess, if it's ever used, will just be swapped out.\n"
++"     Example: mem=64M\n\n"
++);
++
++unsigned long find_iomem(char *driver, unsigned long *len_out)
++{
++      struct iomem_region *region = iomem_regions;
++      
++      while(region != NULL){
++              if(!strcmp(region->driver, driver)){
++                      *len_out = region->size;
++                      return(region->virt);
++              }
++      }
++
++      return(0);
++}
++
++int setup_iomem(void)
++{
++      struct iomem_region *region = iomem_regions;
++      unsigned long iomem_start = high_physmem + PAGE_SIZE;
++      int err;
++
++      while(region != NULL){
++              err = os_map_memory((void *) iomem_start, region->fd, 0, 
++                                  region->size, 1, 1, 0);
++              if(err)
++                      printk("Mapping iomem region for driver '%s' failed, "
++                             "errno = %d\n", region->driver, -err);
++              else {
++                      region->virt = iomem_start;
++                      region->phys = __pa(region->virt);
++              }
++
++              iomem_start += region->size + PAGE_SIZE;
++              region = region->next;
++      }
++
++      return(0);
++}
++
++__initcall(setup_iomem);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/process.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/process.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/process.c      2005-05-03 22:28:14.437415392 +0300
+@@ -0,0 +1,310 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <signal.h>
++#include <sched.h>
++#include <errno.h>
++#include <stdarg.h>
++#include <stdlib.h>
++#include <setjmp.h>
++#include <sys/time.h>
++#include <sys/ptrace.h>
++#include <sys/wait.h>
++#include <sys/mman.h>
++#include <asm/ptrace.h>
++#include <asm/sigcontext.h>
++#include <asm/unistd.h>
++#include <asm/page.h>
++#include <asm/user.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "process.h"
++#include "signal_kern.h"
++#include "signal_user.h"
++#include "sysdep/ptrace.h"
++#include "sysdep/sigcontext.h"
++#include "irq_user.h"
++#include "ptrace_user.h"
++#include "time_user.h"
++#include "init.h"
++#include "os.h"
++#include "uml-config.h"
++#include "choose-mode.h"
++#include "mode.h"
++#ifdef UML_CONFIG_MODE_SKAS
++#include "skas.h"
++#include "skas_ptrace.h"
++#endif
++
++void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
++{
++      int flags = 0, pages;
++
++      if(sig_stack != NULL){
++              pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER);
++              set_sigstack(sig_stack, pages * page_size());
++              flags = SA_ONSTACK;
++      }
++      if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
++}
++
++void init_new_thread_signals(int altstack)
++{
++      int flags = altstack ? SA_ONSTACK : 0;
++
++      set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags, 
++                  SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++      set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, 
++                  SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++      set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, 
++                  SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++      set_handler(SIGILL, (__sighandler_t) sig_handler, flags, 
++                  SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++      set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, 
++                  SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++      set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, 
++                  SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++      set_handler(SIGUSR2, (__sighandler_t) sig_handler, 
++                  flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
++      signal(SIGHUP, SIG_IGN);
++
++      init_irq_signals(altstack);
++}
++
++struct tramp {
++      int (*tramp)(void *);
++      void *tramp_data;
++      unsigned long temp_stack;
++      int flags;
++      int pid;
++};
++
++/* See above for why sigkill is here */
++
++int sigkill = SIGKILL;
++
++int outer_tramp(void *arg)
++{
++      struct tramp *t;
++      int sig = sigkill;
++
++      t = arg;
++      t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
++                     t->flags, t->tramp_data);
++      if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL);
++      kill(os_getpid(), sig);
++      _exit(0);
++}
++
++int start_fork_tramp(void *thread_arg, unsigned long temp_stack, 
++                   int clone_flags, int (*tramp)(void *))
++{
++      struct tramp arg;
++      unsigned long sp;
++      int new_pid, status, err;
++
++      /* The trampoline will run on the temporary stack */
++      sp = stack_sp(temp_stack);
++
++      clone_flags |= CLONE_FILES | SIGCHLD;
++
++      arg.tramp = tramp;
++      arg.tramp_data = thread_arg;
++      arg.temp_stack = temp_stack;
++      arg.flags = clone_flags;
++
++      /* Start the process and wait for it to kill itself */
++      new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
++      if(new_pid < 0) 
++              return(new_pid);
++
++      CATCH_EINTR(err = waitpid(new_pid, &status, 0));
++      if(err < 0) 
++              panic("Waiting for outer trampoline failed - errno = %d", 
++                    errno);
++
++      if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
++              panic("outer trampoline didn't exit with SIGKILL, "
++                    "status = %d", status);
++
++      return(arg.pid);
++}
++
++static int ptrace_child(void *arg)
++{
++      int pid = os_getpid();
++
++      if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
++              perror("ptrace");
++              os_kill_process(pid, 0);
++      }
++      os_stop_process(pid);
++      _exit(os_getpid() == pid);
++}
++
++static int start_ptraced_child(void **stack_out)
++{
++      void *stack;
++      unsigned long sp;
++      int pid, n, status;
++      
++      stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
++                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
++      if(stack == MAP_FAILED)
++              panic("check_ptrace : mmap failed, errno = %d", errno);
++      sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
++      pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
++      if(pid < 0)
++              panic("check_ptrace : clone failed, errno = %d", errno);
++      CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
++      if(n < 0)
++              panic("check_ptrace : wait failed, errno = %d", errno);
++      if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
++              panic("check_ptrace : expected SIGSTOP, got status = %d",
++                    status);
++
++      *stack_out = stack;
++      return(pid);
++}
++
++static void stop_ptraced_child(int pid, void *stack, int exitcode)
++{
++      int status, n;
++
++      if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
++              panic("check_ptrace : ptrace failed, errno = %d", errno);
++      CATCH_EINTR(n = waitpid(pid, &status, 0));
++      if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode))
++              panic("check_ptrace : child exited with status 0x%x", status);
++
++      if(munmap(stack, PAGE_SIZE) < 0)
++              panic("check_ptrace : munmap failed, errno = %d", errno);
++}
++
++int use_sysemu = 0;
++
++void __init check_ptrace(void)
++{
++      void *stack;
++      int pid, syscall, n, status;
++
++      printk("Checking that ptrace can change system call numbers...");
++      pid = start_ptraced_child(&stack);
++
++      while(1){
++              if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
++                      panic("check_ptrace : ptrace failed, errno = %d", 
++                            errno);
++              CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
++              if(n < 0)
++                      panic("check_ptrace : wait failed, errno = %d", errno);
++              if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
++                      panic("check_ptrace : expected SIGTRAP, "
++                            "got status = %d", status);
++              
++              syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
++                               0);
++              if(syscall == __NR_getpid){
++                      n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
++                                 __NR_getppid);
++                      if(n < 0)
++                              panic("check_ptrace : failed to modify system "
++                                    "call, errno = %d", errno);
++                      break;
++              }
++      }
++      stop_ptraced_child(pid, stack, 0);
++      printk("OK\n");
++
++      printk("Checking syscall emulation patch for ptrace...");
++      pid = start_ptraced_child(&stack);
++      if(ptrace(PTRACE_SYSEMU, pid, 0, 0) >= 0) {
++              CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
++              if(n < 0)
++                      panic("check_ptrace : wait failed, errno = %d", errno);
++
++              if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
++                      panic("check_ptrace : expected SIGTRAP, "
++                            "got status = %d", status);
++
++              
++              n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
++                         os_getpid());
++              if(n < 0)
++                      panic("check_ptrace : failed to modify system "
++                            "call return, errno = %d", errno);
++
++              stop_ptraced_child(pid, stack, 0);
++
++              printk("OK\n");
++              use_sysemu = 1;
++      }
++      else {
++              printk("missing\n");
++              stop_ptraced_child(pid, stack, 1);
++      }
++}
++
++int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
++{
++      sigjmp_buf buf;
++      int n;
++
++      *jmp_ptr = &buf;
++      n = sigsetjmp(buf, 1);
++      if(n != 0)
++              return(n);
++      (*fn)(arg);
++      return(0);
++}
++
++int can_do_skas(void)
++{
++#ifdef UML_CONFIG_MODE_SKAS
++      struct ptrace_faultinfo fi;
++      void *stack;
++      int pid, n, ret = 1;
++
++      printf("Checking for the skas3 patch in the host...");
++      pid = start_ptraced_child(&stack);
++
++      n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
++      if(n < 0){
++              if(errno == EIO)
++                      printf("not found\n");
++              else printf("No (unexpected errno - %d)\n", errno);
++              ret = 0;
++      }
++      else printf("found\n");
++
++      init_registers(pid);
++      stop_ptraced_child(pid, stack, 1);
++
++      printf("Checking for /proc/mm...");
++      if(os_access("/proc/mm", OS_ACC_W_OK) < 0){
++              printf("not found\n");
++              ret = 0;
++      }
++      else printf("found\n");
++
++      return(ret);
++#else
++      return(0);
++#endif
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/process_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/process_kern.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/process_kern.c 2005-05-03 22:28:14.439415088 +0300
+@@ -0,0 +1,413 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/kernel.h"
++#include "linux/sched.h"
++#include "linux/interrupt.h"
++#include "linux/mm.h"
++#include "linux/slab.h"
++#include "linux/utsname.h"
++#include "linux/fs.h"
++#include "linux/utime.h"
++#include "linux/smp_lock.h"
++#include "linux/module.h"
++#include "linux/init.h"
++#include "linux/capability.h"
++#include "linux/vmalloc.h"
++#include "linux/ptrace.h"
++#include "asm/unistd.h"
++#include "asm/mman.h"
++#include "asm/segment.h"
++#include "asm/stat.h"
++#include "asm/pgtable.h"
++#include "asm/processor.h"
++#include "asm/pgalloc.h"
++#include "asm/spinlock.h"
++#include "asm/uaccess.h"
++#include "asm/user.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "signal_kern.h"
++#include "signal_user.h"
++#include "init.h"
++#include "irq_user.h"
++#include "mem_user.h"
++#include "time_user.h"
++#include "tlb.h"
++#include "frame_kern.h"
++#include "sigcontext.h"
++#include "2_5compat.h"
++#include "os.h"
++#include "mode.h"
++#include "mode_kern.h"
++#include "choose-mode.h"
++
++/* This is a per-cpu array.  A processor only modifies its entry and it only
++ * cares about its entry, so it's OK if another processor is modifying its
++ * entry.
++ */
++struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
++
++struct task_struct *get_task(int pid, int require)
++{
++        struct task_struct *ret;
++
++        read_lock(&tasklist_lock);
++      ret = find_task_by_pid(pid);
++        read_unlock(&tasklist_lock);
++
++        if(require && (ret == NULL)) panic("get_task couldn't find a task\n");
++        return(ret);
++}
++
++int external_pid(void *t)
++{
++      struct task_struct *task = t ? t : current;
++
++      return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task));
++}
++
++int pid_to_processor_id(int pid)
++{
++      int i;
++
++      for(i = 0; i < smp_num_cpus; i++){
++              if(cpu_tasks[i].pid == pid) return(i);
++      }
++      return(-1);
++}
++
++void free_stack(unsigned long stack, int order)
++{
++      free_pages(stack, order);
++}
++
++unsigned long alloc_stack(int order, int atomic)
++{
++      unsigned long page;
++      int flags = GFP_KERNEL;
++
++      if(atomic) flags |= GFP_ATOMIC;
++      page = __get_free_pages(flags, order);
++      if(page == 0)
++              return(0);
++      stack_protections(page);
++      return(page);
++}
++
++int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
++{
++      int pid;
++
++      current->thread.request.u.thread.proc = fn;
++      current->thread.request.u.thread.arg = arg;
++      pid = do_fork(CLONE_VM | flags, 0, NULL, 0);
++#if 0 /* CLONE_UNTRACED for 2.6 */
++      pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, NULL, 0);
++#endif
++      if(pid < 0) 
++              panic("do_fork failed in kernel_thread, errno = %d", pid);
++      return(pid);
++}
++
++void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
++             struct task_struct *tsk, unsigned cpu)
++{
++      if (prev != next) 
++              clear_bit(cpu, &prev->cpu_vm_mask);
++      set_bit(cpu, &next->cpu_vm_mask);
++}
++
++void set_current(void *t)
++{
++      struct task_struct *task = t;
++
++      cpu_tasks[task->processor] = ((struct cpu_task) 
++              { external_pid(task), task });
++}
++
++void *_switch_to(void *prev, void *next)
++{
++      return(CHOOSE_MODE(_switch_to_tt(prev, next), 
++                         _switch_to_skas(prev, next)));
++}
++
++void interrupt_end(void)
++{
++      if(current->need_resched) schedule();
++      if(current->sigpending != 0) do_signal(0);
++}
++
++void release_thread(struct task_struct *task)
++{
++      CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task));
++}
++
++void exit_thread(void)
++{
++      CHOOSE_MODE(exit_thread_tt(), exit_thread_skas());
++      unprotect_stack((unsigned long) current);
++}
++
++void *get_current(void)
++{
++      return(current);
++}
++
++int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
++              unsigned long stack_top, struct task_struct * p, 
++              struct pt_regs *regs)
++{
++      p->thread = (struct thread_struct) INIT_THREAD;
++      return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, 
++                              clone_flags, sp, stack_top, p, regs));
++}
++
++void initial_thread_cb(void (*proc)(void *), void *arg)
++{
++      int save_kmalloc_ok = kmalloc_ok;
++
++      kmalloc_ok = 0;
++      CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc, 
++                       arg);
++      kmalloc_ok = save_kmalloc_ok;
++}
++
++unsigned long stack_sp(unsigned long page)
++{
++      return(page + PAGE_SIZE - sizeof(void *));
++}
++
++int current_pid(void)
++{
++      return(current->pid);
++}
++
++void cpu_idle(void)
++{
++      CHOOSE_MODE(init_idle_tt(), init_idle_skas());
++
++      atomic_inc(&init_mm.mm_count);
++      current->mm = &init_mm;
++      current->active_mm = &init_mm;
++
++      while(1){
++              /* endless idle loop with no priority at all */
++              SET_PRI(current);
++
++              /*
++               * although we are an idle CPU, we do not want to
++               * get into the scheduler unnecessarily.
++               */
++              if (current->need_resched) {
++                      schedule();
++                      check_pgt_cache();
++              }
++              idle_sleep(10);
++      }
++}
++
++int page_size(void)
++{
++      return(PAGE_SIZE);
++}
++
++int page_mask(void)
++{
++      return(PAGE_MASK);
++}
++
++void *um_virt_to_phys(struct task_struct *task, unsigned long addr, 
++                    pte_t *pte_out)
++{
++      pgd_t *pgd;
++      pmd_t *pmd;
++      pte_t *pte;
++
++      if(task->mm == NULL) 
++              return(ERR_PTR(-EINVAL));
++      pgd = pgd_offset(task->mm, addr);
++      pmd = pmd_offset(pgd, addr);
++      if(!pmd_present(*pmd)) 
++              return(ERR_PTR(-EINVAL));
++      pte = pte_offset(pmd, addr);
++      if(!pte_present(*pte)) 
++              return(ERR_PTR(-EINVAL));
++      if(pte_out != NULL)
++              *pte_out = *pte;
++      return((void *) (pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK));
++}
++
++char *current_cmd(void)
++{
++#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
++      return("(Unknown)");
++#else
++      void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL);
++      return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr);
++#endif
++}
++
++void force_sigbus(void)
++{
++      printk(KERN_ERR "Killing pid %d because of a lack of memory\n", 
++             current->pid);
++      lock_kernel();
++      sigaddset(&current->pending.signal, SIGBUS);
++      recalc_sigpending(current);
++      current->flags |= PF_SIGNALED;
++      do_exit(SIGBUS | 0x80);
++}
++
++void dump_thread(struct pt_regs *regs, struct user *u)
++{
++}
++
++void enable_hlt(void)
++{
++      panic("enable_hlt");
++}
++
++void disable_hlt(void)
++{
++      panic("disable_hlt");
++}
++
++extern int signal_frame_size;
++
++void *um_kmalloc(int size)
++{
++      return(kmalloc(size, GFP_KERNEL));
++}
++
++void *um_kmalloc_atomic(int size)
++{
++      return(kmalloc(size, GFP_ATOMIC));
++}
++
++void *um_vmalloc(int size)
++{
++      return(vmalloc(size));
++}
++
++unsigned long get_fault_addr(void)
++{
++      return((unsigned long) current->thread.fault_addr);
++}
++
++EXPORT_SYMBOL(get_fault_addr);
++
++void not_implemented(void)
++{
++      printk(KERN_DEBUG "Something isn't implemented in here\n");
++}
++
++EXPORT_SYMBOL(not_implemented);
++
++int user_context(unsigned long sp)
++{
++      unsigned long stack;
++
++      stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
++      return(stack != current);
++}
++
++extern void remove_umid_dir(void);
++
++__uml_exitcall(remove_umid_dir);
++
++extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
++
++void do_uml_exitcalls(void)
++{
++      exitcall_t *call;
++
++      call = &__uml_exitcall_end;
++      while (--call >= &__uml_exitcall_begin)
++              (*call)();
++}
++
++char *uml_strdup(char *string)
++{
++      char *new;
++
++      new = kmalloc(strlen(string) + 1, GFP_KERNEL);
++      if(new == NULL) return(NULL);
++      strcpy(new, string);
++      return(new);
++}
++
++void *get_init_task(void)
++{
++      return(&init_task_union.task);
++}
++
++int copy_to_user_proc(void *to, void *from, int size)
++{
++      return(copy_to_user(to, from, size));
++}
++
++int copy_from_user_proc(void *to, void *from, int size)
++{
++      return(copy_from_user(to, from, size));
++}
++
++int clear_user_proc(void *buf, int size)
++{
++      return(clear_user(buf, size));
++}
++
++int strlen_user_proc(char *str)
++{
++      return(strlen_user(str));
++}
++
++int smp_sigio_handler(void)
++{
++#ifdef CONFIG_SMP
++      int cpu = current->processor;
++
++      IPI_handler(cpu);
++      if(cpu != 0)
++              return(1);
++#endif
++      return(0);
++}
++
++int um_in_interrupt(void)
++{
++      return(in_interrupt());
++}
++
++int cpu(void)
++{
++        return(current->processor);
++}
++
++int singlestepping(void * t)
++{
++      struct task_struct *task = t ? t : current;
++
++      if ( ! (task->ptrace & PT_DTRACE) )
++              return(0);
++
++      if (task->thread.singlestep_syscall)
++              return(0);
++
++      return 1;
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/ptrace.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/ptrace.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/ptrace.c       2005-05-03 22:28:14.441414784 +0300
+@@ -0,0 +1,341 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/mm.h"
++#include "linux/errno.h"
++#include "linux/smp_lock.h"
++#ifdef CONFIG_PROC_MM
++#include "linux/proc_mm.h"
++#endif
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++#include "kern_util.h"
++#include "ptrace_user.h"
++
++/*
++ * Called by kernel/ptrace.c when detaching..
++ */
++void ptrace_disable(struct task_struct *child)
++{ 
++      child->ptrace &= ~PT_DTRACE;
++      child->thread.singlestep_syscall = 0;
++}
++
++extern long do_mmap2(struct task_struct *task, unsigned long addr, 
++                   unsigned long len, unsigned long prot, 
++                   unsigned long flags, unsigned long fd,
++                   unsigned long pgoff);
++
++int sys_ptrace(long request, long pid, long addr, long data)
++{
++      struct task_struct *child;
++      int i, ret;
++
++      lock_kernel();
++      ret = -EPERM;
++      if (request == PTRACE_TRACEME) {
++              /* are we already being traced? */
++              if (current->ptrace & PT_PTRACED)
++                      goto out;
++              /* set the ptrace bit in the process flags. */
++              current->ptrace |= PT_PTRACED;
++              ret = 0;
++              goto out;
++      }
++      ret = -ESRCH;
++      read_lock(&tasklist_lock);
++      child = find_task_by_pid(pid);
++      if (child)
++              get_task_struct(child);
++      read_unlock(&tasklist_lock);
++      if (!child)
++              goto out;
++
++      ret = -EPERM;
++      if (pid == 1)           /* you may not mess with init */
++              goto out_tsk;
++
++      if (request == PTRACE_ATTACH) {
++              ret = ptrace_attach(child);
++              goto out_tsk;
++      }
++
++      ret = ptrace_check_attach(child, request == PTRACE_KILL);
++      if (ret < 0)
++              goto out_tsk;
++
++      switch (request) {
++              /* when I and D space are separate, these will need to be fixed. */
++      case PTRACE_PEEKTEXT: /* read word at location addr. */ 
++      case PTRACE_PEEKDATA: {
++              unsigned long tmp;
++              int copied;
++
++              ret = -EIO;
++              copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
++              if (copied != sizeof(tmp))
++                      break;
++              ret = put_user(tmp,(unsigned long *) data);
++              break;
++      }
++
++      /* read the word at location addr in the USER area. */
++      case PTRACE_PEEKUSR: {
++              unsigned long tmp;
++
++              ret = -EIO;
++              if ((addr & 3) || addr < 0) 
++                      break;
++
++              tmp = 0;  /* Default return condition */
++              if(addr < FRAME_SIZE_OFFSET){
++                      tmp = getreg(child, addr);
++              }
++              else if((addr >= offsetof(struct user, u_debugreg[0])) &&
++                      (addr <= offsetof(struct user, u_debugreg[7]))){
++                      addr -= offsetof(struct user, u_debugreg[0]);
++                      addr = addr >> 2;
++                      tmp = child->thread.arch.debugregs[addr];
++              }
++              ret = put_user(tmp, (unsigned long *) data);
++              break;
++      }
++
++      /* when I and D space are separate, this will have to be fixed. */
++      case PTRACE_POKETEXT: /* write the word at location addr. */
++      case PTRACE_POKEDATA:
++              ret = -EIO;
++              if (access_process_vm(child, addr, &data, sizeof(data), 
++                                    1) != sizeof(data))
++                      break;
++              ret = 0;
++              break;
++
++      case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
++              ret = -EIO;
++              if ((addr & 3) || addr < 0)
++                      break;
++
++              if (addr < FRAME_SIZE_OFFSET) {
++                      ret = putreg(child, addr, data);
++                      break;
++              }
++              else if((addr >= offsetof(struct user, u_debugreg[0])) &&
++                      (addr <= offsetof(struct user, u_debugreg[7]))){
++                        addr -= offsetof(struct user, u_debugreg[0]);
++                        addr = addr >> 2;
++                        if((addr == 4) || (addr == 5)) break;
++                        child->thread.arch.debugregs[addr] = data;
++                        ret = 0;
++              }
++
++              break;
++
++      case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
++      case PTRACE_CONT: { /* restart after signal. */
++              ret = -EIO;
++              if ((unsigned long) data > _NSIG)
++                      break;
++
++              child->ptrace &= ~PT_DTRACE;
++              child->thread.singlestep_syscall = 0;
++
++              if (request == PTRACE_SYSCALL)
++                      child->ptrace |= PT_TRACESYS;
++              else
++                      child->ptrace &= ~PT_TRACESYS;
++              child->exit_code = data;
++              wake_up_process(child);
++              ret = 0;
++              break;
++      }
++
++/*
++ * make the child exit.  Best I can do is send it a sigkill. 
++ * perhaps it should be put in the status that it wants to 
++ * exit.
++ */
++      case PTRACE_KILL: {
++              ret = 0;
++              if (child->state == TASK_ZOMBIE)        /* already dead */
++                      break;
++
++              child->ptrace &= ~PT_DTRACE;
++              child->thread.singlestep_syscall = 0;
++              child->exit_code = SIGKILL;
++              wake_up_process(child);
++              break;
++      }
++
++      case PTRACE_SINGLESTEP: {  /* set the trap flag. */
++              ret = -EIO;
++              if ((unsigned long) data > _NSIG)
++                      break;
++              child->ptrace &= ~PT_TRACESYS;
++              child->ptrace |= PT_DTRACE;
++              child->thread.singlestep_syscall = 0;
++              child->exit_code = data;
++              /* give it a chance to run. */
++              wake_up_process(child);
++              ret = 0;
++              break;
++      }
++
++      case PTRACE_DETACH:
++              /* detach a process that was attached. */
++              ret = ptrace_detach(child, data);
++              break;
++
++#ifdef PTRACE_GETREGS
++      case PTRACE_GETREGS: { /* Get all gp regs from the child. */
++              if (!access_ok(VERIFY_WRITE, (unsigned long *)data, 
++                             FRAME_SIZE_OFFSET)) {
++                      ret = -EIO;
++                      break;
++              }
++              for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) {
++                      __put_user(getreg(child, i), (unsigned long *) data);
++                      data += sizeof(long);
++              }
++              ret = 0;
++              break;
++      }
++#endif
++#ifdef PTRACE_SETREGS
++      case PTRACE_SETREGS: { /* Set all gp regs in the child. */
++              unsigned long tmp = 0;
++              if (!access_ok(VERIFY_READ, (unsigned *)data, 
++                             FRAME_SIZE_OFFSET)) {
++                      ret = -EIO;
++                      break;
++              }
++              for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) {
++                      __get_user(tmp, (unsigned long *) data);
++                      putreg(child, i, tmp);
++                      data += sizeof(long);
++              }
++              ret = 0;
++              break;
++      }
++#endif
++#ifdef PTRACE_GETFPREGS
++      case PTRACE_GETFPREGS: /* Get the child FPU state. */
++              ret = get_fpregs(data, child);
++              break;
++#endif
++#ifdef PTRACE_SETFPREGS
++      case PTRACE_SETFPREGS: /* Set the child FPU state. */
++              ret = set_fpregs(data, child);
++              break;
++#endif
++#ifdef PTRACE_GETFPXREGS
++      case PTRACE_GETFPXREGS: /* Get the child FPU state. */
++              ret = get_fpxregs(data, child);
++              break;
++#endif
++#ifdef PTRACE_SETFPXREGS
++      case PTRACE_SETFPXREGS: /* Set the child FPU state. */
++              ret = set_fpxregs(data, child);
++              break;
++#endif
++      case PTRACE_FAULTINFO: {
++              struct ptrace_faultinfo fault;
++
++              fault = ((struct ptrace_faultinfo) 
++                      { .is_write     = child->thread.err,
++                        .addr         = child->thread.cr2 });
++              ret = copy_to_user((unsigned long *) data, &fault, 
++                                 sizeof(fault));
++              if(ret)
++                      break;
++              break;
++      }
++      case PTRACE_SIGPENDING:
++              ret = copy_to_user((unsigned long *) data, 
++                                 &child->pending.signal,
++                                 sizeof(child->pending.signal));
++              break;
++
++      case PTRACE_LDT: {
++              struct ptrace_ldt ldt;
++
++              if(copy_from_user(&ldt, (unsigned long *) data, 
++                                sizeof(ldt))){
++                      ret = -EIO;
++                      break;
++              }
++
++              /* This one is confusing, so just punt and return -EIO for 
++               * now
++               */
++              ret = -EIO;
++              break;
++      }
++#ifdef CONFIG_PROC_MM
++      case PTRACE_SWITCH_MM: {
++              struct mm_struct *old = child->mm;
++              struct mm_struct *new = proc_mm_get_mm(data);
++
++              if(IS_ERR(new)){
++                      ret = PTR_ERR(new);
++                      break;
++              }
++
++              atomic_inc(&new->mm_users);
++              child->mm = new;
++              child->active_mm = new;
++              mmput(old);
++              ret = 0;
++              break;
++      }
++#endif
++      default:
++              ret = -EIO;
++              break;
++      }
++ out_tsk:
++      free_task_struct(child);
++ out:
++      unlock_kernel();
++      return ret;
++}
++
++void syscall_trace(void)
++{
++      int is_singlestep = (current->ptrace & PT_DTRACE);
++
++      if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
++          != (PT_PTRACED|PT_TRACESYS) && !is_singlestep)
++              return;
++      current->exit_code = SIGTRAP;
++      current->state = TASK_STOPPED;
++      notify_parent(current, SIGCHLD);
++
++      schedule();
++      /*
++       * this isn't the same as continuing with a signal, but it will do
++       * for normal use.  strace only continues with a signal if the
++       * stopping signal is not SIGTRAP.  -brl
++       */
++      if (current->exit_code) {
++              send_sig(current->exit_code, current, 1);
++              current->exit_code = 0;
++      }
++
++      if(is_syscall(PT_REGS_IP(&current->thread.regs)))
++              current->thread.singlestep_syscall = 1;
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/reboot.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/reboot.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/reboot.c       2005-05-03 22:28:14.441414784 +0300
+@@ -0,0 +1,73 @@
++/* 
++ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "os.h"
++#include "mode.h"
++#include "choose-mode.h"
++
++#ifdef CONFIG_SMP
++static void kill_idlers(int me)
++{
++#ifdef CONFIG_MODE_TT
++      struct task_struct *p;
++      int i;
++
++      for(i = 0; i < sizeof(init_tasks)/sizeof(init_tasks[0]); i++){
++              p = init_tasks[i];
++              if((p != NULL) && (p->thread.mode.tt.extern_pid != me) &&
++                 (p->thread.mode.tt.extern_pid != -1))
++                      os_kill_process(p->thread.mode.tt.extern_pid, 0);
++      }
++#endif
++}
++#endif
++
++static void kill_off_processes(void)
++{
++      CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas());
++#ifdef CONFIG_SMP
++      kill_idlers(os_getpid());
++#endif
++}
++
++void uml_cleanup(void)
++{
++      kill_off_processes();
++      do_uml_exitcalls();
++}
++
++void machine_restart(char * __unused)
++{
++      do_uml_exitcalls();
++      kill_off_processes();
++      CHOOSE_MODE(reboot_tt(), reboot_skas());
++}
++
++void machine_power_off(void)
++{
++      do_uml_exitcalls();
++      kill_off_processes();
++      CHOOSE_MODE(halt_tt(), halt_skas());
++}
++
++void machine_halt(void)
++{
++      machine_power_off();
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/resource.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/resource.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/resource.c     2005-05-03 22:28:14.442414632 +0300
+@@ -0,0 +1,23 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/pci.h"
++
++unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
++                           unsigned long start, unsigned long size)
++{
++      return start;
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/sigio_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/sigio_kern.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/sigio_kern.c   2005-05-03 22:28:14.443414480 +0300
+@@ -0,0 +1,61 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "linux/list.h"
++#include "linux/slab.h"
++#include "asm/irq.h"
++#include "init.h"
++#include "sigio.h"
++#include "irq_user.h"
++#include "irq_kern.h"
++
++/* Protected by sigio_lock() called from write_sigio_workaround */
++static int sigio_irq_fd = -1;
++
++static void sigio_interrupt(int irq, void *data, struct pt_regs *unused)
++{
++      read_sigio_fd(sigio_irq_fd);
++      reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ);
++}
++
++int write_sigio_irq(int fd)
++{
++      int err;
++
++      err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
++                           SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", 
++                           NULL);
++      if(err){
++              printk("write_sigio_irq : um_request_irq failed, err = %d\n",
++                     err);
++              return(-1);
++      }
++      sigio_irq_fd = fd;
++      return(0);
++}
++
++static spinlock_t sigio_spinlock = SPIN_LOCK_UNLOCKED;
++
++void sigio_lock(void)
++{
++      spin_lock(&sigio_spinlock);
++}
++
++void sigio_unlock(void)
++{
++      spin_unlock(&sigio_spinlock);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/sigio_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/sigio_user.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/sigio_user.c   2005-05-03 22:28:14.445414176 +0300
+@@ -0,0 +1,436 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdlib.h>
++#include <termios.h>
++#include <pty.h>
++#include <signal.h>
++#include <errno.h>
++#include <string.h>
++#include <sched.h>
++#include <sys/socket.h>
++#include <sys/poll.h>
++#include "init.h"
++#include "user.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "sigio.h"
++#include "helper.h"
++#include "os.h"
++
++/* Changed during early boot */
++int pty_output_sigio = 0;
++int pty_close_sigio = 0;
++
++/* Used as a flag during SIGIO testing early in boot */
++static volatile int got_sigio = 0;
++
++void __init handler(int sig)
++{
++      got_sigio = 1;
++}
++
++struct openpty_arg {
++      int master;
++      int slave;
++      int err;
++};
++
++static void openpty_cb(void *arg)
++{
++      struct openpty_arg *info = arg;
++
++      info->err = 0;
++      if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
++              info->err = -errno;
++}
++
++void __init check_one_sigio(void (*proc)(int, int))
++{
++      struct sigaction old, new;
++      struct openpty_arg pty = { .master = -1, .slave = -1 };
++      int master, slave, err;
++
++      initial_thread_cb(openpty_cb, &pty);
++      if(pty.err){
++              printk("openpty failed, errno = %d\n", -pty.err);
++              return;
++      }
++
++      master = pty.master;
++      slave = pty.slave;
++
++      if((master == -1) || (slave == -1)){
++              printk("openpty failed to allocate a pty\n");
++              return;
++      }
++
++      /* Not now, but complain so we now where we failed. */
++      err = raw(master);
++      if (err < 0)
++              panic("check_sigio : __raw failed, errno = %d\n", -err);
++
++      err = os_sigio_async(master, slave);
++      if(err < 0)
++              panic("tty_fds : sigio_async failed, err = %d\n", -err);
++
++      if(sigaction(SIGIO, NULL, &old) < 0)
++              panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
++      new = old;
++      new.sa_handler = handler;
++      if(sigaction(SIGIO, &new, NULL) < 0)
++              panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
++
++      got_sigio = 0;
++      (*proc)(master, slave);
++              
++      os_close_file(master);
++      os_close_file(slave);
++
++      if(sigaction(SIGIO, &old, NULL) < 0)
++              panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
++}
++
++static void tty_output(int master, int slave)
++{
++      int n;
++      char buf[512];
++
++      printk("Checking that host ptys support output SIGIO...");
++
++      memset(buf, 0, sizeof(buf));
++
++      while(os_write_file(master, buf, sizeof(buf)) > 0) ;
++      if(errno != EAGAIN)
++              panic("check_sigio : write failed, errno = %d\n", errno);
++      while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
++
++      if(got_sigio){
++              printk("Yes\n");
++              pty_output_sigio = 1;
++      }
++      else if(n == -EAGAIN) printk("No, enabling workaround\n");
++      else panic("check_sigio : read failed, err = %d\n", n);
++}
++
++static void tty_close(int master, int slave)
++{
++      printk("Checking that host ptys support SIGIO on close...");
++
++      os_close_file(slave);
++      if(got_sigio){
++              printk("Yes\n");
++              pty_close_sigio = 1;
++      }
++      else printk("No, enabling workaround\n");
++}
++
++void __init check_sigio(void)
++{
++      if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
++         (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
++              printk("No pseudo-terminals available - skipping pty SIGIO "
++                     "check\n");
++              return;
++      }
++      check_one_sigio(tty_output);
++      check_one_sigio(tty_close);
++}
++
++/* Protected by sigio_lock(), also used by sigio_cleanup, which is an 
++ * exitcall.
++ */
++static int write_sigio_pid = -1;
++
++/* These arrays are initialized before the sigio thread is started, and
++ * the descriptors closed after it is killed.  So, it can't see them change.
++ * On the UML side, they are changed under the sigio_lock.
++ */
++static int write_sigio_fds[2] = { -1, -1 };
++static int sigio_private[2] = { -1, -1 };
++
++struct pollfds {
++      struct pollfd *poll;
++      int size;
++      int used;
++};
++
++/* Protected by sigio_lock().  Used by the sigio thread, but the UML thread
++ * synchronizes with it.
++ */
++struct pollfds current_poll = {
++      .poll           = NULL,
++      .size           = 0,
++      .used           = 0
++};
++
++struct pollfds next_poll = {
++      .poll           = NULL,
++      .size           = 0,
++      .used           = 0
++};
++
++static int write_sigio_thread(void *unused)
++{
++      struct pollfds *fds, tmp;
++      struct pollfd *p;
++      int i, n, respond_fd;
++      char c;
++
++      fds = &current_poll;
++      while(1){
++              n = poll(fds->poll, fds->used, -1);
++              if(n < 0){
++                      if(errno == EINTR) continue;
++                      printk("write_sigio_thread : poll returned %d, "
++                             "errno = %d\n", n, errno);
++              }
++              for(i = 0; i < fds->used; i++){
++                      p = &fds->poll[i];
++                      if(p->revents == 0) continue;
++                      if(p->fd == sigio_private[1]){
++                              n = os_read_file(sigio_private[1], &c, sizeof(c));
++                              if(n != sizeof(c))
++                                      printk("write_sigio_thread : "
++                                             "read failed, err = %d\n", -n);
++                              tmp = current_poll;
++                              current_poll = next_poll;
++                              next_poll = tmp;
++                              respond_fd = sigio_private[1];
++                      }
++                      else {
++                              respond_fd = write_sigio_fds[1];
++                              fds->used--;
++                              memmove(&fds->poll[i], &fds->poll[i + 1],
++                                      (fds->used - i) * sizeof(*fds->poll));
++                      }
++
++                      n = os_write_file(respond_fd, &c, sizeof(c));
++                      if(n != sizeof(c))
++                              printk("write_sigio_thread : write failed, "
++                                     "err = %d\n", -n);
++              }
++      }
++}
++
++static int need_poll(int n)
++{
++      if(n <= next_poll.size){
++              next_poll.used = n;
++              return(0);
++      }
++      if(next_poll.poll != NULL) kfree(next_poll.poll);
++      next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
++      if(next_poll.poll == NULL){
++              printk("need_poll : failed to allocate new pollfds\n");
++              next_poll.size = 0;
++              next_poll.used = 0;
++              return(-1);
++      }
++      next_poll.size = n;
++      next_poll.used = n;
++      return(0);
++}
++
++static void update_thread(void)
++{
++      unsigned long flags;
++      int n;
++      char c;
++
++      flags = set_signals(0);
++      n = os_write_file(sigio_private[0], &c, sizeof(c));
++      if(n != sizeof(c)){
++              printk("update_thread : write failed, err = %d\n", -n);
++              goto fail;
++      }
++
++      n = os_read_file(sigio_private[0], &c, sizeof(c));
++      if(n != sizeof(c)){
++              printk("update_thread : read failed, err = %d\n", -n);
++              goto fail;
++      }
++
++      set_signals(flags);
++      return;
++ fail:
++      sigio_lock();
++      if(write_sigio_pid != -1) 
++              os_kill_process(write_sigio_pid, 1);
++      write_sigio_pid = -1;
++      os_close_file(sigio_private[0]);
++      os_close_file(sigio_private[1]);        
++      os_close_file(write_sigio_fds[0]);
++      os_close_file(write_sigio_fds[1]);
++      sigio_unlock();
++      set_signals(flags);
++}
++
++int add_sigio_fd(int fd, int read)
++{
++      int err = 0, i, n, events;
++
++      sigio_lock();
++      for(i = 0; i < current_poll.used; i++){
++              if(current_poll.poll[i].fd == fd) 
++                      goto out;
++      }
++
++      n = current_poll.used + 1;
++      err = need_poll(n);
++      if(err) 
++              goto out;
++
++      for(i = 0; i < current_poll.used; i++)
++              next_poll.poll[i] = current_poll.poll[i];
++
++      if(read) events = POLLIN;
++      else events = POLLOUT;
++
++      next_poll.poll[n - 1] = ((struct pollfd) { .fd          = fd,
++                                                 .events      = events,
++                                                 .revents     = 0 });
++      update_thread();
++ out:
++      sigio_unlock();
++      return(err);
++}
++
++int ignore_sigio_fd(int fd)
++{
++      struct pollfd *p;
++      int err = 0, i, n = 0;
++
++      sigio_lock();
++      for(i = 0; i < current_poll.used; i++){
++              if(current_poll.poll[i].fd == fd) break;
++      }
++      if(i == current_poll.used)
++              goto out;
++      
++      err = need_poll(current_poll.used - 1);
++      if(err)
++              goto out;
++
++      for(i = 0; i < current_poll.used; i++){
++              p = &current_poll.poll[i];
++              if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
++      }
++      if(n == i){
++              printk("ignore_sigio_fd : fd %d not found\n", fd);
++              err = -1;
++              goto out;
++      }
++
++      update_thread();
++ out:
++      sigio_unlock();
++      return(err);
++}
++
++static int setup_initial_poll(int fd)
++{
++      struct pollfd *p;
++
++      p = um_kmalloc(sizeof(struct pollfd));
++      if(p == NULL){
++              printk("setup_initial_poll : failed to allocate poll\n");
++              return(-1);
++      }
++      *p = ((struct pollfd) { .fd     = fd,
++                              .events         = POLLIN,
++                              .revents        = 0 });
++      current_poll = ((struct pollfds) { .poll        = p,
++                                         .used        = 1,
++                                         .size        = 1 });
++      return(0);
++}
++
++void write_sigio_workaround(void)
++{
++      unsigned long stack;
++      int err;
++
++      sigio_lock();
++      if(write_sigio_pid != -1)
++              goto out;
++
++      err = os_pipe(write_sigio_fds, 1, 1);
++      if(err < 0){
++              printk("write_sigio_workaround - os_pipe 1 failed, "
++                     "err = %d\n", -err);
++              goto out;
++      }
++      err = os_pipe(sigio_private, 1, 1);
++      if(err < 0){
++              printk("write_sigio_workaround - os_pipe 2 failed, "
++                     "err = %d\n", -err);
++              goto out_close1;
++      }
++      if(setup_initial_poll(sigio_private[1]))
++              goto out_close2;
++
++      write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, 
++                                          CLONE_FILES | CLONE_VM, &stack, 0);
++
++      if(write_sigio_pid < 0) goto out_close2;
++
++      if(write_sigio_irq(write_sigio_fds[0])) 
++              goto out_kill;
++
++ out:
++      sigio_unlock();
++      return;
++
++ out_kill:
++      os_kill_process(write_sigio_pid, 1);
++      write_sigio_pid = -1;
++ out_close2:
++      os_close_file(sigio_private[0]);
++      os_close_file(sigio_private[1]);        
++ out_close1:
++      os_close_file(write_sigio_fds[0]);
++      os_close_file(write_sigio_fds[1]);
++      sigio_unlock();
++}
++
++int read_sigio_fd(int fd)
++{
++      int n;
++      char c;
++
++      n = os_read_file(fd, &c, sizeof(c));
++      if(n != sizeof(c)){
++              if(n < 0) {
++                      printk("read_sigio_fd - read failed, err = %d\n", -n);
++                      return(n);
++              } 
++              else { 
++                      printk("read_sigio_fd - short read, bytes = %d\n", n);
++                      return(-EIO);
++              }
++      }
++      return(n);
++}
++
++static void sigio_cleanup(void)
++{
++      if(write_sigio_pid != -1)
++              os_kill_process(write_sigio_pid, 1);
++}
++
++__uml_exitcall(sigio_cleanup);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/signal_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/signal_kern.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/signal_kern.c  2005-05-03 22:28:14.447413872 +0300
+@@ -0,0 +1,368 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/stddef.h"
++#include "linux/sys.h"
++#include "linux/sched.h"
++#include "linux/wait.h"
++#include "linux/kernel.h"
++#include "linux/smp_lock.h"
++#include "linux/module.h"
++#include "linux/slab.h"
++#include "asm/signal.h"
++#include "asm/uaccess.h"
++#include "asm/ucontext.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "signal_kern.h"
++#include "signal_user.h"
++#include "kern.h"
++#include "frame_kern.h"
++#include "sigcontext.h"
++#include "mode.h"
++
++EXPORT_SYMBOL(block_signals);
++EXPORT_SYMBOL(unblock_signals);
++
++static void force_segv(int sig)
++{
++      if(sig == SIGSEGV){
++              struct k_sigaction *ka;
++
++              ka = &current->sig->action[SIGSEGV - 1];
++              ka->sa.sa_handler = SIG_DFL;
++      }
++      force_sig(SIGSEGV, current);
++}
++
++#define _S(nr) (1<<((nr)-1))
++
++#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
++
++/*
++ * OK, we're invoking a handler
++ */   
++static void handle_signal(struct pt_regs *regs, unsigned long signr, 
++                        struct k_sigaction *ka, siginfo_t *info, 
++                        sigset_t *oldset, int error)
++{
++        __sighandler_t handler;
++      void (*restorer)(void);
++      unsigned long sp;
++      sigset_t save;
++      int err, ret;
++
++      err = PT_REGS_SYSCALL_RET(&current->thread.regs);
++      ret = 0;
++      switch(err){
++      case -ERESTARTNOHAND:
++              ret = -EINTR;
++              break;
++
++      case -ERESTARTSYS:
++              if (!(ka->sa.sa_flags & SA_RESTART)) {
++                      ret = -EINTR;
++                      break;
++              }
++              /* fallthrough */
++      case -ERESTARTNOINTR:
++              PT_REGS_RESTART_SYSCALL(regs);
++              PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
++
++              /* This is because of the UM_SET_SYSCALL_RETURN and the fact
++               * that on i386 the system call number and return value are
++               * in the same register.  When the system call restarts, %eax
++               * had better have the system call number in it.  Since the
++               * return value doesn't matter (except that it shouldn't be
++               * -ERESTART*), we'll stick the system call number there.
++               */
++              ret = PT_REGS_SYSCALL_NR(regs);
++              break;
++      }
++
++      handler = ka->sa.sa_handler;
++      save = *oldset;
++
++      if (ka->sa.sa_flags & SA_ONESHOT)
++              ka->sa.sa_handler = SIG_DFL;
++
++      if (!(ka->sa.sa_flags & SA_NODEFER)) {
++              spin_lock_irq(&current->sigmask_lock);
++              sigorsets(&current->blocked, &current->blocked, 
++                        &ka->sa.sa_mask);
++              sigaddset(&current->blocked, signr);
++              recalc_sigpending(current);
++              spin_unlock_irq(&current->sigmask_lock);
++      }
++
++      sp = PT_REGS_SP(regs);
++
++      if((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
++              sp = current->sas_ss_sp + current->sas_ss_size;
++      
++      if(error != 0) 
++              PT_REGS_SET_SYSCALL_RETURN(regs, ret);
++
++      if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer;
++      else restorer = NULL;
++
++      if(ka->sa.sa_flags & SA_SIGINFO)
++              err = setup_signal_stack_si(sp, signr, (unsigned long) handler,
++                                          restorer, regs, info, &save);
++      else
++              err = setup_signal_stack_sc(sp, signr, (unsigned long) handler,
++                                          restorer, regs, &save);
++      if(err)
++              force_segv(signr);
++}
++
++/*
++ * Note that 'init' is a special process: it doesn't get signals it doesn't
++ * want to handle. Thus you cannot kill init even with a SIGKILL even by
++ * mistake.
++ */
++
++static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error)
++{
++      siginfo_t info;
++      struct k_sigaction *ka;
++
++      if (!oldset)
++              oldset = &current->blocked;
++
++      for (;;) {
++              unsigned long signr;
++
++              spin_lock_irq(&current->sigmask_lock);
++              signr = dequeue_signal(&current->blocked, &info);
++              spin_unlock_irq(&current->sigmask_lock);
++
++              if (!signr)
++                      break;
++
++              if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
++                      /* Let the debugger run.  */
++                      current->exit_code = signr;
++                      current->state = TASK_STOPPED;
++                      notify_parent(current, SIGCHLD);
++                      schedule();
++
++                      /* We're back.  Did the debugger cancel the sig?  */
++                      signr = current->exit_code;
++                      if (!signr)
++                              continue;
++                      current->exit_code = 0;
++
++                      /* The debugger continued.  Ignore SIGSTOP.  */
++                      if (signr == SIGSTOP)
++                              continue;
++
++                      /* Update the siginfo structure.  Is this good?  */
++                      if (signr != info.si_signo) {
++                              info.si_signo = signr;
++                              info.si_errno = 0;
++                              info.si_code = SI_USER;
++                              info.si_pid = current->p_pptr->pid;
++                              info.si_uid = current->p_pptr->uid;
++                      }
++
++                      /* If the (new) signal is now blocked, requeue it.  */
++                      if (sigismember(&current->blocked, signr)) {
++                              send_sig_info(signr, &info, current);
++                              continue;
++                      }
++              }
++
++              ka = &current->sig->action[signr-1];
++              if (ka->sa.sa_handler == SIG_IGN) {
++                      if (signr != SIGCHLD)
++                              continue;
++                      /* Check for SIGCHLD: it's special.  */
++                      while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
++                              /* nothing */;
++                      continue;
++              }
++
++              if (ka->sa.sa_handler == SIG_DFL) {
++                      int exit_code = signr;
++
++                      /* Init gets no signals it doesn't want.  */
++                      if (current->pid == 1)
++                              continue;
++
++                      switch (signr) {
++                      case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
++                              continue;
++
++                      case SIGTSTP: case SIGTTIN: case SIGTTOU:
++                              if (is_orphaned_pgrp(current->pgrp))
++                                      continue;
++                              /* FALLTHRU */
++
++                        case SIGSTOP: {
++                                struct signal_struct *sig;
++                              current->state = TASK_STOPPED;
++                              current->exit_code = signr;
++                                sig = current->p_pptr->sig;
++                                if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
++                                      notify_parent(current, SIGCHLD);
++                              schedule();
++                              continue;
++                      }
++                      case SIGQUIT: case SIGILL: case SIGTRAP:
++                      case SIGABRT: case SIGFPE: case SIGSEGV:
++                      case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
++                              if (do_coredump(signr, &current->thread.regs))
++                                      exit_code |= 0x80;
++                              /* FALLTHRU */
++
++                      default:
++                              sig_exit(signr, exit_code, &info);
++                              /* NOTREACHED */
++                      }
++              }
++
++              /* Whee!  Actually deliver the signal.  */
++              handle_signal(regs, signr, ka, &info, oldset, error);
++              return(1);
++      }
++
++      /* Did we come from a system call? */
++      if(PT_REGS_SYSCALL_NR(regs) >= 0){
++              /* Restart the system call - no handlers present */
++              if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND ||
++                 PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS ||
++                 PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){
++                      PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
++                      PT_REGS_RESTART_SYSCALL(regs);
++              }
++      }
++
++      /* This closes a way to execute a system call on the host.  If
++       * you set a breakpoint on a system call instruction and singlestep
++       * from it, the tracing thread used to PTRACE_SINGLESTEP the process
++       * rather than PTRACE_SYSCALL it, allowing the system call to execute
++       * on the host.  The tracing thread will check this flag and 
++       * PTRACE_SYSCALL if necessary.
++       */
++      if((current->ptrace & PT_DTRACE) && 
++         is_syscall(PT_REGS_IP(&current->thread.regs)))
++              current->thread.singlestep_syscall = 1;
++
++      return(0);
++}
++
++int do_signal(int error)
++{
++      return(kern_do_signal(&current->thread.regs, NULL, error));
++}
++
++/*
++ * Atomically swap in the new signal mask, and wait for a signal.
++ */
++int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
++{
++      sigset_t saveset;
++
++      mask &= _BLOCKABLE;
++      spin_lock_irq(&current->sigmask_lock);
++      saveset = current->blocked;
++      siginitset(&current->blocked, mask);
++      recalc_sigpending(current);
++      spin_unlock_irq(&current->sigmask_lock);
++
++      PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
++      while (1) {
++              current->state = TASK_INTERRUPTIBLE;
++              schedule();
++              if(kern_do_signal(&current->thread.regs, &saveset, -EINTR))
++                      return(-EINTR);
++      }
++}
++
++int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
++{
++      sigset_t saveset, newset;
++
++      /* XXX: Don't preclude handling different sized sigset_t's.  */
++      if (sigsetsize != sizeof(sigset_t))
++              return -EINVAL;
++
++      if (copy_from_user(&newset, unewset, sizeof(newset)))
++              return -EFAULT;
++      sigdelsetmask(&newset, ~_BLOCKABLE);
++
++      spin_lock_irq(&current->sigmask_lock);
++      saveset = current->blocked;
++      current->blocked = newset;
++      recalc_sigpending(current);
++      spin_unlock_irq(&current->sigmask_lock);
++
++      PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
++      while (1) {
++              current->state = TASK_INTERRUPTIBLE;
++              schedule();
++              if (kern_do_signal(&current->thread.regs, &saveset, -EINTR))
++                      return(-EINTR);
++      }
++}
++
++extern int userspace_pid[];
++
++static int copy_sc_from_user(struct pt_regs *to, void *from, 
++                           struct arch_frame_data *arch)
++{
++      int ret;
++
++      ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, arch),
++                        copy_sc_from_user_skas(userspace_pid[0], 
++                                               &to->regs, from));
++      return(ret);
++}
++
++int sys_sigreturn(struct pt_regs regs)
++{
++      void *sc = sp_to_sc(PT_REGS_SP(&current->thread.regs));
++      void *mask = sp_to_mask(PT_REGS_SP(&current->thread.regs));
++      int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
++
++      spin_lock_irq(&current->sigmask_lock);
++      copy_from_user(&current->blocked.sig[0], sc_sigmask(sc), 
++                     sizeof(current->blocked.sig[0]));
++      copy_from_user(&current->blocked.sig[1], mask, sig_size);
++      sigdelsetmask(&current->blocked, ~_BLOCKABLE);
++      recalc_sigpending(current);
++      spin_unlock_irq(&current->sigmask_lock);
++      copy_sc_from_user(&current->thread.regs, sc, 
++                        &signal_frame_sc.common.arch);
++      return(PT_REGS_SYSCALL_RET(&current->thread.regs));
++}
++
++int sys_rt_sigreturn(struct pt_regs regs)
++{
++      struct ucontext *uc = sp_to_uc(PT_REGS_SP(&current->thread.regs));
++      int sig_size = _NSIG_WORDS * sizeof(unsigned long);
++
++      spin_lock_irq(&current->sigmask_lock);
++      copy_from_user(&current->blocked, &uc->uc_sigmask, sig_size);
++      sigdelsetmask(&current->blocked, ~_BLOCKABLE);
++      recalc_sigpending(current);
++      spin_unlock_irq(&current->sigmask_lock);
++      copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext,
++                        &signal_frame_si.common.arch);
++      return(PT_REGS_SYSCALL_RET(&current->thread.regs));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/signal_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/signal_user.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/signal_user.c  2005-05-03 22:28:14.448413720 +0300
+@@ -0,0 +1,142 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <signal.h>
++#include <errno.h>
++#include <stdarg.h>
++#include <string.h>
++#include <sys/mman.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "signal_user.h"
++#include "signal_kern.h"
++#include "sysdep/sigcontext.h"
++#include "sigcontext.h"
++
++void set_sigstack(void *sig_stack, int size)
++{
++      stack_t stack = ((stack_t) { .ss_flags  = 0,
++                                   .ss_sp     = (__ptr_t) sig_stack,
++                                   .ss_size   = size - sizeof(void *) });
++
++      if(sigaltstack(&stack, NULL) != 0)
++              panic("enabling signal stack failed, errno = %d\n", errno);
++}
++
++void set_handler(int sig, void (*handler)(int), int flags, ...)
++{
++      struct sigaction action;
++      va_list ap;
++      int mask;
++
++      va_start(ap, flags);
++      action.sa_handler = handler;
++      sigemptyset(&action.sa_mask);
++      while((mask = va_arg(ap, int)) != -1){
++              sigaddset(&action.sa_mask, mask);
++      }
++      action.sa_flags = flags;
++      action.sa_restorer = NULL;
++      if(sigaction(sig, &action, NULL) < 0)
++              panic("sigaction failed");
++}
++
++int change_sig(int signal, int on)
++{
++      sigset_t sigset, old;
++
++      sigemptyset(&sigset);
++      sigaddset(&sigset, signal);
++      sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
++      return(!sigismember(&old, signal));
++}
++
++static void change_signals(int type)
++{
++      sigset_t mask;
++
++      sigemptyset(&mask);
++      sigaddset(&mask, SIGVTALRM);
++      sigaddset(&mask, SIGALRM);
++      sigaddset(&mask, SIGIO);
++      sigaddset(&mask, SIGPROF);
++      if(sigprocmask(type, &mask, NULL) < 0)
++              panic("Failed to change signal mask - errno = %d", errno);
++}
++
++void block_signals(void)
++{
++      change_signals(SIG_BLOCK);
++}
++
++void unblock_signals(void)
++{
++      change_signals(SIG_UNBLOCK);
++}
++
++#define SIGIO_BIT 0
++#define SIGVTALRM_BIT 1
++
++static int enable_mask(sigset_t *mask)
++{
++      int sigs;
++
++      sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT;
++      sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT;
++      sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT;
++      return(sigs);
++}
++
++int get_signals(void)
++{
++      sigset_t mask;
++      
++      if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
++              panic("Failed to get signal mask");
++      return(enable_mask(&mask));
++}
++
++int set_signals(int enable)
++{
++      sigset_t mask;
++      int ret;
++
++      sigemptyset(&mask);
++      if(enable & (1 << SIGIO_BIT)) 
++              sigaddset(&mask, SIGIO);
++      if(enable & (1 << SIGVTALRM_BIT)){
++              sigaddset(&mask, SIGVTALRM);
++              sigaddset(&mask, SIGALRM);
++      }
++      if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
++              panic("Failed to enable signals");
++      ret = enable_mask(&mask);
++      sigemptyset(&mask);
++      if((enable & (1 << SIGIO_BIT)) == 0) 
++              sigaddset(&mask, SIGIO);
++      if((enable & (1 << SIGVTALRM_BIT)) == 0){
++              sigaddset(&mask, SIGVTALRM);
++              sigaddset(&mask, SIGALRM);
++      }
++      if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
++              panic("Failed to block signals");
++
++      return(ret);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/exec_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/exec_kern.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/exec_kern.c       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,41 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "asm/current.h"
++#include "asm/page.h"
++#include "asm/signal.h"
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++#include "tlb.h"
++#include "skas.h"
++#include "mmu.h"
++#include "os.h"
++
++void flush_thread_skas(void)
++{
++      force_flush_all();
++      switch_mm_skas(current->mm->context.skas.mm_fd);
++}
++
++void start_thread_skas(struct pt_regs *regs, unsigned long eip, 
++                     unsigned long esp)
++{
++      set_fs(USER_DS);
++        PT_REGS_IP(regs) = eip;
++      PT_REGS_SP(regs) = esp;
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/exec_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/exec_user.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/exec_user.c       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,63 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <errno.h>
++#include <signal.h>
++#include <sched.h>
++#include <sys/wait.h>
++#include <sys/ptrace.h>
++#include "user.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "os.h"
++#include "time_user.h"
++
++static int user_thread_tramp(void *arg)
++{
++      if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
++              panic("user_thread_tramp - PTRACE_TRACEME failed, "
++                    "errno = %d\n", errno);
++      enable_timer();
++      os_stop_process(os_getpid());
++      return(0);
++}
++
++int user_thread(unsigned long stack, int flags)
++{
++      int pid, status, err;
++
++      pid = clone(user_thread_tramp, (void *) stack_sp(stack), 
++                  flags | CLONE_FILES | SIGCHLD, NULL);
++      if(pid < 0){
++              printk("user_thread - clone failed, errno = %d\n", errno);
++              return(pid);
++      }
++
++      CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
++      if(err < 0){
++              printk("user_thread - waitpid failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
++              printk("user_thread - trampoline didn't stop, status = %d\n", 
++                     status);
++              return(-EINVAL);
++      }
++
++      return(pid);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/include/mmu.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/include/mmu.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/include/mmu.h     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,27 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SKAS_MMU_H
++#define __SKAS_MMU_H
++
++#include "linux/list.h"
++#include "linux/spinlock.h"
++
++struct mmu_context_skas {
++      int mm_fd;
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/include/mode.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/include/mode.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/include/mode.h    2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,39 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MODE_SKAS_H__
++#define __MODE_SKAS_H__
++
++#include <sysdep/ptrace.h>
++
++extern unsigned long exec_regs[];
++extern unsigned long exec_fp_regs[];
++extern unsigned long exec_fpx_regs[];
++extern int have_fpx_regs;
++
++extern void user_time_init_skas(void);
++extern int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, 
++                                void *from_ptr);
++extern int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, 
++                              union uml_pt_regs *regs, 
++                              unsigned long fault_addr, int fault_type);
++extern void sig_handler_common_skas(int sig, void *sc_ptr);
++extern void halt_skas(void);
++extern void reboot_skas(void);
++extern void kill_off_processes_skas(void);
++extern int is_skas_winch(int pid, int fd, void *data);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/include/mode_kern.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/include/mode_kern.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/include/mode_kern.h       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,51 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SKAS_MODE_KERN_H__
++#define __SKAS_MODE_KERN_H__
++
++#include "linux/sched.h"
++#include "asm/page.h"
++#include "asm/ptrace.h"
++
++extern void flush_thread_skas(void);
++extern void *_switch_to_skas(void *prev, void *next);
++extern void start_thread_skas(struct pt_regs *regs, unsigned long eip, 
++                            unsigned long esp);
++extern int copy_thread_skas(int nr, unsigned long clone_flags, 
++                          unsigned long sp, unsigned long stack_top, 
++                          struct task_struct *p, struct pt_regs *regs);
++extern void release_thread_skas(struct task_struct *task);
++extern void exit_thread_skas(void);
++extern void initial_thread_cb_skas(void (*proc)(void *), void *arg);
++extern void init_idle_skas(void);
++extern void flush_tlb_kernel_vm_skas(void);
++extern void __flush_tlb_one_skas(unsigned long addr);
++extern void flush_tlb_range_skas(struct mm_struct *mm, unsigned long start, 
++                               unsigned long end);
++extern void flush_tlb_mm_skas(struct mm_struct *mm);
++extern void force_flush_all_skas(void);
++extern long execute_syscall_skas(void *r);
++extern void before_mem_skas(unsigned long unused);
++extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
++                                       unsigned long *task_size_out);
++extern int start_uml_skas(void);
++extern int external_pid_skas(struct task_struct *task);
++extern int thread_pid_skas(struct thread_struct *thread);
++
++#define kmem_end_skas (host_task_size - 1024 * 1024)
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/include/proc_mm.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/include/proc_mm.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/include/proc_mm.h 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,55 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SKAS_PROC_MM_H
++#define __SKAS_PROC_MM_H
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++      unsigned long addr;
++      unsigned long len;
++      unsigned long prot;
++      unsigned long flags;
++      unsigned long fd;
++      unsigned long offset;
++};
++
++struct mm_munmap {
++      unsigned long addr;
++      unsigned long len;      
++};
++
++struct mm_mprotect {
++      unsigned long addr;
++      unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++      int op;
++      union {
++              struct mm_mmap mmap;
++              struct mm_munmap munmap;
++              struct mm_mprotect mprotect;
++              int copy_segments;
++      } u;
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/include/ptrace-skas.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/include/ptrace-skas.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/include/ptrace-skas.h     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,57 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PTRACE_SKAS_H
++#define __PTRACE_SKAS_H
++
++#include "uml-config.h"
++
++#ifdef UML_CONFIG_MODE_SKAS
++
++#include "skas_ptregs.h"
++
++#define HOST_FRAME_SIZE 17
++
++#define REGS_IP(r) ((r)[HOST_IP])
++#define REGS_SP(r) ((r)[HOST_SP])
++#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
++#define REGS_EAX(r) ((r)[HOST_EAX])
++#define REGS_EBX(r) ((r)[HOST_EBX])
++#define REGS_ECX(r) ((r)[HOST_ECX])
++#define REGS_EDX(r) ((r)[HOST_EDX])
++#define REGS_ESI(r) ((r)[HOST_ESI])
++#define REGS_EDI(r) ((r)[HOST_EDI])
++#define REGS_EBP(r) ((r)[HOST_EBP])
++#define REGS_CS(r) ((r)[HOST_CS])
++#define REGS_SS(r) ((r)[HOST_SS])
++#define REGS_DS(r) ((r)[HOST_DS])
++#define REGS_ES(r) ((r)[HOST_ES])
++#define REGS_FS(r) ((r)[HOST_FS])
++#define REGS_GS(r) ((r)[HOST_GS])
++
++#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res)
++
++#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
++
++#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type)
++
++#define REGS_FAULT_ADDR(r) ((r)->fault_addr)
++
++#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type)
++
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/include/skas.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/include/skas.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/include/skas.h    2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,48 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SKAS_H
++#define __SKAS_H
++
++#include "sysdep/ptrace.h"
++
++extern int userspace_pid[];
++
++extern void switch_threads(void *me, void *next);
++extern void thread_wait(void *sw, void *fb);
++extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
++                       void (*handler)(int));
++extern int start_idle_thread(void *stack, void *switch_buf_ptr, 
++                           void **fork_buf_ptr);
++extern int user_thread(unsigned long stack, int flags);
++extern void userspace(union uml_pt_regs *regs);
++extern void new_thread_proc(void *stack, void (*handler)(int sig));
++extern void remove_sigstack(void);
++extern void new_thread_handler(int sig);
++extern void handle_syscall(union uml_pt_regs *regs);
++extern void map(int fd, unsigned long virt, unsigned long phys, 
++              unsigned long len, int r, int w, int x);
++extern int unmap(int fd, void *addr, int len);
++extern int protect(int fd, unsigned long addr, unsigned long len, 
++                 int r, int w, int x, int must_succeed);
++extern void user_signal(int sig, union uml_pt_regs *regs);
++extern int new_mm(int from);
++extern void save_registers(union uml_pt_regs *regs);
++extern void restore_registers(union uml_pt_regs *regs);
++extern void start_userspace(int cpu);
++extern void init_registers(int pid);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/include/uaccess.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/include/uaccess.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/include/uaccess.h 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,40 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __SKAS_UACCESS_H
++#define __SKAS_UACCESS_H
++
++#include "asm/errno.h"
++
++#define access_ok_skas(type, addr, size) \
++      ((segment_eq(get_fs(), KERNEL_DS)) || \
++       (((unsigned long) (addr) < TASK_SIZE) && \
++        ((unsigned long) (addr) + (size) <= TASK_SIZE)))
++
++static inline int verify_area_skas(int type, const void * addr, 
++                                 unsigned long size)
++{
++      return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
++}
++
++extern int copy_from_user_skas(void *to, const void *from, int n);
++extern int copy_to_user_skas(void *to, const void *from, int n);
++extern int strncpy_from_user_skas(char *dst, const char *src, int count);
++extern int __clear_user_skas(void *mem, int len);
++extern int clear_user_skas(void *mem, int len);
++extern int strnlen_user_skas(const void *str, int len);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/Makefile     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/Makefile  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,31 @@
++# 
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET = skas.o
++
++obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \
++      process_kern.o syscall_kern.o syscall_user.o time.o tlb.o trap_user.o \
++      uaccess.o
++
++subdir-y = sys-$(SUBARCH)
++
++obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
++
++USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o
++
++include $(TOPDIR)/Rules.make
++
++include/skas_ptregs.h : util/mk_ptregs
++      util/mk_ptregs > $@
++
++util/mk_ptregs :
++      $(MAKE) -C util
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++clean :
++      $(MAKE) -C util clean
++      $(RM) -f include/skas_ptregs.h
+Index: linux-2.4.29/arch/um/kernel/skas/mem.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/mem.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/mem.c     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,30 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/mm.h"
++#include "mem_user.h"
++
++unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, 
++                                unsigned long *task_size_out)
++{
++      /* Round up to the nearest 4M */
++      unsigned long top = ROUND_4M((unsigned long) &arg);
++
++      *host_size_out = top;
++      *task_size_out = top;
++      return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/mem_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/mem_user.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/mem_user.c        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,105 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <errno.h>
++#include <sys/mman.h>
++#include <sys/ptrace.h>
++#include "mem_user.h"
++#include "mem.h"
++#include "user.h"
++#include "os.h"
++#include "proc_mm.h"
++
++void map(int fd, unsigned long virt, unsigned long phys, unsigned long len, 
++       int r, int w, int x)
++{
++      struct proc_mm_op map;
++      __u64 offset;
++      int prot, n, phys_fd;
++
++      prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
++              (x ? PROT_EXEC : 0);
++      phys_fd = phys_mapping(phys, &offset);
++
++      map = ((struct proc_mm_op) { .op        = MM_MMAP,
++                                   .u         = 
++                                   { .mmap    = 
++                                     { .addr          = virt,
++                                       .len           = len,
++                                       .prot          = prot,
++                                       .flags         = MAP_SHARED | 
++                                                        MAP_FIXED,
++                                       .fd            = phys_fd,
++                                       .offset        = offset
++                                     } } } );
++      n = os_write_file(fd, &map, sizeof(map));
++      if(n != sizeof(map)) 
++              printk("map : /proc/mm map failed, err = %d\n", -n);
++}
++
++int unmap(int fd, void *addr, int len)
++{
++      struct proc_mm_op unmap;
++      int n;
++
++      unmap = ((struct proc_mm_op) { .op      = MM_MUNMAP,
++                                     .u       = 
++                                     { .munmap        = 
++                                       { .addr        = (unsigned long) addr,
++                                         .len         = len } } } );
++      n = os_write_file(fd, &unmap, sizeof(unmap));
++      if(n != sizeof(unmap)) {
++              if(n < 0) 
++                      return(n);
++              else if(n > 0) 
++                      return(-EIO);
++      }
++
++      return(0);
++}
++
++int protect(int fd, unsigned long addr, unsigned long len, int r, int w, 
++          int x, int must_succeed)
++{
++      struct proc_mm_op protect;
++      int prot, n;
++
++      prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
++              (x ? PROT_EXEC : 0);
++
++      protect = ((struct proc_mm_op) { .op    = MM_MPROTECT,
++                                     .u       = 
++                                     { .mprotect      = 
++                                       { .addr        = (unsigned long) addr,
++                                         .len         = len,
++                                         .prot        = prot } } } );
++
++      n = os_write_file(fd, &protect, sizeof(protect));
++      if(n != sizeof(protect)) {
++              if(n == 0) return(0);
++
++              if(must_succeed)
++                      panic("protect failed, err = %d", -n);
++
++              return(-EIO);
++      }
++
++      return(0);
++}
++
++void before_mem_skas(unsigned long unused)
++{
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/mmu.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/mmu.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/mmu.c     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,46 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/list.h"
++#include "linux/spinlock.h"
++#include "linux/slab.h"
++#include "asm/segment.h"
++#include "asm/mmu.h"
++#include "os.h"
++#include "skas.h"
++
++int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
++{
++      int from;
++
++      if((current->mm != NULL) && (current->mm != &init_mm))
++              from = current->mm->context.skas.mm_fd;
++      else from = -1;
++
++      mm->context.skas.mm_fd = new_mm(from);
++      if(mm->context.skas.mm_fd < 0){
++              printk("init_new_context_skas - new_mm failed, errno = %d\n",
++                     mm->context.skas.mm_fd);
++              return(mm->context.skas.mm_fd);
++      }
++
++      return(0);
++}
++
++void destroy_context_skas(struct mm_struct *mm)
++{
++      os_close_file(mm->context.skas.mm_fd);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/process.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/process.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/process.c 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,400 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <signal.h>
++#include <setjmp.h>
++#include <sched.h>
++#include <sys/wait.h>
++#include <sys/ptrace.h>
++#include <sys/mman.h>
++#include <sys/user.h>
++#include <asm/unistd.h>
++#include "user.h"
++#include "ptrace_user.h"
++#include "time_user.h"
++#include "sysdep/ptrace.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "skas.h"
++#include "sysdep/sigcontext.h"
++#include "os.h"
++#include "proc_mm.h"
++#include "skas_ptrace.h"
++#include "chan_user.h"
++
++int is_skas_winch(int pid, int fd, void *data)
++{
++      if(pid != getpid())
++              return(0);
++
++      register_winch_irq(-1, fd, -1, data);
++      return(1);
++}
++
++/* These are set once at boot time and not changed thereafter */
++
++unsigned long exec_regs[FRAME_SIZE];
++unsigned long exec_fp_regs[HOST_FP_SIZE];
++unsigned long exec_fpx_regs[HOST_XFP_SIZE];
++int have_fpx_regs = 1;
++
++static void handle_segv(int pid)
++{
++      struct ptrace_faultinfo fault;
++      int err;
++
++      err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault);
++      if(err)
++              panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n",
++                    errno);
++
++      segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL);
++}
++
++static void handle_trap(int pid, union uml_pt_regs *regs)
++{
++      int err, syscall_nr, status;
++
++      syscall_nr = PT_SYSCALL_NR(regs->skas.regs);
++      UPT_SYSCALL_NR(regs) = syscall_nr;
++      if(syscall_nr < 1){
++              relay_signal(SIGTRAP, regs);
++              return;
++      }
++
++      if(!use_sysemu){
++              err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 
++                           __NR_getpid);
++              if(err < 0)
++                      panic("handle_trap - nullifying syscall failed, "
++                            "errno = %d\n", errno);
++
++              err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
++              if(err < 0)
++                      panic("handle_trap - continuing to end of syscall "
++                            "failed, errno = %d\n", errno);
++
++              CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
++              if((err < 0) || !WIFSTOPPED(status) || 
++                 (WSTOPSIG(status) != SIGTRAP))
++                      panic("handle_trap - failed to wait at end of "
++                            "syscall, errno = %d, status = %d\n", errno, 
++                            status);
++      }
++
++      handle_syscall(regs);
++}
++
++static int userspace_tramp(void *arg)
++{
++      init_new_thread_signals(0);
++      enable_timer();
++      ptrace(PTRACE_TRACEME, 0, 0, 0);
++      os_stop_process(os_getpid());
++      return(0);
++}
++
++/* Each element set once, and only accessed by a single processor anyway */
++#define NR_CPUS 1
++int userspace_pid[NR_CPUS];
++
++void start_userspace(int cpu)
++{
++      void *stack;
++      unsigned long sp;
++      int pid, status, n;
++
++      stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
++                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
++      if(stack == MAP_FAILED)
++              panic("start_userspace : mmap failed, errno = %d", errno);
++      sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
++
++      pid = clone(userspace_tramp, (void *) sp, 
++                  CLONE_FILES | CLONE_VM | SIGCHLD, NULL);
++      if(pid < 0)
++              panic("start_userspace : clone failed, errno = %d", errno);
++
++      do {
++              CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
++              if(n < 0)
++                      panic("start_userspace : wait failed, errno = %d", 
++                            errno);
++      } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));
++
++      if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
++              panic("start_userspace : expected SIGSTOP, got status = %d",
++                    status);
++
++      if(munmap(stack, PAGE_SIZE) < 0)
++              panic("start_userspace : munmap failed, errno = %d\n", errno);
++
++      userspace_pid[cpu] = pid;
++}
++
++void userspace(union uml_pt_regs *regs)
++{
++      int err, status, op, do_syscall, pid = userspace_pid[0];
++
++      do_syscall = use_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL;
++      restore_registers(regs);
++              
++      err = ptrace(do_syscall, pid, 0, 0);
++      if(err)
++              panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", 
++                     errno);
++      while(1){
++              CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
++              if(err < 0)
++                      panic("userspace - waitpid failed, errno = %d\n", 
++                            errno);
++
++              regs->skas.is_user = 1;
++              save_registers(regs);
++
++              if(WIFSTOPPED(status)){
++                      switch(WSTOPSIG(status)){
++                      case SIGSEGV:
++                              handle_segv(pid);
++                              break;
++                      case SIGTRAP:
++                              handle_trap(pid, regs);
++                              break;
++                      case SIGIO:
++                      case SIGVTALRM:
++                      case SIGILL:
++                      case SIGBUS:
++                      case SIGFPE:
++                      case SIGWINCH:
++                              user_signal(WSTOPSIG(status), regs);
++                              break;
++                      default:
++                              printk("userspace - child stopped with signal "
++                                     "%d\n", WSTOPSIG(status));
++                      }
++                      interrupt_end();
++              }
++
++              restore_registers(regs);
++
++              op = singlestepping(NULL) ? PTRACE_SINGLESTEP : do_syscall;
++              err = ptrace(op, pid, 0, 0);
++              if(err)
++                      panic("userspace - PTRACE_SYSCALL failed, "
++                            "errno = %d\n", errno);
++      }
++}
++
++void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
++              void (*handler)(int))
++{
++      sigjmp_buf switch_buf, fork_buf;
++
++      *switch_buf_ptr = &switch_buf;
++      *fork_buf_ptr = &fork_buf;
++
++      if(sigsetjmp(fork_buf, 1) == 0)
++              new_thread_proc(stack, handler);
++
++      remove_sigstack();
++}
++
++void thread_wait(void *sw, void *fb)
++{
++      sigjmp_buf buf, **switch_buf = sw, *fork_buf;
++
++      *switch_buf = &buf;
++      fork_buf = fb;
++      if(sigsetjmp(buf, 1) == 0)
++              siglongjmp(*fork_buf, 1);
++}
++
++static int move_registers(int pid, int int_op, int fp_op, 
++                        union uml_pt_regs *regs, unsigned long *fp_regs)
++{
++      if(ptrace(int_op, pid, 0, regs->skas.regs) < 0)
++              return(-errno);
++      if(ptrace(fp_op, pid, 0, fp_regs) < 0)
++              return(-errno);
++      return(0);
++}
++
++void save_registers(union uml_pt_regs *regs)
++{
++      unsigned long *fp_regs;
++      int err, fp_op;
++
++      if(have_fpx_regs){
++              fp_op = PTRACE_GETFPXREGS;
++              fp_regs = regs->skas.xfp;
++      }
++      else {
++              fp_op = PTRACE_GETFPREGS;
++              fp_regs = regs->skas.fp;
++      }
++
++      err = move_registers(userspace_pid[0], PTRACE_GETREGS, fp_op, regs, 
++                           fp_regs);
++      if(err)
++              panic("save_registers - saving registers failed, errno = %d\n",
++                    -err);
++}
++
++void restore_registers(union uml_pt_regs *regs)
++{
++      unsigned long *fp_regs;
++      int err, fp_op;
++
++      if(have_fpx_regs){
++              fp_op = PTRACE_SETFPXREGS;
++              fp_regs = regs->skas.xfp;
++      }
++      else {
++              fp_op = PTRACE_SETFPREGS;
++              fp_regs = regs->skas.fp;
++      }
++
++      err = move_registers(userspace_pid[0], PTRACE_SETREGS, fp_op, regs, 
++                           fp_regs);
++      if(err)
++              panic("restore_registers - saving registers failed, "
++                    "errno = %d\n", -err);
++}
++
++void switch_threads(void *me, void *next)
++{
++      sigjmp_buf my_buf, **me_ptr = me, *next_buf = next;
++      
++      *me_ptr = &my_buf;
++      if(sigsetjmp(my_buf, 1) == 0)
++              siglongjmp(*next_buf, 1);
++}
++
++static sigjmp_buf initial_jmpbuf;
++
++/* XXX Make these percpu */
++static void (*cb_proc)(void *arg);
++static void *cb_arg;
++static sigjmp_buf *cb_back;
++
++int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
++{
++      sigjmp_buf **switch_buf = switch_buf_ptr;
++      int n;
++
++      *fork_buf_ptr = &initial_jmpbuf;
++      n = sigsetjmp(initial_jmpbuf, 1);
++      if(n == 0)
++              new_thread_proc((void *) stack, new_thread_handler);
++      else if(n == 1)
++              remove_sigstack();
++      else if(n == 2){
++              (*cb_proc)(cb_arg);
++              siglongjmp(*cb_back, 1);
++      }
++      else if(n == 3){
++              kmalloc_ok = 0;
++              return(0);
++      }
++      else if(n == 4){
++              kmalloc_ok = 0;
++              return(1);
++      }
++      siglongjmp(**switch_buf, 1);
++}
++
++void remove_sigstack(void)
++{
++      stack_t stack = ((stack_t) { .ss_flags  = SS_DISABLE,
++                                   .ss_sp     = NULL,
++                                   .ss_size   = 0 });
++
++      if(sigaltstack(&stack, NULL) != 0)
++              panic("disabling signal stack failed, errno = %d\n", errno);
++}
++
++void initial_thread_cb_skas(void (*proc)(void *), void *arg)
++{
++      sigjmp_buf here;
++
++      cb_proc = proc;
++      cb_arg = arg;
++      cb_back = &here;
++
++      block_signals();
++      if(sigsetjmp(here, 1) == 0)
++              siglongjmp(initial_jmpbuf, 2);
++      unblock_signals();
++
++      cb_proc = NULL;
++      cb_arg = NULL;
++      cb_back = NULL;
++}
++
++void halt_skas(void)
++{
++      block_signals();
++      siglongjmp(initial_jmpbuf, 3);
++}
++
++void reboot_skas(void)
++{
++      block_signals();
++      siglongjmp(initial_jmpbuf, 4);
++}
++
++void switch_mm_skas(int mm_fd)
++{
++      int err;
++
++#warning need cpu pid in switch_mm_skas
++      err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd);
++      if(err)
++              panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n",
++                    errno);
++}
++
++void kill_off_processes_skas(void)
++{
++#warning need to loop over userspace_pids in kill_off_processes_skas
++      os_kill_process(userspace_pid[0], 1);
++}
++
++void init_registers(int pid)
++{
++      int err;
++
++      if(ptrace(PTRACE_GETREGS, pid, 0, exec_regs) < 0)
++              panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", 
++                    errno);
++
++      err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs);
++      if(!err)
++              return;
++
++      have_fpx_regs = 0;
++      if(errno != EIO)
++              panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", 
++                    errno);
++
++      err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs);
++      if(err)
++              panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d", 
++                    errno);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/process_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/process_kern.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/process_kern.c    2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,211 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/slab.h"
++#include "kern_util.h"
++#include "time_user.h"
++#include "signal_user.h"
++#include "skas.h"
++#include "os.h"
++#include "user_util.h"
++#include "tlb.h"
++#include "frame.h"
++#include "kern.h"
++#include "mode.h"
++#include "filehandle.h"
++#include "proc_mm.h"
++
++void *_switch_to_skas(void *prev, void *next)
++{
++      struct task_struct *from, *to;
++
++      from = prev;
++      to = next;
++
++      /* XXX need to check runqueues[cpu].idle */
++      if(current->pid == 0)
++              switch_timers(0);
++
++      to->thread.prev_sched = from;
++      set_current(to);
++
++      switch_threads(&from->thread.mode.skas.switch_buf, 
++                     to->thread.mode.skas.switch_buf);
++
++      if(current->pid == 0)
++              switch_timers(1);
++
++      return(current->thread.prev_sched);
++}
++
++extern void schedule_tail(struct task_struct *prev);
++
++void new_thread_handler(int sig)
++{
++      int (*fn)(void *), n;
++      void *arg;
++
++      fn = current->thread.request.u.thread.proc;
++      arg = current->thread.request.u.thread.arg;
++      change_sig(SIGUSR1, 1);
++      thread_wait(&current->thread.mode.skas.switch_buf, 
++                  current->thread.mode.skas.fork_buf);
++
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
++      current->thread.prev_sched = NULL;
++
++      /* The return value is 1 if the kernel thread execs a process,
++       * 0 if it just exits
++       */
++      n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
++      if(n == 1)
++              userspace(&current->thread.regs.regs);
++      else do_exit(0);
++}
++
++void new_thread_proc(void *stack, void (*handler)(int sig))
++{
++      init_new_thread_stack(stack, handler);
++      os_usr1_process(os_getpid());
++}
++
++void release_thread_skas(struct task_struct *task)
++{
++}
++
++void exit_thread_skas(void)
++{
++}
++
++void fork_handler(int sig)
++{
++        change_sig(SIGUSR1, 1);
++      thread_wait(&current->thread.mode.skas.switch_buf, 
++                  current->thread.mode.skas.fork_buf);
++      
++      force_flush_all();
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
++      current->thread.prev_sched = NULL;
++      unblock_signals();
++
++      userspace(&current->thread.regs.regs);
++}
++
++int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
++                   unsigned long stack_top, struct task_struct * p, 
++                   struct pt_regs *regs)
++{
++      void (*handler)(int);
++
++      if(current->thread.forking){
++              memcpy(&p->thread.regs.regs.skas, 
++                     &current->thread.regs.regs.skas, 
++                     sizeof(p->thread.regs.regs.skas));
++              REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0);
++              if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
++
++              handler = fork_handler;
++      }
++      else {
++              memcpy(p->thread.regs.regs.skas.regs, exec_regs, 
++                     sizeof(p->thread.regs.regs.skas.regs));
++              memcpy(p->thread.regs.regs.skas.fp, exec_fp_regs, 
++                     sizeof(p->thread.regs.regs.skas.fp));
++              memcpy(p->thread.regs.regs.skas.xfp, exec_fpx_regs, 
++                     sizeof(p->thread.regs.regs.skas.xfp));
++                p->thread.request.u.thread = current->thread.request.u.thread;
++              handler = new_thread_handler;
++      }
++
++      new_thread(p, &p->thread.mode.skas.switch_buf, 
++                 &p->thread.mode.skas.fork_buf, handler);
++      return(0);
++}
++
++int new_mm(int from)
++{
++      struct proc_mm_op copy;
++      int n;
++      int fd = open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
++
++      if(fd < 0)
++              return(fd);
++
++      if(from != -1){
++              copy = ((struct proc_mm_op) { .op       = MM_COPY_SEGMENTS,
++                                            .u        = 
++                                            { .copy_segments  = from } } );
++              n = os_write_file(fd, &copy, sizeof(copy));
++              if(n != sizeof(copy)) 
++                      printk("new_mm : /proc/mm copy_segments failed, "
++                             "err = %d\n", -n);
++      }
++
++      return(fd);
++}
++
++void init_idle_skas(void)
++{
++      cpu_tasks[current->processor].pid = os_getpid();
++}
++
++extern void start_kernel(void);
++
++static int start_kernel_proc(void *unused)
++{
++      int pid;
++
++      block_signals();
++      pid = os_getpid();
++
++      cpu_tasks[0].pid = pid;
++      cpu_tasks[0].task = current;
++#ifdef CONFIG_SMP
++      cpu_online_map = 1;
++#endif
++      start_kernel();
++      return(0);
++}
++
++int start_uml_skas(void)
++{
++      start_userspace(0);
++      capture_signal_stack();
++
++      init_new_thread_signals(1);
++      idle_timer();
++
++      init_task.thread.request.u.thread.proc = start_kernel_proc;
++      init_task.thread.request.u.thread.arg = NULL;
++      return(start_idle_thread(&init_task,
++                               &init_task.thread.mode.skas.switch_buf,
++                               &init_task.thread.mode.skas.fork_buf));
++}
++
++int external_pid_skas(struct task_struct *task)
++{
++#warning Need to look up userspace_pid by cpu 
++      return(userspace_pid[0]);
++}
++
++int thread_pid_skas(struct thread_struct *thread)
++{
++#warning Need to look up userspace_pid by cpu 
++      return(userspace_pid[0]);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/syscall_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/syscall_kern.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/syscall_kern.c    2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,43 @@
++/* 
++ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sys.h"
++#include "linux/ptrace.h"
++#include "asm/errno.h"
++#include "asm/unistd.h"
++#include "asm/ptrace.h"
++#include "asm/current.h"
++#include "sysdep/syscalls.h"
++#include "kern_util.h"
++
++extern syscall_handler_t *sys_call_table[];
++
++long execute_syscall_skas(void *r)
++{
++      struct pt_regs *regs = r;
++      long res;
++      int syscall;
++
++      current->thread.nsyscalls++;
++      nsyscalls++;
++      syscall = UPT_SYSCALL_NR(&regs->regs);
++
++      if((syscall >= NR_syscalls) || (syscall < 1))
++              res = -ENOSYS;
++      else res = EXECUTE_SYSCALL(syscall, regs);
++
++      return(res);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/syscall_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/syscall_user.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/syscall_user.c    2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,46 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <signal.h>
++#include "kern_util.h"
++#include "syscall_user.h"
++#include "sysdep/ptrace.h"
++#include "sysdep/sigcontext.h"
++
++/* XXX Bogus */
++#define ERESTARTSYS   512
++#define ERESTARTNOINTR        513
++#define ERESTARTNOHAND        514
++
++void handle_syscall(union uml_pt_regs *regs)
++{
++      long result;
++      int index;
++
++      index = record_syscall_start(UPT_SYSCALL_NR(regs));
++
++      syscall_trace();
++      result = execute_syscall(regs);
++
++      REGS_SET_SYSCALL_RETURN(regs->skas.regs, result);
++      if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || 
++         (result == -ERESTARTNOINTR))
++              do_signal(result);
++
++      syscall_trace();
++      record_syscall_end(index, result);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/sys-i386/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/sys-i386/Makefile    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/sys-i386/Makefile 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,17 @@
++# 
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET = sys-i386.o
++
++obj-y = sigcontext.o
++
++USER_OBJS = sigcontext.o
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++clean :
+Index: linux-2.4.29/arch/um/kernel/skas/sys-i386/sigcontext.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/sys-i386/sigcontext.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/sys-i386/sigcontext.c     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,114 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <errno.h>
++#include <asm/sigcontext.h>
++#include <sys/ptrace.h>
++#include <linux/ptrace.h>
++#include "sysdep/ptrace.h"
++#include "sysdep/ptrace_user.h"
++#include "kern_util.h"
++#include "user.h"
++#include "sigcontext.h"
++#include "mode.h"
++
++int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, void *from_ptr)
++{
++      struct sigcontext sc, *from = from_ptr;
++      unsigned long fpregs[FP_FRAME_SIZE];
++      int err;
++
++      err = copy_from_user_proc(&sc, from, sizeof(sc));
++      err |= copy_from_user_proc(fpregs, sc.fpstate, sizeof(fpregs));
++      if(err)
++              return(err);
++
++      regs->skas.regs[GS] = sc.gs;
++      regs->skas.regs[FS] = sc.fs;
++      regs->skas.regs[ES] = sc.es;
++      regs->skas.regs[DS] = sc.ds;
++      regs->skas.regs[EDI] = sc.edi;
++      regs->skas.regs[ESI] = sc.esi;
++      regs->skas.regs[EBP] = sc.ebp;
++      regs->skas.regs[UESP] = sc.esp;
++      regs->skas.regs[EBX] = sc.ebx;
++      regs->skas.regs[EDX] = sc.edx;
++      regs->skas.regs[ECX] = sc.ecx;
++      regs->skas.regs[EAX] = sc.eax;
++      regs->skas.regs[EIP] = sc.eip;
++      regs->skas.regs[CS] = sc.cs;
++      regs->skas.regs[EFL] = sc.eflags;
++      regs->skas.regs[SS] = sc.ss;
++      regs->skas.fault_addr = sc.cr2;
++      regs->skas.fault_type = FAULT_WRITE(sc.err);
++      regs->skas.trap_type = sc.trapno;
++
++      err = ptrace(PTRACE_SETFPREGS, pid, 0, fpregs);
++      if(err < 0){
++              printk("copy_sc_to_user - PTRACE_SETFPREGS failed, "
++                     "errno = %d\n", errno);
++              return(1);
++      }
++
++      return(0);
++}
++
++int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, 
++                       union uml_pt_regs *regs, unsigned long fault_addr, 
++                       int fault_type)
++{
++      struct sigcontext sc, *to = to_ptr;
++      struct _fpstate *to_fp;
++      unsigned long fpregs[FP_FRAME_SIZE];
++      int err;
++
++      sc.gs = regs->skas.regs[GS];
++      sc.fs = regs->skas.regs[FS];
++      sc.es = regs->skas.regs[ES];
++      sc.ds = regs->skas.regs[DS];
++      sc.edi = regs->skas.regs[EDI];
++      sc.esi = regs->skas.regs[ESI];
++      sc.ebp = regs->skas.regs[EBP];
++      sc.esp = regs->skas.regs[UESP];
++      sc.ebx = regs->skas.regs[EBX];
++      sc.edx = regs->skas.regs[EDX];
++      sc.ecx = regs->skas.regs[ECX];
++      sc.eax = regs->skas.regs[EAX];
++      sc.eip = regs->skas.regs[EIP];
++      sc.cs = regs->skas.regs[CS];
++      sc.eflags = regs->skas.regs[EFL];
++      sc.esp_at_signal = regs->skas.regs[UESP];
++      sc.ss = regs->skas.regs[SS];
++      sc.cr2 = fault_addr;
++      sc.err = TO_SC_ERR(fault_type);
++      sc.trapno = regs->skas.trap_type;
++
++      err = ptrace(PTRACE_GETFPREGS, pid, 0, fpregs);
++      if(err < 0){
++              printk("copy_sc_to_user - PTRACE_GETFPREGS failed, "
++                     "errno = %d\n", errno);
++              return(1);
++      }
++      to_fp = (struct _fpstate *) 
++              (fp ? (unsigned long) fp : ((unsigned long) to + sizeof(*to)));
++      sc.fpstate = to_fp;
++
++      if(err)
++              return(err);
++
++      return(copy_to_user_proc(to, &sc, sizeof(sc)) ||
++             copy_to_user_proc(to_fp, fpregs, sizeof(fpregs)));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/time.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/time.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/time.c    2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,30 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <sys/signal.h>
++#include <sys/time.h>
++#include "time_user.h"
++#include "process.h"
++#include "user.h"
++
++void user_time_init_skas(void)
++{
++        if(signal(SIGALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
++                panic("Couldn't set SIGALRM handler");
++      if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
++              panic("Couldn't set SIGVTALRM handler");
++      set_interval(ITIMER_VIRTUAL);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/tlb.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/tlb.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/tlb.c     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,153 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/sched.h"
++#include "asm/page.h"
++#include "asm/pgtable.h"
++#include "asm/mmu.h"
++#include "user_util.h"
++#include "mem_user.h"
++#include "skas.h"
++#include "os.h"
++
++static void fix_range(struct mm_struct *mm, unsigned long start_addr,
++                    unsigned long end_addr, int force)
++{
++      pgd_t *npgd;
++      pmd_t *npmd;
++      pte_t *npte;
++      unsigned long addr;
++      int r, w, x, err, fd;
++
++      if(mm == NULL) return;
++      fd = mm->context.skas.mm_fd;
++      for(addr = start_addr; addr < end_addr;){
++              npgd = pgd_offset(mm, addr);
++              npmd = pmd_offset(npgd, addr);
++              if(pmd_present(*npmd)){
++                      npte = pte_offset(npmd, addr);
++                      r = pte_read(*npte);
++                      w = pte_write(*npte);
++                      x = pte_exec(*npte);
++                      if(!pte_dirty(*npte)) w = 0;
++                      if(!pte_young(*npte)){
++                              r = 0;
++                              w = 0;
++                      }
++                      if(force || pte_newpage(*npte)){
++                              err = unmap(fd, (void *) addr, PAGE_SIZE);
++                              if(err < 0)
++                                      panic("munmap failed, errno = %d\n",
++                                            -err);
++                              if(pte_present(*npte))
++                                      map(fd, addr, 
++                                          pte_val(*npte) & PAGE_MASK,
++                                          PAGE_SIZE, r, w, x);
++                      }
++                      else if(pte_newprot(*npte)){
++                              protect(fd, addr, PAGE_SIZE, r, w, x, 1);
++                      }
++                      *npte = pte_mkuptodate(*npte);
++                      addr += PAGE_SIZE;
++              }
++              else {
++                      if(force || pmd_newpage(*npmd)){
++                              err = unmap(fd, (void *) addr, PMD_SIZE);
++                              if(err < 0)
++                                      panic("munmap failed, errno = %d\n",
++                                            -err);
++                              pmd_mkuptodate(*npmd);
++                      }
++                      addr += PMD_SIZE;
++              }
++      }
++}
++
++static void flush_kernel_vm_range(unsigned long start, unsigned long end)
++{
++      struct mm_struct *mm;
++      pgd_t *pgd;
++      pmd_t *pmd;
++      pte_t *pte;
++      unsigned long addr;
++      int updated = 0, err;
++
++      mm = &init_mm;
++      for(addr = start; addr < end;){
++              pgd = pgd_offset(mm, addr);
++              pmd = pmd_offset(pgd, addr);
++              if(pmd_present(*pmd)){
++                      pte = pte_offset(pmd, addr);
++                      if(!pte_present(*pte) || pte_newpage(*pte)){
++                              updated = 1;
++                              err = os_unmap_memory((void *) addr, 
++                                                    PAGE_SIZE);
++                              if(err < 0)
++                                      panic("munmap failed, errno = %d\n",
++                                            -err);
++                              if(pte_present(*pte))
++                                      map_memory(addr, 
++                                                 pte_val(*pte) & PAGE_MASK,
++                                                 PAGE_SIZE, 1, 1, 1);
++                      }
++                      else if(pte_newprot(*pte)){
++                              updated = 1;
++                              protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1);
++                      }
++                      addr += PAGE_SIZE;
++              }
++              else {
++                      if(pmd_newpage(*pmd)){
++                              updated = 1;
++                              err = os_unmap_memory((void *) addr, PMD_SIZE);
++                              if(err < 0)
++                                      panic("munmap failed, errno = %d\n",
++                                            -err);
++                      }
++                      addr += PMD_SIZE;
++              }
++      }
++}
++
++void flush_tlb_kernel_vm_skas(void)
++{
++      flush_kernel_vm_range(start_vm, end_vm);
++}
++
++void __flush_tlb_one_skas(unsigned long addr)
++{
++      flush_kernel_vm_range(addr, addr + PAGE_SIZE);
++}
++
++void flush_tlb_range_skas(struct mm_struct *mm, unsigned long start, 
++                   unsigned long end)
++{
++      if(mm == NULL)
++              flush_kernel_vm_range(start, end);
++      else fix_range(mm, start, end, 0);
++}
++
++void flush_tlb_mm_skas(struct mm_struct *mm)
++{
++      flush_tlb_kernel_vm_skas();
++      fix_range(mm, 0, host_task_size, 0);
++}
++
++void force_flush_all_skas(void)
++{
++      fix_range(current->mm, 0, host_task_size, 1);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/trap_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/trap_user.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/trap_user.c       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,66 @@
++/* 
++ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <signal.h>
++#include <errno.h>
++#include <asm/sigcontext.h>
++#include "sysdep/ptrace.h"
++#include "signal_user.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "task.h"
++#include "sigcontext.h"
++
++void sig_handler_common_skas(int sig, void *sc_ptr)
++{
++      struct sigcontext *sc = sc_ptr;
++      struct skas_regs *r;
++      struct signal_info *info;
++      int save_errno = errno;
++      int save_user;
++
++      r = &TASK_REGS(get_current())->skas;
++      save_user = r->is_user;
++      r->is_user = 0;
++      r->fault_addr = SC_FAULT_ADDR(sc);
++      r->fault_type = SC_FAULT_TYPE(sc);
++      r->trap_type = SC_TRAP_TYPE(sc);
++
++      change_sig(SIGUSR1, 1);
++      info = &sig_info[sig];
++      if(!info->is_irq) unblock_signals();
++
++      (*info->handler)(sig, (union uml_pt_regs *) r);
++
++      errno = save_errno;
++      r->is_user = save_user;
++}
++
++extern int missed_ticks[];
++
++void user_signal(int sig, union uml_pt_regs *regs)
++{
++      struct signal_info *info;
++
++      regs->skas.is_user = 1;
++      regs->skas.fault_addr = 0;
++      regs->skas.fault_type = 0;
++      regs->skas.trap_type = 0;
++      info = &sig_info[sig];
++      (*info->handler)(sig, regs);
++
++      unblock_signals();
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/uaccess.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/uaccess.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/uaccess.c 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,248 @@
++/* 
++ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/kernel.h"
++#include "linux/string.h"
++#include "linux/fs.h"
++#include "linux/highmem.h"
++#include "asm/page.h"
++#include "asm/pgtable.h"
++#include "asm/uaccess.h"
++#include "kern_util.h"
++#include "user_util.h"
++
++extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, 
++                           pte_t *pte_out);
++
++static unsigned long maybe_map(unsigned long virt, int is_write)
++{
++      pte_t pte;
++
++      void *phys = um_virt_to_phys(current, virt, &pte);
++      int dummy_code;
++
++      if(IS_ERR(phys) || (is_write && !pte_write(pte))){
++              if(!handle_page_fault(virt, 0, is_write, 1, &dummy_code))
++                      return(0);
++              phys = um_virt_to_phys(current, virt, NULL);
++      }
++      return((unsigned long) phys);
++}
++
++static int do_op(unsigned long addr, int len, int is_write, 
++               int (*op)(unsigned long addr, int len, void *arg), void *arg)
++{
++      struct page *page;
++      int n;
++
++      addr = maybe_map(addr, is_write);
++      if(addr == -1)
++              return(-1);
++
++      page = phys_to_page(addr);
++      addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK);
++      n = (*op)(addr, len, arg);
++      kunmap(page);
++
++      return(n);
++}
++
++static void do_buffer_op(void *jmpbuf, void *arg_ptr)
++{
++      va_list args = *((va_list *) arg_ptr);
++      unsigned long addr = va_arg(args, unsigned long);
++      int len = va_arg(args, int);
++      int is_write = va_arg(args, int);
++      int (*op)(unsigned long, int, void *) = va_arg(args, void *);
++      void *arg = va_arg(args, void *);
++      int *res = va_arg(args, int *);
++      int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
++      int remain = len, n;
++
++      current->thread.fault_catcher = jmpbuf;
++      n = do_op(addr, size, is_write, op, arg);
++      if(n != 0){
++              *res = (n < 0 ? remain : 0);
++              goto out;
++      }
++
++      addr += size;
++      remain -= size;
++      if(remain == 0){
++              *res = 0;
++              goto out;
++      }
++
++      while(addr < ((addr + remain) & PAGE_MASK)){
++              n = do_op(addr, PAGE_SIZE, is_write, op, arg);
++              if(n != 0){
++                      *res = (n < 0 ? remain : 0);
++                      goto out;
++              }
++
++              addr += PAGE_SIZE;
++              remain -= PAGE_SIZE;
++      }
++      if(remain == 0){
++              *res = 0;
++              goto out;
++      }
++
++      n = do_op(addr, remain, is_write, op, arg);
++      if(n != 0)
++              *res = (n < 0 ? remain : 0);
++      else *res = 0;
++ out:
++      current->thread.fault_catcher = NULL;
++}
++
++static int buffer_op(unsigned long addr, int len, int is_write,
++                   int (*op)(unsigned long addr, int len, void *arg),
++                   void *arg)
++{
++      int faulted, res;
++      
++      faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg, 
++                               &res);
++      if(!faulted)
++              return(res);
++
++      return(addr + len - (unsigned long) current->thread.fault_addr);
++}
++
++static int copy_chunk_from_user(unsigned long from, int len, void *arg)
++{
++      unsigned long *to_ptr = arg, to = *to_ptr;
++
++      memcpy((void *) to, (void *) from, len);
++      *to_ptr += len;
++      return(0);
++}
++
++int copy_from_user_skas(void *to, const void *from, int n)
++{
++      if(segment_eq(get_fs(), KERNEL_DS)){
++              memcpy(to, from, n);
++              return(0);
++      }
++
++      return(access_ok_skas(VERIFY_READ, from, n) ?
++             buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
++             n);
++}
++
++static int copy_chunk_to_user(unsigned long to, int len, void *arg)
++{
++      unsigned long *from_ptr = arg, from = *from_ptr;
++
++      memcpy((void *) to, (void *) from, len);
++      *from_ptr += len;
++      return(0);
++}
++
++int copy_to_user_skas(void *to, const void *from, int n)
++{
++      if(segment_eq(get_fs(), KERNEL_DS)){
++              memcpy(to, from, n);
++              return(0);
++      }
++
++      return(access_ok_skas(VERIFY_WRITE, to, n) ?
++             buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
++             n);
++}
++
++static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)
++{
++      char **to_ptr = arg, *to = *to_ptr;
++      int n;
++
++      strncpy(to, (void *) from, len);
++      n = strnlen(to, len);
++      *to_ptr += n;
++
++      if(n < len) 
++              return(1);
++      return(0);
++}
++
++int strncpy_from_user_skas(char *dst, const char *src, int count)
++{
++      int n;
++      char *ptr = dst;
++
++      if(segment_eq(get_fs(), KERNEL_DS)){
++              strncpy(dst, src, count);
++              return(strnlen(dst, count));
++      }
++
++      if(!access_ok_skas(VERIFY_READ, src, 1))
++              return(-EFAULT);
++
++      n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user, 
++                    &ptr);
++      if(n != 0)
++              return(-EFAULT);
++      return(strnlen(dst, count));
++}
++
++static int clear_chunk(unsigned long addr, int len, void *unused)
++{
++      memset((void *) addr, 0, len);
++      return(0);
++}
++
++int __clear_user_skas(void *mem, int len)
++{
++      return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL));
++}
++
++int clear_user_skas(void *mem, int len)
++{
++      if(segment_eq(get_fs(), KERNEL_DS)){
++              memset(mem, 0, len);
++              return(0);
++      }
++
++      return(access_ok_skas(VERIFY_WRITE, mem, len) ? 
++             buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len);
++}
++
++static int strnlen_chunk(unsigned long str, int len, void *arg)
++{
++      int *len_ptr = arg, n;
++
++      n = strnlen((void *) str, len);
++      *len_ptr += n;
++
++      if(n < len)
++              return(1);
++      return(0);
++}
++
++int strnlen_user_skas(const void *str, int len)
++{
++      int count = 0, n;
++
++      if(segment_eq(get_fs(), KERNEL_DS))
++              return(strnlen(str, len) + 1);
++
++      n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count);
++      if(n == 0)
++              return(count + 1);
++      return(-EFAULT);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/skas/util/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/util/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/util/Makefile     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,10 @@
++all: mk_ptregs
++
++mk_ptregs : mk_ptregs.o
++      $(HOSTCC) -o mk_ptregs mk_ptregs.o
++
++mk_ptregs.o : mk_ptregs.c
++      $(HOSTCC) -c $< 
++
++clean : 
++      $(RM) -f mk_ptregs *.o *~
+Index: linux-2.4.29/arch/um/kernel/skas/util/mk_ptregs.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/skas/util/mk_ptregs.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/skas/util/mk_ptregs.c  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,51 @@
++#include <stdio.h>
++#include <asm/ptrace.h>
++#include <asm/user.h>
++
++#define PRINT_REG(name, val) printf("#define HOST_%s %d\n", (name), (val))
++
++int main(int argc, char **argv)
++{
++      printf("/* Automatically generated by "
++             "arch/um/kernel/skas/util/mk_ptregs */\n");
++      printf("\n");
++      printf("#ifndef __SKAS_PT_REGS_\n");
++      printf("#define __SKAS_PT_REGS_\n");
++      printf("\n");
++      printf("#define HOST_FRAME_SIZE %d\n", FRAME_SIZE);
++      printf("#define HOST_FP_SIZE %d\n", 
++             sizeof(struct user_i387_struct) / sizeof(unsigned long));
++      printf("#define HOST_XFP_SIZE %d\n", 
++             sizeof(struct user_fxsr_struct) / sizeof(unsigned long));
++
++      PRINT_REG("IP", EIP);
++      PRINT_REG("SP", UESP);
++      PRINT_REG("EFLAGS", EFL);
++      PRINT_REG("EAX", EAX);
++      PRINT_REG("EBX", EBX);
++      PRINT_REG("ECX", ECX);
++      PRINT_REG("EDX", EDX);
++      PRINT_REG("ESI", ESI);
++      PRINT_REG("EDI", EDI);
++      PRINT_REG("EBP", EBP);
++      PRINT_REG("CS", CS);
++      PRINT_REG("SS", SS);
++      PRINT_REG("DS", DS);
++      PRINT_REG("FS", FS);
++      PRINT_REG("ES", ES);
++      PRINT_REG("GS", GS);
++      printf("\n");
++      printf("#endif\n");
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/smp.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/smp.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/smp.c  2005-05-03 22:28:14.476409464 +0300
+@@ -0,0 +1,329 @@
++/* 
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++
++#ifdef CONFIG_SMP
++
++#include "linux/sched.h"
++#include "linux/threads.h"
++#include "linux/interrupt.h"
++#include "asm/smp.h"
++#include "asm/processor.h"
++#include "asm/spinlock.h"
++#include "asm/softirq.h"
++#include "asm/hardirq.h"
++#include "asm/tlb.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "irq_user.h"
++#include "kern.h"
++#include "os.h"
++
++/* Total count of live CPUs, set by smp_boot_cpus */
++int smp_num_cpus = 1;
++
++/* The 'big kernel lock' */
++spinlock_cacheline_t kernel_flag_cacheline = {SPIN_LOCK_UNLOCKED};
++
++/* Per CPU bogomips and other parameters */
++
++/* The only piece used here is the ipi pipe, which is set before SMP is
++ * started and never changed.
++ */
++struct cpuinfo_um cpu_data[NR_CPUS];
++
++/* CPU online map, set by smp_boot_cpus */
++unsigned long cpu_online_map;
++
++atomic_t global_bh_count;
++
++/* Set when the idlers are all forked */
++int smp_threads_ready = 0;
++
++/* Not used by UML */
++unsigned char global_irq_holder = 0;
++unsigned volatile long global_irq_lock;
++
++/* A statistic, can be a little off */
++static int num_reschedules_sent = 0;
++
++mmu_gather_t mmu_gathers[NR_CPUS];
++
++void smp_send_reschedule(int cpu)
++{
++      os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1);
++      num_reschedules_sent++;
++}
++
++static void show(char * str)
++{
++      int cpu = smp_processor_id();
++
++      printk(KERN_INFO "\n%s, CPU %d:\n", str, cpu);
++}
++      
++#define MAXCOUNT 100000000
++
++static inline void wait_on_bh(void)
++{
++      int count = MAXCOUNT;
++      do {
++              if (!--count) {
++                      show("wait_on_bh");
++                      count = ~0;
++              }
++              /* nothing .. wait for the other bh's to go away */
++      } while (atomic_read(&global_bh_count) != 0);
++}
++
++/*
++ * This is called when we want to synchronize with
++ * bottom half handlers. We need to wait until
++ * no other CPU is executing any bottom half handler.
++ *
++ * Don't wait if we're already running in an interrupt
++ * context or are inside a bh handler. 
++ */
++void synchronize_bh(void)
++{
++      if (atomic_read(&global_bh_count) && !in_interrupt())
++              wait_on_bh();
++}
++
++void smp_send_stop(void)
++{
++      int i;
++ 
++      printk(KERN_INFO "Stopping all CPUs...");
++      for(i = 0; i < ncpus; i++){
++              if(i == current->processor)
++                      continue;
++              os_write_file(cpu_data[i].ipi_pipe[1], "S", 1);
++      }
++      printk("done\n");
++}
++
++
++static atomic_t smp_commenced = ATOMIC_INIT(0);
++static volatile unsigned long smp_callin_map = 0;
++
++void smp_commence(void)
++{
++      printk("All CPUs are go!\n");
++
++      wmb();
++      atomic_set(&smp_commenced, 1);
++}
++
++static int idle_proc(void *unused)
++{
++      int cpu, err;
++
++      set_current(current);
++      del_from_runqueue(current);
++      unhash_process(current);
++
++      cpu = current->processor;
++      err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1);
++      if(err < 0)
++              panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
++
++      activate_ipi(cpu_data[cpu].ipi_pipe[0], 
++                   current->thread.mode.tt.extern_pid);
++ 
++      wmb();
++      if (test_and_set_bit(current->processor, &smp_callin_map)) {
++              printk("huh, CPU#%d already present??\n", current->processor);
++              BUG();
++      }
++
++      while (!atomic_read(&smp_commenced))
++              cpu_relax();
++
++      init_idle();
++      cpu_idle();
++      return(0);
++}
++
++static int idle_thread(int (*fn)(void *), int cpu)
++{
++      struct task_struct *new_task;
++      int pid;
++      unsigned char c;
++
++        current->thread.request.u.thread.proc = fn;
++        current->thread.request.u.thread.arg = NULL;
++      pid = do_fork(CLONE_VM | CLONE_PID, 0, NULL, 0);
++      if(pid < 0) 
++              panic("do_fork failed in idle_thread");
++      new_task = get_task(pid, 1);
++
++      cpu_tasks[cpu] = ((struct cpu_task) 
++                        { .pid =      new_task->thread.mode.tt.extern_pid,
++                          .task =     new_task } );
++      init_tasks[cpu] = new_task;
++      new_task->processor = cpu;
++      new_task->cpus_allowed = 1 << cpu;
++      new_task->cpus_runnable = new_task->cpus_allowed;
++      CHOOSE_MODE(({ struct file_handle *pipe;
++                     pipe = new_task->thread.mode.tt.switch_pipe;
++                     write_file(&pipe[1], -1, &c, sizeof(c)); }),
++                  ({ panic("skas mode doesn't support SMP"); }));
++      return(new_task->thread.mode.tt.extern_pid);
++}
++
++void smp_boot_cpus(void)
++{
++      int err;
++
++      set_bit(0, &cpu_online_map);
++      set_bit(0, &smp_callin_map);
++
++      err = os_pipe(cpu_data[0].ipi_pipe, 1, 1);
++      if(err < 0) 
++              panic("CPU#0 failed to create IPI pipe, err = %d", -err);
++
++      activate_ipi(cpu_data[0].ipi_pipe[0], 
++                   current->thread.mode.tt.extern_pid);
++
++      if(ncpus < 1){
++              printk(KERN_INFO "ncpus set to 1\n");
++              ncpus = 1;
++      }
++      else if(ncpus > NR_CPUS){
++              printk(KERN_INFO 
++                     "ncpus can't be greater than NR_CPUS, set to %d\n",
++                     NR_CPUS);
++              ncpus = NR_CPUS;
++      }
++
++      if(ncpus > 1){
++              int i, pid;
++
++              printk(KERN_INFO "Starting up other processors:\n");
++              for(i=1;i<ncpus;i++){
++                      int waittime;
++
++                      /* Do this early, for hard_smp_processor_id()  */
++                      cpu_tasks[i].pid = -1;
++                      set_bit(i, &cpu_online_map);
++                      smp_num_cpus++;
++
++                      pid = idle_thread(idle_proc, i);
++                      printk(KERN_INFO "\t#%d - idle thread pid = %d.. ",
++                             i, pid);
++
++                      waittime = 200000000;
++                      while (waittime-- && !test_bit(i, &smp_callin_map))
++                              cpu_relax();
++
++                      if (test_bit(i, &smp_callin_map))
++                              printk("online\n");
++                      else {
++                              printk("failed\n");
++                              clear_bit(i, &cpu_online_map);
++                      }
++              }
++      }
++}
++
++int setup_profiling_timer(unsigned int multiplier)
++{
++      printk(KERN_INFO "setup_profiling_timer\n");
++      return(0);
++}
++
++void smp_call_function_slave(int cpu);
++
++void IPI_handler(int cpu)
++{
++      unsigned char c;
++      int fd;
++
++      fd = cpu_data[cpu].ipi_pipe[0];
++      while (os_read_file(fd, &c, 1) == 1) {
++              switch (c) {
++              case 'C':
++                      smp_call_function_slave(cpu);
++                      break;
++
++              case 'R':
++                      current->need_resched = 1;
++                      break;
++
++              case 'S':
++                      printk("CPU#%d stopping\n", cpu);
++                      while(1)
++                              pause();
++                      break;
++
++              default:
++                      printk("CPU#%d received unknown IPI [%c]!\n", cpu, c);
++                      break;
++              }
++      }
++}
++
++int hard_smp_processor_id(void)
++{
++      return(pid_to_processor_id(os_getpid()));
++}
++
++static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
++static atomic_t scf_started;
++static atomic_t scf_finished;
++static void (*func)(void *info);
++static void *info;
++
++void smp_call_function_slave(int cpu)
++{
++      atomic_inc(&scf_started);
++      (*func)(info);
++      atomic_inc(&scf_finished);
++}
++
++int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, 
++                    int wait)
++{
++      int cpus = smp_num_cpus - 1;
++      int i;
++
++      if (!cpus)
++              return 0;
++
++      spin_lock_bh(&call_lock);
++      atomic_set(&scf_started, 0);
++      atomic_set(&scf_finished, 0);
++      func = _func;
++      info = _info;
++
++      for (i=0;i<NR_CPUS;i++)
++              if (i != current->processor && test_bit(i, &cpu_online_map))
++                      os_write_file(cpu_data[i].ipi_pipe[1], "C", 1);
++
++      while (atomic_read(&scf_started) != cpus)
++              barrier();
++
++      if (wait)
++              while (atomic_read(&scf_finished) != cpus)
++                      barrier();
++
++      spin_unlock_bh(&call_lock);
++      return 0;
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/syscall_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/syscall_kern.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/syscall_kern.c 2005-05-03 22:28:14.477409312 +0300
+@@ -0,0 +1,343 @@
++/* 
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/file.h"
++#include "linux/smp_lock.h"
++#include "linux/mm.h"
++#include "linux/utsname.h"
++#include "linux/msg.h"
++#include "linux/shm.h"
++#include "linux/sys.h"
++#include "linux/unistd.h"
++#include "linux/slab.h"
++#include "linux/utime.h"
++#include "asm/mman.h"
++#include "asm/uaccess.h"
++#include "asm/ipc.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "sysdep/syscalls.h"
++#include "mode_kern.h"
++#include "choose-mode.h"
++
++/*  Unlocked, I don't care if this is a bit off */
++int nsyscalls = 0;
++
++long um_mount(char * dev_name, char * dir_name, char * type,
++            unsigned long new_flags, void * data)
++{
++      if(type == NULL) type = "";
++      return(sys_mount(dev_name, dir_name, type, new_flags, data));
++}
++
++long sys_fork(void)
++{
++      long ret;
++
++      current->thread.forking = 1;
++        ret = do_fork(SIGCHLD, 0, NULL, 0);
++      current->thread.forking = 0;
++      return(ret);
++}
++
++long sys_clone(unsigned long clone_flags, unsigned long newsp)
++{
++      long ret;
++
++      current->thread.forking = 1;
++      ret = do_fork(clone_flags, newsp, NULL, 0);
++      current->thread.forking = 0;
++      return(ret);
++}
++
++long sys_vfork(void)
++{
++      long ret;
++
++      current->thread.forking = 1;
++      ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0);
++      current->thread.forking = 0;
++      return(ret);
++}
++
++/* common code for old and new mmaps */
++long do_mmap2(struct mm_struct *mm, unsigned long addr, unsigned long len,
++            unsigned long prot, unsigned long flags, unsigned long fd,
++            unsigned long pgoff)
++{
++      int error = -EBADF;
++      struct file * file = NULL;
++
++      flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
++      if (!(flags & MAP_ANONYMOUS)) {
++              file = fget(fd);
++              if (!file)
++                      goto out;
++      }
++
++      down_write(&mm->mmap_sem);
++      error = do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++      up_write(&mm->mmap_sem);
++
++      if (file)
++              fput(file);
++ out:
++      return error;
++}
++
++long sys_mmap2(unsigned long addr, unsigned long len,
++             unsigned long prot, unsigned long flags,
++             unsigned long fd, unsigned long pgoff)
++{
++      return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++}
++
++/*
++ * Perform the select(nd, in, out, ex, tv) and mmap() system
++ * calls. Linux/i386 didn't use to be able to handle more than
++ * 4 system call parameters, so these system calls used a memory
++ * block for parameter passing..
++ */
++
++struct mmap_arg_struct {
++      unsigned long addr;
++      unsigned long len;
++      unsigned long prot;
++      unsigned long flags;
++      unsigned long fd;
++      unsigned long offset;
++};
++
++int old_mmap(unsigned long addr, unsigned long len,
++           unsigned long prot, unsigned long flags,
++           unsigned long fd, unsigned long offset)
++{
++      int err = -EINVAL;
++      if (offset & ~PAGE_MASK)
++              goto out;
++
++      err = do_mmap2(current->mm, addr, len, prot, flags, fd, 
++                     offset >> PAGE_SHIFT);
++ out:
++      return err;
++}
++/*
++ * sys_pipe() is the normal C calling standard for creating
++ * a pipe. It's not the way unix traditionally does this, though.
++ */
++int sys_pipe(unsigned long * fildes)
++{
++        int fd[2];
++        int error;
++
++        error = do_pipe(fd);
++        if (!error) {
++              if (copy_to_user(fildes, fd, sizeof(fd)))
++                        error = -EFAULT;
++        }
++        return error;
++}
++
++int sys_pause(void)
++{
++      current->state = TASK_INTERRUPTIBLE;
++      schedule();
++      return -ERESTARTNOHAND;
++}
++
++int sys_sigaction(int sig, const struct old_sigaction *act,
++                       struct old_sigaction *oact)
++{
++      struct k_sigaction new_ka, old_ka;
++      int ret;
++
++      if (act) {
++              old_sigset_t mask;
++              if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
++                  __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
++                  __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
++                      return -EFAULT;
++              __get_user(new_ka.sa.sa_flags, &act->sa_flags);
++              __get_user(mask, &act->sa_mask);
++              siginitset(&new_ka.sa.sa_mask, mask);
++      }
++
++      ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
++
++      if (!ret && oact) {
++              if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
++                  __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
++                  __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
++                      return -EFAULT;
++              __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
++              __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
++      }
++
++      return ret;
++}
++
++/*
++ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
++ *
++ * This is really horribly ugly.
++ */
++int sys_ipc (uint call, int first, int second,
++           int third, void *ptr, long fifth)
++{
++      int version, ret;
++
++      version = call >> 16; /* hack for backward compatibility */
++      call &= 0xffff;
++
++      switch (call) {
++      case SEMOP:
++              return sys_semop (first, (struct sembuf *)ptr, second);
++      case SEMGET:
++              return sys_semget (first, second, third);
++      case SEMCTL: {
++              union semun fourth;
++              if (!ptr)
++                      return -EINVAL;
++              if (get_user(fourth.__pad, (void **) ptr))
++                      return -EFAULT;
++              return sys_semctl (first, second, third, fourth);
++      }
++
++      case MSGSND:
++              return sys_msgsnd (first, (struct msgbuf *) ptr, 
++                                 second, third);
++      case MSGRCV:
++              switch (version) {
++              case 0: {
++                      struct ipc_kludge tmp;
++                      if (!ptr)
++                              return -EINVAL;
++                      
++                      if (copy_from_user(&tmp,
++                                         (struct ipc_kludge *) ptr, 
++                                         sizeof (tmp)))
++                              return -EFAULT;
++                      return sys_msgrcv (first, tmp.msgp, second,
++                                         tmp.msgtyp, third);
++              }
++              default:
++                      panic("msgrcv with version != 0");
++                      return sys_msgrcv (first,
++                                         (struct msgbuf *) ptr,
++                                         second, fifth, third);
++              }
++      case MSGGET:
++              return sys_msgget ((key_t) first, second);
++      case MSGCTL:
++              return sys_msgctl (first, second, (struct msqid_ds *) ptr);
++
++      case SHMAT:
++              switch (version) {
++              default: {
++                      ulong raddr;
++                      ret = sys_shmat (first, (char *) ptr, second, &raddr);
++                      if (ret)
++                              return ret;
++                      return put_user (raddr, (ulong *) third);
++              }
++              case 1: /* iBCS2 emulator entry point */
++                      if (!segment_eq(get_fs(), get_ds()))
++                              return -EINVAL;
++                      return sys_shmat (first, (char *) ptr, second, (ulong *) third);
++              }
++      case SHMDT: 
++              return sys_shmdt ((char *)ptr);
++      case SHMGET:
++              return sys_shmget (first, second, third);
++      case SHMCTL:
++              return sys_shmctl (first, second,
++                                 (struct shmid_ds *) ptr);
++      default:
++              return -EINVAL;
++      }
++}
++
++int sys_uname(struct old_utsname * name)
++{
++      int err;
++      if (!name)
++              return -EFAULT;
++      down_read(&uts_sem);
++      err=copy_to_user(name, &system_utsname, sizeof (*name));
++      up_read(&uts_sem);
++      return err?-EFAULT:0;
++}
++
++int sys_olduname(struct oldold_utsname * name)
++{
++      int error;
++
++      if (!name)
++              return -EFAULT;
++      if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
++              return -EFAULT;
++  
++      down_read(&uts_sem);
++      
++      error = __copy_to_user(&name->sysname,&system_utsname.sysname,
++                             __OLD_UTS_LEN);
++      error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
++      error |= __copy_to_user(&name->nodename,&system_utsname.nodename,
++                              __OLD_UTS_LEN);
++      error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
++      error |= __copy_to_user(&name->release,&system_utsname.release,
++                              __OLD_UTS_LEN);
++      error |= __put_user(0,name->release+__OLD_UTS_LEN);
++      error |= __copy_to_user(&name->version,&system_utsname.version,
++                              __OLD_UTS_LEN);
++      error |= __put_user(0,name->version+__OLD_UTS_LEN);
++      error |= __copy_to_user(&name->machine,&system_utsname.machine,
++                              __OLD_UTS_LEN);
++      error |= __put_user(0,name->machine+__OLD_UTS_LEN);
++      
++      up_read(&uts_sem);
++      
++      error = error ? -EFAULT : 0;
++
++      return error;
++}
++
++int sys_sigaltstack(const stack_t *uss, stack_t *uoss)
++{
++      return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
++}
++
++long execute_syscall(void *r)
++{
++      return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r));
++}
++
++spinlock_t syscall_lock = SPIN_LOCK_UNLOCKED;
++
++static int syscall_index = 0;
++
++int next_syscall_index(int limit)
++{
++      int ret;
++
++      spin_lock(&syscall_lock);
++      ret = syscall_index;
++      if(++syscall_index == limit)
++              syscall_index = 0;
++      spin_unlock(&syscall_lock);
++      return(ret);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/sys_call_table.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/sys_call_table.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/sys_call_table.c       2005-05-03 22:28:14.480408856 +0300
+@@ -0,0 +1,496 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/unistd.h"
++#include "linux/version.h"
++#include "linux/sys.h"
++#include "asm/signal.h"
++#include "sysdep/syscalls.h"
++#include "kern_util.h"
++
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_exit;
++extern syscall_handler_t sys_fork;
++extern syscall_handler_t sys_creat;
++extern syscall_handler_t sys_link;
++extern syscall_handler_t sys_unlink;
++extern syscall_handler_t sys_chdir;
++extern syscall_handler_t sys_mknod;
++extern syscall_handler_t sys_chmod;
++extern syscall_handler_t sys_lchown16;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_stat;
++extern syscall_handler_t sys_getpid;
++extern syscall_handler_t sys_oldumount;
++extern syscall_handler_t sys_setuid16;
++extern syscall_handler_t sys_getuid16;
++extern syscall_handler_t sys_ptrace;
++extern syscall_handler_t sys_alarm;
++extern syscall_handler_t sys_fstat;
++extern syscall_handler_t sys_pause;
++extern syscall_handler_t sys_utime;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_access;
++extern syscall_handler_t sys_nice;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_sync;
++extern syscall_handler_t sys_kill;
++extern syscall_handler_t sys_rename;
++extern syscall_handler_t sys_mkdir;
++extern syscall_handler_t sys_rmdir;
++extern syscall_handler_t sys_pipe;
++extern syscall_handler_t sys_times;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_brk;
++extern syscall_handler_t sys_setgid16;
++extern syscall_handler_t sys_getgid16;
++extern syscall_handler_t sys_signal;
++extern syscall_handler_t sys_geteuid16;
++extern syscall_handler_t sys_getegid16;
++extern syscall_handler_t sys_acct;
++extern syscall_handler_t sys_umount;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_ioctl;
++extern syscall_handler_t sys_fcntl;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_setpgid;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_olduname;
++extern syscall_handler_t sys_umask;
++extern syscall_handler_t sys_chroot;
++extern syscall_handler_t sys_ustat;
++extern syscall_handler_t sys_dup2;
++extern syscall_handler_t sys_getppid;
++extern syscall_handler_t sys_getpgrp;
++extern syscall_handler_t sys_sigaction;
++extern syscall_handler_t sys_sgetmask;
++extern syscall_handler_t sys_ssetmask;
++extern syscall_handler_t sys_setreuid16;
++extern syscall_handler_t sys_setregid16;
++extern syscall_handler_t sys_sigsuspend;
++extern syscall_handler_t sys_sigpending;
++extern syscall_handler_t sys_sethostname;
++extern syscall_handler_t sys_setrlimit;
++extern syscall_handler_t sys_old_getrlimit;
++extern syscall_handler_t sys_getrusage;
++extern syscall_handler_t sys_gettimeofday;
++extern syscall_handler_t sys_settimeofday;
++extern syscall_handler_t sys_getgroups16;
++extern syscall_handler_t sys_setgroups16;
++extern syscall_handler_t sys_symlink;
++extern syscall_handler_t sys_lstat;
++extern syscall_handler_t sys_readlink;
++extern syscall_handler_t sys_uselib;
++extern syscall_handler_t sys_swapon;
++extern syscall_handler_t sys_reboot;
++extern syscall_handler_t old_readdir;
++extern syscall_handler_t sys_munmap;
++extern syscall_handler_t sys_truncate;
++extern syscall_handler_t sys_ftruncate;
++extern syscall_handler_t sys_fchmod;
++extern syscall_handler_t sys_fchown16;
++extern syscall_handler_t sys_getpriority;
++extern syscall_handler_t sys_setpriority;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_statfs;
++extern syscall_handler_t sys_fstatfs;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_socketcall;
++extern syscall_handler_t sys_syslog;
++extern syscall_handler_t sys_setitimer;
++extern syscall_handler_t sys_getitimer;
++extern syscall_handler_t sys_newstat;
++extern syscall_handler_t sys_newlstat;
++extern syscall_handler_t sys_newfstat;
++extern syscall_handler_t sys_uname;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_vhangup;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_swapoff;
++extern syscall_handler_t sys_sysinfo;
++extern syscall_handler_t sys_ipc;
++extern syscall_handler_t sys_fsync;
++extern syscall_handler_t sys_sigreturn;
++extern syscall_handler_t sys_rt_sigreturn;
++extern syscall_handler_t sys_clone;
++extern syscall_handler_t sys_setdomainname;
++extern syscall_handler_t sys_newuname;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_adjtimex;
++extern syscall_handler_t sys_mprotect;
++extern syscall_handler_t sys_sigprocmask;
++extern syscall_handler_t sys_create_module;
++extern syscall_handler_t sys_init_module;
++extern syscall_handler_t sys_delete_module;
++extern syscall_handler_t sys_get_kernel_syms;
++extern syscall_handler_t sys_quotactl;
++extern syscall_handler_t sys_getpgid;
++extern syscall_handler_t sys_fchdir;
++extern syscall_handler_t sys_bdflush;
++extern syscall_handler_t sys_sysfs;
++extern syscall_handler_t sys_personality;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_setfsuid16;
++extern syscall_handler_t sys_setfsgid16;
++extern syscall_handler_t sys_llseek;
++extern syscall_handler_t sys_getdents;
++extern syscall_handler_t sys_flock;
++extern syscall_handler_t sys_msync;
++extern syscall_handler_t sys_readv;
++extern syscall_handler_t sys_writev;
++extern syscall_handler_t sys_getsid;
++extern syscall_handler_t sys_fdatasync;
++extern syscall_handler_t sys_sysctl;
++extern syscall_handler_t sys_mlock;
++extern syscall_handler_t sys_munlock;
++extern syscall_handler_t sys_mlockall;
++extern syscall_handler_t sys_munlockall;
++extern syscall_handler_t sys_sched_setparam;
++extern syscall_handler_t sys_sched_getparam;
++extern syscall_handler_t sys_sched_setscheduler;
++extern syscall_handler_t sys_sched_getscheduler;
++extern syscall_handler_t sys_sched_get_priority_max;
++extern syscall_handler_t sys_sched_get_priority_min;
++extern syscall_handler_t sys_sched_rr_get_interval;
++extern syscall_handler_t sys_nanosleep;
++extern syscall_handler_t sys_mremap;
++extern syscall_handler_t sys_setresuid16;
++extern syscall_handler_t sys_getresuid16;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_query_module;
++extern syscall_handler_t sys_poll;
++extern syscall_handler_t sys_nfsservctl;
++extern syscall_handler_t sys_setresgid16;
++extern syscall_handler_t sys_getresgid16;
++extern syscall_handler_t sys_prctl;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_rt_sigaction;
++extern syscall_handler_t sys_rt_sigprocmask;
++extern syscall_handler_t sys_rt_sigpending;
++extern syscall_handler_t sys_rt_sigtimedwait;
++extern syscall_handler_t sys_rt_sigqueueinfo;
++extern syscall_handler_t sys_rt_sigsuspend;
++extern syscall_handler_t sys_pread;
++extern syscall_handler_t sys_pwrite;
++extern syscall_handler_t sys_chown16;
++extern syscall_handler_t sys_getcwd;
++extern syscall_handler_t sys_capget;
++extern syscall_handler_t sys_capset;
++extern syscall_handler_t sys_sigaltstack;
++extern syscall_handler_t sys_sendfile;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_ni_syscall;
++extern syscall_handler_t sys_vfork;
++extern syscall_handler_t sys_getrlimit;
++extern syscall_handler_t sys_mmap2;
++extern syscall_handler_t sys_truncate64;
++extern syscall_handler_t sys_ftruncate64;
++extern syscall_handler_t sys_stat64;
++extern syscall_handler_t sys_lstat64;
++extern syscall_handler_t sys_fstat64;
++extern syscall_handler_t sys_lchown;
++extern syscall_handler_t sys_getuid;
++extern syscall_handler_t sys_getgid;
++extern syscall_handler_t sys_geteuid;
++extern syscall_handler_t sys_getegid;
++extern syscall_handler_t sys_setreuid;
++extern syscall_handler_t sys_setregid;
++extern syscall_handler_t sys_getgroups;
++extern syscall_handler_t sys_setgroups;
++extern syscall_handler_t sys_fchown;
++extern syscall_handler_t sys_setresuid;
++extern syscall_handler_t sys_getresuid;
++extern syscall_handler_t sys_setresgid;
++extern syscall_handler_t sys_getresgid;
++extern syscall_handler_t sys_chown;
++extern syscall_handler_t sys_setuid;
++extern syscall_handler_t sys_setgid;
++extern syscall_handler_t sys_setfsuid;
++extern syscall_handler_t sys_setfsgid;
++extern syscall_handler_t sys_pivot_root;
++extern syscall_handler_t sys_mincore;
++extern syscall_handler_t sys_madvise;
++extern syscall_handler_t sys_fcntl64;
++extern syscall_handler_t sys_getdents64;
++extern syscall_handler_t sys_gettid;
++extern syscall_handler_t sys_readahead;
++extern syscall_handler_t sys_tkill;
++extern syscall_handler_t sys_setxattr;
++extern syscall_handler_t sys_lsetxattr;
++extern syscall_handler_t sys_fsetxattr;
++extern syscall_handler_t sys_getxattr;
++extern syscall_handler_t sys_lgetxattr;
++extern syscall_handler_t sys_fgetxattr;
++extern syscall_handler_t sys_listxattr;
++extern syscall_handler_t sys_llistxattr;
++extern syscall_handler_t sys_flistxattr;
++extern syscall_handler_t sys_removexattr;
++extern syscall_handler_t sys_lremovexattr;
++extern syscall_handler_t sys_fremovexattr;
++extern syscall_handler_t sys_sendfile64;
++
++extern syscall_handler_t um_mount;
++extern syscall_handler_t um_time;
++extern syscall_handler_t um_stime;
++
++#define LAST_GENERIC_SYSCALL __NR_exit_group
++
++#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
++#define LAST_SYSCALL LAST_GENERIC_SYSCALL
++#else
++#define LAST_SYSCALL LAST_ARCH_SYSCALL
++#endif
++
++syscall_handler_t *sys_call_table[] = {
++      [ 0 ] = sys_ni_syscall,
++      [ __NR_exit ] = sys_exit,
++      [ __NR_fork ] = sys_fork,
++      [ __NR_read ] = (syscall_handler_t *) sys_read,
++      [ __NR_write ] = (syscall_handler_t *) sys_write,
++
++      /* These three are declared differently in asm/unistd.h */
++      [ __NR_open ] = (syscall_handler_t *) sys_open,
++      [ __NR_close ] = (syscall_handler_t *) sys_close,
++      [ __NR_waitpid ] = (syscall_handler_t *) sys_waitpid,
++      [ __NR_creat ] = sys_creat,
++      [ __NR_link ] = sys_link,
++      [ __NR_unlink ] = sys_unlink,
++
++      /* declared differently in kern_util.h */
++      [ __NR_execve ] = (syscall_handler_t *) sys_execve,
++      [ __NR_chdir ] = sys_chdir,
++      [ __NR_time ] = um_time,
++      [ __NR_mknod ] = sys_mknod,
++      [ __NR_chmod ] = sys_chmod,
++      [ __NR_lchown ] = sys_lchown16,
++      [ __NR_break ] = sys_ni_syscall,
++      [ __NR_oldstat ] = sys_stat,
++      [ __NR_lseek ] = (syscall_handler_t *) sys_lseek,
++      [ __NR_getpid ] = sys_getpid,
++      [ __NR_mount ] = um_mount,
++      [ __NR_umount ] = sys_oldumount,
++      [ __NR_setuid ] = sys_setuid16,
++      [ __NR_getuid ] = sys_getuid16,
++      [ __NR_stime ] = um_stime,
++      [ __NR_ptrace ] = sys_ptrace,
++      [ __NR_alarm ] = sys_alarm,
++      [ __NR_oldfstat ] = sys_fstat,
++      [ __NR_pause ] = sys_pause,
++      [ __NR_utime ] = sys_utime,
++      [ __NR_stty ] = sys_ni_syscall,
++      [ __NR_gtty ] = sys_ni_syscall,
++      [ __NR_access ] = sys_access,
++      [ __NR_nice ] = sys_nice,
++      [ __NR_ftime ] = sys_ni_syscall,
++      [ __NR_sync ] = sys_sync,
++      [ __NR_kill ] = sys_kill,
++      [ __NR_rename ] = sys_rename,
++      [ __NR_mkdir ] = sys_mkdir,
++      [ __NR_rmdir ] = sys_rmdir,
++
++      /* Declared differently in asm/unistd.h */
++      [ __NR_dup ] = (syscall_handler_t *) sys_dup,
++      [ __NR_pipe ] = sys_pipe,
++      [ __NR_times ] = sys_times,
++      [ __NR_prof ] = sys_ni_syscall,
++      [ __NR_brk ] = sys_brk,
++      [ __NR_setgid ] = sys_setgid16,
++      [ __NR_getgid ] = sys_getgid16,
++      [ __NR_signal ] = sys_signal,
++      [ __NR_geteuid ] = sys_geteuid16,
++      [ __NR_getegid ] = sys_getegid16,
++      [ __NR_acct ] = sys_acct,
++      [ __NR_umount2 ] = sys_umount,
++      [ __NR_lock ] = sys_ni_syscall,
++      [ __NR_ioctl ] = sys_ioctl,
++      [ __NR_fcntl ] = sys_fcntl,
++      [ __NR_mpx ] = sys_ni_syscall,
++      [ __NR_setpgid ] = sys_setpgid,
++      [ __NR_ulimit ] = sys_ni_syscall,
++      [ __NR_oldolduname ] = sys_olduname,
++      [ __NR_umask ] = sys_umask,
++      [ __NR_chroot ] = sys_chroot,
++      [ __NR_ustat ] = sys_ustat,
++      [ __NR_dup2 ] = sys_dup2,
++      [ __NR_getppid ] = sys_getppid,
++      [ __NR_getpgrp ] = sys_getpgrp,
++      [ __NR_setsid ] = (syscall_handler_t *) sys_setsid,
++      [ __NR_sigaction ] = sys_sigaction,
++      [ __NR_sgetmask ] = sys_sgetmask,
++      [ __NR_ssetmask ] = sys_ssetmask,
++      [ __NR_setreuid ] = sys_setreuid16,
++      [ __NR_setregid ] = sys_setregid16,
++      [ __NR_sigsuspend ] = sys_sigsuspend,
++      [ __NR_sigpending ] = sys_sigpending,
++      [ __NR_sethostname ] = sys_sethostname,
++      [ __NR_setrlimit ] = sys_setrlimit,
++      [ __NR_getrlimit ] = sys_old_getrlimit,
++      [ __NR_getrusage ] = sys_getrusage,
++      [ __NR_gettimeofday ] = sys_gettimeofday,
++      [ __NR_settimeofday ] = sys_settimeofday,
++      [ __NR_getgroups ] = sys_getgroups16,
++      [ __NR_setgroups ] = sys_setgroups16,
++      [ __NR_symlink ] = sys_symlink,
++      [ __NR_oldlstat ] = sys_lstat,
++      [ __NR_readlink ] = sys_readlink,
++      [ __NR_uselib ] = sys_uselib,
++      [ __NR_swapon ] = sys_swapon,
++      [ __NR_reboot ] = sys_reboot,
++      [ __NR_readdir ] = old_readdir,
++      [ __NR_munmap ] = sys_munmap,
++      [ __NR_truncate ] = sys_truncate,
++      [ __NR_ftruncate ] = sys_ftruncate,
++      [ __NR_fchmod ] = sys_fchmod,
++      [ __NR_fchown ] = sys_fchown16,
++      [ __NR_getpriority ] = sys_getpriority,
++      [ __NR_setpriority ] = sys_setpriority,
++      [ __NR_profil ] = sys_ni_syscall,
++      [ __NR_statfs ] = sys_statfs,
++      [ __NR_fstatfs ] = sys_fstatfs,
++      [ __NR_ioperm ] = sys_ni_syscall,
++      [ __NR_socketcall ] = sys_socketcall,
++      [ __NR_syslog ] = sys_syslog,
++      [ __NR_setitimer ] = sys_setitimer,
++      [ __NR_getitimer ] = sys_getitimer,
++      [ __NR_stat ] = sys_newstat,
++      [ __NR_lstat ] = sys_newlstat,
++      [ __NR_fstat ] = sys_newfstat,
++      [ __NR_olduname ] = sys_uname,
++      [ __NR_iopl ] = sys_ni_syscall,
++      [ __NR_vhangup ] = sys_vhangup,
++      [ __NR_idle ] = sys_ni_syscall,
++      [ __NR_wait4 ] = (syscall_handler_t *) sys_wait4,
++      [ __NR_swapoff ] = sys_swapoff,
++      [ __NR_sysinfo ] = sys_sysinfo,
++      [ __NR_ipc ] = sys_ipc,
++      [ __NR_fsync ] = sys_fsync,
++      [ __NR_sigreturn ] = sys_sigreturn,
++      [ __NR_clone ] = sys_clone,
++      [ __NR_setdomainname ] = sys_setdomainname,
++      [ __NR_uname ] = sys_newuname,
++      [ __NR_adjtimex ] = sys_adjtimex,
++      [ __NR_mprotect ] = sys_mprotect,
++      [ __NR_sigprocmask ] = sys_sigprocmask,
++      [ __NR_create_module ] = sys_create_module,
++      [ __NR_init_module ] = sys_init_module,
++      [ __NR_delete_module ] = sys_delete_module,
++      [ __NR_get_kernel_syms ] = sys_get_kernel_syms,
++      [ __NR_quotactl ] = sys_quotactl,
++      [ __NR_getpgid ] = sys_getpgid,
++      [ __NR_fchdir ] = sys_fchdir,
++      [ __NR_bdflush ] = sys_bdflush,
++      [ __NR_sysfs ] = sys_sysfs,
++      [ __NR_personality ] = sys_personality,
++      [ __NR_afs_syscall ] = sys_ni_syscall,
++      [ __NR_setfsuid ] = sys_setfsuid16,
++      [ __NR_setfsgid ] = sys_setfsgid16,
++      [ __NR__llseek ] = sys_llseek,
++      [ __NR_getdents ] = sys_getdents,
++      [ __NR__newselect ] = (syscall_handler_t *) sys_select,
++      [ __NR_flock ] = sys_flock,
++      [ __NR_msync ] = sys_msync,
++      [ __NR_readv ] = sys_readv,
++      [ __NR_writev ] = sys_writev,
++      [ __NR_getsid ] = sys_getsid,
++      [ __NR_fdatasync ] = sys_fdatasync,
++      [ __NR__sysctl ] = sys_sysctl,
++      [ __NR_mlock ] = sys_mlock,
++      [ __NR_munlock ] = sys_munlock,
++      [ __NR_mlockall ] = sys_mlockall,
++      [ __NR_munlockall ] = sys_munlockall,
++      [ __NR_sched_setparam ] = sys_sched_setparam,
++      [ __NR_sched_getparam ] = sys_sched_getparam,
++      [ __NR_sched_setscheduler ] = sys_sched_setscheduler,
++      [ __NR_sched_getscheduler ] = sys_sched_getscheduler,
++      [ __NR_sched_yield ] = (syscall_handler_t *) yield,
++      [ __NR_sched_get_priority_max ] = sys_sched_get_priority_max,
++      [ __NR_sched_get_priority_min ] = sys_sched_get_priority_min,
++      [ __NR_sched_rr_get_interval ] = sys_sched_rr_get_interval,
++      [ __NR_nanosleep ] = sys_nanosleep,
++      [ __NR_mremap ] = sys_mremap,
++      [ __NR_setresuid ] = sys_setresuid16,
++      [ __NR_getresuid ] = sys_getresuid16,
++      [ __NR_vm86 ] = sys_ni_syscall,
++      [ __NR_query_module ] = sys_query_module,
++      [ __NR_poll ] = sys_poll,
++      [ __NR_nfsservctl ] = sys_nfsservctl,
++      [ __NR_setresgid ] = sys_setresgid16,
++      [ __NR_getresgid ] = sys_getresgid16,
++      [ __NR_prctl ] = sys_prctl,
++      [ __NR_rt_sigreturn ] = sys_rt_sigreturn,
++      [ __NR_rt_sigaction ] = sys_rt_sigaction,
++      [ __NR_rt_sigprocmask ] = sys_rt_sigprocmask,
++      [ __NR_rt_sigpending ] = sys_rt_sigpending,
++      [ __NR_rt_sigtimedwait ] = sys_rt_sigtimedwait,
++      [ __NR_rt_sigqueueinfo ] = sys_rt_sigqueueinfo,
++      [ __NR_rt_sigsuspend ] = sys_rt_sigsuspend,
++      [ __NR_pread ] = sys_pread,
++      [ __NR_pwrite ] = sys_pwrite,
++      [ __NR_chown ] = sys_chown16,
++      [ __NR_getcwd ] = sys_getcwd,
++      [ __NR_capget ] = sys_capget,
++      [ __NR_capset ] = sys_capset,
++      [ __NR_sigaltstack ] = sys_sigaltstack,
++      [ __NR_sendfile ] = sys_sendfile,
++      [ __NR_getpmsg ] = sys_ni_syscall,
++      [ __NR_putpmsg ] = sys_ni_syscall,
++      [ __NR_vfork ] = sys_vfork,
++      [ __NR_ugetrlimit ] = sys_getrlimit,
++      [ __NR_mmap2 ] = sys_mmap2,
++      [ __NR_truncate64 ] = sys_truncate64,
++      [ __NR_ftruncate64 ] = sys_ftruncate64,
++      [ __NR_stat64 ] = sys_stat64,
++      [ __NR_lstat64 ] = sys_lstat64,
++      [ __NR_fstat64 ] = sys_fstat64,
++      [ __NR_fcntl64 ] = sys_fcntl64,
++      [ __NR_getdents64 ] = sys_getdents64,
++        [ __NR_security ] = sys_ni_syscall,
++      [ __NR_gettid ] = sys_gettid,
++      [ __NR_readahead ] = sys_readahead,
++      [ __NR_setxattr ] = sys_setxattr,
++      [ __NR_lsetxattr ] = sys_lsetxattr,
++      [ __NR_fsetxattr ] = sys_fsetxattr,
++      [ __NR_getxattr ] = sys_getxattr,
++      [ __NR_lgetxattr ] = sys_lgetxattr,
++      [ __NR_fgetxattr ] = sys_fgetxattr,
++      [ __NR_listxattr ] = sys_listxattr,
++      [ __NR_llistxattr ] = sys_llistxattr,
++      [ __NR_flistxattr ] = sys_flistxattr,
++      [ __NR_removexattr ] = sys_removexattr,
++      [ __NR_lremovexattr ] = sys_lremovexattr,
++      [ __NR_fremovexattr ] = sys_fremovexattr,
++      [ __NR_tkill ] = sys_tkill,
++      [ __NR_sendfile64 ] = sys_sendfile64,
++      [ __NR_futex ] = sys_ni_syscall,
++      [ __NR_sched_setaffinity ] = sys_ni_syscall,
++      [ __NR_sched_getaffinity ] = sys_ni_syscall,
++      [ __NR_set_thread_area ] = sys_ni_syscall,
++      [ __NR_get_thread_area ] = sys_ni_syscall,
++      [ __NR_io_setup ] = sys_ni_syscall,
++      [ __NR_io_destroy ] = sys_ni_syscall,
++      [ __NR_io_getevents ] = sys_ni_syscall,
++      [ __NR_io_submit ] = sys_ni_syscall,
++      [ __NR_io_cancel ] = sys_ni_syscall,
++      [ __NR_alloc_hugepages ] = sys_ni_syscall,
++      [ __NR_free_hugepages ] = sys_ni_syscall,
++      [ __NR_exit_group ] = sys_ni_syscall,
++
++      ARCH_SYSCALLS
++      [ LAST_SYSCALL + 1 ... NR_syscalls ] = 
++              (syscall_handler_t *) sys_ni_syscall
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/syscall_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/syscall_user.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/syscall_user.c 2005-05-03 22:28:14.481408704 +0300
+@@ -0,0 +1,48 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <sys/time.h>
++#include "kern_util.h"
++#include "syscall_user.h"
++
++struct {
++      int syscall;
++      int pid;
++      int result;
++      struct timeval start;
++      struct timeval end;
++} syscall_record[1024];
++
++int record_syscall_start(int syscall)
++{
++      int max, index;
++
++      max = sizeof(syscall_record)/sizeof(syscall_record[0]);
++      index = next_syscall_index(max);
++
++      syscall_record[index].syscall = syscall;
++      syscall_record[index].pid = current_pid();
++      syscall_record[index].result = 0xdeadbeef;
++      gettimeofday(&syscall_record[index].start, NULL);
++      return(index);
++}
++
++void record_syscall_end(int index, int result)
++{
++      syscall_record[index].result = result;
++      gettimeofday(&syscall_record[index].end, NULL);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/sysrq.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/sysrq.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/sysrq.c        2005-05-03 22:28:14.482408552 +0300
+@@ -0,0 +1,98 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/kernel.h"
++#include "linux/module.h"
++#include "asm/page.h"
++#include "asm/processor.h"
++#include "sysrq.h"
++#include "user_util.h"
++
++ /*
++  * If the address is either in the .text section of the
++  * kernel, or in the vmalloc'ed module regions, it *may* 
++  * be the address of a calling routine
++  */
++ 
++#ifdef CONFIG_MODULES
++
++extern struct module *module_list;
++extern struct module kernel_module;
++
++static inline int kernel_text_address(unsigned long addr)
++{
++      int retval = 0;
++      struct module *mod;
++
++      if (addr >= (unsigned long) &_stext &&
++          addr <= (unsigned long) &_etext)
++              return 1;
++
++      for (mod = module_list; mod != &kernel_module; mod = mod->next) {
++              /* mod_bound tests for addr being inside the vmalloc'ed
++               * module area. Of course it'd be better to test only
++               * for the .text subset... */
++              if (mod_bound(addr, 0, mod)) {
++                      retval = 1;
++                      break;
++              }
++      }
++
++      return retval;
++}
++
++#else
++
++static inline int kernel_text_address(unsigned long addr)
++{
++      return (addr >= (unsigned long) &_stext &&
++              addr <= (unsigned long) &_etext);
++}
++
++#endif
++
++void show_trace(unsigned long * stack)
++{
++        int i;
++        unsigned long addr;
++
++        if (!stack)
++                stack = (unsigned long*) &stack;
++
++        printk("Call Trace: ");
++        i = 1;
++        while (((long) stack & (THREAD_SIZE-1)) != 0) {
++                addr = *stack++;
++              if (kernel_text_address(addr)) {
++                      if (i && ((i % 6) == 0))
++                              printk("\n   ");
++                      printk("[<%08lx>] ", addr);
++                      i++;
++                }
++        }
++        printk("\n");
++}
++
++void show_trace_task(struct task_struct *tsk)
++{
++      unsigned long esp = PT_REGS_SP(&tsk->thread.regs);
++
++      /* User space on another CPU? */
++      if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1))
++              return;
++      show_trace((unsigned long *)esp);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tempfile.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tempfile.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tempfile.c     2005-05-03 22:28:14.483408400 +0300
+@@ -0,0 +1,82 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/param.h>
++#include "init.h"
++
++/* Modified from create_mem_file and start_debugger */
++static char *tempdir = NULL;
++
++static void __init find_tempdir(void)
++{
++      char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
++      int i;
++      char *dir = NULL;
++
++      if(tempdir != NULL) return;     /* We've already been called */
++      for(i = 0; dirs[i]; i++){
++              dir = getenv(dirs[i]);
++              if((dir != NULL) && (*dir != '\0'))
++                      break;
++      }
++      if((dir == NULL) || (*dir == '\0')) 
++              dir = "/tmp";
++
++      tempdir = malloc(strlen(dir) + 2);
++      if(tempdir == NULL){
++              fprintf(stderr, "Failed to malloc tempdir, "
++                      "errno = %d\n", errno);
++              return;
++      }
++      strcpy(tempdir, dir);
++      strcat(tempdir, "/");
++}
++
++int make_tempfile(const char *template, char **out_tempname, int do_unlink)
++{
++      char tempname[MAXPATHLEN];
++      int fd;
++
++      find_tempdir();
++      if (*template != '/')
++              strcpy(tempname, tempdir);
++      else
++              *tempname = 0;
++      strcat(tempname, template);
++      fd = mkstemp(tempname);
++      if(fd < 0){
++              fprintf(stderr, "open - cannot create %s: %s\n", tempname, 
++                      strerror(errno));
++              return -1;
++      }
++      if(do_unlink && (unlink(tempname) < 0)){
++              perror("unlink");
++              return -1;
++      }
++      if(out_tempname){
++              *out_tempname = strdup(tempname);
++              if(*out_tempname == NULL){
++                      perror("strdup");
++                      return -1;
++              }
++      }
++      return(fd);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/time.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/time.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/time.c 2005-05-03 22:28:14.484408248 +0300
+@@ -0,0 +1,144 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <time.h>
++#include <sys/time.h>
++#include <signal.h>
++#include <errno.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "process.h"
++#include "signal_user.h"
++#include "time_user.h"
++
++extern struct timeval xtime;
++
++struct timeval local_offset = { 0, 0 };
++
++void timer(void)
++{
++      gettimeofday(&xtime, NULL);
++      timeradd(&xtime, &local_offset, &xtime);
++}
++
++void set_interval(int timer_type)
++{
++      int usec = 1000000/hz();
++      struct itimerval interval = ((struct itimerval) { { 0, usec },
++                                                        { 0, usec } });
++
++      if(setitimer(timer_type, &interval, NULL) == -1)
++              panic("setitimer failed - errno = %d\n", errno);
++}
++
++void enable_timer(void)
++{
++      int usec = 1000000/hz();
++      struct itimerval enable = ((struct itimerval) { { 0, usec },
++                                                      { 0, usec }});
++      if(setitimer(ITIMER_VIRTUAL, &enable, NULL))
++              printk("enable_timer - setitimer failed, errno = %d\n",
++                     errno);
++}
++
++void disable_timer(void)
++{
++      struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
++      if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) ||
++         (setitimer(ITIMER_REAL, &disable, NULL) < 0))
++              printk("disnable_timer - setitimer failed, errno = %d\n",
++                     errno);
++}
++
++void switch_timers(int to_real)
++{
++      struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
++      struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() },
++                                                      { 0, 1000000/hz() }});
++      int old, new;
++
++      if(to_real){
++              old = ITIMER_VIRTUAL;
++              new = ITIMER_REAL;
++      }
++      else {
++              old = ITIMER_REAL;
++              new = ITIMER_VIRTUAL;
++      }
++
++      if((setitimer(old, &disable, NULL) < 0) ||
++         (setitimer(new, &enable, NULL)))
++              printk("switch_timers - setitimer failed, errno = %d\n",
++                     errno);
++}
++
++void idle_timer(void)
++{
++      if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
++              panic("Couldn't unset SIGVTALRM handler");
++      
++      set_handler(SIGALRM, (__sighandler_t) alarm_handler, 
++                  SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
++      set_interval(ITIMER_REAL);
++}
++
++void time_init(void)
++{
++      /* XXX This is to fill xtime with something real - otherwise by the
++       * time /proc is mounted, no timers have fired, and xtime is still 0,
++       * meaning it shows times of Jan 1 1970.  The real fix is to figure
++       * out why no timers have happened by then.
++       */
++      timer();
++
++      if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
++              panic("Couldn't set SIGVTALRM handler");
++      set_interval(ITIMER_VIRTUAL);
++}
++
++void do_gettimeofday(struct timeval *tv)
++{
++      unsigned long flags;
++
++      flags = time_lock();
++      gettimeofday(tv, NULL);
++      timeradd(tv, &local_offset, tv);
++      time_unlock(flags);
++}
++
++void do_settimeofday(struct timeval *tv)
++{
++      struct timeval now;
++      unsigned long flags;
++
++      flags = time_lock();
++      gettimeofday(&now, NULL);
++      timersub(tv, &now, &local_offset);
++      time_unlock(flags);
++}
++
++void idle_sleep(int secs)
++{
++      struct timespec ts;
++
++      ts.tv_sec = secs;
++      ts.tv_nsec = 0;
++      nanosleep(&ts, NULL);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/time_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/time_kern.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/time_kern.c    2005-05-03 22:28:14.485408096 +0300
+@@ -0,0 +1,209 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "linux/unistd.h"
++#include "linux/stddef.h"
++#include "linux/spinlock.h"
++#include "linux/sched.h"
++#include "linux/interrupt.h"
++#include "linux/init.h"
++#include "linux/delay.h"
++#include "asm/irq.h"
++#include "asm/param.h"
++#include "asm/current.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "time_user.h"
++#include "mode.h"
++#include "os.h"
++
++extern rwlock_t xtime_lock;
++
++int hz(void)
++{
++      return(HZ);
++}
++
++/* Changed at early boot */
++int timer_irq_inited = 0;
++
++/* missed_ticks will be modified after kernel memory has been 
++ * write-protected, so this puts it in a section which will be left 
++ * write-enabled.
++ */
++int __attribute__ ((__section__ (".unprotected"))) missed_ticks[NR_CPUS];
++
++static int first_tick;
++static unsigned long long prev_usecs;
++static long long delta;               /* Deviation per interval */
++
++#define MILLION 1000000
++
++void timer_irq(union uml_pt_regs *regs)
++{
++      unsigned long long ticks = 0;
++
++      if(!timer_irq_inited){
++              /* This is to ensure that ticks don't pile up when
++               * the timer handler is suspended */
++              first_tick = 0;
++              return;
++      }
++
++      if(first_tick){
++#if defined(CONFIG_UML_REAL_TIME_CLOCK)
++              /* We've had 1 tick */
++              unsigned long long usecs = os_usecs();
++
++              delta += usecs - prev_usecs;
++              prev_usecs = usecs;
++
++              /* Protect against the host clock being set backwards */
++              if(delta < 0)
++                      delta = 0;
++
++              ticks += (delta * HZ) / MILLION;
++              delta -= (ticks * MILLION) / HZ;
++#else
++              ticks = 1;
++#endif
++      }
++      else {
++              prev_usecs = os_usecs();
++              first_tick = 1;
++      }
++
++      while(ticks > 0){
++              do_IRQ(TIMER_IRQ, regs);
++              ticks--;
++      }
++}
++
++void boot_timer_handler(int sig)
++{
++      struct pt_regs regs;
++
++      CHOOSE_MODE((void) 
++                  (UPT_SC(&regs.regs) = (struct sigcontext *) (&sig + 1)),
++                  (void) (regs.regs.skas.is_user = 0));
++      do_timer(&regs);
++}
++
++void um_timer(int irq, void *dev, struct pt_regs *regs)
++{
++      do_timer(regs);
++      write_lock(&xtime_lock);
++      vxtime_lock();
++      timer();
++      vxtime_unlock();
++      write_unlock(&xtime_lock);
++}
++
++long um_time(int * tloc)
++{
++      struct timeval now;
++
++      do_gettimeofday(&now);
++      if (tloc) {
++              if (put_user(now.tv_sec,tloc))
++                      now.tv_sec = -EFAULT;
++      }
++      return now.tv_sec;
++}
++
++long um_stime(int * tptr)
++{
++      int value;
++      struct timeval new;
++
++      if (get_user(value, tptr))
++                return -EFAULT;
++      new.tv_sec = value;
++      new.tv_usec = 0;
++      do_settimeofday(&new);
++      return 0;
++}
++
++/* XXX Needs to be moved under sys-i386 */
++void __delay(um_udelay_t time)
++{
++      /* Stolen from the i386 __loop_delay */
++      int d0;
++      __asm__ __volatile__(
++              "\tjmp 1f\n"
++              ".align 16\n"
++              "1:\tjmp 2f\n"
++              ".align 16\n"
++              "2:\tdecl %0\n\tjns 2b"
++              :"=&a" (d0)
++              :"0" (time));
++}
++
++void __udelay(um_udelay_t usecs)
++{
++      int i, n;
++
++      n = (loops_per_jiffy * HZ * usecs) / MILLION;
++      for(i=0;i<n;i++) ;
++}
++
++void __const_udelay(um_udelay_t usecs)
++{
++      int i, n;
++
++      n = (loops_per_jiffy * HZ * usecs) / MILLION;
++      for(i=0;i<n;i++) ;
++}
++
++void timer_handler(int sig, union uml_pt_regs *regs)
++{
++#ifdef CONFIG_SMP
++      update_process_times(user_context(UPT_SP(regs)));
++#endif
++      if(current->processor == 0)
++              timer_irq(regs);
++}
++
++static spinlock_t timer_spinlock = SPIN_LOCK_UNLOCKED;
++
++unsigned long time_lock(void)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&timer_spinlock, flags);
++      return(flags);
++}
++
++void time_unlock(unsigned long flags)
++{
++      spin_unlock_irqrestore(&timer_spinlock, flags);
++}
++
++int __init timer_init(void)
++{
++      int err;
++
++      CHOOSE_MODE(user_time_init_tt(), user_time_init_skas());
++      err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL);
++      if(err != 0)
++              printk(KERN_ERR "timer_init : request_irq failed - "
++                     "errno = %d\n", -err);
++      timer_irq_inited = 1;
++      return(0);
++}
++
++__initcall(timer_init);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tlb.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tlb.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tlb.c  2005-05-03 22:28:14.486407944 +0300
+@@ -0,0 +1,80 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "asm/page.h"
++#include "asm/pgalloc.h"
++#include "choose-mode.h"
++#include "mode_kern.h"
++
++void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
++{
++      address &= PAGE_MASK;
++      flush_tlb_range(vma->vm_mm, address, address + PAGE_SIZE);
++}
++
++void flush_tlb_all(void)
++{
++      flush_tlb_mm(current->mm);
++}
++
++void flush_tlb_kernel_vm(void)
++{
++      CHOOSE_MODE(flush_tlb_kernel_vm_tt(), flush_tlb_kernel_vm_skas());
++}
++
++void __flush_tlb_one(unsigned long addr)
++{
++      CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
++}
++
++void flush_tlb_range(struct mm_struct *mm, unsigned long start, 
++                   unsigned long end)
++{
++      CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, mm, start, 
++                       end);
++}
++
++void flush_tlb_mm(struct mm_struct *mm)
++{
++      CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
++}
++
++void force_flush_all(void)
++{
++      CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
++}
++
++
++pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
++{
++      return(pgd_offset(mm, address));
++}
++
++pmd_t *pmd_offset_proc(pgd_t *pgd, unsigned long address)
++{
++      return(pmd_offset(pgd, address));
++}
++
++pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address)
++{
++      return(pte_offset(pmd, address));
++}
++
++pte_t *addr_pte(struct task_struct *task, unsigned long addr)
++{
++      return(pte_offset(pmd_offset(pgd_offset(task->mm, addr), addr), addr));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/trap_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/trap_kern.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/trap_kern.c    2005-05-03 22:28:14.487407792 +0300
+@@ -0,0 +1,220 @@
++/* 
++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "linux/sched.h"
++#include "linux/mm.h"
++#include "linux/spinlock.h"
++#include "linux/config.h"
++#include "linux/init.h"
++#include "asm/semaphore.h"
++#include "asm/pgtable.h"
++#include "asm/pgalloc.h"
++#include "asm/a.out.h"
++#include "asm/current.h"
++#include "asm/irq.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "chan_kern.h"
++#include "mconsole_kern.h"
++#include "2_5compat.h"
++#include "mem.h"
++#include "mem_kern.h"
++
++unsigned long handle_page_fault(unsigned long address, unsigned long ip, 
++                              int is_write, int is_user, int *code_out)
++{
++      struct mm_struct *mm = current->mm;
++      struct vm_area_struct *vma;
++      pgd_t *pgd;
++      pmd_t *pmd;
++      pte_t *pte;
++      unsigned long page;
++      int handled = 0;
++
++      *code_out = SEGV_MAPERR;
++      down_read(&mm->mmap_sem);
++      vma = find_vma(mm, address);
++      if(!vma) 
++              goto out;
++      else if(vma->vm_start <= address) 
++              goto good_area;
++      else if(!(vma->vm_flags & VM_GROWSDOWN)) 
++              goto out;
++      else if(expand_stack(vma, address)) 
++              goto out;
++
++ good_area:
++      *code_out = SEGV_ACCERR;
++      if(is_write && !(vma->vm_flags & VM_WRITE)) 
++              goto out;
++      page = address & PAGE_MASK;
++      if(page == (unsigned long) current + PAGE_SIZE)
++              panic("Kernel stack overflow");
++      pgd = pgd_offset(mm, page);
++      pmd = pmd_offset(pgd, page);
++      do {
++ survive:
++              switch (handle_mm_fault(mm, vma, address, is_write)) {
++              case 1:
++                      current->min_flt++;
++                      break;
++              case 2:
++                      current->maj_flt++;
++                      break;
++              default:
++                      if (current->pid == 1) {
++                              up_read(&mm->mmap_sem);
++                              yield();
++                              down_read(&mm->mmap_sem);
++                              goto survive;
++                      }
++                      /* Fall through to bad area case */
++              case 0:
++                      goto out;
++              }
++              pte = pte_offset(pmd, page);
++      } while(!pte_present(*pte));
++      handled = 1;
++      *pte = pte_mkyoung(*pte);
++      if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
++      flush_tlb_page(vma, page);
++ out:
++      up_read(&mm->mmap_sem);
++      return(handled);
++}
++
++LIST_HEAD(physmem_remappers);
++
++void register_remapper(struct remapper *info)
++{
++      list_add(&info->list, &physmem_remappers);
++}
++
++static int check_remapped_addr(unsigned long address, int is_write, int is_user)
++{
++      struct remapper *remapper;
++      struct list_head *ele;
++      __u64 offset;
++      int fd;
++
++      fd = phys_mapping(__pa(address), &offset);
++      if(fd == -1)
++              return(0);
++
++      list_for_each(ele, &physmem_remappers){
++              remapper = list_entry(ele, struct remapper, list);
++              if((*remapper->proc)(fd, address, is_write, offset, is_user))
++                      return(1);
++      }
++
++      return(0);
++}
++
++unsigned long segv(unsigned long address, unsigned long ip, int is_write, 
++                 int is_user, void *sc)
++{
++      struct siginfo si;
++      void *catcher;
++      int handled;
++
++        if(!is_user && (address >= start_vm) && (address < end_vm)){
++                flush_tlb_kernel_vm();
++                return(0);
++        }
++      else if(check_remapped_addr(address & PAGE_MASK, is_write, is_user))
++              return(0);
++      else if(current->mm == NULL)
++              panic("Segfault with no mm");
++
++      handled = handle_page_fault(address, ip, is_write, is_user, 
++                                  &si.si_code);
++
++      catcher = current->thread.fault_catcher;
++      if(handled)
++              return(0);
++      else if(catcher != NULL){
++              current->thread.fault_addr = (void *) address;
++              do_longjmp(catcher, 1);
++      } 
++      else if(current->thread.fault_addr != NULL)
++              panic("fault_addr set but no fault catcher");
++      else if(arch_fixup(ip, sc))
++              return(0);
++
++      if(!is_user) 
++              panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", 
++                    address, ip);
++      si.si_signo = SIGSEGV;
++      si.si_addr = (void *) address;
++      current->thread.cr2 = address;
++      current->thread.err = is_write;
++      force_sig_info(SIGSEGV, &si, current);
++      return(0);
++}
++
++void bad_segv(unsigned long address, unsigned long ip, int is_write)
++{
++      struct siginfo si;
++
++      si.si_signo = SIGSEGV;
++      si.si_code = SEGV_ACCERR;
++      si.si_addr = (void *) address;
++      current->thread.cr2 = address;
++      current->thread.err = is_write;
++      force_sig_info(SIGSEGV, &si, current);
++}
++
++void relay_signal(int sig, union uml_pt_regs *regs)
++{
++      if(arch_handle_signal(sig, regs)) return;
++      if(!UPT_IS_USER(regs))
++              panic("Kernel mode signal %d", sig);
++      force_sig(sig, current);
++}
++
++void bus_handler(int sig, union uml_pt_regs *regs)
++{
++      if(current->thread.fault_catcher != NULL)
++              do_longjmp(current->thread.fault_catcher, 1);
++      else relay_signal(sig, regs);
++}
++
++void winch(int sig, union uml_pt_regs *regs)
++{
++      do_IRQ(WINCH_IRQ, regs);
++}
++
++void trap_init(void)
++{
++}
++
++spinlock_t trap_lock = SPIN_LOCK_UNLOCKED;
++
++static int trap_index = 0;
++
++int next_trap_index(int limit)
++{
++      int ret;
++
++      spin_lock(&trap_lock);
++      ret = trap_index;
++      if(++trap_index == limit)
++              trap_index = 0;
++      spin_unlock(&trap_lock);
++      return(ret);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/trap_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/trap_user.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/trap_user.c    2005-05-03 22:28:14.489407488 +0300
+@@ -0,0 +1,145 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <errno.h>
++#include <setjmp.h>
++#include <signal.h>
++#include <sys/time.h>
++#include <sys/ptrace.h>
++#include <sys/wait.h>
++#include <asm/page.h>
++#include <asm/unistd.h>
++#include <asm/ptrace.h>
++#include "init.h"
++#include "sysdep/ptrace.h"
++#include "sigcontext.h"
++#include "sysdep/sigcontext.h"
++#include "irq_user.h"
++#include "frame_user.h"
++#include "signal_user.h"
++#include "time_user.h"
++#include "task.h"
++#include "mode.h"
++#include "choose-mode.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "os.h"
++
++void kill_child_dead(int pid)
++{
++      kill(pid, SIGKILL);
++      kill(pid, SIGCONT);
++      do {
++              int n;
++              CATCH_EINTR(n = waitpid(pid, NULL, 0));
++              if (n > 0)
++                      kill(pid, SIGCONT);
++              else
++                      break;
++      } while(1);
++}
++
++/* Unlocked - don't care if this is a bit off */
++int nsegfaults = 0;
++
++struct {
++      unsigned long address;
++      int is_write;
++      int pid;
++      unsigned long sp;
++      int is_user;
++} segfault_record[1024];
++
++void segv_handler(int sig, union uml_pt_regs *regs)
++{
++      int index, max;
++
++      if(UPT_IS_USER(regs) && !UPT_SEGV_IS_FIXABLE(regs)){
++              bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), 
++                       UPT_FAULT_WRITE(regs));
++              return;
++      }
++      max = sizeof(segfault_record)/sizeof(segfault_record[0]);
++      index = next_trap_index(max);
++
++      nsegfaults++;
++      segfault_record[index].address = UPT_FAULT_ADDR(regs);
++      segfault_record[index].pid = os_getpid();
++      segfault_record[index].is_write = UPT_FAULT_WRITE(regs);
++      segfault_record[index].sp = UPT_SP(regs);
++      segfault_record[index].is_user = UPT_IS_USER(regs);
++      segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs),
++           UPT_IS_USER(regs), regs);
++}
++
++void usr2_handler(int sig, union uml_pt_regs *regs)
++{
++      CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0);
++}
++
++struct signal_info sig_info[] = {
++      [ SIGTRAP ] { .handler          = relay_signal,
++                    .is_irq           = 0 },
++      [ SIGFPE ] { .handler           = relay_signal,
++                   .is_irq            = 0 },
++      [ SIGILL ] { .handler           = relay_signal,
++                   .is_irq            = 0 },
++      [ SIGWINCH ] { .handler         = winch,
++                     .is_irq          = 1 },
++      [ SIGBUS ] { .handler           = bus_handler,
++                   .is_irq            = 0 },
++      [ SIGSEGV] { .handler           = segv_handler,
++                   .is_irq            = 0 },
++      [ SIGIO ] { .handler            = sigio_handler,
++                  .is_irq             = 1 },
++      [ SIGVTALRM ] { .handler        = timer_handler,
++                      .is_irq         = 1 },
++        [ SIGALRM ] { .handler          = timer_handler,
++                      .is_irq           = 1 },
++      [ SIGUSR2 ] { .handler          = usr2_handler,
++                    .is_irq           = 0 },
++};
++
++void sig_handler(int sig, struct sigcontext sc)
++{
++      CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
++                       sig, &sc);
++}
++
++extern int timer_irq_inited, missed_ticks[];
++
++void alarm_handler(int sig, struct sigcontext sc)
++{
++      if(!timer_irq_inited) return;
++      missed_ticks[cpu()]++;
++
++      if(sig == SIGALRM)
++              switch_timers(0);
++
++      CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
++                       sig, &sc);
++
++      if(sig == SIGALRM)
++              switch_timers(1);
++}
++
++void do_longjmp(void *b, int val)
++{
++      sigjmp_buf *buf = b;
++
++      siglongjmp(*buf, val);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/exec_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/exec_kern.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/exec_kern.c 2005-05-03 22:28:14.490407336 +0300
+@@ -0,0 +1,86 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "linux/mm.h"
++#include "asm/signal.h"
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++#include "asm/pgalloc.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "irq_user.h"
++#include "time_user.h"
++#include "mem_user.h"
++#include "signal_user.h"
++#include "os.h"
++#include "tlb.h"
++#include "mode.h"
++
++static int exec_tramp(void *sig_stack)
++{
++      init_new_thread_stack(sig_stack, NULL);
++      init_new_thread_signals(1);
++      os_stop_process(os_getpid());
++      return(0);
++}
++
++void flush_thread_tt(void)
++{
++      unsigned long stack;
++      int new_pid;
++
++      stack = alloc_stack(0, 0);
++      if(stack == 0){
++              printk(KERN_ERR 
++                     "flush_thread : failed to allocate temporary stack\n");
++              do_exit(SIGKILL);
++      }
++              
++      new_pid = start_fork_tramp(current, stack, 0, exec_tramp);
++      if(new_pid < 0){
++              printk(KERN_ERR 
++                     "flush_thread : new thread failed, errno = %d\n",
++                     -new_pid);
++              do_exit(SIGKILL);
++      }
++
++      if(current->processor == 0)
++              forward_interrupts(new_pid);
++      current->thread.request.op = OP_EXEC;
++      current->thread.request.u.exec.pid = new_pid;
++      unprotect_stack((unsigned long) current);
++      os_usr1_process(os_getpid());
++      change_sig(SIGUSR1, 1);
++
++      change_sig(SIGUSR1, 0);
++      enable_timer();
++      free_page(stack);
++      protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
++      task_protections((unsigned long) current);
++      force_flush_all();
++      unblock_signals();
++}
++
++void start_thread_tt(struct pt_regs *regs, unsigned long eip, 
++                   unsigned long esp)
++{
++      set_fs(USER_DS);
++      flush_tlb_mm(current->mm);
++      PT_REGS_IP(regs) = eip;
++      PT_REGS_SP(regs) = esp;
++      PT_FIX_EXEC_STACK(esp);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/exec_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/exec_user.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/exec_user.c 2005-05-03 22:28:14.491407184 +0300
+@@ -0,0 +1,54 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <sched.h>
++#include <errno.h>
++#include <sys/wait.h>
++#include <sys/ptrace.h>
++#include <signal.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "ptrace_user.h"
++
++void do_exec(int old_pid, int new_pid)
++{
++      unsigned long regs[FRAME_SIZE];
++      int err;
++
++      if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
++         (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
++              tracer_panic("do_exec failed to attach proc - errno = %d",
++                           errno);
++
++      CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
++      if (err < 0)
++              tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
++                           errno);
++
++      if(ptrace_getregs(old_pid, regs) < 0)
++              tracer_panic("do_exec failed to get registers - errno = %d",
++                           errno);
++
++      kill(old_pid, SIGKILL);
++
++      if(ptrace_setregs(new_pid, regs) < 0)
++              tracer_panic("do_exec failed to start new proc - errno = %d",
++                           errno);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/gdb.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/gdb.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/gdb.c       2005-05-03 22:28:14.492407032 +0300
+@@ -0,0 +1,278 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#include <signal.h>
++#include <sys/ptrace.h>
++#include <sys/types.h>
++#include "uml-config.h"
++#include "kern_constants.h"
++#include "chan_user.h"
++#include "init.h"
++#include "user.h"
++#include "debug.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "tt.h"
++#include "sysdep/thread.h"
++
++extern int debugger_pid;
++extern int debugger_fd;
++extern int debugger_parent;
++
++int detach(int pid, int sig)
++{
++      return(ptrace(PTRACE_DETACH, pid, 0, sig));
++}
++
++int attach(int pid)
++{
++      int err;
++
++      err = ptrace(PTRACE_ATTACH, pid, 0, 0);
++      if(err < 0) return(-errno);
++      else return(err);
++}
++
++int cont(int pid)
++{
++      return(ptrace(PTRACE_CONT, pid, 0, 0));
++}
++
++#ifdef UML_CONFIG_PT_PROXY
++
++int debugger_signal(int status, pid_t pid)
++{
++      return(debugger_proxy(status, pid));
++}
++
++void child_signal(pid_t pid, int status)
++{
++      child_proxy(pid, status);
++}
++
++static void gdb_announce(char *dev_name, int dev)
++{
++      printf("gdb assigned device '%s'\n", dev_name);
++}
++
++static struct chan_opts opts = {
++      .announce       = gdb_announce,
++      .xterm_title    = "UML kernel debugger",
++      .raw            = 0,
++      .tramp_stack    = 0,
++      .in_kernel      = 0,
++};
++
++/* Accessed by the tracing thread, which automatically serializes access */
++static void *xterm_data;
++static int xterm_fd;
++
++extern void *xterm_init(char *, int, struct chan_opts *);
++extern int xterm_open(int, int, int, void *, char **);
++extern void xterm_close(int, void *);
++
++int open_gdb_chan(void)
++{
++      char stack[UM_KERN_PAGE_SIZE], *dummy;
++
++      opts.tramp_stack = (unsigned long) stack;
++      xterm_data = xterm_init("", 0, &opts);
++      xterm_fd = xterm_open(1, 1, 1, xterm_data, &dummy);
++      return(xterm_fd);
++}
++
++static void exit_debugger_cb(void *unused)
++{
++      if(debugger_pid != -1){
++              if(gdb_pid != -1){
++                      fake_child_exit();
++                      gdb_pid = -1;
++              }
++              else kill_child_dead(debugger_pid);
++              debugger_pid = -1;
++              if(debugger_parent != -1)
++                      detach(debugger_parent, SIGINT);
++      }
++      if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
++}
++
++static void exit_debugger(void)
++{
++      initial_thread_cb(exit_debugger_cb, NULL);
++}
++
++__uml_exitcall(exit_debugger);
++
++struct gdb_data {
++      char *str;
++      int err;
++};
++
++static void config_gdb_cb(void *arg)
++{
++      struct gdb_data *data = arg;
++      void *task;
++      int pid;
++
++      data->err = -1;
++      if(debugger_pid != -1) exit_debugger_cb(NULL);
++      if(!strncmp(data->str, "pid,", strlen("pid,"))){
++              data->str += strlen("pid,");
++              pid = strtoul(data->str, NULL, 0);
++              task = cpu_tasks[0].task;
++              debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0);
++              if(debugger_pid != -1){
++                      data->err = 0;
++                      gdb_pid = pid;
++              }
++              return;
++      }
++      data->err = 0;
++      debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
++      init_proxy(debugger_pid, 0, 0);
++}
++
++int gdb_config(char *str)
++{
++      struct gdb_data data;
++
++      if(*str++ != '=') return(-1);
++      data.str = str;
++      initial_thread_cb(config_gdb_cb, &data);
++      return(data.err);
++}
++
++void remove_gdb_cb(void *unused)
++{
++      exit_debugger_cb(NULL);
++}
++
++int gdb_remove(char *unused)
++{
++      initial_thread_cb(remove_gdb_cb, NULL);
++      return(0);
++}
++
++void signal_usr1(int sig)
++{
++      if(debugger_pid != -1){
++              printk(UM_KERN_ERR "The debugger is already running\n");
++              return;
++      }
++      debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
++      init_proxy(debugger_pid, 0, 0);
++}
++
++int init_ptrace_proxy(int idle_pid, int startup, int stop)
++{
++      int pid, status;
++
++      pid = start_debugger(linux_prog, startup, stop, &debugger_fd);
++      status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
++      if(pid < 0){
++              cont(idle_pid);
++              return(-1);
++      }
++      init_proxy(pid, 1, status);
++      return(pid);
++}
++
++int attach_debugger(int idle_pid, int pid, int stop)
++{
++      int status = 0, err;
++
++      err = attach(pid);
++      if(err < 0){
++              printf("Failed to attach pid %d, errno = %d\n", pid, -err);
++              return(-1);
++      }
++      if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
++      init_proxy(pid, 1, status);
++      return(pid);
++}
++
++#ifdef notdef /* Put this back in when it does something useful */
++static int __init uml_gdb_init_setup(char *line, int *add)
++{
++      gdb_init = uml_strdup(line);
++      return 0;
++}
++
++__uml_setup("gdb=", uml_gdb_init_setup, 
++"gdb=<channel description>\n\n"
++);
++#endif
++
++static int __init uml_gdb_pid_setup(char *line, int *add)
++{
++      gdb_pid = strtoul(line, NULL, 0);
++      *add = 0;
++      return 0;
++}
++
++__uml_setup("gdb-pid=", uml_gdb_pid_setup, 
++"gdb-pid=<pid>\n"
++"    gdb-pid is used to attach an external debugger to UML.  This may be\n"
++"    an already-running gdb or a debugger-like process like strace.\n\n"
++);
++
++#else
++
++int debugger_signal(int status, pid_t pid){ return(0); }
++void child_signal(pid_t pid, int status){ }
++int init_ptrace_proxy(int idle_pid, int startup, int stop)
++{
++      printk(UM_KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
++      kill_child_dead(idle_pid);
++      exit(1);
++}
++
++void signal_usr1(int sig)
++{
++      printk(UM_KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
++}
++
++int attach_debugger(int idle_pid, int pid, int stop)
++{
++      printk(UM_KERN_ERR "attach_debugger called when CONFIG_PT_PROXY "
++             "is off\n");
++      return(-1);
++}
++
++int config_gdb(char *str)
++{
++      return(-1);
++}
++
++int remove_gdb(void)
++{
++      return(-1);
++}
++
++int init_parent_proxy(int pid)
++{
++      return(-1);
++}
++
++void debugger_parent_signal(int status, int pid)
++{
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/gdb_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/gdb_kern.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/gdb_kern.c  2005-05-03 22:28:14.493406880 +0300
+@@ -0,0 +1,40 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/init.h"
++#include "linux/config.h"
++#include "mconsole_kern.h"
++
++#ifdef CONFIG_MCONSOLE
++
++extern int gdb_config(char *str);
++extern int gdb_remove(char *unused);
++
++static struct mc_device gdb_mc = {
++      .name           = "gdb",
++      .config         = gdb_config,
++      .remove         = gdb_remove,
++};
++
++int gdb_mc_init(void)
++{
++      mconsole_register_dev(&gdb_mc);
++      return(0);
++}
++
++__initcall(gdb_mc_init);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/include/debug.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/include/debug.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/include/debug.h     2005-05-03 22:28:14.494406728 +0300
+@@ -0,0 +1,29 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002  Jeff Dike (jdike@karaya.com) and
++ * Lars Brinkhoff.
++ * Licensed under the GPL
++ */
++
++#ifndef __DEBUG_H
++#define __DEBUG_H
++
++extern int debugger_proxy(int status, pid_t pid);
++extern void child_proxy(pid_t pid, int status);
++extern void init_proxy (pid_t pid, int waiting, int status);
++extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd);
++extern void fake_child_exit(void);
++extern int gdb_config(char *str);
++extern int gdb_remove(char *unused);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/include/mmu.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/include/mmu.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/include/mmu.h       2005-05-03 22:28:14.495406576 +0300
+@@ -0,0 +1,23 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TT_MMU_H
++#define __TT_MMU_H
++
++struct mmu_context_tt {
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/include/mode.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/include/mode.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/include/mode.h      2005-05-03 22:28:14.496406424 +0300
+@@ -0,0 +1,38 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MODE_TT_H__
++#define __MODE_TT_H__
++
++#include "sysdep/ptrace.h"
++
++enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
++
++extern int tracing_pid;
++
++extern int tracer(int (*init_proc)(void *), void *sp);
++extern void user_time_init_tt(void);
++extern int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data);
++extern int copy_sc_to_user_tt(void *to_ptr, void *fp, void *from_ptr, 
++                            void *data);
++extern void sig_handler_common_tt(int sig, void *sc);
++extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
++extern void reboot_tt(void);
++extern void halt_tt(void);
++extern int is_tracer_winch(int pid, int fd, void *data);
++extern void kill_off_processes_tt(void);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/include/mode_kern.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/include/mode_kern.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/include/mode_kern.h 2005-05-03 22:28:14.496406424 +0300
+@@ -0,0 +1,52 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TT_MODE_KERN_H__
++#define __TT_MODE_KERN_H__
++
++#include "linux/sched.h"
++#include "asm/page.h"
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++
++extern void *_switch_to_tt(void *prev, void *next);
++extern void flush_thread_tt(void);
++extern void start_thread_tt(struct pt_regs *regs, unsigned long eip, 
++                         unsigned long esp);
++extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
++                        unsigned long stack_top, struct task_struct *p, 
++                        struct pt_regs *regs);
++extern void release_thread_tt(struct task_struct *task);
++extern void exit_thread_tt(void);
++extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
++extern void init_idle_tt(void);
++extern void flush_tlb_kernel_vm_tt(void);
++extern void __flush_tlb_one_tt(unsigned long addr);
++extern void flush_tlb_range_tt(struct mm_struct *mm, unsigned long start, 
++                             unsigned long end);
++extern void flush_tlb_mm_tt(struct mm_struct *mm);
++extern void force_flush_all_tt(void);
++extern long execute_syscall_tt(void *r);
++extern void before_mem_tt(unsigned long brk_start);
++extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, 
++                                     unsigned long *task_size_out);
++extern int start_uml_tt(void);
++extern int external_pid_tt(struct task_struct *task);
++extern int thread_pid_tt(struct thread_struct *thread);
++
++#define kmem_end_tt (host_task_size - ABOVE_KMEM)
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/include/ptrace-tt.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/include/ptrace-tt.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/include/ptrace-tt.h 2005-05-03 22:28:14.497406272 +0300
+@@ -0,0 +1,26 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PTRACE_TT_H
++#define __PTRACE_TT_H
++
++#include "uml-config.h"
++
++#ifdef UML_CONFIG_MODE_TT
++#include "sysdep/sc.h"
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/include/tt.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/include/tt.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/include/tt.h        2005-05-03 22:28:14.498406120 +0300
+@@ -0,0 +1,44 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TT_H__
++#define __TT_H__
++
++#include "sysdep/ptrace.h"
++
++extern int gdb_pid;
++extern int debug;
++extern int debug_stop;
++extern int debug_trace;
++
++extern int honeypot;
++
++extern int fork_tramp(void *sig_stack);
++extern int do_proc_op(void *t, int proc_id);
++extern int tracer(int (*init_proc)(void *), void *sp);
++extern void attach_process(int pid);
++extern void tracer_panic(char *format, ...);
++extern void set_init_pid(int pid);
++extern int set_user_mode(void *task);
++extern void set_tracing(void *t, int tracing);
++extern int is_tracing(void *task);
++extern void syscall_handler(int sig, union uml_pt_regs *regs);
++extern void exit_kernel(int pid, void *task);
++extern int do_syscall(void *task, int pid);
++extern int is_valid_pid(int pid);
++extern void remap_data(void *segment_start, void *segment_end, int w);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/include/uaccess.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/include/uaccess.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/include/uaccess.h   2005-05-03 22:28:14.499405968 +0300
+@@ -0,0 +1,71 @@
++/* 
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __TT_UACCESS_H
++#define __TT_UACCESS_H
++
++#include "linux/string.h"
++#include "linux/sched.h"
++#include "asm/processor.h"
++#include "asm/errno.h"
++#include "asm/current.h"
++#include "asm/a.out.h"
++#include "uml_uaccess.h"
++
++#define ABOVE_KMEM (16 * 1024 * 1024)
++
++extern unsigned long end_vm;
++extern unsigned long uml_physmem;
++
++#define under_task_size(addr, size) \
++      (((unsigned long) (addr) < TASK_SIZE) && \
++         (((unsigned long) (addr) + (size)) < TASK_SIZE))
++
++#define is_stack(addr, size) \
++      (((unsigned long) (addr) < STACK_TOP) && \
++       ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
++       (((unsigned long) (addr) + (size)) <= STACK_TOP))
++
++#define access_ok_tt(type, addr, size) \
++      ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
++         (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
++          (under_task_size(addr, size) || is_stack(addr, size))))
++
++static inline int verify_area_tt(int type, const void * addr, 
++                               unsigned long size)
++{
++      return(access_ok_tt(type, addr, size) ? 0 : -EFAULT);
++}
++
++extern unsigned long get_fault_addr(void);
++
++extern int __do_copy_from_user(void *to, const void *from, int n,
++                             void **fault_addr, void **fault_catcher);
++extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
++                                void **fault_addr, void **fault_catcher);
++extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
++                         void **fault_catcher);
++extern int __do_strnlen_user(const char *str, unsigned long n,
++                           void **fault_addr, void **fault_catcher);
++
++extern int copy_from_user_tt(void *to, const void *from, int n);
++extern int copy_to_user_tt(void *to, const void *from, int n);
++extern int strncpy_from_user_tt(char *dst, const char *src, int count);
++extern int __clear_user_tt(void *mem, int len);
++extern int clear_user_tt(void *mem, int len);
++extern int strnlen_user_tt(const void *str, int len);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/ksyms.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/ksyms.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/ksyms.c     2005-05-03 22:28:14.500405816 +0300
+@@ -0,0 +1,28 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/module.h"
++#include "asm/uaccess.h"
++#include "mode.h"
++
++EXPORT_SYMBOL(__do_copy_from_user);
++EXPORT_SYMBOL(__do_copy_to_user);
++EXPORT_SYMBOL(__do_strncpy_from_user);
++EXPORT_SYMBOL(__do_strnlen_user); 
++EXPORT_SYMBOL(__do_clear_user);
++
++EXPORT_SYMBOL(tracing_pid);
++EXPORT_SYMBOL(honeypot);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/Makefile       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/Makefile    2005-05-03 22:28:14.501405664 +0300
+@@ -0,0 +1,39 @@
++# 
++# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
++# Licensed under the GPL
++#
++
++O_TARGET = tt.o
++
++obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
++      syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \
++      uaccess.o uaccess_user.o
++
++obj-$(CONFIG_PT_PROXY) += gdb_kern.o 
++
++subdir-y = sys-$(SUBARCH)
++subdir-$(CONFIG_PT_PROXY) += ptproxy
++
++obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
++
++export-objs = ksyms.o
++
++USER_OBJS = $(filter %_user.o,$(obj-y)) gdb.o time.o tracer.o
++
++UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
++UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++$(O_TARGET) : unmap_fin.o
++
++unmap.o: unmap.c
++      $(CC) $(UNMAP_CFLAGS) -c -o $@ $<
++
++unmap_fin.o : unmap.o
++      ld -r -o $@ $< -lc -L/usr/lib
++
++clean :
+Index: linux-2.4.29/arch/um/kernel/tt/mem.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/mem.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/mem.c       2005-05-03 22:28:14.502405512 +0300
+@@ -0,0 +1,51 @@
++/* 
++ * Copyright (C) 2002 - 2004 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/config.h"
++#include "linux/mm.h"
++#include "asm/uaccess.h"
++#include "mem_user.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "kern.h"
++#include "tt.h"
++
++void before_mem_tt(unsigned long brk_start)
++{
++      if(!jail || debug)
++              remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1);
++      remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1);
++      remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1);
++}
++
++#ifdef CONFIG_HOST_2G_2G
++#define TOP 0x80000000
++#else
++#define TOP 0xc0000000
++#endif
++
++#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
++#define START (TOP - SIZE)
++
++unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, 
++                              unsigned long *task_size_out)
++{
++      /* Round up to the nearest 4M */
++      *host_size_out = ROUND_4M((unsigned long) &arg);
++      *task_size_out = START;
++      return(START);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/mem_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/mem_user.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/mem_user.c  2005-05-03 22:28:14.502405512 +0300
+@@ -0,0 +1,49 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/mman.h>
++#include "tt.h"
++#include "mem_user.h"
++#include "user_util.h"
++
++void remap_data(void *segment_start, void *segment_end, int w)
++{
++      void *addr;
++      unsigned long size;
++      int data, prot;
++
++      if(w) prot = PROT_WRITE;
++      else prot = 0;
++      prot |= PROT_READ | PROT_EXEC;
++      size = (unsigned long) segment_end - 
++              (unsigned long) segment_start;
++      data = create_mem_file(size);
++      addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0);
++      if(addr == MAP_FAILED){
++              perror("mapping new data segment");
++              exit(1);
++      }
++      memcpy(addr, segment_start, size);
++      if(switcheroo(data, prot, addr, segment_start, size) < 0){
++              printf("switcheroo failed\n");
++              exit(1);
++      }
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/process_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/process_kern.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/process_kern.c      2005-05-03 22:28:14.526401864 +0300
+@@ -0,0 +1,615 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "linux/signal.h"
++#include "linux/kernel.h"
++#include "linux/slab.h"
++#include "asm/system.h"
++#include "asm/pgalloc.h"
++#include "asm/ptrace.h"
++#include "irq_user.h"
++#include "signal_user.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "os.h"
++#include "kern.h"
++#include "sigcontext.h"
++#include "time_user.h"
++#include "mem_user.h"
++#include "tlb.h"
++#include "mode.h"
++#include "init.h"
++#include "tt.h"
++#include "filehandle.h"
++
++void *_switch_to_tt(void *prev, void *next)
++{
++      struct task_struct *from, *to, *prev_sched;
++      struct file_handle *pipe;
++      unsigned long flags;
++      int err, vtalrm, alrm, prof, cpu;
++      char c;
++      /* jailing and SMP are incompatible, so this doesn't need to be 
++       * made per-cpu 
++       */
++      static int reading;
++
++      from = prev;
++      to = next;
++
++      to->thread.prev_sched = from;
++
++      cpu = from->processor;
++      if(cpu == 0)
++              forward_interrupts(to->thread.mode.tt.extern_pid);
++#ifdef CONFIG_SMP
++      forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid);
++#endif
++      local_irq_save(flags);
++
++      vtalrm = change_sig(SIGVTALRM, 0);
++      alrm = change_sig(SIGALRM, 0);
++      prof = change_sig(SIGPROF, 0);
++
++      c = 0;
++      set_current(to);
++
++      reading = 0;
++      pipe = to->thread.mode.tt.switch_pipe;
++      err = write_file(&pipe[1], -1, &c, sizeof(c));
++      if(err != sizeof(c))
++              panic("write of switch_pipe failed, err = %d", -err);
++
++      reading = 1;
++      if(from->state == TASK_ZOMBIE)
++              os_kill_process(os_getpid(), 0);
++
++      pipe = from->thread.mode.tt.switch_pipe;
++      err = read_file(&pipe[0], -1, &c, sizeof(c));
++      if(err != sizeof(c))
++              panic("read of switch_pipe failed, errno = %d", -err);
++
++      /* If the process that we have just scheduled away from has exited,
++       * then it needs to be killed here.  The reason is that, even though
++       * it will kill itself when it next runs, that may be too late.  Its
++       * stack will be freed, possibly before then, and if that happens,
++       * we have a use-after-free situation.  So, it gets killed here
++       * in case it has not already killed itself.
++       */
++      prev_sched = current->thread.prev_sched;
++      if(prev_sched->state == TASK_ZOMBIE)
++              os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1);
++
++      /* This works around a nasty race with 'jail'.  If we are switching
++       * between two threads of a threaded app and the incoming process 
++       * runs before the outgoing process reaches the read, and it makes
++       * it all the way out to userspace, then it will have write-protected 
++       * the outgoing process stack.  Then, when the outgoing process 
++       * returns from the write, it will segfault because it can no longer
++       * write its own stack.  So, in order to avoid that, the incoming 
++       * thread sits in a loop yielding until 'reading' is set.  This 
++       * isn't entirely safe, since there may be a reschedule from a timer
++       * happening between setting 'reading' and sleeping in read.  But,
++       * it should get a whole quantum in which to reach the read and sleep,
++       * which should be enough.
++       */
++
++      if(jail){
++              while(!reading) sched_yield();
++      }
++
++      change_sig(SIGVTALRM, vtalrm);
++      change_sig(SIGALRM, alrm);
++      change_sig(SIGPROF, prof);
++
++      arch_switch();
++
++      flush_tlb_all();
++      local_irq_restore(flags);
++
++      return(current->thread.prev_sched);
++}
++
++void release_thread_tt(struct task_struct *task)
++{
++      os_kill_process(task->thread.mode.tt.extern_pid, 0);
++}
++
++void exit_thread_tt(void)
++{
++      struct file_handle *pipe = current->thread.mode.tt.switch_pipe;
++
++      close_file(&pipe[0]);
++      close_file(&pipe[1]);
++      kfree(pipe);
++}
++
++static void suspend_new_thread(struct file_handle *fh)
++{
++      char c;
++
++      os_stop_process(os_getpid());
++
++      if(read_file(fh, -1, &c, sizeof(c)) != sizeof(c))
++              panic("read failed in suspend_new_thread");
++}
++
++extern void schedule_tail(struct task_struct *prev);
++
++static void new_thread_handler(int sig)
++{
++      struct file_handle *pipe;
++      unsigned long disable;
++      int (*fn)(void *);
++      void *arg;
++
++      fn = current->thread.request.u.thread.proc;
++      arg = current->thread.request.u.thread.arg;
++
++      UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
++      disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) |
++              (1 << (SIGIO - 1)) | (1 << (SIGPROF - 1));
++      SC_SIGMASK(UPT_SC(&current->thread.regs.regs)) &= ~disable;
++
++      pipe = current->thread.mode.tt.switch_pipe;
++      suspend_new_thread(&pipe[0]);
++
++      init_new_thread_signals(1);
++      enable_timer();
++      free_page(current->thread.temp_stack);
++      set_cmdline("(kernel thread)");
++      force_flush_all();
++
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
++      current->thread.prev_sched = NULL;
++
++      change_sig(SIGUSR1, 1);
++      change_sig(SIGVTALRM, 1);
++      change_sig(SIGPROF, 1);
++      sti();
++      if(!run_kernel_thread(fn, arg, &current->thread.exec_buf))
++              do_exit(0);
++      
++      /* XXX No set_user_mode here because a newly execed process will
++       * immediately segfault on its non-existent IP, coming straight back
++       * to the signal handler, which will call set_user_mode on its way
++       * out.  This should probably change since it's confusing.
++       */
++}
++
++static int new_thread_proc(void *stack)
++{
++      /* cli is needed to block out signals until this thread is properly
++       * scheduled.  Otherwise, the tracing thread will get mighty upset 
++       * about any signals that arrive before that.  
++       * This has the complication that it sets the saved signal mask in
++       * the sigcontext to block signals.  This gets restored when this
++       * thread (or a descendant, since they get a copy of this sigcontext)
++       * returns to userspace.
++       * So, this is compensated for elsewhere.
++       * XXX There is still a small window until cli() actually finishes
++       * where signals are possible - shouldn't be a problem in practice 
++       * since SIGIO hasn't been forwarded here yet, and the cli should 
++       * finish before a SIGVTALRM has time to be delivered.
++       */
++      cli();
++      init_new_thread_stack(stack, new_thread_handler);
++      os_usr1_process(os_getpid());
++      change_sig(SIGUSR1, 1);
++      return(0);
++}
++
++/* Signal masking - signals are blocked at the start of fork_tramp.  They
++ * are re-enabled when finish_fork_handler is entered by fork_tramp hitting
++ * itself with a SIGUSR1.  set_user_mode has to be run with SIGUSR1 off,
++ * so it is blocked before it's called.  They are re-enabled on sigreturn
++ * despite the fact that they were blocked when the SIGUSR1 was issued because
++ * copy_thread copies the parent's sigcontext, including the signal mask
++ * onto the signal frame.
++ */
++
++static void finish_fork_handler(int sig)
++{
++      struct file_handle *pipe = current->thread.mode.tt.switch_pipe;
++
++      UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
++      suspend_new_thread(&pipe[0]);
++      
++      init_new_thread_signals(1);
++      enable_timer();
++      sti();
++      force_flush_all();
++      if(current->mm != current->p_pptr->mm)
++              protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 
++                             1, 0, 1);
++      task_protections((unsigned long) current);
++
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
++      current->thread.prev_sched = NULL;
++
++      free_page(current->thread.temp_stack);
++      cli();
++      change_sig(SIGUSR1, 0);
++      set_user_mode(current);
++}
++
++int fork_tramp(void *stack)
++{
++      cli();
++      arch_init_thread();
++      init_new_thread_stack(stack, finish_fork_handler);
++      os_usr1_process(os_getpid());
++      change_sig(SIGUSR1, 1);
++      return(0);
++}
++
++struct file_handle *make_switch_pipe(void)
++{
++      struct file_handle *pipe;
++      int err;
++
++      pipe = kmalloc(sizeof(struct file_handle [2]), GFP_KERNEL);
++      if(pipe == NULL){
++              pipe = ERR_PTR(-ENOMEM);
++              goto out;
++      }
++
++      err = make_pipe(pipe);
++      if(err)
++              goto out_free;
++
++ out:
++      return(pipe);
++
++ out_free:
++      kfree(pipe);
++      pipe = ERR_PTR(err);
++      goto out;
++}
++
++int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
++                 unsigned long stack_top, struct task_struct * p, 
++                 struct pt_regs *regs)
++{
++      int (*tramp)(void *);
++      int new_pid, err;
++      unsigned long stack;
++      
++      if(current->thread.forking)
++              tramp = fork_tramp;
++      else {
++              tramp = new_thread_proc;
++              p->thread.request.u.thread = current->thread.request.u.thread;
++      }
++
++      p->thread.mode.tt.switch_pipe = make_switch_pipe();
++      if(IS_ERR(p->thread.mode.tt.switch_pipe)){
++              err = PTR_ERR(p->thread.mode.tt.switch_pipe);
++              goto out;
++      }
++
++      stack = alloc_stack(0, 0);
++      if(stack == 0){
++              printk(KERN_ERR "copy_thread : failed to allocate "
++                     "temporary stack\n");
++              err = -ENOMEM;
++              goto out_close;
++      }
++
++      clone_flags &= CLONE_VM;
++      p->thread.temp_stack = stack;
++      new_pid = start_fork_tramp(p, stack, clone_flags, tramp);
++      if(new_pid < 0){
++              printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", 
++                     -new_pid);
++              err = new_pid;
++              goto out_stack;
++      }
++
++      if(current->thread.forking){
++              sc_to_sc(UPT_SC(&p->thread.regs.regs), 
++                       UPT_SC(&current->thread.regs.regs));
++              SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0);
++              if(sp != 0) SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
++      }
++      p->thread.mode.tt.extern_pid = new_pid;
++
++      current->thread.request.op = OP_FORK;
++      current->thread.request.u.fork.pid = new_pid;
++      os_usr1_process(os_getpid());
++
++      /* Enable the signal and then disable it to ensure that it is handled
++       * here, and nowhere else.
++       */
++      change_sig(SIGUSR1, 1);
++
++      change_sig(SIGUSR1, 0);
++      err = 0;
++
++ out:
++      return(err);
++
++ out_stack:
++      free_stack(stack, 0);
++ out_close:
++      close_file(&((struct file_handle *) p->thread.mode.tt.switch_pipe)[0]);
++      close_file(&((struct file_handle *) p->thread.mode.tt.switch_pipe)[1]);
++      kfree(p->thread.mode.tt.switch_pipe);
++      goto out;
++}
++
++void reboot_tt(void)
++{
++      current->thread.request.op = OP_REBOOT;
++      os_usr1_process(os_getpid());
++      change_sig(SIGUSR1, 1);
++}
++
++void halt_tt(void)
++{
++      current->thread.request.op = OP_HALT;
++      os_usr1_process(os_getpid());
++      change_sig(SIGUSR1, 1);
++}
++
++void kill_off_processes_tt(void)
++{
++      struct task_struct *p;
++      int me;
++
++      me = os_getpid();
++      for_each_task(p){
++              int pid = p->thread.mode.tt.extern_pid;
++              if((pid != me) && (pid != -1))
++                      os_kill_process(p->thread.mode.tt.extern_pid, 0);
++      }
++      if((init_task.thread.mode.tt.extern_pid != me) &&
++         (init_task.thread.mode.tt.extern_pid != -1))
++              os_kill_process(init_task.thread.mode.tt.extern_pid, 0);
++}
++
++void initial_thread_cb_tt(void (*proc)(void *), void *arg)
++{
++      if(os_getpid() == tracing_pid){
++              (*proc)(arg);
++      }
++      else {
++              current->thread.request.op = OP_CB;
++              current->thread.request.u.cb.proc = proc;
++              current->thread.request.u.cb.arg = arg;
++              os_usr1_process(os_getpid());
++              change_sig(SIGUSR1, 1);
++
++              change_sig(SIGUSR1, 0);
++      }
++}
++
++int do_proc_op(void *t, int proc_id)
++{
++      struct task_struct *task;
++      struct thread_struct *thread;
++      int op, pid;
++
++      task = t;
++      thread = &task->thread;
++      op = thread->request.op;
++      switch(op){
++      case OP_NONE:
++      case OP_TRACE_ON:
++              break;
++      case OP_EXEC:
++              pid = thread->request.u.exec.pid;
++              do_exec(thread->mode.tt.extern_pid, pid);
++              thread->mode.tt.extern_pid = pid;
++              cpu_tasks[task->processor].pid = pid;
++              break;
++      case OP_FORK:
++              attach_process(thread->request.u.fork.pid);
++              break;
++      case OP_CB:
++              (*thread->request.u.cb.proc)(thread->request.u.cb.arg);
++              break;
++      case OP_REBOOT:
++      case OP_HALT:
++              break;
++      default:
++              tracer_panic("Bad op in do_proc_op");
++              break;
++      }
++      thread->request.op = OP_NONE;
++      return(op);
++}
++
++void init_idle_tt(void)
++{
++      idle_timer();
++}
++
++/* Changed by jail_setup, which is a setup */
++int jail = 0;
++
++int __init jail_setup(char *line, int *add)
++{
++      int ok = 1;
++
++      if(jail) return(0);
++#ifdef CONFIG_SMP
++      printf("'jail' may not used used in a kernel with CONFIG_SMP "
++             "enabled\n");
++      ok = 0;
++#endif
++#ifdef CONFIG_HOSTFS
++      printf("'jail' may not used used in a kernel with CONFIG_HOSTFS "
++             "enabled\n");
++      ok = 0;
++#endif
++#ifdef CONFIG_MODULES
++      printf("'jail' may not used used in a kernel with CONFIG_MODULES "
++             "enabled\n");
++      ok = 0;
++#endif        
++      if(!ok) exit(1);
++
++      /* CAP_SYS_RAWIO controls the ability to open /dev/mem and /dev/kmem.
++       * Removing it from the bounding set eliminates the ability of anything
++       * to acquire it, and thus read or write kernel memory.
++       */
++      cap_lower(cap_bset, CAP_SYS_RAWIO);
++      jail = 1;
++      return(0);
++}
++
++__uml_setup("jail", jail_setup,
++"jail\n"
++"    Enables the protection of kernel memory from processes.\n\n"
++);
++
++static void mprotect_kernel_mem(int w)
++{
++      unsigned long start, end;
++      int pages;
++
++      if(!jail || (current == &init_task)) return;
++
++      pages = (1 << CONFIG_KERNEL_STACK_ORDER);
++
++      start = (unsigned long) current + PAGE_SIZE;
++      end = (unsigned long) current + PAGE_SIZE * pages;
++      protect_memory(uml_reserved, start - uml_reserved, 1, w, 1, 1);
++      protect_memory(end, high_physmem - end, 1, w, 1, 1);
++
++      start = (unsigned long) UML_ROUND_DOWN(&_stext);
++      end = (unsigned long) UML_ROUND_UP(&_etext);
++      protect_memory(start, end - start, 1, w, 1, 1);
++
++      start = (unsigned long) UML_ROUND_DOWN(&_unprotected_end);
++      end = (unsigned long) UML_ROUND_UP(&_edata);
++      protect_memory(start, end - start, 1, w, 1, 1);
++
++      start = (unsigned long) UML_ROUND_DOWN(&__bss_start);
++      end = (unsigned long) UML_ROUND_UP(&_end);
++      protect_memory(start, end - start, 1, w, 1, 1);
++
++      mprotect_kernel_vm(w);
++}
++
++void unprotect_kernel_mem(void)
++{
++      mprotect_kernel_mem(1);
++}
++
++void protect_kernel_mem(void)
++{
++      mprotect_kernel_mem(0);
++}
++
++extern void start_kernel(void);
++
++static int start_kernel_proc(void *unused)
++{
++      int pid;
++
++      block_signals();
++      pid = os_getpid();
++
++      cpu_tasks[0].pid = pid;
++      cpu_tasks[0].task = current;
++#ifdef CONFIG_SMP
++      cpu_online_map = 1;
++#endif
++      if(debug) os_stop_process(pid);
++      start_kernel();
++      return(0);
++}
++
++void set_tracing(void *task, int tracing)
++{
++      ((struct task_struct *) task)->thread.mode.tt.tracing = tracing;
++}
++
++int is_tracing(void *t)
++{
++      return (((struct task_struct *) t)->thread.mode.tt.tracing);
++}
++
++int set_user_mode(void *t)
++{
++      struct task_struct *task;
++
++      task = t ? t : current;
++      if(task->thread.mode.tt.tracing) 
++              return(1);
++      task->thread.request.op = OP_TRACE_ON;
++      os_usr1_process(os_getpid());
++      return(0);
++}
++
++/* This is static rather than kmalloced because this happens before kmalloc
++ * is initialized.  Also, it is always needed, so might as well be static on
++ * this ground.
++ */
++static struct file_handle init_switch_pipe[2];
++
++void set_init_pid(int pid)
++{
++      int err;
++
++      init_task.thread.mode.tt.extern_pid = pid;
++
++      err = make_pipe(init_switch_pipe);
++      if(err)
++              panic("set_init_pid - make_pipe failed, errno = %d", err);
++      init_task.thread.mode.tt.switch_pipe = init_switch_pipe;
++}
++
++int start_uml_tt(void)
++{
++      void *sp;
++      int pages;
++
++      pages = (1 << CONFIG_KERNEL_STACK_ORDER);
++      sp = (void *) ((unsigned long) &init_task) + pages * PAGE_SIZE - 
++              sizeof(unsigned long);
++      return(tracer(start_kernel_proc, sp));
++}
++
++int external_pid_tt(struct task_struct *task)
++{
++      return(task->thread.mode.tt.extern_pid);
++}
++
++int thread_pid_tt(struct thread_struct *thread)
++{
++      return(thread->mode.tt.extern_pid);
++}
++
++int is_valid_pid(int pid)
++{
++      struct task_struct *task;
++
++        read_lock(&tasklist_lock);
++        for_each_task(task){
++                if(task->thread.mode.tt.extern_pid == pid){
++                      read_unlock(&tasklist_lock);
++                      return(1);
++                }
++        }
++      read_unlock(&tasklist_lock);
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/Makefile       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/ptproxy/Makefile    2005-05-03 22:28:14.526401864 +0300
+@@ -0,0 +1,12 @@
++O_TARGET = ptproxy.o
++
++obj-y = proxy.o ptrace.o sysdep.o wait.o
++
++USER_OBJS = $(obj-y)
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++clean:
+Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/proxy.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/proxy.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/ptproxy/proxy.c     2005-05-03 22:28:14.529401408 +0300
+@@ -0,0 +1,371 @@
++/**********************************************************************
++proxy.c
++
++Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
++terms and conditions.
++
++Jeff Dike (jdike@karaya.com) : Modified for integration into uml
++**********************************************************************/
++
++/* XXX This file shouldn't refer to CONFIG_* */
++
++#include <errno.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <signal.h>
++#include <string.h>
++#include <termios.h>
++#include <sys/wait.h>
++#include <sys/types.h>
++#include <sys/ptrace.h>
++#include <sys/ioctl.h>
++#include <asm/unistd.h>
++
++#include "ptproxy.h"
++#include "sysdep.h"
++#include "wait.h"
++
++#include "user_util.h"
++#include "user.h"
++#include "os.h"
++#include "tempfile.h"
++
++static int debugger_wait(debugger_state *debugger, int *status, int options,
++                       int (*syscall)(debugger_state *debugger, pid_t child),
++                       int (*normal_return)(debugger_state *debugger, 
++                                            pid_t unused),
++                       int (*wait_return)(debugger_state *debugger, 
++                                          pid_t unused))
++{
++      if(debugger->real_wait){
++              debugger->handle_trace = normal_return;
++              syscall_continue(debugger->pid);
++              debugger->real_wait = 0;
++              return(1);
++      }
++      debugger->wait_status_ptr = status;
++      debugger->wait_options = options;
++      if((debugger->debugee != NULL) && debugger->debugee->event){
++              syscall_continue(debugger->pid);
++              wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL,
++                            NULL);
++              (*wait_return)(debugger, -1);
++              return(0);
++      }
++      else if(debugger->wait_options & WNOHANG){
++              syscall_cancel(debugger->pid, 0);
++              debugger->handle_trace = syscall;
++              return(0);
++      }
++      else {
++              syscall_pause(debugger->pid);
++              debugger->handle_trace = wait_return;
++              debugger->waiting = 1;
++      }
++      return(1);
++}
++
++/*
++ * Handle debugger trap, i.e. syscall.
++ */
++
++int debugger_syscall(debugger_state *debugger, pid_t child)
++{
++      long arg1, arg2, arg3, arg4, arg5, result;
++      int syscall, ret = 0;
++
++      syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4, 
++                            &arg5);
++
++      switch(syscall){
++      case __NR_execve:
++              /* execve never returns */
++              debugger->handle_trace = debugger_syscall; 
++              break;
++
++      case __NR_ptrace:
++              if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid;
++              if(!debugger->debugee->in_context) 
++                      child = debugger->debugee->pid;
++              result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child,
++                                    &ret);
++              syscall_cancel(debugger->pid, result);
++              debugger->handle_trace = debugger_syscall;
++              return(ret);
++
++      case __NR_waitpid:
++      case __NR_wait4:
++              if(!debugger_wait(debugger, (int *) arg2, arg3, 
++                                debugger_syscall, debugger_normal_return, 
++                                proxy_wait_return))
++                      return(0);
++              break;
++
++      case __NR_kill:
++              if(!debugger->debugee->in_context) 
++                      child = debugger->debugee->pid;
++              if(arg1 == debugger->debugee->pid){
++                      result = kill(child, arg2);
++                      syscall_cancel(debugger->pid, result);
++                      debugger->handle_trace = debugger_syscall;
++                      return(0);
++              }
++              else debugger->handle_trace = debugger_normal_return;
++              break;
++
++      default:
++              debugger->handle_trace = debugger_normal_return;
++      }
++
++      syscall_continue(debugger->pid);
++      return(0);
++}
++
++/* Used by the tracing thread */
++static debugger_state parent;
++static int parent_syscall(debugger_state *debugger, int pid);
++
++int init_parent_proxy(int pid)
++{
++      parent = ((debugger_state) { .pid               = pid,
++                                   .wait_options      = 0,
++                                   .wait_status_ptr   = NULL,
++                                   .waiting           = 0,
++                                   .real_wait         = 0,
++                                   .expecting_child   = 0,
++                                   .handle_trace      = parent_syscall,
++                                   .debugee           = NULL } );
++      return(0);
++}
++
++int parent_normal_return(debugger_state *debugger, pid_t unused)
++{
++      debugger->handle_trace = parent_syscall;
++      syscall_continue(debugger->pid);
++      return(0);
++}
++
++static int parent_syscall(debugger_state *debugger, int pid)
++{
++      long arg1, arg2, arg3, arg4, arg5;
++      int syscall;
++
++      syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5);
++              
++      if((syscall == __NR_waitpid) || (syscall == __NR_wait4)){
++              debugger_wait(&parent, (int *) arg2, arg3, parent_syscall,
++                            parent_normal_return, parent_wait_return);
++      }
++      else ptrace(PTRACE_SYSCALL, pid, 0, 0);
++      return(0);
++}
++
++int debugger_normal_return(debugger_state *debugger, pid_t unused)
++{
++      debugger->handle_trace = debugger_syscall;
++      syscall_continue(debugger->pid);
++      return(0);
++}
++
++void debugger_cancelled_return(debugger_state *debugger, int result)
++{
++      debugger->handle_trace = debugger_syscall;
++      syscall_set_result(debugger->pid, result);
++      syscall_continue(debugger->pid);
++}
++
++/* Used by the tracing thread */
++static debugger_state debugger;
++static debugee_state debugee;
++
++void init_proxy (pid_t debugger_pid, int stopped, int status)
++{
++      debugger.pid = debugger_pid;
++      debugger.handle_trace = debugger_syscall;
++      debugger.debugee = &debugee;
++      debugger.waiting = 0;
++      debugger.real_wait = 0;
++      debugger.expecting_child = 0;
++
++      debugee.pid = 0;
++      debugee.traced = 0;
++      debugee.stopped = stopped;
++      debugee.event = 0;
++      debugee.zombie = 0;
++      debugee.died = 0;
++      debugee.wait_status = status;
++      debugee.in_context = 1;
++}
++
++int debugger_proxy(int status, int pid)
++{
++      int ret = 0, sig;
++
++      if(WIFSTOPPED(status)){
++              sig = WSTOPSIG(status);
++              if (sig == SIGTRAP)
++                      ret = (*debugger.handle_trace)(&debugger, pid);
++                                                     
++              else if(sig == SIGCHLD){
++                      if(debugger.expecting_child){
++                              ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
++                              debugger.expecting_child = 0;
++                      }
++                      else if(debugger.waiting)
++                              real_wait_return(&debugger);
++                      else {
++                              ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
++                              debugger.real_wait = 1;
++                      }
++              }
++              else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
++      }
++      else if(WIFEXITED(status)){
++              tracer_panic("debugger (pid %d) exited with status %d", 
++                           debugger.pid, WEXITSTATUS(status));
++      }
++      else if(WIFSIGNALED(status)){
++              tracer_panic("debugger (pid %d) exited with signal %d", 
++                           debugger.pid, WTERMSIG(status));
++      }
++      else {
++              tracer_panic("proxy got unknown status (0x%x) on debugger "
++                           "(pid %d)", status, debugger.pid);
++      }
++      return(ret);
++}
++
++void child_proxy(pid_t pid, int status)
++{
++      debugee.event = 1;
++      debugee.wait_status = status;
++
++      if(WIFSTOPPED(status)){
++              debugee.stopped = 1;
++              debugger.expecting_child = 1;
++              kill(debugger.pid, SIGCHLD);
++      }
++      else if(WIFEXITED(status) || WIFSIGNALED(status)){
++              debugee.zombie = 1;
++              debugger.expecting_child = 1;
++              kill(debugger.pid, SIGCHLD);
++      }
++      else panic("proxy got unknown status (0x%x) on child (pid %d)", 
++                 status, pid);
++}
++
++void debugger_parent_signal(int status, int pid)
++{
++      int sig;
++
++      if(WIFSTOPPED(status)){
++              sig = WSTOPSIG(status);
++              if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid);
++              else ptrace(PTRACE_SYSCALL, pid, 0, sig);
++      }
++}
++
++void fake_child_exit(void)
++{
++      int status, pid;
++
++      child_proxy(1, W_EXITCODE(0, 0));
++      while(debugger.waiting == 1){
++              CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
++              if(pid != debugger.pid){
++                      printk("fake_child_exit - waitpid failed, "
++                             "errno = %d\n", errno);
++                      return;
++              }
++              debugger_proxy(status, debugger.pid);
++      }
++      CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
++      if(pid != debugger.pid){
++              printk("fake_child_exit - waitpid failed, "
++                     "errno = %d\n", errno);
++              return;
++      }
++      if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0)
++              printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n",
++                     errno);
++}
++
++char gdb_init_string[] = 
++"att 1 \n\
++b panic \n\
++b stop \n\
++handle SIGWINCH nostop noprint pass \n\
++";
++
++int start_debugger(char *prog, int startup, int stop, int *fd_out)
++{
++      int slave, child;
++
++      slave = open_gdb_chan();
++      child = fork();
++      if(child == 0){
++              char *tempname = NULL;
++              int fd;
++
++              if(setsid() < 0) perror("setsid");
++              if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) || 
++                 (dup2(slave, 2) < 0)){
++                      printk("start_debugger : dup2 failed, errno = %d\n",
++                             errno);
++                      exit(1);
++              }
++              if(ioctl(0, TIOCSCTTY, 0) < 0){
++                      printk("start_debugger : TIOCSCTTY failed, "
++                             "errno = %d\n", errno);
++                      exit(1);
++              }
++              if(tcsetpgrp (1, os_getpid()) < 0){
++                      printk("start_debugger : tcsetpgrp failed, "
++                             "errno = %d\n", errno);
++#ifdef notdef
++                      exit(1);
++#endif
++              }
++              fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0);
++              if(fd < 0){
++                      printk("start_debugger : make_tempfile failed,"
++                             "err = %d\n", -fd);
++                      exit(1);
++              }
++              os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
++              if(startup){
++                      if(stop){
++                              os_write_file(fd, "b start_kernel\n",
++                                    strlen("b start_kernel\n"));
++                      }
++                      os_write_file(fd, "c\n", strlen("c\n"));
++              }
++              if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
++                      printk("start_debugger :  PTRACE_TRACEME failed, "
++                             "errno = %d\n", errno);
++                      exit(1);
++              }
++              execlp("gdb", "gdb", "--command", tempname, prog, NULL);
++              printk("start_debugger : exec of gdb failed, errno = %d\n",
++                     errno);
++      }
++      if(child < 0){
++              printk("start_debugger : fork for gdb failed, errno = %d\n",
++                     errno);
++              return(-1);
++      }
++      *fd_out = slave;
++      return(child);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/ptproxy.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/ptproxy.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/ptproxy/ptproxy.h   2005-05-03 22:28:14.529401408 +0300
+@@ -0,0 +1,61 @@
++/**********************************************************************
++ptproxy.h
++
++Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
++terms and conditions.
++**********************************************************************/
++
++#ifndef __PTPROXY_H
++#define __PTPROXY_H
++
++#include <sys/types.h>
++
++typedef struct debugger debugger_state;
++typedef struct debugee debugee_state;
++
++struct debugger
++{
++      pid_t pid;
++      int wait_options;
++      int *wait_status_ptr;
++      unsigned int waiting : 1;
++      unsigned int real_wait : 1;
++      unsigned int expecting_child : 1;
++      int (*handle_trace) (debugger_state *, pid_t);
++
++      debugee_state *debugee;
++};
++
++struct debugee
++{
++      pid_t pid;
++      int wait_status;
++      unsigned int died : 1;
++      unsigned int event : 1;
++      unsigned int stopped : 1;
++      unsigned int trace_singlestep : 1;
++      unsigned int trace_syscall : 1;
++      unsigned int traced : 1;
++      unsigned int zombie : 1;
++      unsigned int in_context : 1;
++};
++
++extern int debugger_syscall(debugger_state *debugger, pid_t pid);
++extern int debugger_normal_return (debugger_state *debugger, pid_t unused);
++
++extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t,
++                        int *strace_out);
++extern void debugger_cancelled_return(debugger_state *debugger, int result);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/ptrace.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/ptrace.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/ptproxy/ptrace.c    2005-05-03 22:28:14.531401104 +0300
+@@ -0,0 +1,239 @@
++/**********************************************************************
++ptrace.c
++
++Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
++terms and conditions.
++
++Jeff Dike (jdike@karaya.com) : Modified for integration into uml
++**********************************************************************/
++
++#include <errno.h>
++#include <unistd.h>
++#include <signal.h>
++#include <sys/types.h>
++#include <sys/time.h>
++#include <sys/ptrace.h>
++#include <sys/wait.h>
++#include <asm/ptrace.h>
++
++#include "ptproxy.h"
++#include "debug.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "ptrace_user.h"
++#include "tt.h"
++
++long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
++                long arg3, long arg4, pid_t child, int *ret)
++{
++      sigset_t relay;
++      long result;
++      int status;
++
++      *ret = 0;
++      if(debugger->debugee->died) return(-ESRCH);
++
++      switch(arg1){
++      case PTRACE_ATTACH:
++              if(debugger->debugee->traced) return(-EPERM);
++
++              debugger->debugee->pid = arg2;
++              debugger->debugee->traced = 1;
++
++              if(is_valid_pid(arg2) && (arg2 != child)){
++                      debugger->debugee->in_context = 0;
++                      kill(arg2, SIGSTOP);
++                      debugger->debugee->event = 1;
++                      debugger->debugee->wait_status = W_STOPCODE(SIGSTOP);
++              }
++              else {
++                      debugger->debugee->in_context = 1;
++                      if(debugger->debugee->stopped) 
++                              child_proxy(child, W_STOPCODE(SIGSTOP));
++                      else kill(child, SIGSTOP);
++              }
++
++              return(0);
++
++      case PTRACE_DETACH:
++              if(!debugger->debugee->traced) return(-EPERM);
++              
++              debugger->debugee->traced = 0;
++              debugger->debugee->pid = 0;
++              if(!debugger->debugee->in_context)
++                      kill(child, SIGCONT);
++
++              return(0);
++
++      case PTRACE_CONT:
++              if(!debugger->debugee->in_context) return(-EPERM);
++              *ret = PTRACE_CONT;
++              return(ptrace(PTRACE_CONT, child, arg3, arg4));
++
++#ifdef UM_HAVE_GETFPREGS
++      case PTRACE_GETFPREGS:
++      {
++              long regs[FP_FRAME_SIZE];
++              int i, result;
++
++              result = ptrace(PTRACE_GETFPREGS, child, 0, regs);
++              if(result == -1) return(-errno);
++              
++              for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
++                      ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
++                             regs[i]);
++              return(result);
++      }
++#endif
++
++#ifdef UM_HAVE_GETFPXREGS
++      case PTRACE_GETFPXREGS:
++      {
++              long regs[FPX_FRAME_SIZE];
++              int i, result;
++
++              result = ptrace(PTRACE_GETFPXREGS, child, 0, regs);
++              if(result == -1) return(-errno);
++              
++              for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
++                      ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
++                             regs[i]);
++              return(result);
++      }
++#endif
++
++#ifdef UM_HAVE_GETREGS
++      case PTRACE_GETREGS:
++      {
++              long regs[FRAME_SIZE];
++              int i, result;
++
++              result = ptrace(PTRACE_GETREGS, child, 0, regs);
++              if(result == -1) return(-errno);
++
++              for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
++                      ptrace (PTRACE_POKEDATA, debugger->pid,
++                              arg4 + 4 * i, regs[i]);
++              return(result);
++      }
++      break;
++#endif
++
++      case PTRACE_KILL:
++              result = ptrace(PTRACE_KILL, child, arg3, arg4);
++              if(result == -1) return(-errno);
++
++              return(result);
++
++      case PTRACE_PEEKDATA:
++      case PTRACE_PEEKTEXT:
++      case PTRACE_PEEKUSER:
++              /* The value being read out could be -1, so we have to 
++               * check errno to see if there's an error, and zero it
++               * beforehand so we're not faked out by an old error
++               */
++
++              errno = 0;
++              result = ptrace(arg1, child, arg3, 0);
++              if((result == -1) && (errno != 0)) return(-errno);
++
++              result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result);
++              if(result == -1) return(-errno);
++                      
++              return(result);
++
++      case PTRACE_POKEDATA:
++      case PTRACE_POKETEXT:
++      case PTRACE_POKEUSER:
++              result = ptrace(arg1, child, arg3, arg4);
++              if(result == -1) return(-errno);
++
++              if(arg1 == PTRACE_POKEUSER) ptrace_pokeuser(arg3, arg4);
++              return(result);
++
++#ifdef UM_HAVE_SETFPREGS
++      case PTRACE_SETFPREGS:
++      {
++              long regs[FP_FRAME_SIZE];
++              int i;
++
++              for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
++                      regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
++                                        arg4 + 4 * i, 0);
++              result = ptrace(PTRACE_SETFPREGS, child, 0, regs);
++              if(result == -1) return(-errno);
++
++              return(result);
++      }
++#endif
++
++#ifdef UM_HAVE_SETFPXREGS
++      case PTRACE_SETFPXREGS:
++      {
++              long regs[FPX_FRAME_SIZE];
++              int i;
++
++              for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
++                      regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
++                                        arg4 + 4 * i, 0);
++              result = ptrace(PTRACE_SETFPXREGS, child, 0, regs);
++              if(result == -1) return(-errno);
++
++              return(result);
++      }
++#endif
++
++#ifdef UM_HAVE_SETREGS
++      case PTRACE_SETREGS:
++      {
++              long regs[FRAME_SIZE];
++              int i;
++
++              for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
++                      regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid,
++                                       arg4 + 4 * i, 0);
++              result = ptrace(PTRACE_SETREGS, child, 0, regs);
++              if(result == -1) return(-errno);
++
++              return(result);
++      }
++#endif
++
++      case PTRACE_SINGLESTEP:
++              if(!debugger->debugee->in_context) return(-EPERM);
++              sigemptyset(&relay);
++              sigaddset(&relay, SIGSEGV);
++              sigaddset(&relay, SIGILL);
++              sigaddset(&relay, SIGBUS);
++              result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4);
++              if(result == -1) return(-errno);
++              
++              status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP,
++                                     &relay);
++              child_proxy(child, status);
++              return(result);
++
++      case PTRACE_SYSCALL:
++              if(!debugger->debugee->in_context) return(-EPERM);
++              result = ptrace(PTRACE_SYSCALL, child, arg3, arg4);
++              if(result == -1) return(-errno);
++
++              *ret = PTRACE_SYSCALL;
++              return(result);
++
++      case PTRACE_TRACEME:
++      default:
++              return(-EINVAL);
++      }
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/sysdep.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/sysdep.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/ptproxy/sysdep.c    2005-05-03 22:28:14.532400952 +0300
+@@ -0,0 +1,72 @@
++/**********************************************************************
++sysdep.c
++
++Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
++terms and conditions.
++**********************************************************************/
++
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <signal.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/ptrace.h>
++#include <asm/ptrace.h>
++#include <linux/unistd.h>
++#include "ptrace_user.h"
++#include "user_util.h"
++#include "user.h"
++
++int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4, 
++              long *arg5)
++{
++      *arg1 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG1_OFFSET, 0);
++      *arg2 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG2_OFFSET, 0);
++      *arg3 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG3_OFFSET, 0);
++      *arg4 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG4_OFFSET, 0);
++      *arg5 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG5_OFFSET, 0);
++      return(ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 0));
++}
++
++void syscall_cancel(pid_t pid, int result)
++{
++      if((ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 
++                 __NR_getpid) < 0) ||
++         (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ||
++         (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) ||
++         (ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result) < 0) ||
++         (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0))
++              printk("ptproxy: couldn't cancel syscall: errno = %d\n", 
++                     errno);
++}
++
++void syscall_set_result(pid_t pid, long result)
++{
++      ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result);
++}
++
++void syscall_continue(pid_t pid)
++{
++      ptrace(PTRACE_SYSCALL, pid, 0, 0);
++}
++
++int syscall_pause(pid_t pid) 
++{
++      if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){
++              printk("syscall_change - ptrace failed, errno = %d\n", errno);
++              return(-1);
++      }
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/sysdep.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/sysdep.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/ptproxy/sysdep.h    2005-05-03 22:28:14.533400800 +0300
+@@ -0,0 +1,25 @@
++/**********************************************************************
++sysdep.h
++
++Copyright (C) 1999 Lars Brinkhoff.
++Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++See the file COPYING for licensing terms and conditions.
++**********************************************************************/
++
++extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, 
++                     long *arg4, long *arg5);
++extern void syscall_cancel (pid_t pid, long result);
++extern void syscall_set_result (pid_t pid, long result);
++extern void syscall_continue (pid_t pid);
++extern int syscall_pause(pid_t pid);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/wait.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/wait.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/ptproxy/wait.c      2005-05-03 22:28:14.534400648 +0300
+@@ -0,0 +1,88 @@
++/**********************************************************************
++wait.c
++
++Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
++terms and conditions.
++
++**********************************************************************/
++
++#include <errno.h>
++#include <signal.h>
++#include <sys/wait.h>
++#include <sys/ptrace.h>
++#include <asm/ptrace.h>
++
++#include "ptproxy.h"
++#include "sysdep.h"
++#include "wait.h"
++#include "user_util.h"
++#include "sysdep/ptrace.h"
++#include "sysdep/ptrace_user.h"
++#include "sysdep/sigcontext.h"
++
++int proxy_wait_return(struct debugger *debugger, pid_t unused)
++{
++      debugger->waiting = 0;
++
++      if(debugger->debugee->died || (debugger->wait_options & __WCLONE)){
++              debugger_cancelled_return(debugger, -ECHILD);
++              return(0);
++      }
++
++      if(debugger->debugee->zombie && debugger->debugee->event)
++              debugger->debugee->died = 1;
++
++      if(debugger->debugee->event){
++              debugger->debugee->event = 0;
++              ptrace(PTRACE_POKEDATA, debugger->pid,
++                     debugger->wait_status_ptr, 
++                     debugger->debugee->wait_status);
++              /* if (wait4)
++                 ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */
++              debugger_cancelled_return(debugger, debugger->debugee->pid);
++              return(0);
++      }
++
++      /* pause will return -EINTR, which happens to be right for wait */
++      debugger_normal_return(debugger, -1);
++      return(0);
++}
++
++int parent_wait_return(struct debugger *debugger, pid_t unused)
++{
++      return(debugger_normal_return(debugger, -1));
++}
++
++int real_wait_return(struct debugger *debugger)
++{
++      unsigned long ip;
++      int pid;
++
++      pid = debugger->pid;
++
++      ip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
++      IP_RESTART_SYSCALL(ip);
++
++      if(ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip) < 0)
++              tracer_panic("real_wait_return : Failed to restart system "
++                           "call, errno = %d\n", errno);
++
++      if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) ||
++         (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
++         (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
++         debugger_normal_return(debugger, -1))
++              tracer_panic("real_wait_return : gdb failed to wait, "
++                           "errno = %d\n", errno);
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/ptproxy/wait.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/ptproxy/wait.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/ptproxy/wait.h      2005-05-03 22:28:14.534400648 +0300
+@@ -0,0 +1,15 @@
++/**********************************************************************
++wait.h
++
++Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
++terms and conditions.
++**********************************************************************/
++
++#ifndef __PTPROXY_WAIT_H
++#define __PTPROXY_WAIT_H
++
++extern int proxy_wait_return(struct debugger *debugger, pid_t unused);
++extern int real_wait_return(struct debugger *debugger);
++extern int parent_wait_return(struct debugger *debugger, pid_t unused);
++
++#endif
+Index: linux-2.4.29/arch/um/kernel/tt/syscall_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/syscall_kern.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/syscall_kern.c      2005-05-03 22:28:14.536400344 +0300
+@@ -0,0 +1,136 @@
++/* 
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/types.h"
++#include "linux/utime.h"
++#include "linux/sys.h"
++#include "asm/unistd.h"
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++#include "sysdep/syscalls.h"
++#include "kern_util.h"
++
++static inline int check_area(void *ptr, int size)
++{
++      return(verify_area(VERIFY_WRITE, ptr, size));
++}
++
++static int check_readlink(struct pt_regs *regs)
++{
++      return(check_area((void *) UPT_SYSCALL_ARG1(&regs->regs),
++                        UPT_SYSCALL_ARG2(&regs->regs)));
++}
++
++static int check_utime(struct pt_regs *regs)
++{
++      return(check_area((void *) UPT_SYSCALL_ARG1(&regs->regs),
++                        sizeof(struct utimbuf)));
++}
++
++static int check_oldstat(struct pt_regs *regs)
++{
++      return(check_area((void *) UPT_SYSCALL_ARG1(&regs->regs), 
++                        sizeof(struct __old_kernel_stat)));
++}
++
++static int check_stat(struct pt_regs *regs)
++{
++      return(check_area((void *) UPT_SYSCALL_ARG1(&regs->regs), 
++                        sizeof(struct stat)));
++}
++
++static int check_stat64(struct pt_regs *regs)
++{
++      return(check_area((void *) UPT_SYSCALL_ARG1(&regs->regs), 
++                        sizeof(struct stat64)));
++}
++
++struct bogus {
++      int kernel_ds;
++      int (*check_params)(struct pt_regs *);
++};
++
++struct bogus this_is_bogus[256] = {
++      [ __NR_mknod ] = { 1, NULL },
++      [ __NR_mkdir ] = { 1, NULL },
++      [ __NR_rmdir ] = { 1, NULL },
++      [ __NR_unlink ] = { 1, NULL },
++      [ __NR_symlink ] = { 1, NULL },
++      [ __NR_link ] = { 1, NULL },
++      [ __NR_rename ] = { 1, NULL },
++      [ __NR_umount ] = { 1, NULL },
++      [ __NR_mount ] = { 1, NULL },
++      [ __NR_pivot_root ] = { 1, NULL },
++      [ __NR_chdir ] = { 1, NULL },
++      [ __NR_chroot ] = { 1, NULL },
++      [ __NR_open ] = { 1, NULL },
++      [ __NR_quotactl ] = { 1, NULL },
++      [ __NR_sysfs ] = { 1, NULL },
++      [ __NR_readlink ] = { 1, check_readlink },
++      [ __NR_acct ] = { 1, NULL },
++      [ __NR_execve ] = { 1, NULL },
++      [ __NR_uselib ] = { 1, NULL },
++      [ __NR_statfs ] = { 1, NULL },
++      [ __NR_truncate ] = { 1, NULL },
++      [ __NR_access ] = { 1, NULL },
++      [ __NR_chmod ] = { 1, NULL },
++      [ __NR_chown ] = { 1, NULL },
++      [ __NR_lchown ] = { 1, NULL },
++      [ __NR_utime ] = { 1, check_utime },
++      [ __NR_oldlstat ] = { 1, check_oldstat },
++      [ __NR_oldstat ] = { 1, check_oldstat },
++      [ __NR_stat ] = { 1, check_stat },
++      [ __NR_lstat ] = { 1, check_stat },
++      [ __NR_stat64 ] = { 1, check_stat64 },
++      [ __NR_lstat64 ] = { 1, check_stat64 },
++      [ __NR_chown32 ] = { 1, NULL },
++};
++
++/* sys_utimes */
++
++static int check_bogosity(struct pt_regs *regs)
++{
++      struct bogus *bogon = &this_is_bogus[UPT_SYSCALL_NR(&regs->regs)];
++
++      if(!bogon->kernel_ds) return(0);
++      if(bogon->check_params && (*bogon->check_params)(regs))
++              return(-EFAULT);
++      set_fs(KERNEL_DS);
++      return(0);
++}
++
++extern syscall_handler_t *sys_call_table[];
++
++long execute_syscall_tt(void *r)
++{
++      struct pt_regs *regs = r;
++      long res;
++      int syscall;
++
++      current->thread.nsyscalls++;
++      nsyscalls++;
++      syscall = UPT_SYSCALL_NR(&regs->regs);
++
++      if((syscall >= NR_syscalls) || (syscall < 0))
++              res = -ENOSYS;
++      else if(honeypot && check_bogosity(regs))
++              res = -EFAULT;
++      else res = EXECUTE_SYSCALL(syscall, regs);
++
++      set_fs(USER_DS);
++
++      return(res);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/syscall_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/syscall_user.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/syscall_user.c      2005-05-03 22:28:14.537400192 +0300
+@@ -0,0 +1,92 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <signal.h>
++#include <errno.h>
++#include <sys/ptrace.h>
++#include <asm/unistd.h>
++#include "sysdep/ptrace.h"
++#include "sigcontext.h"
++#include "ptrace_user.h"
++#include "task.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "syscall_user.h"
++#include "tt.h"
++
++/* XXX Bogus */
++#define ERESTARTSYS   512
++#define ERESTARTNOINTR        513
++#define ERESTARTNOHAND        514
++
++void syscall_handler_tt(int sig, union uml_pt_regs *regs)
++{
++      void *sc;
++      long result;
++      int index, syscall;
++
++      syscall = UPT_SYSCALL_NR(regs);
++      sc = UPT_SC(regs);
++      SC_START_SYSCALL(sc);
++
++      index = record_syscall_start(syscall);
++      syscall_trace();
++      result = execute_syscall(regs);
++
++      /* regs->sc may have changed while the system call ran (there may
++       * have been an interrupt or segfault), so it needs to be refreshed.
++       */
++      UPT_SC(regs) = sc;
++
++      SC_SET_SYSCALL_RETURN(sc, result);
++      if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || 
++         (result == -ERESTARTNOINTR))
++              do_signal(result);
++
++      syscall_trace();
++      record_syscall_end(index, result);
++}
++
++int do_syscall(void *task, int pid)
++{
++      unsigned long proc_regs[FRAME_SIZE];
++      union uml_pt_regs *regs;
++      int syscall;
++
++      if(ptrace_getregs(pid, proc_regs) < 0)
++              tracer_panic("Couldn't read registers");
++      syscall = PT_SYSCALL_NR(proc_regs);
++
++      regs = TASK_REGS(task);
++      UPT_SYSCALL_NR(regs) = syscall;
++
++      if(syscall < 1) return(0);
++
++      if((syscall != __NR_sigreturn) &&
++         ((unsigned long *) PT_IP(proc_regs) >= &_stext) && 
++         ((unsigned long *) PT_IP(proc_regs) <= &_etext))
++              tracer_panic("I'm tracing myself and I can't get out");
++
++      if(use_sysemu) 
++              return(1);
++
++      if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 
++                __NR_getpid) < 0)
++              tracer_panic("do_syscall : Nullifying syscall failed, "
++                           "errno = %d", errno);
++      return(1);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/sys-i386/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/sys-i386/Makefile      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/sys-i386/Makefile   2005-05-03 22:28:14.538400040 +0300
+@@ -0,0 +1,17 @@
++# 
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET = sys-i386.o
++
++obj-y = sigcontext.o
++
++USER_OBJS = sigcontext.o
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++clean :
+Index: linux-2.4.29/arch/um/kernel/tt/sys-i386/sigcontext.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/sys-i386/sigcontext.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/sys-i386/sigcontext.c       2005-05-03 22:28:14.539399888 +0300
+@@ -0,0 +1,60 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <asm/sigcontext.h>
++#include "kern_util.h"
++#include "sysdep/frame.h"
++
++int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data)
++{
++      struct arch_frame_data *arch = data;
++      struct sigcontext *to = to_ptr, *from = from_ptr;
++      struct _fpstate *to_fp, *from_fp;
++      unsigned long sigs;
++      int err;
++
++      to_fp = to->fpstate;
++      from_fp = from->fpstate;
++      sigs = to->oldmask;
++      err = copy_from_user_proc(to, from, sizeof(*to));
++      to->oldmask = sigs;
++      if(to_fp != NULL){
++              err |= copy_from_user_proc(&to->fpstate, &to_fp,
++                                         sizeof(to->fpstate));
++              err |= copy_from_user_proc(to_fp, from_fp, arch->fpstate_size);
++      }
++      return(err);
++}
++
++int copy_sc_to_user_tt(void *to_ptr, void *fp, void *from_ptr, void *data)
++{
++      struct arch_frame_data *arch = data;
++      struct sigcontext *to = to_ptr, *from = from_ptr;
++      struct _fpstate *to_fp, *from_fp;
++      int err;
++
++      to_fp = (struct _fpstate *) 
++              (fp ? (unsigned long) fp : ((unsigned long) to + sizeof(*to)));
++      from_fp = from->fpstate;
++      err = copy_to_user_proc(to, from, sizeof(*to));
++      if(from_fp != NULL){
++              err |= copy_to_user_proc(&to->fpstate, &to_fp,
++                                       sizeof(to->fpstate));
++              err |= copy_to_user_proc(to_fp, from_fp, arch->fpstate_size);
++      }
++      return(err);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/time.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/time.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/time.c      2005-05-03 22:28:14.540399736 +0300
+@@ -0,0 +1,28 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <signal.h>
++#include <sys/time.h>
++#include <time_user.h>
++#include "process.h"
++#include "user.h"
++
++void user_time_init_tt(void)
++{
++      if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
++              panic("Couldn't set SIGVTALRM handler");
++      set_interval(ITIMER_VIRTUAL);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/tlb.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/tlb.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/tlb.c       2005-05-03 22:28:14.541399584 +0300
+@@ -0,0 +1,220 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/kernel.h"
++#include "linux/sched.h"
++#include "asm/page.h"
++#include "asm/pgtable.h"
++#include "asm/uaccess.h"
++#include "user_util.h"
++#include "mem_user.h"
++#include "os.h"
++
++static void fix_range(struct mm_struct *mm, unsigned long start_addr, 
++                    unsigned long end_addr, int force)
++{
++      pgd_t *npgd;
++      pmd_t *npmd;
++      pte_t *npte;
++      unsigned long addr;
++      int r, w, x, err;
++
++      if((current->thread.mode.tt.extern_pid != -1) && 
++         (current->thread.mode.tt.extern_pid != os_getpid()))
++              panic("fix_range fixing wrong address space, current = 0x%p",
++                    current);
++      if(mm == NULL) return;
++      for(addr=start_addr;addr<end_addr;){
++              if(addr == TASK_SIZE){
++                      /* Skip over kernel text, kernel data, and physical
++                       * memory, which don't have ptes, plus kernel virtual
++                       * memory, which is flushed separately, and remap
++                       * the process stack.  The only way to get here is
++                       * if (end_addr == STACK_TOP) > TASK_SIZE, which is
++                       * only true in the honeypot case.
++                       */
++                      addr = STACK_TOP - ABOVE_KMEM;
++                      continue;
++              }
++              npgd = pgd_offset(mm, addr);
++              npmd = pmd_offset(npgd, addr);
++              if(pmd_present(*npmd)){
++                      npte = pte_offset(npmd, addr);
++                      r = pte_read(*npte);
++                      w = pte_write(*npte);
++                      x = pte_exec(*npte);
++                      if(!pte_dirty(*npte)) w = 0;
++                      if(!pte_young(*npte)){
++                              r = 0;
++                              w = 0;
++                      }
++                      if(force || pte_newpage(*npte)){
++                              err = os_unmap_memory((void *) addr, 
++                                                    PAGE_SIZE);
++                              if(err < 0)
++                                      panic("munmap failed, errno = %d\n",
++                                            -err);
++                              if(pte_present(*npte))
++                                      map_memory(addr, 
++                                                 pte_val(*npte) & PAGE_MASK,
++                                                 PAGE_SIZE, r, w, x);
++                      }
++                      else if(pte_newprot(*npte)){
++                              protect_memory(addr, PAGE_SIZE, r, w, x, 1);
++                      }
++                      *npte = pte_mkuptodate(*npte);
++                      addr += PAGE_SIZE;
++              }
++              else {
++                      if(force || pmd_newpage(*npmd)){
++                              err = os_unmap_memory((void *) addr, PMD_SIZE);
++                              if(err < 0)
++                                      panic("munmap failed, errno = %d\n",
++                                            -err);
++                              pmd_mkuptodate(*npmd);
++                      }
++                      addr += PMD_SIZE;
++              }
++      }
++}
++
++atomic_t vmchange_seq = ATOMIC_INIT(1);
++
++static void flush_kernel_vm_range(unsigned long start, unsigned long end,
++                                int update_seq)
++{
++      struct mm_struct *mm;
++      pgd_t *pgd;
++      pmd_t *pmd;
++      pte_t *pte;
++      unsigned long addr;
++      int updated = 0, err;
++
++      mm = &init_mm;
++      for(addr = start; addr < end;){
++              pgd = pgd_offset(mm, addr);
++              pmd = pmd_offset(pgd, addr);
++              if(pmd_present(*pmd)){
++                      pte = pte_offset(pmd, addr);
++                      if(!pte_present(*pte) || pte_newpage(*pte)){
++                              updated = 1;
++                              err = os_unmap_memory((void *) addr, 
++                                                    PAGE_SIZE);
++                              if(err < 0)
++                                      panic("munmap failed, errno = %d\n",
++                                            -err);
++                              if(pte_present(*pte))
++                                      map_memory(addr, 
++                                                 pte_val(*pte) & PAGE_MASK,
++                                                 PAGE_SIZE, 1, 1, 1);
++                      }
++                      else if(pte_newprot(*pte)){
++                              updated = 1;
++                              protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1);
++                      }
++                      addr += PAGE_SIZE;
++              }
++              else {
++                      if(pmd_newpage(*pmd)){
++                              updated = 1;
++                              err = os_unmap_memory((void *) addr, PMD_SIZE);
++                              if(err < 0)
++                                      panic("munmap failed, errno = %d\n",
++                                            -err);
++                      }
++                      addr += PMD_SIZE;
++              }
++      }
++      if(updated && update_seq) atomic_inc(&vmchange_seq);
++}
++
++static void protect_vm_page(unsigned long addr, int w, int must_succeed)
++{
++      int err;
++
++      err = protect_memory(addr, PAGE_SIZE, 1, w, 1, must_succeed);
++      if(err == 0) return;
++      else if((err == -EFAULT) || (err == -ENOMEM)){
++              flush_kernel_vm_range(addr, addr + PAGE_SIZE, 1);
++              protect_vm_page(addr, w, 1);
++      }
++      else panic("protect_vm_page : protect failed, errno = %d\n", err);
++}
++
++void mprotect_kernel_vm(int w)
++{
++      struct mm_struct *mm;
++      pgd_t *pgd;
++      pmd_t *pmd;
++      pte_t *pte;
++      unsigned long addr;
++      
++      mm = &init_mm;
++      for(addr = start_vm; addr < end_vm;){
++              pgd = pgd_offset(mm, addr);
++              pmd = pmd_offset(pgd, addr);
++              if(pmd_present(*pmd)){
++                      pte = pte_offset(pmd, addr);
++                      if(pte_present(*pte)) protect_vm_page(addr, w, 0);
++                      addr += PAGE_SIZE;
++              }
++              else addr += PMD_SIZE;
++      }
++}
++
++void flush_tlb_kernel_vm_tt(void)
++{
++      flush_kernel_vm_range(start_vm, end_vm, 1);
++}
++
++void __flush_tlb_one_tt(unsigned long addr)
++{
++      flush_kernel_vm_range(addr, addr + PAGE_SIZE, 1);
++}
++
++void flush_tlb_range_tt(struct mm_struct *mm, unsigned long start, 
++                   unsigned long end)
++{
++      if(mm != current->mm) return;
++
++      /* Assumes that the range start ... end is entirely within
++       * either process memory or kernel vm
++       */
++      if((start >= start_vm) && (start < end_vm)) 
++              flush_kernel_vm_range(start, end, 1);
++      else fix_range(mm, start, end, 0);
++}
++
++void flush_tlb_mm_tt(struct mm_struct *mm)
++{
++      unsigned long seq;
++
++      if(mm != current->mm) return;
++
++      fix_range(mm, 0, STACK_TOP, 0);
++
++      seq = atomic_read(&vmchange_seq);
++      if(current->thread.mode.tt.vm_seq == seq) return;
++      current->thread.mode.tt.vm_seq = seq;
++      flush_kernel_vm_range(start_vm, end_vm, 0);
++}
++
++void force_flush_all_tt(void)
++{
++      fix_range(current->mm, 0, STACK_TOP, 1);
++      flush_kernel_vm_range(start_vm, end_vm, 0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/tracer.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/tracer.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/tracer.c    2005-05-03 22:28:14.543399280 +0300
+@@ -0,0 +1,457 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <stdarg.h>
++#include <unistd.h>
++#include <signal.h>
++#include <errno.h>
++#include <sched.h>
++#include <string.h>
++#include <sys/mman.h>
++#include <sys/ptrace.h>
++#include <sys/time.h>
++#include <sys/wait.h>
++#include "user.h"
++#include "sysdep/ptrace.h"
++#include "sigcontext.h"
++#include "sysdep/sigcontext.h"
++#include "os.h"
++#include "signal_user.h"
++#include "user_util.h"
++#include "mem_user.h"
++#include "process.h"
++#include "kern_util.h"
++#include "frame.h"
++#include "chan_user.h"
++#include "ptrace_user.h"
++#include "mode.h"
++#include "tt.h"
++
++static int tracer_winch[2];
++
++int is_tracer_winch(int pid, int fd, void *data)
++{
++      if(pid != tracing_pid)
++              return(0);
++
++      register_winch_irq(tracer_winch[0], fd, -1, data);
++      return(1);
++}
++
++static void tracer_winch_handler(int sig)
++{
++      int n;
++      char c = 1;
++
++      n = os_write_file(tracer_winch[1], &c, sizeof(c));
++      if(n != sizeof(c))
++              printk("tracer_winch_handler - write failed, err = %d\n", -n);
++}
++
++/* Called only by the tracing thread during initialization */
++
++static void setup_tracer_winch(void)
++{
++      int err;
++
++      err = os_pipe(tracer_winch, 1, 1);
++      if(err < 0){
++              printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err);
++              return;
++      }
++      signal(SIGWINCH, tracer_winch_handler);
++}
++
++void attach_process(int pid)
++{
++      if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
++         (ptrace(PTRACE_CONT, pid, 0, 0) < 0))
++              tracer_panic("OP_FORK failed to attach pid");
++      wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
++      if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
++              tracer_panic("OP_FORK failed to continue process");
++}
++
++void tracer_panic(char *format, ...)
++{
++      va_list ap;
++
++      va_start(ap, format);
++      vprintf(format, ap);
++      printf("\n");
++      while(1) pause();
++}
++
++static void tracer_segv(int sig, struct sigcontext sc)
++{
++      printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n",
++             SC_FAULT_ADDR(&sc), SC_IP(&sc));
++      while(1)
++              pause();
++}
++
++/* Changed early in boot, and then only read */
++int debug = 0;
++int debug_stop = 1;
++int debug_parent = 0;
++int honeypot = 0;
++
++static int signal_tramp(void *arg)
++{
++      int (*proc)(void *);
++
++      if(honeypot && munmap((void *) (host_task_size - 0x10000000),
++                            0x10000000)) 
++              panic("Unmapping stack failed");
++      if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
++              panic("ptrace PTRACE_TRACEME failed");
++      os_stop_process(os_getpid());
++      change_sig(SIGWINCH, 0);
++      signal(SIGUSR1, SIG_IGN);
++      change_sig(SIGCHLD, 0);
++      signal(SIGSEGV, (__sighandler_t) sig_handler);
++      set_cmdline("(idle thread)");
++      set_init_pid(os_getpid());
++      proc = arg;
++      return((*proc)(NULL));
++}
++
++static void sleeping_process_signal(int pid, int sig)
++{
++      switch(sig){
++      /* These two result from UML being ^Z-ed and bg-ed.  PTRACE_CONT is
++       * right because the process must be in the kernel already.
++       */
++      case SIGCONT:
++      case SIGTSTP:
++              if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
++                      tracer_panic("sleeping_process_signal : Failed to "
++                                   "continue pid %d, signal = %d, "
++                                   "errno = %d\n", pid, sig, errno);
++              break;
++
++      /* This happens when the debugger (e.g. strace) is doing system call 
++       * tracing on the kernel.  During a context switch, the current task
++       * will be set to the incoming process and the outgoing process will
++       * hop into write and then read.  Since it's not the current process
++       * any more, the trace of those will land here.  So, we need to just 
++       * PTRACE_SYSCALL it.
++       */
++      case SIGTRAP:
++              if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
++                      tracer_panic("sleeping_process_signal : Failed to "
++                                   "PTRACE_SYSCALL pid %d, errno = %d\n",
++                                   pid, errno);
++              break;
++      case SIGSTOP:
++              break;
++      default:
++              tracer_panic("sleeping process %d got unexpected "
++                           "signal : %d\n", pid, sig);
++              break;
++      }
++}
++
++/* Accessed only by the tracing thread */
++int debugger_pid = -1;
++int debugger_parent = -1;
++int debugger_fd = -1;
++int gdb_pid = -1;
++
++struct {
++      int pid;
++      int signal;
++      unsigned long addr;
++      struct timeval time;
++} signal_record[1024][32];
++
++int signal_index[32];
++int nsignals = 0;
++int debug_trace = 0;
++extern int io_nsignals, io_count, intr_count;
++
++extern void signal_usr1(int sig);
++
++int tracing_pid = -1;
++
++int tracer(int (*init_proc)(void *), void *sp)
++{
++      void *task = NULL;
++      unsigned long eip = 0;
++      int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
++      int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0;
++      int cont_syscall;
++
++      capture_signal_stack();
++      signal(SIGPIPE, SIG_IGN);
++      setup_tracer_winch();
++      tracing_pid = os_getpid();
++      printf("tracing thread pid = %d\n", tracing_pid);
++
++      pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
++      CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
++      if(n < 0){
++              printf("waitpid on idle thread failed, errno = %d\n", errno);
++              exit(1);
++      }
++      if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
++              printf("Failed to continue idle thread, errno = %d\n", errno);
++              exit(1);
++      }
++
++      signal(SIGSEGV, (sighandler_t) tracer_segv);
++      signal(SIGUSR1, signal_usr1);
++      if(debug_trace){
++              printf("Tracing thread pausing to be attached\n");
++              stop();
++      }
++      if(debug){
++              if(gdb_pid != -1) 
++                      debugger_pid = attach_debugger(pid, gdb_pid, 1);
++              else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
++              if(debug_parent){
++                      debugger_parent = os_process_parent(debugger_pid);
++                      init_parent_proxy(debugger_parent);
++                      err = attach(debugger_parent);
++                      if(err){
++                              printf("Failed to attach debugger parent %d, "
++                                     "errno = %d\n", debugger_parent, -err);
++                              debugger_parent = -1;
++                      }
++                      else {
++                              if(ptrace(PTRACE_SYSCALL, debugger_parent, 
++                                        0, 0) < 0){
++                                      printf("Failed to continue debugger "
++                                             "parent, errno = %d\n", errno);
++                                      debugger_parent = -1;
++                              }
++                      }
++              }
++      }
++      set_cmdline("(tracing thread)");
++      while(1){
++              CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED));
++              if(pid <= 0){
++                      if(errno != ECHILD){
++                              printf("wait failed - errno = %d\n", errno);
++                      }
++                      continue;
++              }
++              if(pid == debugger_pid){
++                      int cont = 0;
++
++                      if(WIFEXITED(status) || WIFSIGNALED(status))
++                              debugger_pid = -1;
++                      /* XXX Figure out how to deal with gdb and SMP */
++                      else cont = debugger_signal(status, cpu_tasks[0].pid);
++                      if(cont == PTRACE_SYSCALL) strace = 1;
++                      continue;
++              }
++              else if(pid == debugger_parent){
++                      debugger_parent_signal(status, pid);
++                      continue;
++              }
++              nsignals++;
++              if(WIFEXITED(status)) ;
++#ifdef notdef
++              {
++                      printf("Child %d exited with status %d\n", pid, 
++                             WEXITSTATUS(status));
++              }
++#endif
++              else if(WIFSIGNALED(status)){
++                      sig = WTERMSIG(status);
++                      if(sig != 9){
++                              printf("Child %d exited with signal %d\n", pid,
++                                     sig);
++                      }
++              }
++              else if(WIFSTOPPED(status)){
++                      proc_id = pid_to_processor_id(pid);
++                      sig = WSTOPSIG(status);
++                      if(signal_index[proc_id] == 1024){
++                              signal_index[proc_id] = 0;
++                              last_index = 1023;
++                      }
++                      else last_index = signal_index[proc_id] - 1;
++                      if(((sig == SIGPROF) || (sig == SIGVTALRM) || 
++                          (sig == SIGALRM)) &&
++                         (signal_record[proc_id][last_index].signal == sig)&&
++                         (signal_record[proc_id][last_index].pid == pid))
++                              signal_index[proc_id] = last_index;
++                      signal_record[proc_id][signal_index[proc_id]].pid = pid;
++                      gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL);
++                      eip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
++                      signal_record[proc_id][signal_index[proc_id]].addr = eip;
++                      signal_record[proc_id][signal_index[proc_id]++].signal = sig;
++                      
++                      if(proc_id == -1){
++                              sleeping_process_signal(pid, sig);
++                              continue;
++                      }
++
++                      task = cpu_tasks[proc_id].task;
++                      tracing = is_tracing(task);
++                      old_tracing = tracing;
++
++                      cont_syscall = use_sysemu ? PTRACE_SYSEMU : 
++                              PTRACE_SYSCALL;
++                      switch(sig){
++                      case SIGUSR1:
++                              sig = 0;
++                              op = do_proc_op(task, proc_id);
++                              switch(op){
++                              case OP_TRACE_ON:
++                                      arch_leave_kernel(task, pid);
++                                      tracing = 1;
++                                      break;
++                              case OP_REBOOT:
++                              case OP_HALT:
++                                      unmap_physmem();
++                                      kmalloc_ok = 0;
++                                      ptrace(PTRACE_KILL, pid, 0, 0);
++                                      return(op == OP_REBOOT);
++                              case OP_NONE:
++                                      printf("Detaching pid %d\n", pid);
++                                      detach(pid, SIGSTOP);
++                                      continue;
++                              default:
++                                      break;
++                              }
++                              /* OP_EXEC switches host processes on us,
++                               * we want to continue the new one.
++                               */
++                              pid = cpu_tasks[proc_id].pid;
++                              break;
++                      case SIGTRAP:
++                              if(!tracing && (debugger_pid != -1)){
++                                      child_signal(pid, status);
++                                      continue;
++                              }
++                              tracing = 0;
++                              if(do_syscall(task, pid))
++                                      sig = SIGUSR2;
++                              break;
++                      case SIGPROF:
++                              if(tracing) sig = 0;
++                              break;
++                      case SIGCHLD:
++                      case SIGHUP:
++                              sig = 0;
++                              break;
++                      case SIGSEGV:
++                      case SIGIO:
++                      case SIGALRM:
++                      case SIGVTALRM:
++                      case SIGFPE:
++                      case SIGBUS:
++                      case SIGILL:
++                      case SIGWINCH:
++                      default:
++                              tracing = 0;
++                              break;
++                      }
++                      set_tracing(task, tracing);
++
++                      if(!tracing && old_tracing)
++                              arch_enter_kernel(task, pid);
++
++                      if(!tracing && (debugger_pid != -1) && (sig != 0) &&
++                              (sig != SIGALRM) && (sig != SIGVTALRM) &&
++                              (sig != SIGSEGV) && (sig != SIGTRAP) &&
++                              (sig != SIGUSR2) && (sig != SIGIO) &&
++                              (sig != SIGFPE)){
++                              child_signal(pid, status);
++                              continue;
++                      }
++
++                      if(tracing){
++                              if(singlestepping(task))
++                                      cont_type = PTRACE_SINGLESTEP;
++                              else cont_type = cont_syscall;
++                      }
++                      else cont_type = PTRACE_CONT;
++
++                      if((cont_type == PTRACE_CONT) && 
++                         (debugger_pid != -1) && strace)
++                              cont_type = PTRACE_SYSCALL;
++
++                      if(ptrace(cont_type, pid, 0, sig) != 0){
++                              tracer_panic("ptrace failed to continue "
++                                           "process - errno = %d\n", 
++                                           errno);
++                      }
++              }
++      }
++      return(0);
++}
++
++static int __init uml_debug_setup(char *line, int *add)
++{
++      char *next;
++
++      debug = 1;
++      *add = 0;
++      if(*line != '=') return(0);
++      line++;
++
++      while(line != NULL){
++              next = strchr(line, ',');
++              if(next) *next++ = '\0';
++              
++              if(!strcmp(line, "go")) debug_stop = 0;
++              else if(!strcmp(line, "parent")) debug_parent = 1;
++              else printf("Unknown debug option : '%s'\n", line);
++
++              line = next;
++      }
++      return(0);
++}
++
++__uml_setup("debug", uml_debug_setup,
++"debug\n"
++"    Starts up the kernel under the control of gdb. See the \n"
++"    kernel debugging tutorial and the debugging session pages\n"
++"    at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
++);
++
++static int __init uml_debugtrace_setup(char *line, int *add)
++{
++      debug_trace = 1;
++      return 0;
++}
++__uml_setup("debugtrace", uml_debugtrace_setup,
++"debugtrace\n"
++"    Causes the tracing thread to pause until it is attached by a\n"
++"    debugger and continued.  This is mostly for debugging crashes\n"
++"    early during boot, and should be pretty much obsoleted by\n"
++"    the debug switch.\n\n"
++);
++
++static int __init uml_honeypot_setup(char *line, int *add)
++{
++      jail_setup("", add);
++      honeypot = 1;
++      return 0;
++}
++__uml_setup("honeypot", uml_honeypot_setup, 
++"honeypot\n"
++"    This makes UML put process stacks in the same location as they are\n"
++"    on the host, allowing expoits such as stack smashes to work against\n"
++"    UML.  This implies 'jail'.\n\n"
++);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/trap_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/trap_user.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/trap_user.c 2005-05-03 22:28:14.544399128 +0300
+@@ -0,0 +1,64 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <errno.h>
++#include <signal.h>
++#include <asm/sigcontext.h>
++#include "sysdep/ptrace.h"
++#include "signal_user.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "task.h"
++#include "tt.h"
++
++void sig_handler_common_tt(int sig, void *sc_ptr)
++{
++      struct sigcontext *sc = sc_ptr;
++      struct tt_regs save_regs, *r;
++      struct signal_info *info;
++      int save_errno = errno, is_user;
++
++      unprotect_kernel_mem();
++
++      /* This is done because to allow SIGSEGV to be delivered inside a SEGV
++       * handler.  This can happen in copy_user, and if SEGV is disabled,
++       * the process will die.
++       */
++      if(sig == SIGSEGV)
++              change_sig(SIGSEGV, 1);
++
++      r = &TASK_REGS(get_current())->tt;
++      save_regs = *r;
++      is_user = user_context(SC_SP(sc));
++      r->sc = sc;
++      if(sig != SIGUSR2) 
++              r->syscall = -1;
++
++      info = &sig_info[sig];
++      if(!info->is_irq) unblock_signals();
++
++      (*info->handler)(sig, (union uml_pt_regs *) r);
++
++      if(is_user){
++              interrupt_end();
++              block_signals();
++              set_user_mode(NULL);
++      }
++      *r = save_regs;
++      errno = save_errno;
++      if(is_user) protect_kernel_mem();
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/uaccess.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/uaccess.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/uaccess.c   2005-05-03 22:28:14.545398976 +0300
+@@ -0,0 +1,73 @@
++/* 
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "asm/uaccess.h"
++
++int copy_from_user_tt(void *to, const void *from, int n)
++{
++      if(!access_ok_tt(VERIFY_READ, from, n)) 
++              return(n);
++
++      return(__do_copy_from_user(to, from, n, &current->thread.fault_addr,
++                                 &current->thread.fault_catcher));
++}
++
++int copy_to_user_tt(void *to, const void *from, int n)
++{
++      if(!access_ok_tt(VERIFY_WRITE, to, n))
++              return(n);
++              
++      return(__do_copy_to_user(to, from, n, &current->thread.fault_addr,
++                               &current->thread.fault_catcher));
++}
++
++int strncpy_from_user_tt(char *dst, const char *src, int count)
++{
++      int n;
++
++      if(!access_ok_tt(VERIFY_READ, src, 1)) 
++              return(-EFAULT);
++
++      n = __do_strncpy_from_user(dst, src, count, 
++                                 &current->thread.fault_addr,
++                                 &current->thread.fault_catcher);
++      if(n < 0) return(-EFAULT);
++      return(n);
++}
++
++int __clear_user_tt(void *mem, int len)
++{
++      return(__do_clear_user(mem, len,
++                             &current->thread.fault_addr,
++                             &current->thread.fault_catcher));
++}
++
++int clear_user_tt(void *mem, int len)
++{
++      if(!access_ok_tt(VERIFY_WRITE, mem, len))
++              return(len);
++
++      return(__do_clear_user(mem, len, &current->thread.fault_addr,
++                             &current->thread.fault_catcher));
++}
++
++int strnlen_user_tt(const void *str, int len)
++{
++      return(__do_strnlen_user(str, len,
++                               &current->thread.fault_addr,
++                               &current->thread.fault_catcher));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/uaccess_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/uaccess_user.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/uaccess_user.c      2005-05-03 22:28:14.546398824 +0300
+@@ -0,0 +1,98 @@
++/* 
++ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <setjmp.h>
++#include <string.h>
++#include "user_util.h"
++#include "uml_uaccess.h"
++#include "task.h"
++#include "kern_util.h"
++
++int __do_copy_from_user(void *to, const void *from, int n,
++                      void **fault_addr, void **fault_catcher)
++{
++      struct tt_regs save = TASK_REGS(get_current())->tt;
++      unsigned long fault;
++      int faulted;
++
++      fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
++                             __do_copy, &faulted);
++      TASK_REGS(get_current())->tt = save;
++
++      if(!faulted) return(0);
++      else return(n - (fault - (unsigned long) from));
++}
++
++static void __do_strncpy(void *dst, const void *src, int count)
++{
++      strncpy(dst, src, count);
++}     
++
++int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
++                         void **fault_addr, void **fault_catcher)
++{
++      struct tt_regs save = TASK_REGS(get_current())->tt;
++      unsigned long fault;
++      int faulted;
++
++      fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
++                             __do_strncpy, &faulted);
++      TASK_REGS(get_current())->tt = save;
++
++      if(!faulted) return(strlen(dst));
++      else return(-1);
++}
++
++static void __do_clear(void *to, const void *from, int n)
++{
++      memset(to, 0, n);
++}     
++
++int __do_clear_user(void *mem, unsigned long len,
++                  void **fault_addr, void **fault_catcher)
++{
++      struct tt_regs save = TASK_REGS(get_current())->tt;
++      unsigned long fault;
++      int faulted;
++
++      fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
++                             __do_clear, &faulted);
++      TASK_REGS(get_current())->tt = save;
++
++      if(!faulted) return(0);
++      else return(len - (fault - (unsigned long) mem));
++}
++
++int __do_strnlen_user(const char *str, unsigned long n,
++                    void **fault_addr, void **fault_catcher)
++{
++      struct tt_regs save = TASK_REGS(get_current())->tt;
++      int ret;
++      unsigned long *faddrp = (unsigned long *)fault_addr;
++      sigjmp_buf jbuf;
++
++      *fault_catcher = &jbuf;
++      if(sigsetjmp(jbuf, 1) == 0)
++              ret = strlen(str) + 1;
++      else ret = *faddrp - (unsigned long) str;
++
++      *fault_addr = NULL;
++      *fault_catcher = NULL;
++
++      TASK_REGS(get_current())->tt = save;
++      return ret;
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tt/unmap.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tt/unmap.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tt/unmap.c     2005-05-03 22:28:14.547398672 +0300
+@@ -0,0 +1,31 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <sys/mman.h>
++
++int switcheroo(int fd, int prot, void *from, void *to, int size)
++{
++      if(munmap(to, size) < 0){
++              return(-1);
++      }
++      if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){
++              return(-1);
++      }
++      if(munmap(from, size) < 0){
++              return(-1);
++      }
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/tty_log.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/tty_log.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/tty_log.c      2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,230 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and 
++ * geoffrey hing <ghing@net.ohio-state.edu>
++ * Licensed under the GPL
++ */
++
++#include <errno.h>
++#include <string.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <sys/time.h>
++#include "init.h"
++#include "user.h"
++#include "kern_util.h"
++#include "os.h"
++
++#define TTY_LOG_DIR "./"
++
++/* Set early in boot and then unchanged */
++static char *tty_log_dir = TTY_LOG_DIR;
++static int tty_log_fd = -1;
++
++#define TTY_LOG_OPEN 1
++#define TTY_LOG_CLOSE 2
++#define TTY_LOG_WRITE 3
++#define TTY_LOG_EXEC 4
++
++#define TTY_READ 1
++#define TTY_WRITE 2
++
++struct tty_log_buf {
++      int what;
++      unsigned long tty;
++      int len;
++      int direction;
++      unsigned long sec;
++      unsigned long usec;
++};
++
++int open_tty_log(void *tty, void *current_tty)
++{
++      struct timeval tv;
++      struct tty_log_buf data;
++      char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")];
++      int fd;
++
++      gettimeofday(&tv, NULL);
++      if(tty_log_fd != -1){
++              data = ((struct tty_log_buf) { .what    = TTY_LOG_OPEN,
++                                             .tty  = (unsigned long) tty,
++                                             .len  = sizeof(current_tty),
++                                             .direction = 0,
++                                             .sec = tv.tv_sec,
++                                             .usec = tv.tv_usec } );
++              os_write_file(tty_log_fd, &data, sizeof(data));
++              os_write_file(tty_log_fd, &current_tty, data.len);
++              return(tty_log_fd);
++      }
++
++      sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, 
++              (unsigned int) tv.tv_usec);
++
++      fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))),
++                        0644);
++      if(fd < 0){
++              printk("open_tty_log : couldn't open '%s', errno = %d\n",
++                     buf, -fd);
++      }
++      return(fd);
++}
++
++void close_tty_log(int fd, void *tty)
++{
++      struct tty_log_buf data;
++      struct timeval tv;
++
++      if(tty_log_fd != -1){
++              gettimeofday(&tv, NULL);
++              data = ((struct tty_log_buf) { .what    = TTY_LOG_CLOSE,
++                                             .tty  = (unsigned long) tty,
++                                             .len  = 0,
++                                             .direction = 0,
++                                             .sec = tv.tv_sec,
++                                             .usec = tv.tv_usec } );
++              os_write_file(tty_log_fd, &data, sizeof(data));
++              return;
++      }
++      os_close_file(fd);
++}
++
++static int log_chunk(int fd, const char *buf, int len)
++{
++      int total = 0, try, missed, n;
++      char chunk[64];
++
++      while(len > 0){
++              try = (len > sizeof(chunk)) ? sizeof(chunk) : len;
++              missed = copy_from_user_proc(chunk, (char *) buf, try);
++              try -= missed;
++              n = os_write_file(fd, chunk, try);
++              if(n != try) {
++                      if(n < 0) 
++                              return(n);
++                      return(-EIO);
++              }
++              if(missed != 0)
++                      return(-EFAULT);
++
++              len -= try;
++              total += try;
++              buf += try;
++      }
++
++      return(total);
++}
++
++int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read)
++{
++      struct timeval tv;
++      struct tty_log_buf data;
++      int direction;
++
++      if(fd == tty_log_fd){
++              gettimeofday(&tv, NULL);
++              direction = is_read ? TTY_READ : TTY_WRITE;
++              data = ((struct tty_log_buf) { .what    = TTY_LOG_WRITE,
++                                             .tty  = (unsigned long) tty,
++                                             .len  = len,
++                                             .direction = direction,
++                                             .sec = tv.tv_sec,
++                                             .usec = tv.tv_usec } );
++              os_write_file(tty_log_fd, &data, sizeof(data));
++      }
++
++      return(log_chunk(fd, buf, len));
++}
++
++void log_exec(char **argv, void *tty)
++{
++      struct timeval tv;
++      struct tty_log_buf data;
++      char **ptr,*arg;
++      int len;
++      
++      if(tty_log_fd == -1) return;
++
++      gettimeofday(&tv, NULL);
++
++      len = 0;
++      for(ptr = argv; ; ptr++){
++              if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
++                      return;
++              if(arg == NULL) break;
++              len += strlen_user_proc(arg);
++      }
++
++      data = ((struct tty_log_buf) { .what    = TTY_LOG_EXEC,
++                                     .tty  = (unsigned long) tty,
++                                     .len  = len,
++                                     .direction = 0,
++                                     .sec = tv.tv_sec,
++                                     .usec = tv.tv_usec } );
++      os_write_file(tty_log_fd, &data, sizeof(data));
++
++      for(ptr = argv; ; ptr++){
++              if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
++                      return;
++              if(arg == NULL) break;
++              log_chunk(tty_log_fd, arg, strlen_user_proc(arg));
++      }
++}
++
++extern void register_tty_logger(int (*opener)(void *, void *),
++                              int (*writer)(int, const char *, int, 
++                                            void *, int),
++                              void (*closer)(int, void *));
++
++static int register_logger(void)
++{
++      register_tty_logger(open_tty_log, write_tty_log, close_tty_log);
++      return(0);
++}
++
++__uml_initcall(register_logger);
++
++static int __init set_tty_log_dir(char *name, int *add)
++{
++      tty_log_dir = name;
++      return 0;
++}
++
++__uml_setup("tty_log_dir=", set_tty_log_dir,
++"tty_log_dir=<directory>\n"
++"    This is used to specify the directory where the logs of all pty\n"
++"    data from this UML machine will be written.\n\n"
++);
++
++static int __init set_tty_log_fd(char *name, int *add)
++{
++      char *end;
++
++      tty_log_fd = strtoul(name, &end, 0);
++      if((*end != '\0') || (end == name)){
++              printf("set_tty_log_fd - strtoul failed on '%s'\n", name);
++              tty_log_fd = -1;
++      }
++
++      *add = 0;
++      return 0;
++}
++
++__uml_setup("tty_log_fd=", set_tty_log_fd,
++"tty_log_fd=<fd>\n"
++"    This is used to specify a preconfigured file descriptor to which all\n"
++"    tty data will be written.  Preconfigure the descriptor with something\n"
++"    like '10>tty_log tty_log_fd=10'.\n\n"
++);
++
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/uaccess_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/uaccess_user.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/uaccess_user.c 2005-05-03 22:28:14.549398368 +0300
+@@ -0,0 +1,64 @@
++/* 
++ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <setjmp.h>
++#include <string.h>
++
++/* These are here rather than tt/uaccess.c because skas mode needs them in
++ * order to do SIGBUS recovery when a tmpfs mount runs out of room.
++ */
++
++unsigned long __do_user_copy(void *to, const void *from, int n,
++                           void **fault_addr, void **fault_catcher,
++                           void (*op)(void *to, const void *from,
++                                      int n), int *faulted_out)
++{
++      unsigned long *faddrp = (unsigned long *) fault_addr, ret;
++
++      sigjmp_buf jbuf;
++      *fault_catcher = &jbuf;
++      if(sigsetjmp(jbuf, 1) == 0){
++              (*op)(to, from, n);
++              ret = 0;
++              *faulted_out = 0;
++      } 
++      else {
++              ret = *faddrp;
++              *faulted_out = 1;
++      }
++      *fault_addr = NULL;
++      *fault_catcher = NULL;
++      return ret;
++}
++
++void __do_copy(void *to, const void *from, int n)
++{
++      memcpy(to, from, n);
++}     
++
++
++int __do_copy_to_user(void *to, const void *from, int n,
++                    void **fault_addr, void **fault_catcher)
++{
++      unsigned long fault;
++      int faulted;
++
++      fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
++                             __do_copy, &faulted);
++      if(!faulted) return(0);
++      else return(n - (fault - (unsigned long) to));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/um_arch.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/um_arch.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/um_arch.c      2005-05-03 22:28:14.552397912 +0300
+@@ -0,0 +1,445 @@
++/* 
++ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/kernel.h"
++#include "linux/sched.h"
++#include "linux/notifier.h"
++#include "linux/mm.h"
++#include "linux/types.h"
++#include "linux/tty.h"
++#include "linux/init.h"
++#include "linux/bootmem.h"
++#include "linux/spinlock.h"
++#include "linux/utsname.h"
++#include "linux/sysrq.h"
++#include "linux/seq_file.h"
++#include "linux/delay.h"
++#include "asm/page.h"
++#include "asm/pgtable.h"
++#include "asm/ptrace.h"
++#include "asm/elf.h"
++#include "asm/user.h"
++#include "ubd_user.h"
++#include "asm/current.h"
++#include "user_util.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "mem_user.h"
++#include "mem.h"
++#include "umid.h"
++#include "initrd.h"
++#include "init.h"
++#include "os.h"
++#include "choose-mode.h"
++#include "mode_kern.h"
++#include "mode.h"
++
++#define DEFAULT_COMMAND_LINE "root=/dev/ubd0"
++
++struct cpuinfo_um boot_cpu_data = { 
++      .loops_per_jiffy        = 0,
++      .pgd_quick              = NULL,
++      .pmd_quick              = NULL,
++      .pte_quick              = NULL,
++      .pgtable_cache_sz       = 0,
++      .ipi_pipe               = { -1, -1 }
++};
++
++unsigned long thread_saved_pc(struct thread_struct *thread)
++{
++      return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
++                                            thread)));
++}
++
++static int show_cpuinfo(struct seq_file *m, void *v)
++{
++      int index = 0;
++
++#ifdef CONFIG_SMP
++      index = (struct cpuinfo_um *)v - cpu_data;
++      if (!(cpu_online_map & (1 << index)))
++              return 0;
++#endif
++
++      seq_printf(m, "processor\t: %d\n", index);
++      seq_printf(m, "vendor_id\t: User Mode Linux\n");
++      seq_printf(m, "model name\t: UML\n");
++      seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
++      seq_printf(m, "host\t\t: %s\n", host_info);
++      seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
++                 loops_per_jiffy/(500000/HZ),
++                 (loops_per_jiffy/(5000/HZ)) % 100);
++
++      return(0);
++}
++
++static void *c_start(struct seq_file *m, loff_t *pos)
++{
++      return *pos < NR_CPUS ? cpu_data + *pos : NULL;
++}
++
++static void *c_next(struct seq_file *m, void *v, loff_t *pos)
++{
++      ++*pos;
++      return c_start(m, pos);
++}
++
++static void c_stop(struct seq_file *m, void *v)
++{
++}
++
++struct seq_operations cpuinfo_op = {
++      .start  = c_start,
++      .next   = c_next,
++      .stop   = c_stop,
++      .show   = show_cpuinfo,
++};
++
++pte_t * __bad_pagetable(void)
++{
++      panic("Someone should implement __bad_pagetable");
++      return(NULL);
++}
++
++/* Set in linux_main */
++unsigned long host_task_size;
++unsigned long task_size;
++unsigned long uml_start;
++
++/* Set in early boot */
++unsigned long uml_physmem;
++unsigned long uml_reserved;
++unsigned long start_vm;
++unsigned long end_vm;
++int ncpus = 1;
++
++#ifdef CONFIG_MODE_TT
++/* Pointer set in linux_main, the array itself is private to each thread,
++ * and changed at address space creation time so this poses no concurrency
++ * problems.
++ */
++static char *argv1_begin = NULL;
++static char *argv1_end = NULL;
++#endif
++
++/* Set in early boot */
++static int have_root __initdata = 0;
++long physmem_size = 32 * 1024 * 1024;
++
++void set_cmdline(char *cmd)
++{
++#ifdef CONFIG_MODE_TT
++      char *umid, *ptr;
++
++      if(CHOOSE_MODE(honeypot, 0)) return;
++
++      umid = get_umid(1);
++      if(umid != NULL){
++              snprintf(argv1_begin, 
++                       (argv1_end - argv1_begin) * sizeof(*ptr), 
++                       "(%s) ", umid);
++              ptr = &argv1_begin[strlen(argv1_begin)];
++      }
++      else ptr = argv1_begin;
++
++      snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
++      memset(argv1_begin + strlen(argv1_begin), '\0', 
++             argv1_end - argv1_begin - strlen(argv1_begin));
++#endif
++}
++
++static char *usage_string = 
++"User Mode Linux v%s\n"
++"     available at http://user-mode-linux.sourceforge.net/\n\n";
++
++static int __init uml_version_setup(char *line, int *add)
++{
++      printf("%s\n", system_utsname.release);
++      exit(0);
++}
++
++__uml_setup("--version", uml_version_setup,
++"--version\n"
++"    Prints the version number of the kernel.\n\n"
++);
++
++static int __init uml_root_setup(char *line, int *add)
++{
++      have_root = 1;
++      return 0;
++}
++
++__uml_setup("root=", uml_root_setup,
++"root=<file containing the root fs>\n"
++"    This is actually used by the generic kernel in exactly the same\n"
++"    way as in any other kernel. If you configure a number of block\n"
++"    devices and want to boot off something other than ubd0, you \n"
++"    would use something like:\n"
++"        root=/dev/ubd5\n\n"
++);
++
++#ifdef CONFIG_SMP
++static int __init uml_ncpus_setup(char *line, int *add)
++{
++       if (!sscanf(line, "%d", &ncpus)) {
++               printf("Couldn't parse [%s]\n", line);
++               return -1;
++       }
++
++       return 0;
++}
++
++__uml_setup("ncpus=", uml_ncpus_setup,
++"ncpus=<# of desired CPUs>\n"
++"    This tells an SMP kernel how many virtual processors to start.\n\n" 
++);
++#endif
++
++int force_tt = 0;
++
++#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
++#define DEFAULT_TT 0
++
++static int __init mode_tt_setup(char *line, int *add)
++{
++      force_tt = 1;
++      return(0);
++}
++
++#else
++#ifdef CONFIG_MODE_SKAS
++
++#define DEFAULT_TT 0
++
++static int __init mode_tt_setup(char *line, int *add)
++{
++      printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
++      return(0);
++}
++
++#else
++#ifdef CONFIG_MODE_TT
++
++#define DEFAULT_TT 1
++
++static int __init mode_tt_setup(char *line, int *add)
++{
++      printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
++      return(0);
++}
++
++#else
++
++#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled
++
++#endif
++#endif
++#endif
++
++__uml_setup("mode=tt", mode_tt_setup,
++"mode=tt\n"
++"    When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
++"    forces UML to run in tt (tracing thread) mode.  It is not the default\n"
++"    because it's slower and less secure than skas mode.\n\n"
++);
++
++int mode_tt = DEFAULT_TT;
++
++static int __init Usage(char *line, int *add)
++{
++      const char **p;
++
++      printf(usage_string, system_utsname.release);
++      p = &__uml_help_start;
++      while (p < &__uml_help_end) {
++              printf("%s", *p);
++              p++;
++      }
++      exit(0);
++}
++
++__uml_setup("--help", Usage,
++"--help\n"
++"    Prints this message.\n\n"
++);
++
++static int __init uml_checksetup(char *line, int *add)
++{
++      struct uml_param *p;
++
++      p = &__uml_setup_start;
++      while(p < &__uml_setup_end) {
++              int n;
++
++              n = strlen(p->str);
++              if(!strncmp(line, p->str, n)){
++                      if (p->setup_func(line + n, add)) return 1;
++              }
++              p++;
++      }
++      return 0;
++}
++
++static void __init uml_postsetup(void)
++{
++      initcall_t *p;
++
++      p = &__uml_postsetup_start;
++      while(p < &__uml_postsetup_end){
++              (*p)();
++              p++;
++      }
++      return;
++}
++
++/* Set during early boot */
++unsigned long brk_start;
++unsigned long end_iomem;
++
++#define MIN_VMALLOC (32 * 1024 * 1024)
++
++int linux_main(int argc, char **argv)
++{
++      unsigned long avail, diff;
++      unsigned long virtmem_size, max_physmem;
++      unsigned int i, add;
++
++      for (i = 1; i < argc; i++){
++              if((i == 1) && (argv[i][0] == ' ')) continue;
++              add = 1;
++              uml_checksetup(argv[i], &add);
++              if(add) add_arg(saved_command_line, argv[i]);
++      }
++      if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE);
++
++      mode_tt = force_tt ? 1 : !can_do_skas();
++      uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
++                                   &host_task_size, &task_size);
++
++      /* Need to check this early because mmapping happens before the
++       * kernel is running.
++       */
++      check_tmpexec();
++
++      brk_start = (unsigned long) sbrk(0);
++      CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
++      /* Increase physical memory size for exec-shield users
++      so they actually get what they asked for. This should
++      add zero for non-exec shield users */
++      
++      diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
++      if(diff > 1024 * 1024){
++              printf("Adding %ld bytes to physical memory to account for "
++                     "exec-shield gap\n", diff);
++              physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
++      }
++
++      uml_physmem = uml_start;
++
++      /* Reserve up to 4M after the current brk */
++      uml_reserved = ROUND_4M(brk_start) + (1 << 22);
++
++      setup_machinename(system_utsname.machine);
++
++#ifdef CONFIG_MODE_TT
++      argv1_begin = argv[1];
++      argv1_end = &argv[1][strlen(argv[1])];
++#endif
++  
++      highmem = 0;
++      iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
++      max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
++
++      /* Zones have to begin on a 1 << MAX_ORDER page boundary,
++       * so this makes sure that's true for highmem
++       */
++      max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
++      if(physmem_size + iomem_size > max_physmem){
++              highmem = physmem_size + iomem_size - max_physmem;
++              physmem_size -= highmem;
++#ifndef CONFIG_HIGHMEM
++              highmem = 0;
++              printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
++                     "to %ld bytes\n", physmem_size);
++#endif
++      }
++
++      high_physmem = uml_physmem + physmem_size;
++      end_iomem = high_physmem + iomem_size;
++      high_memory = (void *) end_iomem;
++
++      start_vm = VMALLOC_START;
++
++      setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
++      if(init_maps(physmem_size, iomem_size, highmem)){
++              printf("Failed to allocate mem_map for %ld bytes of physical "
++                     "memory and %ld bytes of highmem\n", physmem_size,
++                     highmem);
++              exit(1);
++      }
++
++      virtmem_size = physmem_size;
++      avail = get_kmem_end() - start_vm;
++      if(physmem_size > avail) virtmem_size = avail;
++      end_vm = start_vm + virtmem_size;
++
++      if(virtmem_size < physmem_size)
++              printf("Kernel virtual memory size shrunk to %ld bytes\n",
++                     virtmem_size);
++
++      uml_postsetup();
++
++      task_protections((unsigned long) &init_task);
++      os_flush_stdout();
++
++      return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
++}
++
++extern int uml_exitcode;
++
++static int panic_exit(struct notifier_block *self, unsigned long unused1,
++                    void *unused2)
++{
++#ifdef CONFIG_MAGIC_SYSRQ
++      handle_sysrq('p', &current->thread.regs, NULL, NULL);
++#endif
++      uml_exitcode = 1;
++      machine_halt();
++      return(0);
++}
++
++static struct notifier_block panic_exit_notifier = {
++      .notifier_call          = panic_exit,
++      .next                   = NULL,
++      .priority               = 0
++};
++
++void __init setup_arch(char **cmdline_p)
++{
++      notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
++      paging_init();
++      strcpy(command_line, saved_command_line);
++      *cmdline_p = command_line;
++      setup_hostinfo();
++}
++
++void __init check_bugs(void)
++{
++      arch_check_bugs();
++      check_ptrace();
++      check_sigio();
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/umid.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/umid.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/umid.c 2005-05-03 22:28:14.554397608 +0300
+@@ -0,0 +1,328 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <errno.h>
++#include <string.h>
++#include <stdlib.h>
++#include <dirent.h>
++#include <signal.h>
++#include <sys/stat.h>
++#include <sys/param.h>
++#include "user.h"
++#include "umid.h"
++#include "init.h"
++#include "os.h"
++#include "user_util.h"
++#include "choose-mode.h"
++
++#define UMID_LEN 64
++#define UML_DIR "~/.uml/"
++
++/* Changed by set_umid and make_umid, which are run early in boot */
++static char umid[UMID_LEN] = { 0 };
++
++/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */
++static char *uml_dir = UML_DIR;
++
++/* Changed by set_umid */
++static int umid_is_random = 1;
++static int umid_inited = 0;
++
++static int make_umid(int (*printer)(const char *fmt, ...));
++
++static int __init set_umid(char *name, int is_random, 
++                         int (*printer)(const char *fmt, ...))
++{
++      if(umid_inited){
++              (*printer)("Unique machine name can't be set twice\n");
++              return(-1);
++      }
++
++      if(strlen(name) > UMID_LEN - 1)
++              (*printer)("Unique machine name is being truncated to %d "
++                         "characters\n", UMID_LEN);
++      strncpy(umid, name, UMID_LEN - 1);
++      umid[UMID_LEN - 1] = '\0';
++
++      umid_is_random = is_random;
++      umid_inited = 1;
++      return 0;
++}
++
++static int __init set_umid_arg(char *name, int *add)
++{
++      *add = 0;
++      return(set_umid(name, 0, printf));
++}
++
++__uml_setup("umid=", set_umid_arg,
++"umid=<name>\n"
++"    This is used to assign a unique identity to this UML machine and\n"
++"    is used for naming the pid file and management console socket.\n\n"
++);
++
++int __init umid_file_name(char *name, char *buf, int len)
++{
++      int n;
++
++      if(!umid_inited && make_umid(printk)) return(-1);
++
++      n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1;
++      if(n > len){
++              printk("umid_file_name : buffer too short\n");
++              return(-1);
++      }
++
++      sprintf(buf, "%s%s/%s", uml_dir, umid, name);
++      return(0);
++}
++
++extern int tracing_pid;
++
++static int __init create_pid_file(void)
++{
++      char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
++      char pid[sizeof("nnnnn\0")];
++      int fd, n;
++
++      if(umid_file_name("pid", file, sizeof(file))) return 0;
++
++      fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), 
++                        0644);
++      if(fd < 0){
++              printf("Open of machine pid file \"%s\" failed - "
++                     "err = %d\n", file, -fd);
++              return 0;
++      }
++
++      sprintf(pid, "%d\n", os_getpid());
++      n = os_write_file(fd, pid, strlen(pid));
++      if(n != strlen(pid))
++              printf("Write of pid file failed - err = %d\n", -n);
++      os_close_file(fd);
++      return 0;
++}
++
++static int actually_do_remove(char *dir)
++{
++      DIR *directory;
++      struct dirent *ent;
++      int len;
++      char file[256];
++
++      directory = opendir(dir);
++      if(directory == NULL){
++              printk("actually_do_remove : couldn't open directory '%s', "
++                     "errno = %d\n", dir, errno);
++              return(1);
++      }
++      while((ent = readdir(directory)) != NULL){
++              if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
++                      continue;
++              len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1;
++              if(len > sizeof(file)){
++                      printk("Not deleting '%s' from '%s' - name too long\n",
++                             ent->d_name, dir);
++                      continue;
++              }
++              sprintf(file, "%s/%s", dir, ent->d_name);
++              if(unlink(file) < 0){
++                      printk("actually_do_remove : couldn't remove '%s' "
++                             "from '%s', errno = %d\n", ent->d_name, dir, 
++                             errno);
++                      return(1);
++              }
++      }
++      if(rmdir(dir) < 0){
++              printk("actually_do_remove : couldn't rmdir '%s', "
++                     "errno = %d\n", dir, errno);
++              return(1);
++      }
++      return(0);
++}
++
++void remove_umid_dir(void)
++{
++      char dir[strlen(uml_dir) + UMID_LEN + 1];
++      if(!umid_inited) return;
++
++      sprintf(dir, "%s%s", uml_dir, umid);
++      actually_do_remove(dir);
++}
++
++char *get_umid(int only_if_set)
++{
++      if(only_if_set && umid_is_random) return(NULL);
++      return(umid);
++}
++
++int not_dead_yet(char *dir)
++{
++      char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
++      char pid[sizeof("nnnnn\0")], *end;
++      int dead, fd, p, n;
++
++      sprintf(file, "%s/pid", dir);
++      dead = 0;
++      fd = os_open_file(file, of_read(OPENFLAGS()), 0);
++      if(fd < 0){
++              if(fd != -ENOENT){
++                      printk("not_dead_yet : couldn't open pid file '%s', "
++                             "err = %d\n", file, -fd);
++                      return(1);
++              }
++              dead = 1;
++      }
++      if(fd > 0){
++              n = os_read_file(fd, pid, sizeof(pid));
++              if(n < 0){
++                      printk("not_dead_yet : couldn't read pid file '%s', "
++                             "err = %d\n", file, -n);
++                      return(1);
++              }
++              p = strtoul(pid, &end, 0);
++              if(end == pid){
++                      printk("not_dead_yet : couldn't parse pid file '%s', "
++                             "errno = %d\n", file, errno);
++                      dead = 1;
++              }
++              if(((kill(p, 0) < 0) && (errno == ESRCH)) ||
++                 (p == CHOOSE_MODE(tracing_pid, os_getpid())))
++                      dead = 1;
++      }
++      if(!dead) return(1);
++      return(actually_do_remove(dir));
++}
++
++static int __init set_uml_dir(char *name, int *add)
++{
++      if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
++              uml_dir = malloc(strlen(name) + 2);
++              if(uml_dir == NULL){
++                      printf("Failed to malloc uml_dir - error = %d\n",
++                             errno);
++                      uml_dir = name;
++                      /* Return 0 here because do_initcalls doesn't look at
++                       * the return value.
++                       */
++                      return(0);
++              }
++              sprintf(uml_dir, "%s/", name);
++      }
++      else uml_dir = name;
++      return(0);
++}
++
++static int __init make_uml_dir(void)
++{
++      char dir[MAXPATHLEN + 1] = { '\0' };
++      int len;
++
++      if(*uml_dir == '~'){
++              char *home = getenv("HOME");
++
++              if(home == NULL){
++                      printf("make_uml_dir : no value in environment for "
++                             "$HOME\n");
++                      exit(1);
++              }
++              strncpy(dir, home, sizeof(dir));
++              uml_dir++;
++      }
++      len = strlen(dir);
++      strncat(dir, uml_dir, sizeof(dir) - len);
++      len = strlen(dir);
++      if((len > 0) && (len < sizeof(dir) - 1) && (dir[len - 1] != '/')){
++              dir[len] = '/';
++              dir[len + 1] = '\0';
++      }
++
++      uml_dir = malloc(strlen(dir) + 1);
++      if(uml_dir == NULL){
++              printf("make_uml_dir : malloc failed, errno = %d\n", errno);
++              exit(1);
++      }
++      strcpy(uml_dir, dir);
++      
++      if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){
++              printf("Failed to mkdir %s - errno = %i\n", uml_dir, errno);
++              return(-1);
++      }
++      return 0;
++}
++
++static int __init make_umid(int (*printer)(const char *fmt, ...))
++{
++      int fd, err;
++      char tmp[strlen(uml_dir) + UMID_LEN + 1];
++
++      strncpy(tmp, uml_dir, sizeof(tmp) - 1);
++      tmp[sizeof(tmp) - 1] = '\0';
++
++      if(!umid_inited){
++              strcat(tmp, "XXXXXX");
++              fd = mkstemp(tmp);
++              if(fd < 0){
++                      (*printer)("make_umid - mkstemp failed, errno = %d\n",
++                                 errno);
++                      return(1);
++              }
++
++              os_close_file(fd);
++              /* There's a nice tiny little race between this unlink and
++               * the mkdir below.  It'd be nice if there were a mkstemp
++               * for directories.
++               */
++              unlink(tmp);
++              set_umid(&tmp[strlen(uml_dir)], 1, printer);
++      }
++      
++      sprintf(tmp, "%s%s", uml_dir, umid);
++
++      err = mkdir(tmp, 0777);
++      if(err < 0){
++              if(errno == EEXIST){
++                      if(not_dead_yet(tmp)){
++                              (*printer)("umid '%s' is in use\n", umid);
++                              return(-1);
++                      }
++                      err = mkdir(tmp, 0777);
++              }
++      }
++      if(err < 0){
++              (*printer)("Failed to create %s - errno = %d\n", umid, errno);
++              return(-1);
++      }
++
++      return(0);
++}
++
++__uml_setup("uml_dir=", set_uml_dir,
++"uml_dir=<directory>\n"
++"    The location to place the pid and umid files.\n\n"
++);
++
++__uml_postsetup(make_uml_dir);
++
++static int __init make_umid_setup(void)
++{
++      return(make_umid(printf));
++}
++
++__uml_postsetup(make_umid_setup);
++__uml_postsetup(create_pid_file);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/kernel/user_syms.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/user_syms.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/user_syms.c    2005-05-03 23:38:38.888201256 +0300
+@@ -0,0 +1,85 @@
++#include "linux/types.h"
++#include "linux/module.h"
++
++/* XXX Deleted a number of symbols because they clashed strangely with headers
++ * Add them back later.
++ */
++
++#if 1
++/* Some of this are builtin function (some are not but could in the future),
++ * so I *must* declare good prototypes for them and then EXPORT them.
++ * The kernel code uses the macro defined by include/linux/string.h,
++ * so I undef macros; the userspace code does not include that and I
++ * add an EXPORT for the glibc one.*/
++
++#undef strlen
++#undef memcpy
++#undef memset
++
++//extern size_t strlen(const char *);
++extern void *memcpy(void *, const void *, size_t);
++extern void *memset(void *, int, size_t);
++//extern int printf(const char *, ...);
++
++//EXPORT_SYMBOL(strlen);
++EXPORT_SYMBOL(memset);
++EXPORT_SYMBOL(memcpy);
++#undef strstr
++
++EXPORT_SYMBOL(strstr);
++
++#endif
++
++/* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms.
++ * However, the modules will use the CRC defined *here*, no matter if it is 
++ * good; so the versions of these symbols will always match
++ */
++#define EXPORT_SYMBOL_PROTO(sym)       \
++       int sym(void);                  \
++       EXPORT_SYMBOL(sym);
++
++EXPORT_SYMBOL_PROTO(__errno_location);
++
++EXPORT_SYMBOL_PROTO(access);
++EXPORT_SYMBOL_PROTO(open);
++EXPORT_SYMBOL_PROTO(open64);
++EXPORT_SYMBOL_PROTO(close);
++EXPORT_SYMBOL_PROTO(read);
++EXPORT_SYMBOL_PROTO(write);
++EXPORT_SYMBOL_PROTO(dup2);
++EXPORT_SYMBOL_PROTO(__xstat);
++EXPORT_SYMBOL_PROTO(__lxstat);
++EXPORT_SYMBOL_PROTO(__lxstat64);
++EXPORT_SYMBOL_PROTO(lseek);
++EXPORT_SYMBOL_PROTO(lseek64);
++EXPORT_SYMBOL_PROTO(chown);
++EXPORT_SYMBOL_PROTO(truncate);
++EXPORT_SYMBOL_PROTO(utime);
++EXPORT_SYMBOL_PROTO(chmod);
++EXPORT_SYMBOL_PROTO(rename);
++EXPORT_SYMBOL_PROTO(__xmknod);
++
++EXPORT_SYMBOL_PROTO(symlink);
++EXPORT_SYMBOL_PROTO(link);
++EXPORT_SYMBOL_PROTO(unlink);
++EXPORT_SYMBOL_PROTO(readlink);
++
++EXPORT_SYMBOL_PROTO(mkdir);
++EXPORT_SYMBOL_PROTO(rmdir);
++EXPORT_SYMBOL_PROTO(opendir);
++EXPORT_SYMBOL_PROTO(readdir);
++EXPORT_SYMBOL_PROTO(closedir);
++EXPORT_SYMBOL_PROTO(seekdir);
++EXPORT_SYMBOL_PROTO(telldir);
++
++EXPORT_SYMBOL_PROTO(ioctl);
++
++EXPORT_SYMBOL_PROTO(pread64);
++EXPORT_SYMBOL_PROTO(pwrite64);
++
++EXPORT_SYMBOL_PROTO(statfs);
++EXPORT_SYMBOL_PROTO(statfs64);
++
++EXPORT_SYMBOL_PROTO(getuid);
++
++EXPORT_SYMBOL_PROTO(printf);
+Index: linux-2.4.29/arch/um/kernel/user_util.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/kernel/user_util.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/kernel/user_util.c    2005-05-03 22:28:14.556397304 +0300
+@@ -0,0 +1,188 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <limits.h>
++#include <setjmp.h>
++#include <sys/mman.h> 
++#include <sys/stat.h>
++#include <sys/ptrace.h>
++#include <sys/utsname.h>
++#include <sys/param.h>
++#include <sys/time.h>
++#include "asm/types.h"
++#include <ctype.h>
++#include <signal.h>
++#include <wait.h>
++#include <errno.h>
++#include <stdarg.h>
++#include <sched.h>
++#include <termios.h>
++#include <string.h>
++#include "user_util.h"
++#include "kern_util.h"
++#include "user.h"
++#include "mem_user.h"
++#include "init.h"
++#include "helper.h"
++#include "uml-config.h"
++
++#define COMMAND_LINE_SIZE _POSIX_ARG_MAX
++
++/* Changed in linux_main and setup_arch, which run before SMP is started */
++char saved_command_line[COMMAND_LINE_SIZE] = { 0 };
++char command_line[COMMAND_LINE_SIZE] = { 0 };
++
++void add_arg(char *cmd_line, char *arg)
++{
++      if (strlen(cmd_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
++              printf("add_arg: Too much command line!\n");
++              exit(1);
++      }
++      if(strlen(cmd_line) > 0) strcat(cmd_line, " ");
++      strcat(cmd_line, arg);
++}
++
++void stop(void)
++{
++      while(1) sleep(1000000);
++}
++
++void stack_protections(unsigned long address)
++{
++      int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
++
++        if(mprotect((void *) address, page_size(), prot) < 0)
++              panic("protecting stack failed, errno = %d", errno);
++}
++
++void task_protections(unsigned long address)
++{
++      unsigned long guard = address + page_size();
++      unsigned long stack = guard + page_size();
++      int prot = 0, pages;
++#ifdef notdef
++      if(mprotect((void *) guard, page_size(), prot) < 0)
++              panic("protecting guard page failed, errno = %d", errno);
++#endif
++      pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2;
++      prot = PROT_READ | PROT_WRITE | PROT_EXEC;
++      if(mprotect((void *) stack, pages * page_size(), prot) < 0)
++              panic("protecting stack failed, errno = %d", errno);
++}
++
++int wait_for_stop(int pid, int sig, int cont_type, void *relay)
++{
++      sigset_t *relay_signals = relay;
++      int status, ret;
++
++      while(1){
++              CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED));
++              if((ret < 0) ||
++                 !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){
++                      if(ret < 0){
++                              printk("wait failed, errno = %d\n",
++                                     errno);
++                      }
++                      else if(WIFEXITED(status)) 
++                              printk("process %d exited with status %d\n", 
++                                     pid, WEXITSTATUS(status));
++                      else if(WIFSIGNALED(status))
++                              printk("process %d exited with signal %d\n", 
++                                     pid, WTERMSIG(status));
++                      else if((WSTOPSIG(status) == SIGVTALRM) ||
++                              (WSTOPSIG(status) == SIGALRM) ||
++                              (WSTOPSIG(status) == SIGIO) ||
++                              (WSTOPSIG(status) == SIGPROF) ||
++                              (WSTOPSIG(status) == SIGCHLD) ||
++                              (WSTOPSIG(status) == SIGWINCH) ||
++                              (WSTOPSIG(status) == SIGINT)){
++                              ptrace(cont_type, pid, 0, WSTOPSIG(status));
++                              continue;
++                      }
++                      else if((relay_signals != NULL) &&
++                              sigismember(relay_signals, WSTOPSIG(status))){
++                              ptrace(cont_type, pid, 0, WSTOPSIG(status));
++                              continue;
++                      }
++                      else printk("process %d stopped with signal %d\n", 
++                                  pid, WSTOPSIG(status));
++                      panic("wait_for_stop failed to wait for %d to stop "
++                            "with %d\n", pid, sig);
++              }
++              return(status);
++      }
++}
++
++int raw(int fd)
++{
++      struct termios tt;
++      int err;
++
++      CATCH_EINTR(err = tcgetattr(fd, &tt));
++      if (err < 0) {
++              printk("tcgetattr failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      cfmakeraw(&tt);
++
++      CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt));
++      if (err < 0) {
++              printk("tcsetattr failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      /* XXX tcsetattr could have applied only some changes
++       * (and cfmakeraw() is a set of changes) */
++      return(0);
++}
++
++void setup_machinename(char *machine_out)
++{
++      struct utsname host;
++
++      uname(&host);
++      strcpy(machine_out, host.machine);
++}
++
++char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1];
++
++void setup_hostinfo(void)
++{
++      struct utsname host;
++
++      uname(&host);
++      sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename,
++              host.release, host.version, host.machine);
++}
++
++int setjmp_wrapper(void (*proc)(void *, void *), ...)
++{
++        va_list args;
++      sigjmp_buf buf;
++      int n;
++
++      n = sigsetjmp(buf, 1);
++      if(n == 0){
++              va_start(args, proc);
++              (*proc)(&buf, &args);
++      }
++      va_end(args);
++      return(n);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/Makefile 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/Makefile      2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,191 @@
++# 
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++OS := $(shell uname -s)
++
++ARCH_DIR = arch/um
++
++core-y := kernel sys-$(SUBARCH) os-$(OS)
++drivers-y := fs drivers
++subdir-y := $(core-y) $(drivers-y)
++SUBDIRS += $(foreach dir,$(subdir-y),$(ARCH_DIR)/$(dir))
++
++CORE_FILES += $(foreach dir,$(core-y),$(ARCH_DIR)/$(dir)/built-in.o)
++DRIVERS += $(foreach dir,$(drivers-y),$(ARCH_DIR)/$(dir)/built-in.o)
++
++include $(ARCH_DIR)/Makefile-$(SUBARCH)
++include $(ARCH_DIR)/Makefile-os-$(OS)
++
++MAKEFILE-$(CONFIG_MODE_TT) += Makefile-tt
++MAKEFILE-$(CONFIG_MODE_SKAS) += Makefile-skas
++
++ifneq ($(MAKEFILE-y),)
++  include $(addprefix $(ARCH_DIR)/,$(MAKEFILE-y))
++endif
++
++EXTRAVERSION := $(EXTRAVERSION)-1um
++
++include/linux/version.h: arch/$(ARCH)/Makefile
++
++# We require bash because the vmlinux link and loader script cpp use bash
++# features.
++SHELL := /bin/bash
++
++# Recalculate MODLIB to reflect the EXTRAVERSION changes (via KERNELRELEASE)
++# The way the toplevel Makefile is written EXTRAVERSION is not supposed
++# to be changed outside the toplevel Makefile, but recalculating MODLIB is
++# a sufficient workaround until we no longer need architecture dependent
++# EXTRAVERSION...
++MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
++
++ifeq ($(CONFIG_DEBUGSYM),y)
++CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS))
++endif
++
++CFLAGS-$(CONFIG_DEBUGSYM) += -g
++
++ARCH_INCLUDE = -I$(TOPDIR)/$(ARCH_DIR)/include
++
++# -Derrno=kernel_errno - This turns all kernel references to errno into
++# kernel_errno to separate them from the libc errno.  This allows -fno-common
++# in CFLAGS.  Otherwise, it would cause ld to complain about the two different
++# errnos.
++
++CFLAGS += $(ARCH_CFLAGS) $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
++      -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \
++      $(MODE_INCLUDE)
++
++check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
++
++CFLAGS += $(call check_gcc,-fno-unit-at-a-time,)
++
++LINKFLAGS += -r
++
++LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
++
++# These are needed for clean and mrproper, since in that case .config is not
++# included; the values here are meaningless
++
++CONFIG_NEST_LEVEL ?= 0
++CONFIG_KERNEL_HALF_GIGS ?= 0
++
++SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
++
++# These aren't in Makefile-tt because they are needed in the !CONFIG_MODE_TT +
++# CONFIG_MODE_SKAS + CONFIG_STATIC_LINK case.
++
++LINK_TT = -static
++LD_SCRIPT_TT := link.ld
++
++ifeq ($(CONFIG_STATIC_LINK),y)
++  LINK-y += $(LINK_TT)
++  LD_SCRIPT-y := $(LD_SCRIPT_TT)
++else
++ifeq ($(CONFIG_MODE_TT),y)
++  LINK-y += $(LINK_TT)
++  LD_SCRIPT-y := $(LD_SCRIPT_TT)
++else
++ifeq ($(CONFIG_MODE_SKAS),y)
++  LINK-y += $(LINK_SKAS)
++  LD_SCRIPT-y := $(LD_SCRIPT_SKAS)
++endif
++endif
++endif
++
++LD_SCRIPT-y := $(ARCH_DIR)/kernel/$(LD_SCRIPT-y)
++M4_MODE_TT := $(shell [ "$(CONFIG_MODE_TT)" = "y" ] && echo -DMODE_TT)
++
++ifndef START
++  START = $$(($(TOP_ADDR) - $(SIZE)))
++endif
++
++$(LD_SCRIPT-y): $(LD_SCRIPT-y).in
++      pages=$$(( 1 << $(CONFIG_KERNEL_STACK_ORDER) )) ; \
++      m4 -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \
++              -DELF_FORMAT=$(ELF_FORMAT) $(M4_MODE_TT) \
++              -DKERNEL_STACK_SIZE=$$(( 4096 * $$pages )) $< > $@
++
++SYMLINK_HEADERS = archparam.h system.h sigcontext.h processor.h ptrace.h \
++      arch-signal.h
++SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header))
++
++ARCH_SYMLINKS = include/asm-um/arch arch/um/include/sysdep arch/um/os \
++      $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h
++
++ifeq ($(CONFIG_MODE_SKAS), y)
++$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
++endif
++
++GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h 
++
++setup: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) 
++
++linux: setup vmlinux $(LD_SCRIPT-y)
++      mv vmlinux vmlinux.o
++      $(CC) -Wl,-T,$(LD_SCRIPT-y) $(LINK-y) $(LINK_WRAPS) \
++              -o linux vmlinux.o -L/usr/lib -lutil
++
++USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
++USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS))
++USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
++      $(MODE_INCLUDE)
++
++# To get a definition of F_SETSIG
++USER_CFLAGS += -D_GNU_SOURCE
++
++CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/link.ld $(ARCH_DIR)/dyn_link.ld \
++      $(GEN_HEADERS) 
++# $(ARCH_DIR)/include/uml-config.h removed temporarily because this causes
++# make to fail after make clean
++
++archmrproper:
++      rm -f $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) include/asm \
++              $(LD_SCRIPT) $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS))
++
++archclean: sysclean
++      find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
++              -o -name '*.gcov' \) -type f -print | xargs rm -f
++      cd $(ARCH_DIR) ; \
++      for dir in $(subdir-y) util ; do $(MAKE) -C $$dir clean; done
++
++archdep: 
++
++$(SYMLINK_HEADERS):
++      cd $(TOPDIR)/$(dir $@) ; \
++      ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@)
++
++include/asm-um/arch:
++      cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch
++
++arch/um/include/sysdep:
++      cd $(TOPDIR)/arch/um/include && ln -sf sysdep-$(SUBARCH) sysdep
++
++arch/um/os:
++      cd $(ARCH_DIR) && ln -sf os-$(OS) os
++
++$(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task
++      $< > $@
++
++$(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants
++      $< > $@
++
++$(ARCH_DIR)/include/uml-config.h : $(TOPDIR)/include/linux/autoconf.h
++      sed 's/ CONFIG/ UML_CONFIG/' $(TOPDIR)/include/linux/autoconf.h > $@
++
++$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util/mk_task_user.c \
++      $(ARCH_DIR)/util/mk_task_kern.c $(SYS_HEADERS)
++      $(MAKE) $(MFLAGS) -C $(ARCH_DIR)/util mk_task
++
++$(ARCH_DIR)/util/mk_constants : $(ARCH_DIR)/util/mk_constants_user.c \
++      $(ARCH_DIR)/util/mk_constants_kern.c 
++      $(MAKE) $(MFLAGS) -C $(ARCH_DIR)/util mk_constants
++
++export SUBARCH USER_CFLAGS OS
++
++all: linux
++
++define archhelp
++  echo  '* linux      - Binary kernel image (./linux)'
++endef
+Index: linux-2.4.29/arch/um/Makefile-i386
+===================================================================
+--- linux-2.4.29.orig/arch/um/Makefile-i386    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/Makefile-i386 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,46 @@
++ifeq ($(CONFIG_HOST_2G_2G),y)
++TOP_ADDR = 0x80000000
++else
++TOP_ADDR = 0xc0000000
++endif
++
++ifeq ($(CONFIG_MODE_SKAS),y)
++  ifneq ($(CONFIG_MODE_TT),y)
++     START = 0x8048000
++  endif
++endif
++
++ARCH_CFLAGS = -U__$(SUBARCH)__ -U$(SUBARCH)
++
++ifneq ($(CONFIG_GPROF),y)
++ARCH_CFLAGS += -DUM_FASTCALL
++endif
++
++ELF_ARCH = $(SUBARCH)
++ELF_FORMAT = elf32-$(SUBARCH)
++
++I386_H = $(ARCH_DIR)/include/sysdep-i386
++SYS = $(ARCH_DIR)/sys-i386
++UTIL = $(SYS)/util
++SUBDIRS += $(UTIL)
++
++SYS_HEADERS = $(I386_H)/sc.h $(I386_H)/thread.h
++
++$(I386_H)/sc.h : $(UTIL)/mk_sc
++      $(UTIL)/mk_sc > $@
++
++$(I386_H)/thread.h : $(UTIL)/mk_thread
++      $(UTIL)/mk_thread > $@
++
++$(UTIL)/mk_sc : $(UTIL)/mk_sc.c
++      $(MAKE) -C $(UTIL) mk_sc
++
++$(UTIL)/mk_thread : $(UTIL)/mk_thread_user.c $(UTIL)/mk_thread_kern.c \
++      $(I386_H)/sc.h
++      $(MAKE) -C $(UTIL) mk_thread
++
++sysclean :
++      rm -f $(SYS_HEADERS)
++      $(MAKE) -C $(UTIL) clean
++      $(MAKE) -C $(SYS) clean
++
+Index: linux-2.4.29/arch/um/Makefile-ia64
+===================================================================
+--- linux-2.4.29.orig/arch/um/Makefile-ia64    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/Makefile-ia64 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1 @@
++START_ADDR = 0x1000000000000000
+Index: linux-2.4.29/arch/um/Makefile-os-Linux
+===================================================================
+--- linux-2.4.29.orig/arch/um/Makefile-os-Linux        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/Makefile-os-Linux     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,7 @@
++# 
++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++SUBDIRS += $(ARCH_DIR)/os-$(OS)/drivers
++DRIVERS += $(ARCH_DIR)/os-$(OS)/drivers/drivers.o
+Index: linux-2.4.29/arch/um/Makefile-ppc
+===================================================================
+--- linux-2.4.29.orig/arch/um/Makefile-ppc     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/Makefile-ppc  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,9 @@
++ifeq ($(CONFIG_HOST_2G_2G), y)
++START_ADDR = 0x80000000
++else
++START_ADDR = 0xc0000000
++endif
++ARCH_CFLAGS = -U__powerpc__ -D__UM_PPC__
++
++# The arch is ppc, but the elf32 name is powerpc
++ELF_SUBARCH = powerpc
+Index: linux-2.4.29/arch/um/Makefile-skas
+===================================================================
+--- linux-2.4.29.orig/arch/um/Makefile-skas    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/Makefile-skas 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,20 @@
++# 
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++PROFILE += -pg
++
++CFLAGS-$(CONFIG_GCOV) += -fprofile-arcs -ftest-coverage
++CFLAGS-$(CONFIG_GPROF) += $(PROFILE)
++LINK-$(CONFIG_GPROF) += $(PROFILE)
++
++MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/skas/include
++
++LINK_SKAS = -Wl,-rpath,/lib 
++LD_SCRIPT_SKAS = dyn_link.ld
++
++GEN_HEADERS += $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
++
++$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h :
++      $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h
+Index: linux-2.4.29/arch/um/Makefile-tt
+===================================================================
+--- linux-2.4.29.orig/arch/um/Makefile-tt      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/Makefile-tt   2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,7 @@
++# 
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/tt/include
++
+Index: linux-2.4.29/arch/um/os-Linux/aio.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/aio.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/aio.c        2005-05-03 22:28:14.563396240 +0300
+@@ -0,0 +1,404 @@
++/* 
++ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <signal.h>
++#include <errno.h>
++#include <sched.h>
++#include <sys/syscall.h>
++#include "os.h"
++#include "helper.h"
++#include "aio.h"
++#include "init.h"
++#include "user.h"
++#include "mode.h"
++
++struct aio_thread_req {
++      enum aio_type type;
++      int io_fd;
++      unsigned long long offset;
++      char *buf;
++      int len;
++      int reply_fd;
++      void *data;
++};
++
++static int aio_req_fd_r = -1;
++static int aio_req_fd_w = -1;
++
++#if defined(HAVE_AIO_ABI)
++#include <linux/aio_abi.h>
++
++/* If we have the headers, we are going to build with AIO enabled.
++ * If we don't have aio in libc, we define the necessary stubs here.
++ */
++
++#if !defined(HAVE_AIO_LIBC)
++
++#define __NR_io_setup 245
++#define __NR_io_getevents 247
++#define __NR_io_submit 248
++
++static long io_setup(int n, aio_context_t *ctxp)
++{
++  return(syscall(__NR_io_setup, n, ctxp));
++}
++
++static long io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp)
++{
++  return(syscall(__NR_io_submit, ctx, nr, iocbpp));
++}
++
++static long io_getevents(aio_context_t ctx_id, long min_nr, long nr,
++                       struct io_event *events, struct timespec *timeout)
++{
++  return(syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout));
++}
++
++#endif
++
++/* The AIO_MMAP cases force the mmapped page into memory here
++ * rather than in whatever place first touches the data.  I used
++ * to do this by touching the page, but that's delicate because
++ * gcc is prone to optimizing that away.  So, what's done here
++ * is we read from the descriptor from which the page was 
++ * mapped.  The caller is required to pass an offset which is
++ * inside the page that was mapped.  Thus, when the read 
++ * returns, we know that the page is in the page cache, and
++ * that it now backs the mmapped area.
++ */
++
++static int do_aio(aio_context_t ctx, enum aio_type type, int fd, char *buf, 
++                int len, unsigned long long offset, void *data)
++{
++      struct iocb iocb, *iocbp = &iocb;
++      char c;
++      int err;
++
++      iocb = ((struct iocb) { .aio_data       = (unsigned long) data,
++                              .aio_reqprio    = 0,
++                              .aio_fildes     = fd,
++                              .aio_buf        = (unsigned long) buf,
++                              .aio_nbytes     = len,
++                              .aio_offset     = offset,
++                              .aio_reserved1  = 0,
++                              .aio_reserved2  = 0,
++                              .aio_reserved3  = 0 });
++
++      switch(type){
++      case AIO_READ:
++              iocb.aio_lio_opcode = IOCB_CMD_PREAD;
++              err = io_submit(ctx, 1, &iocbp);
++              break;
++      case AIO_WRITE:
++              iocb.aio_lio_opcode = IOCB_CMD_PWRITE;
++              err = io_submit(ctx, 1, &iocbp);
++              break;
++      case AIO_MMAP:
++              iocb.aio_lio_opcode = IOCB_CMD_PREAD;
++              iocb.aio_buf = (unsigned long) &c;
++              iocb.aio_nbytes = sizeof(c);
++              err = io_submit(ctx, 1, &iocbp);
++              break;
++      default:
++              printk("Bogus op in do_aio - %d\n", type);
++              err = -EINVAL;
++              break;
++      }
++      if(err > 0)
++              err = 0;
++
++      return(err);    
++}
++
++static aio_context_t ctx = 0;
++
++static int aio_thread(void *arg)
++{
++      struct aio_thread_reply reply;
++      struct io_event event;
++      int err, n, reply_fd;
++
++      signal(SIGWINCH, SIG_IGN);
++
++      while(1){
++              n = io_getevents(ctx, 1, 1, &event, NULL);
++              if(n < 0){
++                      if(errno == EINTR)
++                              continue;
++                      printk("aio_thread - io_getevents failed, "
++                             "errno = %d\n", errno);
++              }
++              else {
++                      reply = ((struct aio_thread_reply) 
++                              { .data = (void *) event.data,
++                                .err  = event.res });
++                      reply_fd = 
++                              ((struct aio_context *) event.data)->reply_fd;
++                      err = os_write_file(reply_fd, &reply, sizeof(reply));
++                      if(err != sizeof(reply))
++                              printk("not_aio_thread - write failed, "
++                                     "fd = %d, err = %d\n", 
++                                     aio_req_fd_r, -err);
++              }
++      }
++      return(0);
++}
++
++#endif
++
++static int do_not_aio(struct aio_thread_req *req)
++{
++      char c;
++      int err;
++
++      switch(req->type){
++      case AIO_READ:
++              err = os_seek_file(req->io_fd, req->offset);
++              if(err)
++                      goto out;
++
++              err = os_read_file(req->io_fd, req->buf, req->len);
++              break;
++      case AIO_WRITE:
++              err = os_seek_file(req->io_fd, req->offset);
++              if(err)
++                      goto out;
++
++              err = os_write_file(req->io_fd, req->buf, req->len);
++              break;
++      case AIO_MMAP:
++              err = os_seek_file(req->io_fd, req->offset);
++              if(err)
++                      goto out;
++
++              err = os_read_file(req->io_fd, &c, sizeof(c));
++              break;
++      default:
++              printk("do_not_aio - bad request type : %d\n", req->type);
++              err = -EINVAL;
++              break;
++      }
++
++ out:
++      return(err);
++}
++
++static int not_aio_thread(void *arg)
++{
++      struct aio_thread_req req;
++      struct aio_thread_reply reply;
++      int err;
++
++      signal(SIGWINCH, SIG_IGN);
++      while(1){
++              err = os_read_file(aio_req_fd_r, &req, sizeof(req));
++              if(err != sizeof(req)){
++                      if(err < 0)
++                              printk("not_aio_thread - read failed, fd = %d, "
++                                     "err = %d\n", aio_req_fd_r, -err);
++                      else {
++                              printk("not_aio_thread - short read, fd = %d, "
++                                     "length = %d\n", aio_req_fd_r, err);
++                      }
++                      continue;
++              }
++              err = do_not_aio(&req);
++              reply = ((struct aio_thread_reply) { .data      = req.data,
++                                                   .err       = err });
++              err = os_write_file(req.reply_fd, &reply, sizeof(reply));
++              if(err != sizeof(reply))
++                      printk("not_aio_thread - write failed, fd = %d, "
++                             "err = %d\n", aio_req_fd_r, -err);
++      }
++}
++
++static int aio_pid = -1;
++
++static int init_aio_24(void)
++{
++      unsigned long stack;
++      int fds[2], err;
++      
++      err = os_pipe(fds, 1, 1);
++      if(err)
++              goto out;
++
++      aio_req_fd_w = fds[0];
++      aio_req_fd_r = fds[1];
++      err = run_helper_thread(not_aio_thread, NULL, 
++                              CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
++      if(err < 0)
++              goto out_close_pipe;
++
++      aio_pid = err;
++      goto out;
++
++ out_close_pipe:
++      os_close_file(fds[0]);
++      os_close_file(fds[1]);
++      aio_req_fd_w = -1;
++      aio_req_fd_r = -1;      
++ out:
++      return(0);
++}
++
++#ifdef HAVE_AIO_ABI
++#define DEFAULT_24_AIO 0
++static int init_aio_26(void)
++{
++      unsigned long stack;
++      int err;
++      
++      if(io_setup(256, &ctx)){
++              printk("aio_thread failed to initialize context, err = %d\n",
++                     errno);
++              return(-errno);
++      }
++
++      err = run_helper_thread(aio_thread, NULL, 
++                              CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
++      if(err < 0)
++              return(-errno);
++
++      aio_pid = err;
++      err = 0;
++ out:
++      return(err);
++}
++
++int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, 
++                unsigned long long offset, int reply_fd, void *data)
++{
++      struct aio_thread_reply reply;
++      int err;
++
++      ((struct aio_context *) data)->reply_fd = reply_fd;
++
++      err = do_aio(ctx, type, io_fd, buf, len, offset, data);
++      if(err){
++              reply = ((struct aio_thread_reply) { .data = data,
++                                                   .err  = err });
++              err = os_write_file(reply_fd, &reply, sizeof(reply));
++              if(err != sizeof(reply))
++                      printk("submit_aio_26 - write failed, "
++                             "fd = %d, err = %d\n", reply_fd, -err);
++              else err = 0;
++      }
++
++      return(err);
++}
++
++#else
++#define DEFAULT_24_AIO 1
++static int init_aio_26(void)
++{
++      return(-ENOSYS);
++}
++
++int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, 
++                unsigned long long offset, int reply_fd, void *data)
++{
++      return(-ENOSYS);
++}
++#endif
++
++static int aio_24 = DEFAULT_24_AIO;
++
++static int __init set_aio_24(char *name, int *add)
++{
++      aio_24 = 1;
++      return(0);
++}
++
++__uml_setup("aio=2.4", set_aio_24,
++"aio=2.4\n"
++"    This is used to force UML to use 2.4-style AIO even when 2.6 AIO is\n"
++"    available.  2.4 AIO is a single thread that handles one request at a\n"
++"    time, synchronously.  2.6 AIO is a thread which uses 2.5 AIO interface\n"
++"    to handle an arbitrary number of pending requests.  2.6 AIO is not\n"
++"    available in tt mode, on 2.4 hosts, or when UML is built with\n"
++"    /usr/include/linux/aio_abi no available.\n\n"
++);
++
++static int init_aio(void)
++{
++      int err;
++
++      CHOOSE_MODE(({ 
++              if(!aio_24){ 
++                      printk("Disabling 2.6 AIO in tt mode\n");
++                      aio_24 = 1;
++              } }), (void) 0);
++
++      if(!aio_24){
++              err = init_aio_26();
++              if(err && (errno == ENOSYS)){
++                      printk("2.6 AIO not supported on the host - "
++                             "reverting to 2.4 AIO\n");
++                      aio_24 = 1;
++              }
++              else return(err);
++      }
++
++      if(aio_24)
++              return(init_aio_24());
++
++      return(0);
++}
++
++__initcall(init_aio);
++
++static void exit_aio(void)
++{
++      if(aio_pid != -1)
++              os_kill_process(aio_pid, 1);
++}
++
++__uml_exitcall(exit_aio);
++
++int submit_aio_24(enum aio_type type, int io_fd, char *buf, int len, 
++                unsigned long long offset, int reply_fd, void *data)
++{
++      struct aio_thread_req req = { .type             = type,
++                                    .io_fd            = io_fd,
++                                    .offset           = offset,
++                                    .buf              = buf,
++                                    .len              = len,
++                                    .reply_fd         = reply_fd,
++                                    .data             = data,
++      };
++      int err;
++
++      err = os_write_file(aio_req_fd_w, &req, sizeof(req));
++      if(err == sizeof(req))
++              err = 0;
++
++      return(err);
++}
++
++int submit_aio(enum aio_type type, int io_fd, char *buf, int len, 
++             unsigned long long offset, int reply_fd, void *data)
++{
++      if(aio_24)
++              return(submit_aio_24(type, io_fd, buf, len, offset, reply_fd, 
++                                   data));
++      else {
++              return(submit_aio_26(type, io_fd, buf, len, offset, reply_fd, 
++                                   data));
++      }
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/os-Linux/drivers/etap.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/drivers/etap.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/drivers/etap.h       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,27 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "net_user.h"
++
++struct ethertap_data {
++      char *dev_name;
++      char *gate_addr;
++      int data_fd;
++      int control_fd;
++      void *dev;
++};
++
++extern struct net_user_info ethertap_user_info;
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/os-Linux/drivers/ethertap_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/drivers/ethertap_kern.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/drivers/ethertap_kern.c      2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,121 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ * Licensed under the GPL.
++ */
++
++#include "linux/init.h"
++#include "linux/netdevice.h"
++#include "linux/etherdevice.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "etap.h"
++
++struct ethertap_init {
++      char *dev_name;
++      char *gate_addr;
++};
++
++static void etap_init(struct net_device *dev, void *data)
++{
++      struct uml_net_private *pri;
++      struct ethertap_data *epri;
++      struct ethertap_init *init = data;
++
++      init_etherdev(dev, 0);
++      pri = dev->priv;
++      epri = (struct ethertap_data *) pri->user;
++      *epri = ((struct ethertap_data)
++              { .dev_name             = init->dev_name,
++                .gate_addr            = init->gate_addr,
++                .data_fd              = -1,
++                .control_fd           = -1,
++                .dev                  = dev });
++
++      printk("ethertap backend - %s", epri->dev_name);
++      if(epri->gate_addr != NULL) 
++              printk(", IP = %s", epri->gate_addr);
++      printk("\n");
++}
++
++static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
++{
++      int len;
++
++      *skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP);
++      if(*skb == NULL) return(-ENOMEM);
++      len = net_recvfrom(fd, (*skb)->mac.raw, 
++                         (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP);
++      if(len <= 0) return(len);
++      skb_pull(*skb, 2);
++      len -= 2;
++      return(len);
++}
++
++static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
++{
++      if(skb_headroom(*skb) < 2){
++              struct sk_buff *skb2;
++
++              skb2 = skb_realloc_headroom(*skb, 2);
++              dev_kfree_skb(*skb);
++              if (skb2 == NULL) return(-ENOMEM);
++              *skb = skb2;
++      }
++      skb_push(*skb, 2);
++      return(net_send(fd, (*skb)->data, (*skb)->len));
++}
++
++struct net_kern_info ethertap_kern_info = {
++      .init                   = etap_init,
++      .protocol               = eth_protocol,
++      .read                   = etap_read,
++      .write                  = etap_write,
++};
++
++int ethertap_setup(char *str, char **mac_out, void *data)
++{
++      struct ethertap_init *init = data;
++
++      *init = ((struct ethertap_init)
++              { .dev_name     = NULL,
++                .gate_addr    = NULL });
++      if(tap_setup_common(str, "ethertap", &init->dev_name, mac_out,
++                          &init->gate_addr))
++              return(0);
++      if(init->dev_name == NULL){
++              printk("ethertap_setup : Missing tap device name\n");
++              return(0);
++      }
++
++      return(1);
++}
++
++static struct transport ethertap_transport = {
++      .list           = LIST_HEAD_INIT(ethertap_transport.list),
++      .name           = "ethertap",
++      .setup          = ethertap_setup,
++      .user           = &ethertap_user_info,
++      .kern           = &ethertap_kern_info,
++      .private_size   = sizeof(struct ethertap_data),
++};
++
++static int register_ethertap(void)
++{
++      register_transport(&ethertap_transport);
++      return(1);
++}
++
++__initcall(register_ethertap);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/os-Linux/drivers/ethertap_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/drivers/ethertap_user.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/drivers/ethertap_user.c      2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,240 @@
++/*
++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
++ * James Leu (jleu@mindspring.net).
++ * Copyright (C) 2001 by various other people who didn't put their name here.
++ * Licensed under the GPL.
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stddef.h>
++#include <stdlib.h>
++#include <sys/errno.h>
++#include <sys/socket.h>
++#include <sys/wait.h>
++#include <sys/un.h>
++#include <net/if.h>
++#include "user.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "net_user.h"
++#include "etap.h"
++#include "helper.h"
++#include "os.h"
++
++#define MAX_PACKET ETH_MAX_PACKET
++
++void etap_user_init(void *data, void *dev)
++{
++      struct ethertap_data *pri = data;
++
++      pri->dev = dev;
++}
++
++struct addr_change {
++      enum { ADD_ADDR, DEL_ADDR } what;
++      unsigned char addr[4];
++      unsigned char netmask[4];
++};
++
++static void etap_change(int op, unsigned char *addr, unsigned char *netmask,
++                      int fd)
++{
++      struct addr_change change;
++      void *output;
++      int n;
++
++      change.what = op;
++      memcpy(change.addr, addr, sizeof(change.addr));
++      memcpy(change.netmask, netmask, sizeof(change.netmask));
++      n = os_write_file(fd, &change, sizeof(change));
++      if(n != sizeof(change))
++              printk("etap_change - request failed, err = %d\n", -n);
++      output = um_kmalloc(page_size());
++      if(output == NULL)
++              printk("etap_change : Failed to allocate output buffer\n");
++      read_output(fd, output, page_size());
++      if(output != NULL){
++              printk("%s", output);
++              kfree(output);
++      }
++}
++
++static void etap_open_addr(unsigned char *addr, unsigned char *netmask,
++                         void *arg)
++{
++      etap_change(ADD_ADDR, addr, netmask, *((int *) arg));
++}
++
++static void etap_close_addr(unsigned char *addr, unsigned char *netmask,
++                          void *arg)
++{
++      etap_change(DEL_ADDR, addr, netmask, *((int *) arg));
++}
++
++struct etap_pre_exec_data {
++      int control_remote;
++      int control_me;
++      int data_me;
++};
++
++static void etap_pre_exec(void *arg)
++{
++      struct etap_pre_exec_data *data = arg;
++
++      dup2(data->control_remote, 1);
++      os_close_file(data->data_me);
++      os_close_file(data->control_me);
++}
++
++static int etap_tramp(char *dev, char *gate, int control_me, 
++                    int control_remote, int data_me, int data_remote)
++{
++      struct etap_pre_exec_data pe_data;
++      int pid, status, err, n;
++      char version_buf[sizeof("nnnnn\0")];
++      char data_fd_buf[sizeof("nnnnnn\0")];
++      char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
++      char *setup_args[] = { "uml_net", version_buf, "ethertap", dev,
++                             data_fd_buf, gate_buf, NULL };
++      char *nosetup_args[] = { "uml_net", version_buf, "ethertap", 
++                               dev, data_fd_buf, NULL };
++      char **args, c;
++
++      sprintf(data_fd_buf, "%d", data_remote);
++      sprintf(version_buf, "%d", UML_NET_VERSION);
++      if(gate != NULL){
++              strcpy(gate_buf, gate);
++              args = setup_args;
++      }
++      else args = nosetup_args;
++
++      err = 0;
++      pe_data.control_remote = control_remote;
++      pe_data.control_me = control_me;
++      pe_data.data_me = data_me;
++      pid = run_helper(etap_pre_exec, &pe_data, args, NULL);
++
++      if(pid < 0) err = pid;
++      os_close_file(data_remote);
++      os_close_file(control_remote);
++      n = os_read_file(control_me, &c, sizeof(c));
++      if(n != sizeof(c)){
++              printk("etap_tramp : read of status failed, err = %d\n", -n);
++              return(-EINVAL);
++      }
++      if(c != 1){
++              printk("etap_tramp : uml_net failed\n");
++              err = -EINVAL;
++              CATCH_EINTR(n = waitpid(pid, &status, 0));
++              if(n < 0)
++                      err = -errno;
++              else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1))
++                      printk("uml_net didn't exit with status 1\n");
++      }
++      return(err);
++}
++
++static int etap_open(void *data)
++{
++      struct ethertap_data *pri = data;
++      char *output;
++      int data_fds[2], control_fds[2], err, output_len;
++
++      err = tap_open_common(pri->dev, pri->gate_addr);
++      if(err) return(err);
++
++      err = os_pipe(data_fds, 0, 0);
++      if(err < 0){
++              printk("data os_pipe failed - err = %d\n", -err);
++              return(err);
++      }
++
++      err = os_pipe(control_fds, 1, 0);
++      if(err < 0){
++              printk("control os_pipe failed - err = %d\n", -err);
++              return(err);
++      }
++      
++      err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], 
++                       control_fds[1], data_fds[0], data_fds[1]);
++      output_len = page_size();
++      output = um_kmalloc(output_len);
++      read_output(control_fds[0], output, output_len);
++
++      if(output == NULL)
++              printk("etap_open : failed to allocate output buffer\n");
++      else {
++              printk("%s", output);
++              kfree(output);
++      }
++
++      if(err < 0){
++              printk("etap_tramp failed - err = %d\n", -err);
++              return(err);
++      }
++
++      pri->data_fd = data_fds[0];
++      pri->control_fd = control_fds[0];
++      iter_addresses(pri->dev, etap_open_addr, &pri->control_fd);
++      return(data_fds[0]);
++}
++
++static void etap_close(int fd, void *data)
++{
++      struct ethertap_data *pri = data;
++
++      iter_addresses(pri->dev, etap_close_addr, &pri->control_fd);
++      os_close_file(fd);
++      os_shutdown_socket(pri->data_fd, 1, 1);
++      os_close_file(pri->data_fd);
++      pri->data_fd = -1;
++      os_close_file(pri->control_fd);
++      pri->control_fd = -1;
++}
++
++static int etap_set_mtu(int mtu, void *data)
++{
++      return(mtu);
++}
++
++static void etap_add_addr(unsigned char *addr, unsigned char *netmask,
++                        void *data)
++{
++      struct ethertap_data *pri = data;
++
++      tap_check_ips(pri->gate_addr, addr);
++      if(pri->control_fd == -1) return;
++      etap_open_addr(addr, netmask, &pri->control_fd);
++}
++
++static void etap_del_addr(unsigned char *addr, unsigned char *netmask, 
++                        void *data)
++{
++      struct ethertap_data *pri = data;
++
++      if(pri->control_fd == -1) return;
++      etap_close_addr(addr, netmask, &pri->control_fd);
++}
++
++struct net_user_info ethertap_user_info = {
++      .init           = etap_user_init,
++      .open           = etap_open,
++      .close          = etap_close,
++      .remove         = NULL,
++      .set_mtu        = etap_set_mtu,
++      .add_address    = etap_add_addr,
++      .delete_address = etap_del_addr,
++      .max_packet     = MAX_PACKET - ETH_HEADER_ETHERTAP
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/os-Linux/drivers/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/drivers/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/drivers/Makefile     2005-05-03 22:28:14.568395480 +0300
+@@ -0,0 +1,31 @@
++# 
++# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET := drivers.o
++
++list-multi := tuntap.o ethertap.o
++
++ethertap-objs := ethertap_kern.o ethertap_user.o
++tuntap-objs := tuntap_kern.o tuntap_user.o
++
++obj-y = 
++obj-$(CONFIG_UML_NET_ETHERTAP) += ethertap.o
++obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o
++
++USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y)),$($(f)-objs))
++
++USER_OBJS = $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS))
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++ethertap.o : $(ethertap-objs)
++
++tuntap.o : $(tuntap-objs)
++
++$(list-multi) : # This doesn't work, but should : '%.o : $(%-objs)'
++      $(LD) $(LD_RFLAG) -r -o $@ $($(patsubst %.o,%,$@)-objs)
+Index: linux-2.4.29/arch/um/os-Linux/drivers/tuntap.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/drivers/tuntap.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/drivers/tuntap.h     2005-05-03 22:28:14.568395480 +0300
+@@ -0,0 +1,32 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_TUNTAP_H
++#define __UM_TUNTAP_H
++
++#include "net_user.h"
++
++struct tuntap_data {
++      char *dev_name;
++      int fixed_config;
++      char *gate_addr;
++      int fd;
++      void *dev;
++};
++
++extern struct net_user_info tuntap_user_info;
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/os-Linux/drivers/tuntap_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/drivers/tuntap_kern.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/drivers/tuntap_kern.c        2005-05-03 22:28:14.569395328 +0300
+@@ -0,0 +1,105 @@
++/* 
++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/netdevice.h"
++#include "linux/etherdevice.h"
++#include "linux/skbuff.h"
++#include "linux/init.h"
++#include "asm/errno.h"
++#include "net_kern.h"
++#include "net_user.h"
++#include "tuntap.h"
++
++struct tuntap_init {
++      char *dev_name;
++      char *gate_addr;
++};
++
++static void tuntap_init(struct net_device *dev, void *data)
++{
++      struct uml_net_private *pri;
++      struct tuntap_data *tpri;
++      struct tuntap_init *init = data;
++
++      init_etherdev(dev, 0);
++      pri = dev->priv;
++      tpri = (struct tuntap_data *) pri->user;
++      *tpri = ((struct tuntap_data)
++              { .dev_name             = init->dev_name,
++                .fixed_config         = (init->dev_name != NULL),
++                .gate_addr            = init->gate_addr,
++                .fd                   = -1,
++                .dev                  = dev });
++      printk("TUN/TAP backend - ");
++      if(tpri->gate_addr != NULL) 
++              printk("IP = %s", tpri->gate_addr);
++      printk("\n");
++}
++
++static int tuntap_read(int fd, struct sk_buff **skb, 
++                     struct uml_net_private *lp)
++{
++      *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
++      if(*skb == NULL) return(-ENOMEM);
++      return(net_read(fd, (*skb)->mac.raw, 
++                      (*skb)->dev->mtu + ETH_HEADER_OTHER));
++}
++
++static int tuntap_write(int fd, struct sk_buff **skb, 
++                      struct uml_net_private *lp)
++{
++      return(net_write(fd, (*skb)->data, (*skb)->len));
++}
++
++struct net_kern_info tuntap_kern_info = {
++      .init                   = tuntap_init,
++      .protocol               = eth_protocol,
++      .read                   = tuntap_read,
++      .write                  = tuntap_write,
++};
++
++int tuntap_setup(char *str, char **mac_out, void *data)
++{
++      struct tuntap_init *init = data;
++
++      *init = ((struct tuntap_init)
++              { .dev_name     = NULL,
++                .gate_addr    = NULL });
++      if(tap_setup_common(str, "tuntap", &init->dev_name, mac_out,
++                          &init->gate_addr))
++              return(0);
++
++      return(1);
++}
++
++static struct transport tuntap_transport = {
++      .list           = LIST_HEAD_INIT(tuntap_transport.list),
++      .name           = "tuntap",
++      .setup          = tuntap_setup,
++      .user           = &tuntap_user_info,
++      .kern           = &tuntap_kern_info,
++      .private_size   = sizeof(struct tuntap_data),
++      .setup_size     = sizeof(struct tuntap_init),
++};
++
++static int register_tuntap(void)
++{
++      register_transport(&tuntap_transport);
++      return(1);
++}
++
++__initcall(register_tuntap);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/os-Linux/drivers/tuntap_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/drivers/tuntap_user.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/drivers/tuntap_user.c        2005-05-03 22:28:14.571395024 +0300
+@@ -0,0 +1,225 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <stddef.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <sys/wait.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <sys/uio.h>
++#include <sys/ioctl.h>
++#include <net/if.h>
++#include <linux/if_tun.h>
++#include "net_user.h"
++#include "tuntap.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "user.h"
++#include "helper.h"
++#include "os.h"
++
++#define MAX_PACKET ETH_MAX_PACKET
++
++void tuntap_user_init(void *data, void *dev)
++{
++      struct tuntap_data *pri = data;
++
++      pri->dev = dev;
++}
++
++static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask,
++                          void *data)
++{
++      struct tuntap_data *pri = data;
++
++      tap_check_ips(pri->gate_addr, addr);
++      if((pri->fd == -1) || pri->fixed_config) return;
++      open_addr(addr, netmask, pri->dev_name);
++}
++
++static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask,
++                          void *data)
++{
++      struct tuntap_data *pri = data;
++
++      if((pri->fd == -1) || pri->fixed_config) return;
++      close_addr(addr, netmask, pri->dev_name);
++}
++
++struct tuntap_pre_exec_data {
++      int stdout;
++      int close_me;
++};
++
++static void tuntap_pre_exec(void *arg)
++{
++      struct tuntap_pre_exec_data *data = arg;
++      
++      dup2(data->stdout, 1);
++      os_close_file(data->close_me);
++}
++
++static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
++                           char *buffer, int buffer_len, int *used_out)
++{
++      struct tuntap_pre_exec_data data;
++      char version_buf[sizeof("nnnnn\0")];
++      char *argv[] = { "uml_net", version_buf, "tuntap", "up", gate,
++                       NULL };
++      char buf[CMSG_SPACE(sizeof(*fd_out))];
++      struct msghdr msg;
++      struct cmsghdr *cmsg;
++      struct iovec iov;
++      int pid, n;
++
++      sprintf(version_buf, "%d", UML_NET_VERSION);
++
++      data.stdout = remote;
++      data.close_me = me;
++
++      pid = run_helper(tuntap_pre_exec, &data, argv, NULL);
++
++      if(pid < 0) return(-pid);
++
++      os_close_file(remote);
++
++      msg.msg_name = NULL;
++      msg.msg_namelen = 0;
++      if(buffer != NULL){
++              iov = ((struct iovec) { buffer, buffer_len });
++              msg.msg_iov = &iov;
++              msg.msg_iovlen = 1;
++      }
++      else {
++              msg.msg_iov = NULL;
++              msg.msg_iovlen = 0;
++      }
++      msg.msg_control = buf;
++      msg.msg_controllen = sizeof(buf);
++      msg.msg_flags = 0;
++      n = recvmsg(me, &msg, 0);
++      *used_out = n;
++      if(n < 0){
++              printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", 
++                     errno);
++              return(-errno);
++      }
++      CATCH_EINTR(waitpid(pid, NULL, 0));
++
++      cmsg = CMSG_FIRSTHDR(&msg);
++      if(cmsg == NULL){
++              printk("tuntap_open_tramp : didn't receive a message\n");
++              return(-EINVAL);
++      }
++      if((cmsg->cmsg_level != SOL_SOCKET) || 
++         (cmsg->cmsg_type != SCM_RIGHTS)){
++              printk("tuntap_open_tramp : didn't receive a descriptor\n");
++              return(-EINVAL);
++      }
++      *fd_out = ((int *) CMSG_DATA(cmsg))[0];
++      return(0);
++}
++
++static int tuntap_open(void *data)
++{
++      struct ifreq ifr;
++      struct tuntap_data *pri = data;
++      char *output, *buffer;
++      int err, fds[2], len, used;
++
++      err = tap_open_common(pri->dev, pri->gate_addr);
++      if(err < 0) 
++              return(err);
++
++      if(pri->fixed_config){
++              pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0);
++              if(pri->fd < 0){
++                      printk("Failed to open /dev/net/tun, err = %d\n",
++                             -pri->fd);
++                      return(pri->fd);
++              }
++              memset(&ifr, 0, sizeof(ifr));
++              ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
++              strncpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name) - 1);
++              if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){
++                      printk("TUNSETIFF failed, errno = %d\n", errno);
++                      os_close_file(pri->fd);
++                      return(-errno);
++              }
++      }
++      else {
++              err = os_pipe(fds, 0, 0);
++              if(err < 0){
++                      printk("tuntap_open : os_pipe failed - err = %d\n",
++                             -err);
++                      return(err);
++              }
++
++              buffer = get_output_buffer(&len);
++              if(buffer != NULL) len--;
++              used = 0;
++
++              err = tuntap_open_tramp(pri->gate_addr, &pri->fd, fds[0],
++                                      fds[1], buffer, len, &used);
++
++              output = buffer;
++              if(err < 0) {
++                      printk("%s", output);
++                      free_output_buffer(buffer);
++                      printk("tuntap_open_tramp failed - err = %d\n", -err);
++                      return(err);
++              }
++
++              pri->dev_name = uml_strdup(buffer);
++              output += IFNAMSIZ;
++              printk("%s", output);
++              free_output_buffer(buffer);
++
++              os_close_file(fds[0]);
++              iter_addresses(pri->dev, open_addr, pri->dev_name);
++      }
++
++      return(pri->fd);
++}
++
++static void tuntap_close(int fd, void *data)
++{
++      struct tuntap_data *pri = data;
++
++      if(!pri->fixed_config) 
++              iter_addresses(pri->dev, close_addr, pri->dev_name);
++      os_close_file(fd);
++      pri->fd = -1;
++}
++
++static int tuntap_set_mtu(int mtu, void *data)
++{
++      return(mtu);
++}
++
++struct net_user_info tuntap_user_info = {
++      .init           = tuntap_user_init,
++      .open           = tuntap_open,
++      .close          = tuntap_close,
++      .remove         = NULL,
++      .set_mtu        = tuntap_set_mtu,
++      .add_address    = tuntap_add_addr,
++      .delete_address = tuntap_del_addr,
++      .max_packet     = MAX_PACKET
++};
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/os-Linux/file.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/file.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/file.c       2005-05-03 22:28:14.574394568 +0300
+@@ -0,0 +1,942 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <signal.h>
++#include <utime.h>
++#include <dirent.h>
++#include <linux/kdev_t.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <sys/ioctl.h>
++#include <sys/mount.h>
++#include <sys/uio.h>
++#include <sys/utsname.h>
++#include <sys/vfs.h>
++#include "os.h"
++#include "user.h"
++#include "kern_util.h"
++
++static void copy_stat(struct uml_stat *dst, struct stat64 *src)
++{
++      *dst = ((struct uml_stat) {
++              .ust_major   = MAJOR(src->st_dev),     /* device */
++              .ust_minor   = MINOR(src->st_dev),
++              .ust_ino     = src->st_ino,     /* inode */
++              .ust_mode    = src->st_mode,    /* protection */
++              .ust_nlink   = src->st_nlink,   /* number of hard links */
++              .ust_uid     = src->st_uid,     /* user ID of owner */
++              .ust_gid     = src->st_gid,     /* group ID of owner */
++              .ust_size    = src->st_size,    /* total size, in bytes */
++              .ust_blksize = src->st_blksize, /* blocksize for filesys I/O */
++              .ust_blocks  = src->st_blocks,  /* number of blocks allocated */
++              .ust_atime   = src->st_atime,   /* time of last access */
++              .ust_mtime   = src->st_mtime,   /* time of last modification */
++              .ust_ctime   = src->st_ctime,   /* time of last change */
++              .ust_rmajor  = MAJOR(src->st_rdev),
++              .ust_rminor  = MINOR(src->st_rdev),
++      });
++}
++
++int os_stat_fd(const int fd, struct uml_stat *ubuf)
++{
++      struct stat64 sbuf;
++      int err;
++
++      do {
++              err = fstat64(fd, &sbuf);
++      } while((err < 0) && (errno == EINTR)) ;
++
++      if(err < 0) 
++              return(-errno);
++
++      if(ubuf != NULL)
++              copy_stat(ubuf, &sbuf);
++      return(err);
++}
++
++int os_stat_file(const char *file_name, struct uml_stat *ubuf)
++{
++      struct stat64 sbuf;
++      int err;
++
++      do {
++              err = stat64(file_name, &sbuf);
++      } while((err < 0) && (errno == EINTR)) ;
++
++      if(err < 0) 
++              return(-errno);
++
++      if(ubuf != NULL)
++              copy_stat(ubuf, &sbuf);
++      return(err);
++}
++
++int os_lstat_file(const char *file_name, struct uml_stat *ubuf)
++{
++      struct stat64 sbuf;
++      int err;
++
++      do {
++              err = lstat64(file_name, &sbuf);
++      } while((err < 0) && (errno == EINTR)) ;
++
++      if(err < 0) 
++              return(-errno);
++
++      if(ubuf != NULL)
++              copy_stat(ubuf, &sbuf);
++      return(err);
++}
++
++int os_access(const char *file, int mode)
++{
++      int amode, err;
++
++      amode=(mode& OS_ACC_R_OK ? R_OK : 0) | (mode& OS_ACC_W_OK ? W_OK : 0) |
++            (mode& OS_ACC_X_OK ? X_OK : 0) | (mode& OS_ACC_F_OK ? F_OK : 0) ;
++
++      err = access(file, amode);
++      if(err < 0)
++              return(-errno);
++
++      return(0);
++}
++
++int os_set_file_time(const char *file, unsigned long access, unsigned long mod)
++{
++      struct utimbuf buf = ((struct utimbuf){ .actime = access, 
++                                              .modtime = mod });
++      int err;
++
++      err = utime(file, &buf);
++      if(err < 0)
++              return(-errno);
++
++      return(0);
++}
++
++int os_set_file_perms(const char *file, int mode)
++{
++      int err;
++
++      err = chmod(file, mode);
++      if(err < 0)
++              return(-errno);
++
++      return(0);
++}
++
++int os_set_file_owner(const char *file, int owner, int group)
++{
++      int err;
++
++      err = chown(file, owner, group);
++      if(err < 0)
++              return(-errno);
++
++      return(0);
++}
++
++void os_print_error(int error, const char* str)
++{
++      errno = error < 0 ? -error : error;
++
++      perror(str);
++}
++
++/* FIXME? required only by hostaudio (because it passes ioctls verbatim) */
++int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg)
++{
++      int err;
++
++      err = ioctl(fd, cmd, arg);
++      if(err < 0)
++              return(-errno);
++
++      return(err);
++}
++
++int os_window_size(int fd, int *rows, int *cols)
++{
++      struct winsize size;
++
++      if(ioctl(fd, TIOCGWINSZ, &size) < 0)
++              return(-errno);
++
++      *rows = size.ws_row;
++      *cols = size.ws_col;
++
++      return(0);
++}
++
++int os_new_tty_pgrp(int fd, int pid)
++{
++      if(ioctl(fd, TIOCSCTTY, 0) < 0){
++              printk("TIOCSCTTY failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      if(tcsetpgrp(fd, pid) < 0){
++              printk("tcsetpgrp failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      return(0);
++}
++
++/* FIXME: ensure namebuf in os_get_if_name is big enough */
++int os_get_ifname(int fd, char* namebuf)
++{
++      if(ioctl(fd, SIOCGIFNAME, namebuf) < 0)
++              return(-errno);
++
++      return(0);
++}
++
++int os_set_slip(int fd)
++{
++      int disc, sencap;
++
++      disc = N_SLIP;
++      if(ioctl(fd, TIOCSETD, &disc) < 0){
++              printk("Failed to set slip line discipline - "
++                     "errno = %d\n", errno);
++              return(-errno);
++      }
++
++      sencap = 0;
++      if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0){
++              printk("Failed to set slip encapsulation - "
++                     "errno = %d\n", errno);
++              return(-errno);
++      }
++
++      return(0);
++}
++
++int os_set_owner(int fd, int pid)
++{
++      if(fcntl(fd, F_SETOWN, pid) < 0){
++              int save_errno = errno;
++
++              if(fcntl(fd, F_GETOWN, 0) != pid)
++                      return(-save_errno);
++      }
++
++      return(0);
++}
++
++/* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */ 
++int os_sigio_async(int master, int slave)
++{
++      int flags;
++
++      flags = fcntl(master, F_GETFL);
++      if(flags < 0) {
++              printk("fcntl F_GETFL failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
++         (fcntl(master, F_SETOWN, os_getpid()) < 0)){
++              printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n", 
++                     errno);
++              return(-errno);
++      }
++
++      if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)){
++              printk("fcntl F_SETFL failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      return(0);
++}
++
++int os_mode_fd(int fd, int mode)
++{
++      int err;
++
++      do {
++              err = fchmod(fd, mode);
++      } while((err < 0) && (errno==EINTR)) ;
++
++      if(err < 0)
++              return(-errno);
++
++      return(0);
++}
++
++int os_file_type(char *file)
++{
++      struct uml_stat buf;
++      int err;
++
++      err = os_lstat_file(file, &buf);
++      if(err < 0)
++              return(err);
++
++      if(S_ISDIR(buf.ust_mode)) return(OS_TYPE_DIR);
++      else if(S_ISLNK(buf.ust_mode)) return(OS_TYPE_SYMLINK);
++      else if(S_ISCHR(buf.ust_mode)) return(OS_TYPE_CHARDEV);
++      else if(S_ISBLK(buf.ust_mode)) return(OS_TYPE_BLOCKDEV);
++      else if(S_ISFIFO(buf.ust_mode)) return(OS_TYPE_FIFO);
++      else if(S_ISSOCK(buf.ust_mode)) return(OS_TYPE_SOCK);
++      else return(OS_TYPE_FILE);
++}
++
++int os_file_mode(char *file, struct openflags *mode_out)
++{
++      int err;
++
++      *mode_out = OPENFLAGS();
++
++      err = os_access(file, OS_ACC_W_OK);
++      if((err < 0) && (err != -EACCES))
++              return(err);
++
++      *mode_out = of_write(*mode_out);
++
++      err = os_access(file, OS_ACC_R_OK);
++      if((err < 0) && (err != -EACCES))
++              return(err);
++
++      *mode_out = of_read(*mode_out);
++
++      return(0);
++}
++
++int os_open_file(char *file, struct openflags flags, int mode)
++{
++      int fd, f = 0;
++
++      if(flags.r && flags.w) f = O_RDWR;
++      else if(flags.r) f = O_RDONLY;
++      else if(flags.w) f = O_WRONLY;
++      else f = 0;
++
++      if(flags.s) f |= O_SYNC;
++      if(flags.c) f |= O_CREAT;
++      if(flags.t) f |= O_TRUNC;
++      if(flags.e) f |= O_EXCL;
++      if(flags.d) f |= O_DIRECT;
++
++      fd = open64(file, f, mode);
++      if(fd < 0)
++              return(-errno);
++
++      if(flags.cl && fcntl(fd, F_SETFD, 1)){
++              os_close_file(fd);
++              return(-errno);
++      }
++
++      return(fd);
++}
++
++void *os_open_dir(char *path, int *err_out)
++{
++      void *dir;
++
++      dir = opendir(path);
++      *err_out = -errno;
++      return(dir);
++}
++
++int os_seek_dir(void *stream, unsigned long long pos)
++{
++      seekdir(stream, pos);
++      return(0);
++}
++
++int os_read_dir(void *stream, unsigned long long *ino_out, char **name_out)
++{
++      struct dirent *ent;
++
++      errno = 0;
++      ent = readdir(stream);
++      if(ent == NULL){
++              if(errno != 0)
++                      return(-errno);
++              *name_out = NULL;
++              return(0);
++      }
++
++      *ino_out = ent->d_ino;
++      *name_out = ent->d_name;
++      return(0);
++}
++
++int os_tell_dir(void *stream)
++{
++      return(telldir(stream));
++}
++
++int os_close_dir(void *stream)
++{
++      int err;
++
++      err = closedir(stream);
++      if(err < 0)
++              return(-errno);
++      return(0);
++}
++
++int os_remove_file(const char *file)
++{
++      int err;
++
++      err = unlink(file);
++      if(err)
++              return(-errno);
++
++      return(0);
++}
++
++int os_move_file(const char *from, const char *to)
++{
++      int err;
++
++      err = rename(from, to);
++      if(err)
++              return(-errno);
++
++      return(0);
++}
++
++int os_truncate_fd(int fd, unsigned long long len)
++{
++      int err;
++
++      err = ftruncate(fd, len);
++      if(err)
++              return(-errno);
++      return(0);
++}
++
++int os_truncate_file(const char *file, unsigned long long len)
++{
++      int err;
++
++      err = truncate(file, len);
++      if(err)
++              return(-errno);
++      return(0);
++}
++
++int os_connect_socket(char *name)
++{
++      struct sockaddr_un sock;
++      int fd, err;
++
++      sock.sun_family = AF_UNIX;
++      snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
++
++      fd = socket(AF_UNIX, SOCK_STREAM, 0);
++      if(fd < 0)
++              return(fd);
++
++      err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
++      if(err)
++              return(-errno);
++
++      return(fd);
++}
++
++void os_close_file(int fd)
++{
++      close(fd);
++}
++
++int os_seek_file(int fd, __u64 offset)
++{
++      __u64 actual;
++
++      actual = lseek64(fd, offset, SEEK_SET);
++      if(actual != offset)
++              return(-errno);
++      return(0);
++}
++
++static int fault_buffer(void *start, int len, 
++                      int (*copy_proc)(void *addr, void *buf, int len))
++{
++      int page = getpagesize(), i;
++      char c;
++
++      for(i = 0; i < len; i += page){
++              if((*copy_proc)(start + i, &c, sizeof(c)))
++                      return(-EFAULT);
++      }
++      if((len % page) != 0){
++              if((*copy_proc)(start + len - 1, &c, sizeof(c)))
++                      return(-EFAULT);
++      }
++      return(0);
++}
++
++static int file_io(int fd, void *buf, int len,
++                 int (*io_proc)(int fd, void *buf, int len),
++                 int (*copy_user_proc)(void *addr, void *buf, int len))
++{
++      int n, err;
++
++      do {
++              n = (*io_proc)(fd, buf, len);
++              if((n < 0) && (errno == EFAULT)){
++                      err = fault_buffer(buf, len, copy_user_proc);
++                      if(err)
++                              return(err);
++                      n = (*io_proc)(fd, buf, len);
++              }
++      } while((n < 0) && (errno == EINTR));
++
++      if(n < 0)
++              return(-errno);
++      return(n);
++}
++
++int os_read_file(int fd, void *buf, int len)
++{
++      return(file_io(fd, buf, len, (int (*)(int, void *, int)) read, 
++                     copy_from_user_proc));
++}
++
++int os_write_file(int fd, const void *buf, int len)
++{
++      return(file_io(fd, (void *) buf, len, 
++                     (int (*)(int, void *, int)) write, copy_to_user_proc));
++}
++
++int os_file_size(char *file, long long *size_out)
++{
++      struct uml_stat buf;
++      int err;
++
++      err = os_stat_file(file, &buf);
++      if(err < 0){
++              printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
++              return(err);
++      }
++
++      if(S_ISBLK(buf.ust_mode)){
++              int fd, blocks;
++
++              fd = os_open_file(file, of_read(OPENFLAGS()), 0);
++              if(fd < 0){
++                      printk("Couldn't open \"%s\", errno = %d\n", file, -fd);
++                      return(fd);
++              }
++              if(ioctl(fd, BLKGETSIZE, &blocks) < 0){
++                      printk("Couldn't get the block size of \"%s\", "
++                             "errno = %d\n", file, errno);
++                      err = -errno;
++                      os_close_file(fd);
++                      return(err);
++              }
++              *size_out = ((long long) blocks) * 512;
++              os_close_file(fd);
++              return(0);
++      }
++      *size_out = buf.ust_size;
++      return(0);
++}
++
++int os_fd_size(int fd, long long *size_out)
++{
++      struct stat buf;
++      int err;
++
++      err = fstat(fd, &buf);
++      if(err)
++              return(-errno);
++
++      *size_out = buf.st_size;
++      return(0);
++}
++
++int os_file_modtime(char *file, unsigned long *modtime)
++{
++      struct uml_stat buf;
++      int err;
++
++      err = os_stat_file(file, &buf);
++      if(err < 0){
++              printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
++              return(err);
++      }
++
++      *modtime = buf.ust_mtime;
++      return(0);
++}
++
++int os_get_exec_close(int fd, int* close_on_exec)
++{
++      int ret;
++
++      do {
++              ret = fcntl(fd, F_GETFD);
++      } while((ret < 0) && (errno == EINTR)) ;
++
++      if(ret < 0)
++              return(-errno);
++
++      *close_on_exec = (ret&FD_CLOEXEC) ? 1 : 0;
++      return(ret);
++}
++
++int os_set_exec_close(int fd, int close_on_exec)
++{
++      int flag, err;
++
++      if(close_on_exec) flag = FD_CLOEXEC;
++      else flag = 0;
++
++      do {
++              err = fcntl(fd, F_SETFD, flag);
++      } while((err < 0) && (errno == EINTR)) ;
++
++      if(err < 0)
++              return(-errno);
++      return(err);
++}
++
++int os_pipe(int *fds, int stream, int close_on_exec)
++{
++      int err, type = stream ? SOCK_STREAM : SOCK_DGRAM;
++
++      err = socketpair(AF_UNIX, type, 0, fds);
++      if(err < 0) 
++              return(-errno);
++
++      if(!close_on_exec)
++              return(0);
++
++      err = os_set_exec_close(fds[0], 1);
++      if(err < 0)
++              goto error;
++
++      err = os_set_exec_close(fds[1], 1);
++      if(err < 0)
++              goto error;
++
++      return(0);
++
++ error:
++      printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err);
++      os_close_file(fds[1]);
++      os_close_file(fds[0]);
++      return(err);
++}
++
++int os_set_fd_async(int fd, int owner)
++{
++      /* XXX This should do F_GETFL first */
++      if(fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK) < 0){
++              printk("os_set_fd_async : failed to set O_ASYNC and "
++                     "O_NONBLOCK on fd # %d, errno = %d\n", fd, errno);
++              return(-errno);
++      }
++#ifdef notdef
++      if(fcntl(fd, F_SETFD, 1) < 0){
++              printk("os_set_fd_async : Setting FD_CLOEXEC failed, "
++                     "errno = %d\n", errno);
++      }
++#endif
++
++      if((fcntl(fd, F_SETSIG, SIGIO) < 0) ||
++         (fcntl(fd, F_SETOWN, owner) < 0)){
++              printk("os_set_fd_async : Failed to fcntl F_SETOWN "
++                     "(or F_SETSIG) fd %d to pid %d, errno = %d\n", fd, 
++                     owner, errno);
++              return(-errno);
++      }
++
++      return(0);
++}
++
++int os_clear_fd_async(int fd)
++{
++      int flags = fcntl(fd, F_GETFL);
++
++      flags &= ~(O_ASYNC | O_NONBLOCK);
++      if(fcntl(fd, F_SETFL, flags) < 0)
++              return(-errno);
++      return(0);
++}
++
++int os_set_fd_block(int fd, int blocking)
++{
++      int flags;
++
++      flags = fcntl(fd, F_GETFL);
++
++      if(blocking) flags &= ~O_NONBLOCK;
++      else flags |= O_NONBLOCK;
++
++      if(fcntl(fd, F_SETFL, flags) < 0){
++              printk("Failed to change blocking on fd # %d, errno = %d\n",
++                     fd, errno);
++              return(-errno);
++      }
++      return(0);
++}
++
++int os_accept_connection(int fd)
++{
++      int new;
++
++      new = accept(fd, NULL, 0);
++      if(new < 0) 
++              return(-errno);
++      return(new);
++}
++
++#ifndef SHUT_RD
++#define SHUT_RD 0
++#endif
++
++#ifndef SHUT_WR
++#define SHUT_WR 1
++#endif
++
++#ifndef SHUT_RDWR
++#define SHUT_RDWR 2
++#endif
++
++int os_shutdown_socket(int fd, int r, int w)
++{
++      int what, err;
++
++      if(r && w) what = SHUT_RDWR;
++      else if(r) what = SHUT_RD;
++      else if(w) what = SHUT_WR;
++      else {
++              printk("os_shutdown_socket : neither r or w was set\n");
++              return(-EINVAL);
++      }
++      err = shutdown(fd, what);
++      if(err < 0)
++              return(-errno);
++      return(0);
++}
++
++int os_rcv_fd(int fd, int *helper_pid_out)
++{
++      int new, n;
++      char buf[CMSG_SPACE(sizeof(new))];
++      struct msghdr msg;
++      struct cmsghdr *cmsg;
++      struct iovec iov;
++
++      msg.msg_name = NULL;
++      msg.msg_namelen = 0;
++      iov = ((struct iovec) { .iov_base  = helper_pid_out,
++                              .iov_len   = sizeof(*helper_pid_out) });
++      msg.msg_iov = &iov;
++      msg.msg_iovlen = 1;
++      msg.msg_control = buf;
++      msg.msg_controllen = sizeof(buf);
++      msg.msg_flags = 0;
++
++      n = recvmsg(fd, &msg, 0);
++      if(n < 0)
++              return(-errno);
++
++      else if(n != sizeof(iov.iov_len))
++              *helper_pid_out = -1;
++
++      cmsg = CMSG_FIRSTHDR(&msg);
++      if(cmsg == NULL){
++              printk("rcv_fd didn't receive anything, error = %d\n", errno);
++              return(-1);
++      }
++      if((cmsg->cmsg_level != SOL_SOCKET) || 
++         (cmsg->cmsg_type != SCM_RIGHTS)){
++              printk("rcv_fd didn't receive a descriptor\n");
++              return(-1);
++      }
++
++      new = ((int *) CMSG_DATA(cmsg))[0];
++      return(new);
++}
++
++int os_create_unix_socket(char *file, int len, int close_on_exec)
++{
++      struct sockaddr_un addr;
++      int sock, err;
++
++      sock = socket(PF_UNIX, SOCK_DGRAM, 0);
++      if (sock < 0){
++              printk("create_unix_socket - socket failed, errno = %d\n",
++                     errno);
++              return(-errno);
++      }
++
++      if(close_on_exec) {
++              err = os_set_exec_close(sock, 1);
++              if(err < 0)
++                      printk("create_unix_socket : close_on_exec failed, "
++                     "err = %d", -err);
++      }
++
++      addr.sun_family = AF_UNIX;
++
++      /* XXX Be more careful about overflow */
++      snprintf(addr.sun_path, len, "%s", file);
++
++      err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
++      if (err < 0){
++              printk("create_listening_socket at '%s' - bind failed, "
++                     "errno = %d\n", file, errno);
++              return(-errno);
++      }
++
++      return(sock);
++}
++
++int os_make_symlink(const char *to, const char *from)
++{
++      int err;
++
++      err = symlink(to, from);
++      if(err)
++              return(-errno);
++
++      return(0);
++}
++
++int os_read_symlink(const char *file, char *buf, int size)
++{
++      int err;
++
++      err = readlink(file, buf, size);
++      if(err < 0)
++              return(-errno);
++
++      return(err);
++}
++
++int os_link_file(const char *to, const char *from)
++{
++      int err;
++
++      err = link(to, from);
++      if(err)
++              return(-errno);
++
++      return(0);
++}
++
++int os_make_dir(const char *dir, int mode)
++{
++      int err;
++
++      err = mkdir(dir, mode);
++      if(err)
++              return(-errno);
++
++      return(0);
++}
++
++int os_make_dev(const char *name, int mode, int major, int minor)
++{
++      int err;
++
++      err = mknod(name, mode, MKDEV(major, minor));
++      if(err)
++              return(-errno);
++
++      return(0);
++}
++
++int os_remove_dir(const char *dir)
++{
++      int err;
++
++      err = rmdir(dir);
++      if(err)
++              return(-errno);
++
++      return(0);
++}
++
++void os_flush_stdout(void)
++{
++      fflush(stdout);
++}
++
++int os_lock_file(int fd, int excl)
++{
++      int type = excl ? F_WRLCK : F_RDLCK;
++      struct flock lock = ((struct flock) { .l_type   = type,
++                                            .l_whence = SEEK_SET,
++                                            .l_start  = 0,
++                                            .l_len    = 0 } );
++      int err, save;
++
++      err = fcntl(fd, F_SETLK, &lock);
++      if(!err)
++              goto out;
++
++      save = -errno;
++      err = fcntl(fd, F_GETLK, &lock);
++      if(err){
++              err = -errno;
++              goto out;
++      }
++
++      printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid);
++      err = save;
++ out:
++      return(err);
++}
++
++int os_stat_filesystem(char *path, long *bsize_out, long long *blocks_out, 
++                     long long *bfree_out, long long *bavail_out, 
++                     long long *files_out, long long *ffree_out, 
++                     void *fsid_out, int fsid_size, long *namelen_out, 
++                     long *spare_out)
++{
++      struct statfs64 buf;
++      int err;
++
++      err = statfs64(path, &buf);
++      if(err < 0)
++              return(-errno);
++
++      *bsize_out = buf.f_bsize;
++      *blocks_out = buf.f_blocks;
++      *bfree_out = buf.f_bfree;
++      *bavail_out = buf.f_bavail;
++      *files_out = buf.f_files;
++      *ffree_out = buf.f_ffree;
++      memcpy(fsid_out, &buf.f_fsid, 
++             sizeof(buf.f_fsid) > fsid_size ? fsid_size : 
++             sizeof(buf.f_fsid));
++      *namelen_out = buf.f_namelen;
++      spare_out[0] = buf.f_spare[0];
++      spare_out[1] = buf.f_spare[1];
++      spare_out[2] = buf.f_spare[2];
++      spare_out[3] = buf.f_spare[3];
++      spare_out[4] = buf.f_spare[4];
++      spare_out[5] = buf.f_spare[5];
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/os-Linux/include/file.h
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/include/file.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/include/file.h       2005-05-03 22:28:14.575394416 +0300
+@@ -0,0 +1,22 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __OS_FILE_H__
++#define __OS_FILE_H__
++
++#define DEV_NULL "/dev/null"
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/os-Linux/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/Makefile     2005-05-03 22:28:14.575394416 +0300
+@@ -0,0 +1,23 @@
++# 
++# Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com)
++# Licensed under the GPL
++#
++
++O_TARGET = built-in.o
++
++obj-y = aio.o file.o process.o time.o tty.o
++
++HAVE_AIO_ABI = $(shell [ -e /usr/include/linux/aio_abi.h ] && \
++      echo -DHAVE_AIO_ABI)
++HAVE_AIO_LIBC = $(shell objdump -T /lib/libc-*.so | grep io_submit && \
++      echo -DHAVE_AIO_LIBC)
++CFLAGS_aio.o = $(HAVE_AIO_ABI) $(HAVE_AIO_LIBC)
++
++include $(TOPDIR)/Rules.make
++
++$(obj-y) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++clean :
++
++archmrproper:
+Index: linux-2.4.29/arch/um/os-Linux/process.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/process.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/process.c    2005-05-03 22:28:14.577394112 +0300
+@@ -0,0 +1,151 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdio.h>
++#include <errno.h>
++#include <signal.h>
++#include <sys/mman.h>
++#include <sys/wait.h>
++#include "os.h"
++#include "user.h"
++#include "user_util.h"
++
++#define ARBITRARY_ADDR -1
++#define FAILURE_PID    -1
++
++#define STAT_PATH_LEN sizeof("/proc/#######/stat\0")
++#define COMM_SCANF "%*[^)])"
++
++unsigned long os_process_pc(int pid)
++{
++      char proc_stat[STAT_PATH_LEN], buf[256];
++      unsigned long pc;
++      int fd, err;
++
++      sprintf(proc_stat, "/proc/%d/stat", pid);
++      fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0);
++      if(fd < 0){
++              printk("os_process_pc - couldn't open '%s', err = %d\n", 
++                     proc_stat, -fd);
++              return(ARBITRARY_ADDR);
++      }
++      err = os_read_file(fd, buf, sizeof(buf));
++      if(err < 0){
++              printk("os_process_pc - couldn't read '%s', err = %d\n", 
++                     proc_stat, -err);
++              os_close_file(fd);
++              return(ARBITRARY_ADDR);
++      }
++      os_close_file(fd);
++      pc = ARBITRARY_ADDR;
++      if(sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d "
++                "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
++                "%*d %*d %*d %*d %*d %lu", &pc) != 1){
++              printk("os_process_pc - couldn't find pc in '%s'\n", buf);
++      }
++      return(pc);
++}
++
++int os_process_parent(int pid)
++{
++      char stat[STAT_PATH_LEN];
++      char data[256];
++      int parent, n, fd;
++
++      if(pid == -1) return(-1);
++
++      snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
++      fd = os_open_file(stat, of_read(OPENFLAGS()), 0);
++      if(fd < 0){
++              printk("Couldn't open '%s', err = %d\n", stat, -fd);
++              return(FAILURE_PID);
++      }
++
++      n = os_read_file(fd, data, sizeof(data));
++      os_close_file(fd);
++
++      if(n < 0){
++              printk("Couldn't read '%s', err = %d\n", stat, -n);
++              return(FAILURE_PID);
++      }
++
++      parent = FAILURE_PID;
++      n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent);
++      if(n != 1) 
++              printk("Failed to scan '%s'\n", data);
++
++      return(parent);
++}
++
++void os_stop_process(int pid)
++{
++      kill(pid, SIGSTOP);
++}
++
++void os_kill_process(int pid, int reap_child)
++{
++      kill(pid, SIGKILL);
++      if(reap_child)
++              CATCH_EINTR(waitpid(pid, NULL, 0));
++              
++}
++
++void os_usr1_process(int pid)
++{
++      kill(pid, SIGUSR1);
++}
++
++int os_getpid(void)
++{
++      return(getpid());
++}
++
++int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len,
++                int r, int w, int x)
++{
++      void *loc;
++      int prot;
++
++      prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
++              (x ? PROT_EXEC : 0);
++
++      loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, 
++                   fd, off);
++      if(loc == MAP_FAILED)
++              return(-errno);
++      return(0);
++}
++
++int os_protect_memory(void *addr, unsigned long len, int r, int w, int x)
++{
++        int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
++                  (x ? PROT_EXEC : 0));
++
++        if(mprotect(addr, len, prot) < 0)
++              return(-errno);
++        return(0);
++}
++
++int os_unmap_memory(void *addr, int len)
++{
++        int err;
++
++        err = munmap(addr, len);
++      if(err < 0)
++              return(-errno);
++        return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/os-Linux/time.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/time.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/time.c       2005-05-03 22:28:14.578393960 +0300
+@@ -0,0 +1,21 @@
++#include <stdlib.h>
++#include <sys/time.h>
++
++unsigned long long os_usecs(void)
++{
++      struct timeval tv;
++
++      gettimeofday(&tv, NULL);
++      return((unsigned long long) tv.tv_sec * 1000000 + tv.tv_usec);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/os-Linux/tty.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/os-Linux/tty.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/os-Linux/tty.c        2005-05-03 22:28:14.579393808 +0300
+@@ -0,0 +1,61 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdlib.h>
++#include <errno.h>
++#include "os.h"
++#include "user.h"
++#include "kern_util.h"
++
++struct grantpt_info {
++      int fd;
++      int res;
++      int err;
++};
++
++static void grantpt_cb(void *arg)
++{
++      struct grantpt_info *info = arg;
++
++      info->res = grantpt(info->fd);
++      info->err = errno;
++}
++
++int get_pty(void)
++{
++      struct grantpt_info info;
++      int fd;
++
++      fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0);
++      if(fd < 0){
++              printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd);
++              return(fd);
++      }
++
++      info.fd = fd;
++      initial_thread_cb(grantpt_cb, &info);
++
++      if(info.res < 0){
++              printk("get_pty : Couldn't grant pty - errno = %d\n", 
++                     -info.err);
++              return(-1);
++      }
++      if(unlockpt(fd) < 0){
++              printk("get_pty : Couldn't unlock pty - errno = %d\n", errno);
++              return(-1);
++      }
++      return(fd);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/sys-i386/bugs.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/bugs.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/bugs.c       2005-05-03 22:28:14.580393656 +0300
+@@ -0,0 +1,222 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <errno.h>
++#include <string.h>
++#include <sys/signal.h>
++#include <asm/ldt.h>
++#include "kern_util.h"
++#include "user.h"
++#include "sysdep/ptrace.h"
++#include "task.h"
++#include "os.h"
++
++#define MAXTOKEN 64
++
++/* Set during early boot */
++int host_has_cmov = 1;
++int host_has_xmm = 0;
++
++static char token(int fd, char *buf, int len, char stop)
++{
++      int n;
++      char *ptr, *end, c;
++
++      ptr = buf;
++      end = &buf[len];
++      do {
++              n = os_read_file(fd, ptr, sizeof(*ptr));
++              c = *ptr++;
++              if(n != sizeof(*ptr)){
++                      if(n == 0) return(0);
++                      printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
++                      if(n < 0) 
++                              return(n);
++                      else 
++                              return(-EIO);
++              }
++      } while((c != '\n') && (c != stop) && (ptr < end));
++
++      if(ptr == end){
++              printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
++              return(-1);
++      }
++      *(ptr - 1) = '\0';
++      return(c);
++}
++
++static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
++{
++      int n;
++      char c;
++
++      scratch[len - 1] = '\0';
++      while(1){
++              c = token(fd, scratch, len - 1, ':');
++              if(c <= 0)
++                      return(0);
++              else if(c != ':'){
++                      printk("Failed to find ':' in /proc/cpuinfo\n");
++                      return(0);
++              }
++
++              if(!strncmp(scratch, key, strlen(key))) 
++                      return(1);
++
++              do {
++                      n = os_read_file(fd, &c, sizeof(c));
++                      if(n != sizeof(c)){
++                              printk("Failed to find newline in "
++                                     "/proc/cpuinfo, err = %d\n", -n);
++                              return(0);
++                      }
++              } while(c != '\n');
++      }
++      return(0);
++}
++
++int cpu_feature(char *what, char *buf, int len)
++{
++      int fd, ret = 0;
++
++      fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
++      if(fd < 0){
++              printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
++              return(0);
++      }
++
++      if(!find_cpuinfo_line(fd, what, buf, len)){
++              printk("Couldn't find '%s' line in /proc/cpuinfo\n", what);
++              goto out_close;
++      }
++
++      token(fd, buf, len, '\n');
++      ret = 1;
++
++ out_close:
++      os_close_file(fd);
++      return(ret);
++}
++
++static int check_cpu_flag(char *feature, int *have_it)
++{
++      char buf[MAXTOKEN], c;
++      int fd, len = sizeof(buf)/sizeof(buf[0]);
++
++      printk("Checking for host processor %s support...", feature);
++      fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
++      if(fd < 0){
++              printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
++              return(0);
++      }
++
++      *have_it = 0;
++      if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0])))
++              goto out;
++
++      c = token(fd, buf, len - 1, ' ');
++      if(c < 0) goto out;
++      else if(c != ' '){
++              printk("Failed to find ' ' in /proc/cpuinfo\n");
++              goto out;
++      }
++
++      while(1){
++              c = token(fd, buf, len - 1, ' ');
++              if(c < 0) goto out;
++              else if(c == '\n') break;
++
++              if(!strcmp(buf, feature)){
++                      *have_it = 1;
++                      goto out;
++              }
++      }
++ out:
++      if(*have_it == 0) printk("No\n");
++      else if(*have_it == 1) printk("Yes\n");
++      os_close_file(fd);
++      return(1);
++}
++
++#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems
++       * for some people.
++       */
++static void disable_lcall(void)
++{
++      struct modify_ldt_ldt_s ldt;
++      int err;
++
++      bzero(&ldt, sizeof(ldt));
++      ldt.entry_number = 7;
++      ldt.base_addr = 0;
++      ldt.limit = 0;
++      err = modify_ldt(1, &ldt, sizeof(ldt));
++      if(err)
++              printk("Failed to disable lcall7 - errno = %d\n", errno);
++}
++#endif
++
++void arch_init_thread(void)
++{
++#if 0
++      disable_lcall();
++#endif
++}
++
++void arch_check_bugs(void)
++{
++      int have_it;
++
++      if(os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0){
++              printk("/proc/cpuinfo not available - skipping CPU capability "
++                     "checks\n");
++              return;
++      }
++      if(check_cpu_flag("cmov", &have_it)) 
++              host_has_cmov = have_it;
++      if(check_cpu_flag("xmm", &have_it)) 
++              host_has_xmm = have_it;
++}
++
++int arch_handle_signal(int sig, union uml_pt_regs *regs)
++{
++      unsigned char tmp[2];
++
++      /* This is testing for a cmov (0x0f 0x4x) instruction causing a
++       * SIGILL in init.
++       */
++      if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0);
++
++      if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
++              panic("SIGILL in init, could not read instructions!\n");
++      if((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
++              return(0);
++
++      if(host_has_cmov == 0)
++              panic("SIGILL caused by cmov, which this processor doesn't "
++                    "implement, boot a filesystem compiled for older "
++                    "processors");
++      else if(host_has_cmov == 1)
++              panic("SIGILL caused by cmov, which this processor claims to "
++                    "implement");
++      else if(host_has_cmov == -1)
++              panic("SIGILL caused by cmov, couldn't tell if this processor "
++                    "implements it, boot a filesystem compiled for older "
++                    "processors");
++      else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/sys-i386/checksum.S
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/checksum.S      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/checksum.S   2005-05-03 22:28:14.582393352 +0300
+@@ -0,0 +1,460 @@
++/*
++ * INET               An implementation of the TCP/IP protocol suite for the LINUX
++ *            operating system.  INET is implemented using the  BSD Socket
++ *            interface as the means of communication with the user level.
++ *
++ *            IP/TCP/UDP checksumming routines
++ *
++ * Authors:   Jorge Cwik, <jorge@laser.satlink.net>
++ *            Arnt Gulbrandsen, <agulbra@nvg.unit.no>
++ *            Tom May, <ftom@netcom.com>
++ *              Pentium Pro/II routines:
++ *              Alexander Kjeldaas <astor@guardian.no>
++ *              Finn Arne Gangstad <finnag@guardian.no>
++ *            Lots of code moved from tcp.c and ip.c; see those files
++ *            for more names.
++ *
++ * Changes:     Ingo Molnar, converted csum_partial_copy() to 2.1 exception
++ *                         handling.
++ *            Andi Kleen,  add zeroing on error
++ *                   converted to pure assembler
++ *
++ *            This program is free software; you can redistribute it and/or
++ *            modify it under the terms of the GNU General Public License
++ *            as published by the Free Software Foundation; either version
++ *            2 of the License, or (at your option) any later version.
++ */
++
++#include <linux/config.h>
++#include <asm/errno.h>
++                              
++/*
++ * computes a partial checksum, e.g. for TCP/UDP fragments
++ */
++
++/*    
++unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
++ */
++              
++.text
++.align 4
++.globl arch_csum_partial                                                              
++              
++#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
++
++        /*            
++         * Experiments with Ethernet and SLIP connections show that buff
++         * is aligned on either a 2-byte or 4-byte boundary.  We get at
++         * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
++         * Fortunately, it is easy to convert 2-byte alignment to 4-byte
++         * alignment for the unrolled loop.
++         */           
++arch_csum_partial:    
++      pushl %esi
++      pushl %ebx
++      movl 20(%esp),%eax      # Function arg: unsigned int sum
++      movl 16(%esp),%ecx      # Function arg: int len
++      movl 12(%esp),%esi      # Function arg: unsigned char *buff
++      testl $2, %esi          # Check alignment.
++      jz 2f                   # Jump if alignment is ok.
++      subl $2, %ecx           # Alignment uses up two bytes.
++      jae 1f                  # Jump if we had at least two bytes.
++      addl $2, %ecx           # ecx was < 2.  Deal with it.
++      jmp 4f
++1:    movw (%esi), %bx
++      addl $2, %esi
++      addw %bx, %ax
++      adcl $0, %eax
++2:
++      movl %ecx, %edx
++      shrl $5, %ecx
++      jz 2f
++      testl %esi, %esi
++1:    movl (%esi), %ebx
++      adcl %ebx, %eax
++      movl 4(%esi), %ebx
++      adcl %ebx, %eax
++      movl 8(%esi), %ebx
++      adcl %ebx, %eax
++      movl 12(%esi), %ebx
++      adcl %ebx, %eax
++      movl 16(%esi), %ebx
++      adcl %ebx, %eax
++      movl 20(%esi), %ebx
++      adcl %ebx, %eax
++      movl 24(%esi), %ebx
++      adcl %ebx, %eax
++      movl 28(%esi), %ebx
++      adcl %ebx, %eax
++      lea 32(%esi), %esi
++      dec %ecx
++      jne 1b
++      adcl $0, %eax
++2:    movl %edx, %ecx
++      andl $0x1c, %edx
++      je 4f
++      shrl $2, %edx           # This clears CF
++3:    adcl (%esi), %eax
++      lea 4(%esi), %esi
++      dec %edx
++      jne 3b
++      adcl $0, %eax
++4:    andl $3, %ecx
++      jz 7f
++      cmpl $2, %ecx
++      jb 5f
++      movw (%esi),%cx
++      leal 2(%esi),%esi
++      je 6f
++      shll $16,%ecx
++5:    movb (%esi),%cl
++6:    addl %ecx,%eax
++      adcl $0, %eax 
++7:    
++      popl %ebx
++      popl %esi
++      ret
++
++#else
++
++/* Version for PentiumII/PPro */
++
++arch_csum_partial:
++      pushl %esi
++      pushl %ebx
++      movl 20(%esp),%eax      # Function arg: unsigned int sum
++      movl 16(%esp),%ecx      # Function arg: int len
++      movl 12(%esp),%esi      # Function arg: const unsigned char *buf
++
++      testl $2, %esi         
++      jnz 30f                 
++10:
++      movl %ecx, %edx
++      movl %ecx, %ebx
++      andl $0x7c, %ebx
++      shrl $7, %ecx
++      addl %ebx,%esi
++      shrl $2, %ebx  
++      negl %ebx
++      lea 45f(%ebx,%ebx,2), %ebx
++      testl %esi, %esi
++      jmp *%ebx
++
++      # Handle 2-byte-aligned regions
++20:   addw (%esi), %ax
++      lea 2(%esi), %esi
++      adcl $0, %eax
++      jmp 10b
++
++30:   subl $2, %ecx          
++      ja 20b                 
++      je 32f
++      movzbl (%esi),%ebx      # csumming 1 byte, 2-aligned
++      addl %ebx, %eax
++      adcl $0, %eax
++      jmp 80f
++32:
++      addw (%esi), %ax        # csumming 2 bytes, 2-aligned
++      adcl $0, %eax
++      jmp 80f
++
++40: 
++      addl -128(%esi), %eax
++      adcl -124(%esi), %eax
++      adcl -120(%esi), %eax
++      adcl -116(%esi), %eax   
++      adcl -112(%esi), %eax   
++      adcl -108(%esi), %eax
++      adcl -104(%esi), %eax
++      adcl -100(%esi), %eax
++      adcl -96(%esi), %eax
++      adcl -92(%esi), %eax
++      adcl -88(%esi), %eax
++      adcl -84(%esi), %eax
++      adcl -80(%esi), %eax
++      adcl -76(%esi), %eax
++      adcl -72(%esi), %eax
++      adcl -68(%esi), %eax
++      adcl -64(%esi), %eax     
++      adcl -60(%esi), %eax     
++      adcl -56(%esi), %eax     
++      adcl -52(%esi), %eax   
++      adcl -48(%esi), %eax   
++      adcl -44(%esi), %eax
++      adcl -40(%esi), %eax
++      adcl -36(%esi), %eax
++      adcl -32(%esi), %eax
++      adcl -28(%esi), %eax
++      adcl -24(%esi), %eax
++      adcl -20(%esi), %eax
++      adcl -16(%esi), %eax
++      adcl -12(%esi), %eax
++      adcl -8(%esi), %eax
++      adcl -4(%esi), %eax
++45:
++      lea 128(%esi), %esi
++      adcl $0, %eax
++      dec %ecx
++      jge 40b
++      movl %edx, %ecx
++50:   andl $3, %ecx
++      jz 80f
++
++      # Handle the last 1-3 bytes without jumping
++      notl %ecx               # 1->2, 2->1, 3->0, higher bits are masked
++      movl $0xffffff,%ebx     # by the shll and shrl instructions
++      shll $3,%ecx
++      shrl %cl,%ebx
++      andl -128(%esi),%ebx    # esi is 4-aligned so should be ok
++      addl %ebx,%eax
++      adcl $0,%eax
++80: 
++      popl %ebx
++      popl %esi
++      ret
++                              
++#endif
++
++/*
++unsigned int csum_partial_copy_generic (const char *src, char *dst,
++                                int len, int sum, int *src_err_ptr, int *dst_err_ptr)
++ */ 
++
++/*
++ * Copy from ds while checksumming, otherwise like csum_partial
++ *
++ * The macros SRC and DST specify the type of access for the instruction.
++ * thus we can call a custom exception handler for all access types.
++ *
++ * FIXME: could someone double-check whether I haven't mixed up some SRC and
++ *      DST definitions? It's damn hard to trigger all cases.  I hope I got
++ *      them all but there's no guarantee.
++ */
++
++#define SRC(y...)                     \
++      9999: y;                        \
++      .section __ex_table, "a";       \
++      .long 9999b, 6001f      ;       \
++      .previous
++
++#define DST(y...)                     \
++      9999: y;                        \
++      .section __ex_table, "a";       \
++      .long 9999b, 6002f      ;       \
++      .previous
++
++.align 4
++.globl csum_partial_copy_generic_i386
++                              
++#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
++
++#define ARGBASE 16            
++#define FP            12
++              
++csum_partial_copy_generic_i386:
++      subl  $4,%esp   
++      pushl %edi
++      pushl %esi
++      pushl %ebx
++      movl ARGBASE+16(%esp),%eax      # sum
++      movl ARGBASE+12(%esp),%ecx      # len
++      movl ARGBASE+4(%esp),%esi       # src
++      movl ARGBASE+8(%esp),%edi       # dst
++
++      testl $2, %edi                  # Check alignment. 
++      jz 2f                           # Jump if alignment is ok.
++      subl $2, %ecx                   # Alignment uses up two bytes.
++      jae 1f                          # Jump if we had at least two bytes.
++      addl $2, %ecx                   # ecx was < 2.  Deal with it.
++      jmp 4f
++SRC(1:        movw (%esi), %bx        )
++      addl $2, %esi
++DST(  movw %bx, (%edi)        )
++      addl $2, %edi
++      addw %bx, %ax   
++      adcl $0, %eax
++2:
++      movl %ecx, FP(%esp)
++      shrl $5, %ecx
++      jz 2f
++      testl %esi, %esi
++SRC(1:        movl (%esi), %ebx       )
++SRC(  movl 4(%esi), %edx      )
++      adcl %ebx, %eax
++DST(  movl %ebx, (%edi)       )
++      adcl %edx, %eax
++DST(  movl %edx, 4(%edi)      )
++
++SRC(  movl 8(%esi), %ebx      )
++SRC(  movl 12(%esi), %edx     )
++      adcl %ebx, %eax
++DST(  movl %ebx, 8(%edi)      )
++      adcl %edx, %eax
++DST(  movl %edx, 12(%edi)     )
++
++SRC(  movl 16(%esi), %ebx     )
++SRC(  movl 20(%esi), %edx     )
++      adcl %ebx, %eax
++DST(  movl %ebx, 16(%edi)     )
++      adcl %edx, %eax
++DST(  movl %edx, 20(%edi)     )
++
++SRC(  movl 24(%esi), %ebx     )
++SRC(  movl 28(%esi), %edx     )
++      adcl %ebx, %eax
++DST(  movl %ebx, 24(%edi)     )
++      adcl %edx, %eax
++DST(  movl %edx, 28(%edi)     )
++
++      lea 32(%esi), %esi
++      lea 32(%edi), %edi
++      dec %ecx
++      jne 1b
++      adcl $0, %eax
++2:    movl FP(%esp), %edx
++      movl %edx, %ecx
++      andl $0x1c, %edx
++      je 4f
++      shrl $2, %edx                   # This clears CF
++SRC(3:        movl (%esi), %ebx       )
++      adcl %ebx, %eax
++DST(  movl %ebx, (%edi)       )
++      lea 4(%esi), %esi
++      lea 4(%edi), %edi
++      dec %edx
++      jne 3b
++      adcl $0, %eax
++4:    andl $3, %ecx
++      jz 7f
++      cmpl $2, %ecx
++      jb 5f
++SRC(  movw (%esi), %cx        )
++      leal 2(%esi), %esi
++DST(  movw %cx, (%edi)        )
++      leal 2(%edi), %edi
++      je 6f
++      shll $16,%ecx
++SRC(5:        movb (%esi), %cl        )
++DST(  movb %cl, (%edi)        )
++6:    addl %ecx, %eax
++      adcl $0, %eax
++7:
++5000:
++
++# Exception handler:
++.section .fixup, "ax"                                                 
++
++6001:
++      movl ARGBASE+20(%esp), %ebx     # src_err_ptr
++      movl $-EFAULT, (%ebx)
++
++      # zero the complete destination - computing the rest
++      # is too much work 
++      movl ARGBASE+8(%esp), %edi      # dst
++      movl ARGBASE+12(%esp), %ecx     # len
++      xorl %eax,%eax
++      rep ; stosb
++
++      jmp 5000b
++
++6002:
++      movl ARGBASE+24(%esp), %ebx     # dst_err_ptr
++      movl $-EFAULT,(%ebx)
++      jmp 5000b
++
++.previous
++
++      popl %ebx
++      popl %esi
++      popl %edi
++      popl %ecx                       # equivalent to addl $4,%esp
++      ret     
++
++#else
++
++/* Version for PentiumII/PPro */
++
++#define ROUND1(x) \
++      SRC(movl x(%esi), %ebx  )       ;       \
++      addl %ebx, %eax                 ;       \
++      DST(movl %ebx, x(%edi)  )       ; 
++
++#define ROUND(x) \
++      SRC(movl x(%esi), %ebx  )       ;       \
++      adcl %ebx, %eax                 ;       \
++      DST(movl %ebx, x(%edi)  )       ;
++
++#define ARGBASE 12
++              
++csum_partial_copy_generic_i386:
++      pushl %ebx
++      pushl %edi
++      pushl %esi
++      movl ARGBASE+4(%esp),%esi       #src
++      movl ARGBASE+8(%esp),%edi       #dst    
++      movl ARGBASE+12(%esp),%ecx      #len
++      movl ARGBASE+16(%esp),%eax      #sum
++#     movl %ecx, %edx  
++      movl %ecx, %ebx  
++      movl %esi, %edx
++      shrl $6, %ecx     
++      andl $0x3c, %ebx  
++      negl %ebx
++      subl %ebx, %esi  
++      subl %ebx, %edi  
++      lea  -1(%esi),%edx
++      andl $-32,%edx
++      lea 3f(%ebx,%ebx), %ebx
++      testl %esi, %esi 
++      jmp *%ebx
++1:    addl $64,%esi
++      addl $64,%edi 
++      SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl)
++      ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)    
++      ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)    
++      ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)    
++      ROUND (-16) ROUND(-12) ROUND(-8)  ROUND(-4)     
++3:    adcl $0,%eax
++      addl $64, %edx
++      dec %ecx
++      jge 1b
++4:    movl ARGBASE+12(%esp),%edx      #len
++      andl $3, %edx
++      jz 7f
++      cmpl $2, %edx
++      jb 5f
++SRC(  movw (%esi), %dx         )
++      leal 2(%esi), %esi
++DST(  movw %dx, (%edi)         )
++      leal 2(%edi), %edi
++      je 6f
++      shll $16,%edx
++5:
++SRC(  movb (%esi), %dl         )
++DST(  movb %dl, (%edi)         )
++6:    addl %edx, %eax
++      adcl $0, %eax
++7:
++.section .fixup, "ax"
++6001: movl    ARGBASE+20(%esp), %ebx  # src_err_ptr   
++      movl $-EFAULT, (%ebx)
++      # zero the complete destination (computing the rest is too much work)
++      movl ARGBASE+8(%esp),%edi       # dst
++      movl ARGBASE+12(%esp),%ecx      # len
++      xorl %eax,%eax
++      rep; stosb
++      jmp 7b
++6002: movl ARGBASE+24(%esp), %ebx     # dst_err_ptr
++      movl $-EFAULT, (%ebx)
++      jmp  7b                 
++.previous                             
++
++      popl %esi
++      popl %edi
++      popl %ebx
++      ret
++                              
++#undef ROUND
++#undef ROUND1         
++              
++#endif
+Index: linux-2.4.29/arch/um/sys-i386/fault.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/fault.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/fault.c      2005-05-03 22:28:14.583393200 +0300
+@@ -0,0 +1,34 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <signal.h>
++#include "sysdep/ptrace.h"
++#include "sysdep/sigcontext.h"
++
++extern unsigned long search_exception_table(unsigned long addr);
++
++int arch_fixup(unsigned long address, void *sc_ptr)
++{
++      struct sigcontext *sc = sc_ptr;
++      unsigned long fixup;
++
++      fixup = search_exception_table(address);
++      if(fixup != 0){
++              sc->eip = fixup;
++              return(1);
++      }
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/sys-i386/ksyms.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/ksyms.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/ksyms.c      2005-05-03 22:28:14.584393048 +0300
+@@ -0,0 +1,17 @@
++#include "linux/module.h"
++#include "linux/in6.h"
++#include "linux/rwsem.h"
++#include "asm/byteorder.h"
++#include "asm/semaphore.h"
++#include "asm/uaccess.h"
++#include "asm/checksum.h"
++#include "asm/errno.h"
++
++EXPORT_SYMBOL(__down_failed);
++EXPORT_SYMBOL(__down_failed_interruptible);
++EXPORT_SYMBOL(__down_failed_trylock);
++EXPORT_SYMBOL(__up_wakeup);
++
++/* Networking helper routines. */
++EXPORT_SYMBOL(csum_partial_copy_from);
++EXPORT_SYMBOL(csum_partial_copy_to);
+Index: linux-2.4.29/arch/um/sys-i386/ldt.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/ldt.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/ldt.c        2005-05-03 22:28:14.585392896 +0300
+@@ -0,0 +1,94 @@
++/*
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/config.h"
++#include "linux/slab.h"
++#include "asm/uaccess.h"
++#include "asm/ptrace.h"
++#include "choose-mode.h"
++#include "kern.h"
++
++#ifdef CONFIG_MODE_TT
++extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
++
++/* XXX this needs copy_to_user and copy_from_user */
++
++int sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount)
++{
++      if(verify_area(VERIFY_READ, ptr, bytecount)) return(-EFAULT);
++      return(modify_ldt(func, ptr, bytecount));
++}
++#endif
++
++#ifdef CONFIG_MODE_SKAS
++extern int userspace_pid;
++
++int sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount)
++{
++      struct ptrace_ldt ldt;
++      void *buf;
++      int res, n;
++
++      buf = kmalloc(bytecount, GFP_KERNEL);
++      if(buf == NULL)
++              return(-ENOMEM);
++
++      res = 0;
++
++      switch(func){
++      case 1:
++      case 0x11:
++              res = copy_from_user(buf, ptr, bytecount);
++              break;
++      }
++
++      if(res != 0){
++              res = -EFAULT;
++              goto out;
++      }
++
++      ldt = ((struct ptrace_ldt) { .func      = func,
++                                   .ptr       = buf,
++                                   .bytecount = bytecount });
++      res = ptrace(PTRACE_LDT, userspace_pid, 0, (unsigned long) &ldt);
++      if(res < 0)
++              goto out;
++
++      switch(func){
++      case 0:
++      case 2:
++              n = res;
++              res = copy_to_user(ptr, buf, n);
++              if(res != 0)
++                      res = -EFAULT;
++              else 
++                      res = n;
++              break;
++      }
++
++ out:
++      kfree(buf);
++      return(res);
++}
++#endif
++
++int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
++{
++      return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func, 
++                              ptr, bytecount));
++}
++
++
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/sys-i386/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/Makefile     2005-05-03 22:28:14.586392744 +0300
+@@ -0,0 +1,46 @@
++# 
++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++O_TARGET = built-in.o
++
++obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o ptrace.o \
++      ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o
++export-objs = ksyms.o
++
++USER_OBJS = bugs.o ptrace_user.o sigcontext.o fault.o
++
++SYMLINKS = semaphore.c extable.c
++
++semaphore.c-dir = kernel
++extable.c-dir = mm
++
++include $(TOPDIR)/Rules.make
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
++
++define make_link
++      -rm -f $1
++      ln -sf $(TOPDIR)/arch/i386/$($1-dir)/$1 $1
++endef
++
++$(SYMLINKS): 
++      $(call make_link,$@)
++
++clean:
++      $(MAKE) -C util clean
++      rm -f $(SYMLINKS)
++
++fastdep:
++
++dep:
++
++archmrproper:
++
++archclean:
++
++archdep:
++
++modules:
+Index: linux-2.4.29/arch/um/sys-i386/ptrace.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/ptrace.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/ptrace.c     2005-05-03 22:28:14.588392440 +0300
+@@ -0,0 +1,367 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "asm/elf.h"
++#include "asm/ptrace.h"
++#include "asm/uaccess.h"
++#include "asm/unistd.h"
++#include "ptrace_user.h"
++#include "sysdep/sigcontext.h"
++#include "sysdep/sc.h"
++
++void arch_switch(void)
++{
++      update_debugregs(current->thread.arch.debugregs_seq);
++}
++
++int is_syscall(unsigned long addr)
++{
++      unsigned short instr;
++      int n;
++
++      n = copy_from_user(&instr, (void *) addr, sizeof(instr));
++      if(n){
++              printk("is_syscall : failed to read instruction from 0x%lx\n", 
++                     addr);
++              return(0);
++      }
++      /* int 0x80 or sysenter */
++      return((instr == 0x80cd) || (instr == 0x340f));
++}
++
++/* determines which flags the user has access to. */
++/* 1 = access 0 = no access */
++#define FLAG_MASK 0x00044dd5
++
++int putreg(struct task_struct *child, int regno, unsigned long value)
++{
++      regno >>= 2;
++      switch (regno) {
++      case FS:
++              if (value && (value & 3) != 3)
++                      return -EIO;
++              PT_REGS_FS(&child->thread.regs) = value;
++              return 0;
++      case GS:
++              if (value && (value & 3) != 3)
++                      return -EIO;
++              PT_REGS_GS(&child->thread.regs) = value;
++              return 0;
++      case DS:
++      case ES:
++              if (value && (value & 3) != 3)
++                      return -EIO;
++              value &= 0xffff;
++              break;
++      case SS:
++      case CS:
++              if ((value & 3) != 3)
++                      return -EIO;
++              value &= 0xffff;
++              break;
++      case EFL:
++              value &= FLAG_MASK;
++              value |= PT_REGS_EFLAGS(&child->thread.regs);
++              break;
++      }
++      PT_REGS_SET(&child->thread.regs, regno, value);
++      return 0;
++}
++
++unsigned long getreg(struct task_struct *child, int regno)
++{
++      unsigned long retval = ~0UL;
++
++      regno >>= 2;
++      switch (regno) {
++      case FS:
++      case GS:
++      case DS:
++      case ES:
++      case SS:
++      case CS:
++              retval = 0xffff;
++              /* fall through */
++      default:
++              retval &= PT_REG(&child->thread.regs, regno);
++      }
++      return retval;
++}
++
++struct i387_fxsave_struct {
++      unsigned short  cwd;
++      unsigned short  swd;
++      unsigned short  twd;
++      unsigned short  fop;
++      long    fip;
++      long    fcs;
++      long    foo;
++      long    fos;
++      long    mxcsr;
++      long    reserved;
++      long    st_space[32];   /* 8*16 bytes for each FP-reg = 128 bytes */
++      long    xmm_space[32];  /* 8*16 bytes for each XMM-reg = 128 bytes */
++      long    padding[56];
++};
++
++/*
++ * FPU tag word conversions.
++ */
++
++static inline unsigned short twd_i387_to_fxsr( unsigned short twd )
++{
++      unsigned int tmp; /* to avoid 16 bit prefixes in the code */
++ 
++      /* Transform each pair of bits into 01 (valid) or 00 (empty) */
++        tmp = ~twd;
++        tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
++        /* and move the valid bits to the lower byte. */
++        tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
++        tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
++        tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
++        return tmp;
++}
++
++static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave )
++{
++      struct _fpxreg *st = NULL;
++      unsigned long twd = (unsigned long) fxsave->twd;
++      unsigned long tag;
++      unsigned long ret = 0xffff0000;
++      int i;
++
++#define FPREG_ADDR(f, n)      ((char *)&(f)->st_space + (n) * 16);
++
++      for ( i = 0 ; i < 8 ; i++ ) {
++              if ( twd & 0x1 ) {
++                      st = (struct _fpxreg *) FPREG_ADDR( fxsave, i );
++
++                      switch ( st->exponent & 0x7fff ) {
++                      case 0x7fff:
++                              tag = 2;                /* Special */
++                              break;
++                      case 0x0000:
++                              if ( !st->significand[0] &&
++                                   !st->significand[1] &&
++                                   !st->significand[2] &&
++                                   !st->significand[3] ) {
++                                      tag = 1;        /* Zero */
++                              } else {
++                                      tag = 2;        /* Special */
++                              }
++                              break;
++                      default:
++                              if ( st->significand[3] & 0x8000 ) {
++                                      tag = 0;        /* Valid */
++                              } else {
++                                      tag = 2;        /* Special */
++                              }
++                              break;
++                      }
++              } else {
++                      tag = 3;                        /* Empty */
++              }
++              ret |= (tag << (2 * i));
++              twd = twd >> 1;
++      }
++      return ret;
++}
++
++/*
++ * FXSR floating point environment conversions.
++ */
++
++#ifdef CONFIG_MODE_TT
++static inline int convert_fxsr_to_user_tt(struct _fpstate *buf, 
++                                        struct pt_regs *regs)
++{
++      struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
++      unsigned long env[7];
++      struct _fpreg *to;
++      struct _fpxreg *from;
++      int i;
++
++      env[0] = (unsigned long)fxsave->cwd | 0xffff0000;
++      env[1] = (unsigned long)fxsave->swd | 0xffff0000;
++      env[2] = twd_fxsr_to_i387(fxsave);
++      env[3] = fxsave->fip;
++      env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
++      env[5] = fxsave->foo;
++      env[6] = fxsave->fos;
++
++      if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
++              return 1;
++
++      to = &buf->_st[0];
++      from = (struct _fpxreg *) &fxsave->st_space[0];
++      for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
++              if ( __copy_to_user( to, from, sizeof(*to) ) )
++                      return 1;
++      }
++      return 0;
++}
++#endif
++
++static inline int convert_fxsr_to_user(struct _fpstate *buf, 
++                                     struct pt_regs *regs)
++{
++      return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0));
++}
++
++#ifdef CONFIG_MODE_TT
++static inline int convert_fxsr_from_user_tt(struct pt_regs *regs,
++                                          struct _fpstate *buf)
++{
++      struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
++      unsigned long env[7];
++      struct _fpxreg *to;
++      struct _fpreg *from;
++      int i;
++
++      if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
++              return 1;
++
++      fxsave->cwd = (unsigned short)(env[0] & 0xffff);
++      fxsave->swd = (unsigned short)(env[1] & 0xffff);
++      fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
++      fxsave->fip = env[3];
++      fxsave->fop = (unsigned short)((env[4] & 0xffff0000) >> 16);
++      fxsave->fcs = (env[4] & 0xffff);
++      fxsave->foo = env[5];
++      fxsave->fos = env[6];
++
++      to = (struct _fpxreg *) &fxsave->st_space[0];
++      from = &buf->_st[0];
++      for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
++              if ( __copy_from_user( to, from, sizeof(*from) ) )
++                      return 1;
++      }
++      return 0;
++}
++#endif
++
++static inline int convert_fxsr_from_user(struct pt_regs *regs, 
++                                       struct _fpstate *buf)
++{
++      return(CHOOSE_MODE(convert_fxsr_from_user_tt(regs, buf), 0));
++}
++
++int get_fpregs(unsigned long buf, struct task_struct *child)
++{
++      int err;
++
++      err = convert_fxsr_to_user((struct _fpstate *) buf, 
++                                 &child->thread.regs);
++      if(err) return(-EFAULT);
++      else return(0);
++}
++
++int set_fpregs(unsigned long buf, struct task_struct *child)
++{
++      int err;
++
++      err = convert_fxsr_from_user(&child->thread.regs, 
++                                   (struct _fpstate *) buf);
++      if(err) return(-EFAULT);
++      else return(0);
++}
++
++#ifdef CONFIG_MODE_TT
++int get_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
++{
++      struct pt_regs *regs = &tsk->thread.regs;
++      struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
++      int err;
++
++      err = __copy_to_user((void *) buf, fxsave,
++                           sizeof(struct user_fxsr_struct));
++      if(err) return -EFAULT;
++      else return 0;
++}
++#endif
++
++int get_fpxregs(unsigned long buf, struct task_struct *tsk)
++{
++      return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0));
++}
++
++#ifdef CONFIG_MODE_TT
++int set_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
++{
++      struct pt_regs *regs = &tsk->thread.regs;
++      struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
++      int err;
++
++      err = __copy_from_user(fxsave, (void *) buf,
++                             sizeof(struct user_fxsr_struct) );
++      if(err) return -EFAULT;
++      else return 0;
++}
++#endif
++
++int set_fpxregs(unsigned long buf, struct task_struct *tsk)
++{
++      return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 0));
++}
++
++#ifdef notdef
++int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
++{
++      fpu->cwd = (((SC_FP_CW(PT_REGS_SC(regs)) & 0xffff) << 16) |
++                  (SC_FP_SW(PT_REGS_SC(regs)) & 0xffff));
++      fpu->swd = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
++      fpu->twd = SC_FP_IPOFF(PT_REGS_SC(regs));
++      fpu->fip = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
++      fpu->fcs = SC_FP_DATAOFF(PT_REGS_SC(regs));
++      fpu->foo = SC_FP_DATASEL(PT_REGS_SC(regs));
++      fpu->fos = 0;
++      memcpy(fpu->st_space, (void *) SC_FP_ST(PT_REGS_SC(regs)),
++             sizeof(fpu->st_space));
++      return(1);
++}
++#endif
++
++#ifdef CONFIG_MODE_TT
++static inline void copy_fpu_fxsave_tt(struct pt_regs *regs,
++                                    struct user_i387_struct *buf)
++{
++      struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs));
++      unsigned short *to;
++      unsigned short *from;
++      int i;
++
++      memcpy( buf, fpu, 7 * sizeof(long) );
++
++      to = (unsigned short *) &buf->st_space[0];
++      from = (unsigned short *) &fpu->st_space[0];
++      for ( i = 0 ; i < 8 ; i++, to += 5, from += 8 ) {
++              memcpy( to, from, 5 * sizeof(unsigned short) );
++      }
++}
++#endif
++
++static inline void copy_fpu_fxsave(struct pt_regs *regs,
++                                 struct user_i387_struct *buf)
++{
++      (void) CHOOSE_MODE(copy_fpu_fxsave_tt(regs, buf), 0);
++}
++
++int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu )
++{
++      copy_fpu_fxsave(regs, (struct user_i387_struct *) fpu);
++      return(1);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/sys-i386/ptrace_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/ptrace_user.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/ptrace_user.c        2005-05-03 22:28:14.589392288 +0300
+@@ -0,0 +1,118 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stdio.h>
++#include <errno.h>
++#include <unistd.h>
++#include <linux/stddef.h>
++#include <sys/ptrace.h>
++#include <asm/ptrace.h>
++#include <asm/user.h>
++#include "kern_util.h"
++#include "sysdep/thread.h"
++#include "user.h"
++#include "os.h"
++
++int ptrace_getregs(long pid, unsigned long *regs_out)
++{
++      return(ptrace(PTRACE_GETREGS, pid, 0, regs_out));
++}
++
++int ptrace_setregs(long pid, unsigned long *regs)
++{
++      return(ptrace(PTRACE_SETREGS, pid, 0, regs));
++}
++
++int ptrace_getfpregs(long pid, unsigned long *regs)
++{
++      return(ptrace(PTRACE_GETFPREGS, pid, 0, regs));
++}
++
++static void write_debugregs(int pid, unsigned long *regs)
++{
++      struct user *dummy;
++      int nregs, i;
++
++      dummy = NULL;
++      nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
++      for(i = 0; i < nregs; i++){
++              if((i == 4) || (i == 5)) continue;
++              if(ptrace(PTRACE_POKEUSER, pid, &dummy->u_debugreg[i],
++                        regs[i]) < 0)
++                      printk("write_debugregs - ptrace failed on "
++                             "register %d, value = 0x%x, errno = %d\n", i, 
++                             regs[i], errno);
++      }
++}
++
++static void read_debugregs(int pid, unsigned long *regs)
++{
++      struct user *dummy;
++      int nregs, i;
++
++      dummy = NULL;
++      nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
++      for(i = 0; i < nregs; i++){
++              regs[i] = ptrace(PTRACE_PEEKUSER, pid, 
++                               &dummy->u_debugreg[i], 0);
++      }
++}
++
++/* Accessed only by the tracing thread */
++static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 };
++static int debugregs_seq = 0;
++
++void arch_enter_kernel(void *task, int pid)
++{
++      read_debugregs(pid, TASK_DEBUGREGS(task));
++      write_debugregs(pid, kernel_debugregs);
++}
++
++void arch_leave_kernel(void *task, int pid)
++{
++      read_debugregs(pid, kernel_debugregs);
++      write_debugregs(pid, TASK_DEBUGREGS(task));
++}
++
++void ptrace_pokeuser(unsigned long addr, unsigned long data)
++{
++      if((addr < offsetof(struct user, u_debugreg[0])) ||
++         (addr > offsetof(struct user, u_debugreg[7])))
++              return;
++      addr -= offsetof(struct user, u_debugreg[0]);
++      addr = addr >> 2;
++      if(kernel_debugregs[addr] == data) return;
++
++      kernel_debugregs[addr] = data;
++      debugregs_seq++;
++}
++
++static void update_debugregs_cb(void *arg)
++{
++      int pid = *((int *) arg);
++
++      write_debugregs(pid, kernel_debugregs);
++}
++
++void update_debugregs(int seq)
++{
++      int me;
++
++      if(seq == debugregs_seq) return;
++
++      me = os_getpid();
++      initial_thread_cb(update_debugregs_cb, &me);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/sys-i386/sigcontext.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/sigcontext.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/sigcontext.c 2005-05-03 22:28:14.590392136 +0300
+@@ -0,0 +1,80 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <stddef.h>
++#include <string.h>
++#include <asm/ptrace.h>
++#include <asm/sigcontext.h>
++#include "sysdep/ptrace.h"
++#include "kern_util.h"
++#include "frame_user.h"
++
++int sc_size(void *data)
++{
++      struct arch_frame_data *arch = data;
++
++      return(sizeof(struct sigcontext) + arch->fpstate_size);
++}
++
++void sc_to_sc(void *to_ptr, void *from_ptr)
++{
++      struct sigcontext *to = to_ptr, *from = from_ptr;
++      int size = sizeof(*to) + signal_frame_sc.common.arch.fpstate_size;
++
++      memcpy(to, from, size);
++      if(from->fpstate != NULL) to->fpstate = (struct _fpstate *) (to + 1);
++}
++
++unsigned long *sc_sigmask(void *sc_ptr)
++{
++      struct sigcontext *sc = sc_ptr;
++
++      return(&sc->oldmask);
++}
++
++int sc_get_fpregs(unsigned long buf, void *sc_ptr)
++{
++      struct sigcontext *sc = sc_ptr;
++      struct _fpstate *from = sc->fpstate, *to = (struct _fpstate *) buf;
++      int err = 0;
++
++      if(from == NULL){
++              err |= clear_user_proc(&to->cw, sizeof(to->cw));
++              err |= clear_user_proc(&to->sw, sizeof(to->sw));
++              err |= clear_user_proc(&to->tag, sizeof(to->tag));
++              err |= clear_user_proc(&to->ipoff, sizeof(to->ipoff));
++              err |= clear_user_proc(&to->cssel, sizeof(to->cssel));
++              err |= clear_user_proc(&to->dataoff, sizeof(to->dataoff));
++              err |= clear_user_proc(&to->datasel, sizeof(to->datasel));
++              err |= clear_user_proc(&to->_st, sizeof(to->_st));
++      }
++      else {
++              err |= copy_to_user_proc(&to->cw, &from->cw, sizeof(to->cw));
++              err |= copy_to_user_proc(&to->sw, &from->sw, sizeof(to->sw));
++              err |= copy_to_user_proc(&to->tag, &from->tag, 
++                                       sizeof(to->tag));
++              err |= copy_to_user_proc(&to->ipoff, &from->ipoff, 
++                                       sizeof(to->ipoff));
++              err |= copy_to_user_proc(&to->cssel,& from->cssel, 
++                                       sizeof(to->cssel));
++              err |= copy_to_user_proc(&to->dataoff, &from->dataoff, 
++                                  sizeof(to->dataoff));
++              err |= copy_to_user_proc(&to->datasel, &from->datasel, 
++                                  sizeof(to->datasel));
++              err |= copy_to_user_proc(to->_st, from->_st, sizeof(to->_st));
++      }
++      return(err);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/sys-i386/syscalls.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/syscalls.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/syscalls.c   2005-05-03 22:28:14.590392136 +0300
+@@ -0,0 +1,68 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "asm/mman.h"
++#include "asm/uaccess.h"
++#include "asm/unistd.h"
++
++/*
++ * Perform the select(nd, in, out, ex, tv) and mmap() system
++ * calls. Linux/i386 didn't use to be able to handle more than
++ * 4 system call parameters, so these system calls used a memory
++ * block for parameter passing..
++ */
++
++struct mmap_arg_struct {
++      unsigned long addr;
++      unsigned long len;
++      unsigned long prot;
++      unsigned long flags;
++      unsigned long fd;
++      unsigned long offset;
++};
++
++extern int old_mmap(unsigned long addr, unsigned long len,
++                  unsigned long prot, unsigned long flags,
++                  unsigned long fd, unsigned long offset);
++
++int old_mmap_i386(struct mmap_arg_struct *arg)
++{
++      struct mmap_arg_struct a;
++      int err = -EFAULT;
++
++      if (copy_from_user(&a, arg, sizeof(a)))
++              goto out;
++
++      err = old_mmap(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
++ out:
++      return err;
++}
++
++struct sel_arg_struct {
++      unsigned long n;
++      fd_set *inp, *outp, *exp;
++      struct timeval *tvp;
++};
++
++int old_select(struct sel_arg_struct *arg)
++{
++      struct sel_arg_struct a;
++
++      if (copy_from_user(&a, arg, sizeof(a)))
++              return -EFAULT;
++      /* sys_select() does the appropriate kernel locking */
++      return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/sys-i386/sysrq.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/sysrq.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/sysrq.c      2005-05-03 22:28:14.591391984 +0300
+@@ -0,0 +1,30 @@
++#include "linux/kernel.h"
++#include "linux/smp.h"
++#include "linux/sched.h"
++#include "asm/ptrace.h"
++#include "sysrq.h"
++
++void show_regs(struct pt_regs *regs)
++{
++        printk("\n");
++        printk("EIP: %04lx:[<%08lx>] CPU: %d %s", 
++             0xffff & PT_REGS_CS(regs), PT_REGS_IP(regs),
++             smp_processor_id(), print_tainted());
++        if (PT_REGS_CS(regs) & 3)
++                printk(" ESP: %04lx:%08lx", 0xffff & PT_REGS_SS(regs),
++                     PT_REGS_SP(regs));
++        printk(" EFLAGS: %08lx\n    %s\n", PT_REGS_EFLAGS(regs),
++             print_tainted());
++        printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
++                PT_REGS_EAX(regs), PT_REGS_EBX(regs), 
++             PT_REGS_ECX(regs), 
++             PT_REGS_EDX(regs));
++        printk("ESI: %08lx EDI: %08lx EBP: %08lx",
++             PT_REGS_ESI(regs), PT_REGS_EDI(regs), 
++             PT_REGS_EBP(regs));
++        printk(" DS: %04lx ES: %04lx\n",
++             0xffff & PT_REGS_DS(regs), 
++             0xffff & PT_REGS_ES(regs));
++
++        show_trace((unsigned long *) &regs);
++}
+Index: linux-2.4.29/arch/um/sys-i386/util/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/util/Makefile   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/util/Makefile        2005-05-03 22:28:14.592391832 +0300
+@@ -0,0 +1,28 @@
++EXE = mk_sc mk_thread
++
++include $(TOPDIR)/Rules.make
++
++all : $(EXE)
++
++mk_sc : mk_sc.o
++      $(HOSTCC) -o mk_sc mk_sc.o
++
++mk_sc.o : mk_sc.c
++      $(HOSTCC) -c $< 
++
++mk_thread : mk_thread_user.o mk_thread_kern.o
++      $(HOSTCC) -o mk_thread mk_thread_user.o mk_thread_kern.o
++
++mk_thread_user.o : mk_thread_user.c
++      $(HOSTCC) -c $< 
++
++mk_thread_kern.o : mk_thread_kern.c
++      $(HOSTCC) $(CFLAGS) -c $< 
++
++clean :
++      $(RM) $(EXE) *.o
++
++archmrproper : clean
++
++fastdep :
++
+Index: linux-2.4.29/arch/um/sys-i386/util/mk_sc.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/util/mk_sc.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/util/mk_sc.c 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,52 @@
++#include <stdio.h>
++#include <signal.h>
++#include <linux/stddef.h>
++
++#define SC_OFFSET(name, field) \
++  printf("#define " name "(sc) *((unsigned long *) &(((char *) (sc))[%d]))\n",\
++       offsetof(struct sigcontext, field))
++
++#define SC_FP_OFFSET(name, field) \
++  printf("#define " name \
++       "(sc) *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
++       offsetof(struct _fpstate, field))
++
++#define SC_FP_OFFSET_PTR(name, field, type) \
++  printf("#define " name \
++       "(sc) ((" type " *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
++       offsetof(struct _fpstate, field))
++
++int main(int argc, char **argv)
++{
++  SC_OFFSET("SC_IP", eip);
++  SC_OFFSET("SC_SP", esp);
++  SC_OFFSET("SC_FS", fs);
++  SC_OFFSET("SC_GS", gs);
++  SC_OFFSET("SC_DS", ds);
++  SC_OFFSET("SC_ES", es);
++  SC_OFFSET("SC_SS", ss);
++  SC_OFFSET("SC_CS", cs);
++  SC_OFFSET("SC_EFLAGS", eflags);
++  SC_OFFSET("SC_EAX", eax);
++  SC_OFFSET("SC_EBX", ebx);
++  SC_OFFSET("SC_ECX", ecx);
++  SC_OFFSET("SC_EDX", edx);
++  SC_OFFSET("SC_EDI", edi);
++  SC_OFFSET("SC_ESI", esi);
++  SC_OFFSET("SC_EBP", ebp);
++  SC_OFFSET("SC_TRAPNO", trapno);
++  SC_OFFSET("SC_ERR", err);
++  SC_OFFSET("SC_CR2", cr2);
++  SC_OFFSET("SC_FPSTATE", fpstate);
++  SC_OFFSET("SC_SIGMASK", oldmask);
++  SC_FP_OFFSET("SC_FP_CW", cw);
++  SC_FP_OFFSET("SC_FP_SW", sw);
++  SC_FP_OFFSET("SC_FP_TAG", tag);
++  SC_FP_OFFSET("SC_FP_IPOFF", ipoff);
++  SC_FP_OFFSET("SC_FP_CSSEL", cssel);
++  SC_FP_OFFSET("SC_FP_DATAOFF", dataoff);
++  SC_FP_OFFSET("SC_FP_DATASEL", datasel);
++  SC_FP_OFFSET_PTR("SC_FP_ST", _st, "struct _fpstate");
++  SC_FP_OFFSET_PTR("SC_FXSR_ENV", _fxsr_env, "void");
++  return(0);
++}
+Index: linux-2.4.29/arch/um/sys-i386/util/mk_thread_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/util/mk_thread_kern.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/util/mk_thread_kern.c        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,22 @@
++#include "linux/config.h"
++#include "linux/stddef.h"
++#include "linux/sched.h"
++
++extern void print_head(void);
++extern void print_constant_ptr(char *name, int value);
++extern void print_constant(char *name, char *type, int value);
++extern void print_tail(void);
++
++#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field)
++
++int main(int argc, char **argv)
++{
++  print_head();
++  print_constant_ptr("TASK_DEBUGREGS", THREAD_OFFSET(arch.debugregs));
++#ifdef CONFIG_MODE_TT
++  print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid));
++#endif
++  print_tail();
++  return(0);
++}
++
+Index: linux-2.4.29/arch/um/sys-i386/util/mk_thread_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-i386/util/mk_thread_user.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-i386/util/mk_thread_user.c        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,30 @@
++#include <stdio.h>
++
++void print_head(void)
++{
++  printf("/*\n");
++  printf(" * Generated by mk_thread\n");
++  printf(" */\n");
++  printf("\n");
++  printf("#ifndef __UM_THREAD_H\n");
++  printf("#define __UM_THREAD_H\n");
++  printf("\n");
++}
++
++void print_constant_ptr(char *name, int value)
++{
++  printf("#define %s(task) ((unsigned long *) "
++       "&(((char *) (task))[%d]))\n", name, value);
++}
++
++void print_constant(char *name, char *type, int value)
++{
++  printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type, 
++       value);
++}
++
++void print_tail(void)
++{
++  printf("\n");
++  printf("#endif\n");
++}
+Index: linux-2.4.29/arch/um/sys-ia64/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-ia64/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-ia64/Makefile     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,26 @@
++OBJ = sys.o
++
++OBJS =
++
++all: $(OBJ)
++
++$(OBJ): $(OBJS)
++      rm -f $@
++      $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
++clean:
++      rm -f $(OBJS)
++
++fastdep:
++
++archmrproper:
++
++archclean:
++      rm -f link.ld
++      @$(MAKEBOOT) clean
++
++archdep:
++      @$(MAKEBOOT) dep
++
++modules:
++
++include $(TOPDIR)/Rules.make
+Index: linux-2.4.29/arch/um/sys-ppc/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-ppc/Makefile 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-ppc/Makefile      2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,80 @@
++OBJ = sys.o
++
++.S.o:
++      $(CC) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
++
++OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \
++      ptrace_user.o sysrq.o
++
++EXTRA_AFLAGS := -DCONFIG_ALL_PPC -I. -I$(TOPDIR)/arch/ppc/kernel
++
++all: $(OBJ)
++
++$(OBJ): $(OBJS)
++      rm -f $@
++      $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
++
++ptrace_user.o: ptrace_user.c
++      $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
++
++sigcontext.o: sigcontext.c
++      $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
++
++semaphore.c:
++      rm -f $@
++      ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
++
++checksum.S:
++      rm -f $@
++      ln -s $(TOPDIR)/arch/ppc/lib/$@ $@
++
++mk_defs.c:
++      rm -f $@
++      ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
++
++ppc_defs.head:
++      rm -f $@
++      ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
++
++ppc_defs.h: mk_defs.c ppc_defs.head \
++              $(TOPDIR)/include/asm-ppc/mmu.h \
++              $(TOPDIR)/include/asm-ppc/processor.h \
++              $(TOPDIR)/include/asm-ppc/pgtable.h \
++              $(TOPDIR)/include/asm-ppc/ptrace.h
++#     $(CC) $(CFLAGS) -S mk_defs.c
++      cp ppc_defs.head ppc_defs.h
++# for bk, this way we can write to the file even if it's not checked out
++      echo '#define THREAD 608' >> ppc_defs.h
++      echo '#define PT_REGS 8' >> ppc_defs.h
++      echo '#define CLONE_VM 256' >> ppc_defs.h
++#     chmod u+w ppc_defs.h
++#     grep '^#define' mk_defs.s >> ppc_defs.h
++#     rm mk_defs.s
++
++# the asm link is horrible, and breaks the other targets.  This is also
++# not going to work with parallel makes.
++
++checksum.o: checksum.S
++      rm -f asm
++      ln -s $(TOPDIR)/include/asm-ppc asm
++      $(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
++      rm -f asm
++
++misc.o: misc.S ppc_defs.h
++      rm -f asm
++      ln -s $(TOPDIR)/include/asm-ppc asm
++      $(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
++      rm -f asm
++
++clean:
++      rm -f $(OBJS)
++      rm -f ppc_defs.h
++      rm -f checksum.S semaphore.c mk_defs.c
++
++fastdep:
++
++dep:
++
++modules:
++
++include $(TOPDIR)/Rules.make
+Index: linux-2.4.29/arch/um/sys-ppc/misc.S
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-ppc/misc.S   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-ppc/misc.S        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,116 @@
++/*
++ * This file contains miscellaneous low-level functions.
++ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
++ *
++ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
++ * and Paul Mackerras.
++ *
++ * A couple of functions stolen from arch/ppc/kernel/misc.S for UML
++ * by Chris Emerson.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ */
++
++#include <linux/config.h>
++#include <asm/processor.h>
++#include "ppc_asm.h"
++
++#if defined(CONFIG_4xx) || defined(CONFIG_8xx)
++#define CACHE_LINE_SIZE               16
++#define LG_CACHE_LINE_SIZE    4
++#define MAX_COPY_PREFETCH     1
++#elif !defined(CONFIG_PPC64BRIDGE)
++#define CACHE_LINE_SIZE               32
++#define LG_CACHE_LINE_SIZE    5
++#define MAX_COPY_PREFETCH     4
++#else
++#define CACHE_LINE_SIZE               128
++#define LG_CACHE_LINE_SIZE    7
++#define MAX_COPY_PREFETCH     1
++#endif /* CONFIG_4xx || CONFIG_8xx */
++
++      .text
++
++/*
++ * Clear a page using the dcbz instruction, which doesn't cause any
++ * memory traffic (except to write out any cache lines which get
++ * displaced).  This only works on cacheable memory.
++ */
++_GLOBAL(clear_page)
++      li      r0,4096/CACHE_LINE_SIZE
++      mtctr   r0
++#ifdef CONFIG_8xx
++      li      r4, 0
++1:    stw     r4, 0(r3)
++      stw     r4, 4(r3)
++      stw     r4, 8(r3)
++      stw     r4, 12(r3)
++#else
++1:    dcbz    0,r3
++#endif
++      addi    r3,r3,CACHE_LINE_SIZE
++      bdnz    1b
++      blr
++
++/*
++ * Copy a whole page.  We use the dcbz instruction on the destination
++ * to reduce memory traffic (it eliminates the unnecessary reads of
++ * the destination into cache).  This requires that the destination
++ * is cacheable.
++ */
++#define COPY_16_BYTES         \
++      lwz     r6,4(r4);       \
++      lwz     r7,8(r4);       \
++      lwz     r8,12(r4);      \
++      lwzu    r9,16(r4);      \
++      stw     r6,4(r3);       \
++      stw     r7,8(r3);       \
++      stw     r8,12(r3);      \
++      stwu    r9,16(r3)
++
++_GLOBAL(copy_page)
++      addi    r3,r3,-4
++      addi    r4,r4,-4
++      li      r5,4
++
++#ifndef CONFIG_8xx
++#if MAX_COPY_PREFETCH > 1
++      li      r0,MAX_COPY_PREFETCH
++      li      r11,4
++      mtctr   r0
++11:   dcbt    r11,r4
++      addi    r11,r11,CACHE_LINE_SIZE
++      bdnz    11b
++#else /* MAX_COPY_PREFETCH == 1 */
++      dcbt    r5,r4
++      li      r11,CACHE_LINE_SIZE+4
++#endif /* MAX_COPY_PREFETCH */
++#endif /* CONFIG_8xx */
++
++      li      r0,4096/CACHE_LINE_SIZE
++      mtctr   r0
++1:
++#ifndef CONFIG_8xx
++      dcbt    r11,r4
++      dcbz    r5,r3
++#endif
++      COPY_16_BYTES
++#if CACHE_LINE_SIZE >= 32
++      COPY_16_BYTES
++#if CACHE_LINE_SIZE >= 64
++      COPY_16_BYTES
++      COPY_16_BYTES
++#if CACHE_LINE_SIZE >= 128
++      COPY_16_BYTES
++      COPY_16_BYTES
++      COPY_16_BYTES
++      COPY_16_BYTES
++#endif
++#endif
++#endif
++      bdnz    1b
++      blr
+Index: linux-2.4.29/arch/um/sys-ppc/miscthings.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-ppc/miscthings.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-ppc/miscthings.c  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,53 @@
++#include "linux/threads.h"
++#include "linux/stddef.h"  // for NULL
++#include "linux/elf.h"  // for AT_NULL
++
++/* The following function nicked from arch/ppc/kernel/process.c and
++ * adapted slightly */
++/*
++ * XXX ld.so expects the auxiliary table to start on
++ * a 16-byte boundary, so we have to find it and
++ * move it up. :-(
++ */
++void shove_aux_table(unsigned long sp)
++{
++      int argc;
++      char *p;
++      unsigned long e;
++      unsigned long aux_start, offset;
++
++      argc = *(int *)sp;
++      sp += sizeof(int) + (argc + 1) * sizeof(char *);
++      /* skip over the environment pointers */
++      do {
++              p = *(char **)sp;
++              sp += sizeof(char *);
++      } while (p != NULL);
++      aux_start = sp;
++      /* skip to the end of the auxiliary table */
++      do {
++              e = *(unsigned long *)sp;
++              sp += 2 * sizeof(unsigned long);
++      } while (e != AT_NULL);
++      offset = ((aux_start + 15) & ~15) - aux_start;
++      if (offset != 0) {
++              do {
++                      sp -= sizeof(unsigned long);
++                      e = *(unsigned long *)sp;
++                      *(unsigned long *)(sp + offset) = e;
++              } while (sp > aux_start);
++      }
++}
++/* END stuff taken from arch/ppc/kernel/process.c */
++
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/sys-ppc/ptrace.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-ppc/ptrace.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-ppc/ptrace.c      2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,28 @@
++#include "linux/sched.h"
++#include "asm/ptrace.h"
++
++int putreg(struct task_struct *child, unsigned long regno, 
++                unsigned long value)
++{
++      child->thread.process_regs.regs[regno >> 2] = value;
++      return 0;
++}
++
++unsigned long getreg(struct task_struct *child, unsigned long regno)
++{
++      unsigned long retval = ~0UL;
++
++      retval &= child->thread.process_regs.regs[regno >> 2];
++      return retval;
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/sys-ppc/ptrace_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-ppc/ptrace_user.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-ppc/ptrace_user.c 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,40 @@
++#include <sys/ptrace.h>
++#include <errno.h>
++#include <asm/ptrace.h>
++#include "sysdep/ptrace.h"
++
++int ptrace_getregs(long pid, unsigned long *regs_out)
++{
++    int i;
++    for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) {
++      errno = 0;
++      regs_out->regs[i] = ptrace(PTRACE_PEEKUSER, pid, i*4, 0);
++      if (errno) {
++          return -errno;
++      }
++    }
++    return 0;
++}
++
++int ptrace_setregs(long pid, unsigned long *regs_in)
++{
++    int i;
++    for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) {
++      if (i != 34 /* FIXME: PT_ORIG_R3 */ && i <= PT_MQ) {
++          if (ptrace(PTRACE_POKEUSER, pid, i*4, regs_in->regs[i]) < 0) {
++              return -errno;
++          }
++      }
++    }
++    return 0;
++}
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/sys-ppc/sigcontext.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-ppc/sigcontext.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-ppc/sigcontext.c  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,15 @@
++#include "asm/ptrace.h"
++#include "asm/sigcontext.h"
++#include "sysdep/ptrace.h"
++#include "user_util.h"
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/sys-ppc/sysrq.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/sys-ppc/sysrq.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/sys-ppc/sysrq.c       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,43 @@
++/* 
++ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
++ * Licensed under the GPL
++ */
++
++#include "linux/kernel.h"
++#include "linux/smp.h"
++#include "asm/ptrace.h"
++#include "sysrq.h"
++
++void show_regs(struct pt_regs_subarch *regs)
++{
++      printk("\n");
++      printk("show_regs(): insert regs here.\n");
++#if 0
++        printk("\n");
++        printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs, regs->eip,
++             smp_processor_id());
++        if (regs->xcs & 3)
++                printk(" ESP: %04x:%08lx",0xffff & regs->xss, regs->esp);
++        printk(" EFLAGS: %08lx\n", regs->eflags);
++        printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
++                regs->eax, regs->ebx, regs->ecx, regs->edx);
++        printk("ESI: %08lx EDI: %08lx EBP: %08lx",
++                regs->esi, regs->edi, regs->ebp);
++        printk(" DS: %04x ES: %04x\n",
++                0xffff & regs->xds, 0xffff & regs->xes);
++#endif
++
++        show_trace(&regs->gpr[1]);
++}
++
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/arch/um/util/Makefile
+===================================================================
+--- linux-2.4.29.orig/arch/um/util/Makefile    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/util/Makefile 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,26 @@
++ALL = mk_task mk_constants
++
++all : $(ALL)
++
++mk_task : mk_task_user.o mk_task_kern.o
++      $(HOSTCC) -o mk_task mk_task_user.o mk_task_kern.o
++
++mk_task_user.o : mk_task_user.c
++      $(HOSTCC) -c $< 
++
++mk_task_kern.o : mk_task_kern.c
++      $(HOSTCC) $(CFLAGS) -c $< 
++
++mk_constants : mk_constants_user.o mk_constants_kern.o
++      $(HOSTCC) -o mk_constants mk_constants_user.o mk_constants_kern.o
++
++mk_constants_user.o : mk_constants_user.c
++      $(HOSTCC) -c $< 
++
++mk_constants_kern.o : mk_constants_kern.c
++      $(HOSTCC) $(CFLAGS) -c $< 
++
++clean :
++      $(RM) $(ALL) *.o *~
++
++archmrproper : clean
+Index: linux-2.4.29/arch/um/util/mk_constants_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/util/mk_constants_kern.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/util/mk_constants_kern.c      2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,25 @@
++#include "linux/kernel.h"
++#include "linux/stringify.h"
++#include "asm/page.h"
++
++extern void print_head(void);
++extern void print_constant_str(char *name, char *value);
++extern void print_constant_int(char *name, int value);
++extern void print_tail(void);
++
++int main(int argc, char **argv)
++{
++  print_head();
++  print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE);
++
++  print_constant_str("UM_KERN_EMERG", KERN_EMERG);
++  print_constant_str("UM_KERN_ALERT", KERN_ALERT);
++  print_constant_str("UM_KERN_CRIT", KERN_CRIT);
++  print_constant_str("UM_KERN_ERR", KERN_ERR);
++  print_constant_str("UM_KERN_WARNING", KERN_WARNING);
++  print_constant_str("UM_KERN_NOTICE", KERN_NOTICE);
++  print_constant_str("UM_KERN_INFO", KERN_INFO);
++  print_constant_str("UM_KERN_DEBUG", KERN_DEBUG);
++  print_tail();
++  return(0);
++}
+Index: linux-2.4.29/arch/um/util/mk_constants_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/util/mk_constants_user.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/util/mk_constants_user.c      2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,28 @@
++#include <stdio.h>
++
++void print_head(void)
++{
++  printf("/*\n");
++  printf(" * Generated by mk_constants\n");
++  printf(" */\n");
++  printf("\n");
++  printf("#ifndef __UM_CONSTANTS_H\n");
++  printf("#define __UM_CONSTANTS_H\n");
++  printf("\n");
++}
++
++void print_constant_str(char *name, char *value)
++{
++  printf("#define %s \"%s\"\n", name, value);
++}
++
++void print_constant_int(char *name, int value)
++{
++  printf("#define %s %d\n", name, value);
++}
++
++void print_tail(void)
++{
++  printf("\n");
++  printf("#endif\n");
++}
+Index: linux-2.4.29/arch/um/util/mk_task_kern.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/util/mk_task_kern.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/util/mk_task_kern.c   2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,17 @@
++#include "linux/sched.h"
++#include "linux/stddef.h"
++
++extern void print(char *name, char *type, int offset);
++extern void print_ptr(char *name, char *type, int offset);
++extern void print_head(void);
++extern void print_tail(void);
++
++int main(int argc, char **argv)
++{
++  print_head();
++  print_ptr("TASK_REGS", "union uml_pt_regs", 
++          offsetof(struct task_struct, thread.regs));
++  print("TASK_PID", "int", offsetof(struct task_struct, pid));
++  print_tail();
++  return(0);
++}
+Index: linux-2.4.29/arch/um/util/mk_task_user.c
+===================================================================
+--- linux-2.4.29.orig/arch/um/util/mk_task_user.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/arch/um/util/mk_task_user.c   2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,30 @@
++#include <stdio.h>
++
++void print(char *name, char *type, int offset)
++{
++  printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
++       offset);
++}
++
++void print_ptr(char *name, char *type, int offset)
++{
++  printf("#define %s(task) ((%s *) &(((char *) (task))[%d]))\n", name, type,
++       offset);
++}
++
++void print_head(void)
++{
++  printf("/*\n");
++  printf(" * Generated by mk_task\n");
++  printf(" */\n");
++  printf("\n");
++  printf("#ifndef __TASK_H\n");
++  printf("#define __TASK_H\n");
++  printf("\n");
++}
++
++void print_tail(void)
++{
++  printf("\n");
++  printf("#endif\n");
++}
+Index: linux-2.4.29/CREDITS
+===================================================================
+--- linux-2.4.29.orig/CREDITS  2005-05-03 21:08:24.000000000 +0300
++++ linux-2.4.29/CREDITS       2005-05-03 22:28:14.000000000 +0300
+@@ -434,6 +434,7 @@
+ E: lars@nocrew.org
+ W: http://lars.nocrew.org/
+ D: dsp56k device driver
++D: ptrace proxy in user mode kernel port
+ S: Kopmansg 2
+ S: 411 13  Goteborg
+ S: Sweden
+@@ -727,7 +728,7 @@
+ E: jdike@karaya.com
+ W: http://user-mode-linux.sourceforge.net
+ D: User mode kernel port
+-S: RR1 Box 67C
++S: 375 Tubbs Hill Rd
+ S: Deering NH 03244
+ S: USA
+Index: linux-2.4.29/Documentation/Configure.help
+===================================================================
+--- linux-2.4.29.orig/Documentation/Configure.help     2005-05-03 21:09:27.000000000 +0300
++++ linux-2.4.29/Documentation/Configure.help  2005-05-03 23:55:57.615290736 +0300
+@@ -16184,6 +16184,63 @@
+   The module will be called speedtch.o. If you want to compile it as
+   a module, say M here and read <file:Documentation/modules.txt>.
++Support for /proc/mm
++CONFIG_PROC_MM
++  Enables support for address space separation through /proc/mm.
++  A host kernel needs to have this enabled in order for UML to
++  run in skas mode.  UML kernels do not need to have this option
++  unless they will host sub-UMLs.
++
++  If you don't know what this does just say Y.
++
++Separate Kernel Address Space support
++CONFIG_MODE_SKAS
++  This option controls whether skas (separate kernel address space)
++  support is compiled in.  If you have applied the skas patch to the
++  host and enabled support for /proc/mm in the host kernel, then you
++  certainly want to say Y here (and consider saying N to
++  CONFIG_MODE_TT).  Otherwise, it is safe to say Y.  Disabling this
++  option will shrink the UML binary slightly.
++
++Tracing thread support
++CONFIG_MODE_TT
++  This option controls whether tracing thread support is compiled
++  into UML.  Normally, this should be set to Y.  If you intend to
++  use only skas mode (and the host has the skas patch applied to it),
++  then it is OK to say N here.
++
++Force a static link
++CONFIG_STATIC_LINK
++  If CONFIG_MODE_TT is disabled, then this option gives you the ability
++  to force a static link of UML.  Normally, if only skas mode is built
++  in to UML, it will be linked as a shared binary.  This is inconvenient
++  for use in a chroot jail.  So, if you intend to run UML inside a
++  chroot, and you disable CONFIG_MODE_TT, you probably want to say Y
++  here.
++
++2G/2G host address space split
++CONFIG_HOST_2G_2G
++  Most Linux machines are configured so that the kernel occupies the
++  upper 1G of the 4G address space and processes use the lower 3G.
++  However, some machine are configured with a 2G/2G split, with the
++  kernel occupying the upper 2G and processes using the lower 2G.
++
++  To allow UML to run on a such host you have to say Y here. N should be
++  a safe choice most of the time.
++
++Kernel stack size order
++CONFIG_KERNEL_STACK_ORDER
++  This option determines the size of UML kernel stacks.  They will
++  be 1 << order pages.  The default is OK unless you're running Valgrind
++  on UML, in which case, set this to 3.
++
++UML ubd block driver
++CONFIG_BLK_DEV_UBD
++  The User-Mode Linux port includes a driver called UBD which will let
++  you access arbitrary files on the host computer as block devices.
++  Unless you know that you do not need such virtual block devices say
++  Y here.
++
+ CONFIG_USB_GADGET
+   USB is a master/slave protocol, organized with one master
+   host (such as a PC) controlling up to 127 peripheral devices.
+@@ -16289,17 +16346,15 @@
+ Always do synchronous disk IO for UBD
+ CONFIG_BLK_DEV_UBD_SYNC
+-  The User-Mode Linux port includes a driver called UBD which will let
+-  you access arbitrary files on the host computer as block devices.
+-  Writes to such a block device are not immediately written to the
+-  host's disk; this may cause problems if, for example, the User-Mode
+-  Linux 'Virtual Machine' uses a journalling file system and the host
+-  computer crashes.
++  Writes to the virtual block device are not immediately written to the host's
++  disk; this may cause problems if, for example, the User-Mode Linux
++  'Virtual Machine' uses a journalling filesystem and the host computer
++  crashes.
+   Synchronous operation (i.e. always writing data to the host's disk
+   immediately) is configurable on a per-UBD basis by using a special
+   kernel command line option.  Alternatively, you can say Y here to
+-  turn on synchronous operation by default for all block.
++  turn on synchronous operation by default for all block devices.
+   If you're running a journalling file system (like reiserfs, for
+   example) in your virtual machine, you will want to say Y here.  If
+@@ -16311,6 +16366,7 @@
+ CONFIG_PT_PROXY
+   This option enables a debugging interface which allows gdb to debug
+   the kernel without needing to actually attach to kernel threads.
++  CONFIG_XTERM_CHAN must be enabled in order to enable CONFIG_PT_PROXY.
+   If you want to do kernel debugging, say Y here; otherwise say N.
+ Management console
+@@ -16357,6 +16413,9 @@
+   See <http://user-mode-linux.sourceforge.net/gprof.html> for more
+   details.
++  This option requires that CONFIG_MODE_TT be disabled, as UML will
++  not build with both enabled.
++
+   If you're involved in UML kernel development and want to use gprof,
+   say Y.  If you're unsure, say N.
+@@ -16380,6 +16439,19 @@
+   If you'd like to be able to work with files stored on the host, 
+   say Y or M here; otherwise say N.
++HoneyPot ProcFS
++CONFIG_HPPFS
++  hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
++  entries to be overridden, removed, or fabricated from the host.
++  Its purpose is to allow a UML to appear to be a physical machine
++  by removing or changing anything in /proc which gives away the
++  identity of a UML.
++
++  See <http://user-mode-linux.sf.net/hppfs.html> for more information.
++
++  You only need this if you are setting up a UML honeypot.  Otherwise,
++  it is safe to say 'N' here.
++
+ Example IO Memory driver
+ CONFIG_MMAPPER
+   The User-Mode Linux port can provide support for IO Memory
+@@ -16395,6 +16467,21 @@
+   If you'd like to be able to provide a simulated IO port space for
+   User-Mode Linux processes, say Y.  If unsure, say N.
++Anonymous Memory support
++CONFIG_DEV_ANON
++  Don't ask. Just say Y.
++
++Support for software watchdog inside UML
++CONFIG_UML_WATCHDOG
++  Support for a virtual hardware watchdog. It's safe to say N here.
++
++COW block device
++CONFIG_COW
++  This is a layered driver which sits above two other block devices.
++  One is read-only, and the other is a read-write layer which stores
++  all changes.  This provides the illusion that the read-only layer
++  can be mounted read-write and changed.
++
+ Virtual Serial Line
+ CONFIG_SSL
+   The User-Mode Linux environment allows you to create virtual serial
+@@ -16505,26 +16592,197 @@
+ SLIP transport
+ CONFIG_UML_NET_SLIP
+-  The Slip User-Mode Linux network transport allows a running UML to
++  The slip User-Mode Linux network transport allows a running UML to
+   network with its host over a point-to-point link.  Unlike Ethertap,
+   which can carry any Ethernet frame (and hence even non-IP packets),
+-  the Slip transport can only carry IP packets.
++  the slip transport can only carry IP packets.
+-  To use this, your host must support Slip devices.
++  To use this, your host must support slip devices.
+   For more information, see
+   <http://user-mode-linux.sourceforge.net/networking.html>.  That site
+-  has examples of the UML command line to use to enable Slip
++  has examples of the UML command line to use to enable slip
+   networking, and details of a few quirks with it.
+-  The Ethertap Transport is preferred over Slip because of its
+-  limitation.  If you prefer Slip, however, say Y here.  Otherwise
++  The Ethertap Transport is preferred over slip because of its
++  limitations.  If you prefer slip, however, say Y here.  Otherwise
+   choose the Multicast transport (to network multiple UMLs on 
+   multiple hosts), Ethertap (to network with the host and the
+   outside world), and/or the Daemon transport (to network multiple
+   UMLs on a single host).  You may choose more than one without
+   conflict.  If you don't need UML networking, say N.
++SLiRP transport
++CONFIG_UML_NET_SLIRP
++  The SLiRP User-Mode Linux network transport allows a running UML
++  to network by invoking a program that can handle SLIP encapsulated
++  packets.  This is commonly (but not limited to) the application
++  known as SLiRP, a program that can re-socket IP packets back onto
++  the host on which it is run.  Only IP packets are supported,
++  unlike other network transports that can handle all Ethernet
++  frames.  In general, slirp allows the UML the same IP connectivity
++  to the outside world that the host user is permitted, and unlike
++  other transports, SLiRP works without the need of root level
++  privleges, setuid binaries, or SLIP devices on the host.  This
++  also means not every type of connection is possible, but most
++  situations can be accomodated with carefully crafted slirp
++  commands that can be passed along as part of the network device's
++  setup string.  The effect of this transport on the UML is similar
++  that of a host behind a firewall that masquerades all network
++  connections passing through it (but is less secure).
++
++  To use this you should first have slirp compiled somewhere
++  accessible on the host, and have read its documentation.  If you
++  don't need UML networking, say N.
++
++  Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
++
++pcap transport
++CONFIG_UML_NET_PCAP
++ The pcap transport makes a pcap packet stream on the host look
++  like an ethernet device inside UML.  This is useful for making
++  UML act as a network monitor for the host.  You must have libcap
++  installed in order to build the pcap transport into UML.
++
++  For more information, see
++  <http://user-mode-linux.sourceforge.net/networking.html>  That site
++  has examples of the UML command line to use to enable this option.
++
++  If you intend to use UML as a network monitor for the host, say
++  Y here.  Otherwise, say N.
++
++Default main console channel initialization
++CONFIG_CON_ZERO_CHAN
++  This is the string describing the channel to which the main console
++  will be attached by default.  This value can be overridden from the
++  command line.  The default value is "fd:0,fd:1", which attaches the
++  main console to stdin and stdout.
++  It is safe to leave this unchanged.
++
++Default console channel initialization
++CONFIG_CON_CHAN
++  This is the string describing the channel to which all consoles
++  except the main console will be attached by default.  This value can
++  be overridden from the command line.  The default value is "xterm",
++  which brings them up in xterms.
++  It is safe to leave this unchanged, although you may wish to change
++  this if you expect the UML that you build to be run in environments
++  which don't have X or xterm available.
++
++Default serial line channel initialization
++CONFIG_SSL_CHAN
++  This is the string describing the channel to which the serial lines
++  will be attached by default.  This value can be overridden from the
++  command line.  The default value is "pty", which attaches them to
++  traditional pseudo-terminals.
++  It is safe to leave this unchanged, although you may wish to change
++  this if you expect the UML that you build to be run in environments
++  which don't have a set of /dev/pty* devices.
++
++Nesting level
++CONFIG_NEST_LEVEL
++  This is set to the number of layers of UMLs that this UML will be run
++  in.  Normally, this is zero, meaning that it will run directly on the
++  host.  Setting it to one will build a UML that can run inside a UML
++  that is running on the host.  Generally, if you intend this UML to run
++  inside another UML, set CONFIG_NEST_LEVEL to one more than the host UML.
++  Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to 
++  greater than one, then the guest UML should have its CONFIG_NEST_LEVEL 
++  set to the host's CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS.
++  Only change this if you are running nested UMLs.
++
++Kernel address space size (in .5G units)
++CONFIG_KERNEL_HALF_GIGS
++  This determines the amount of address space that UML will allocate for
++  its own, measured in half Gigabyte units.  The default is 1.
++  Change this only if you need to boot UML with an unusually large amount
++  of physical memory.
++
++UML sound support
++CONFIG_UML_SOUND
++  This option enables UML sound support.  If enabled, it will pull in
++  soundcore and the UML hostaudio relay, which acts as a intermediary
++  between the host's dsp and mixer devices and the UML sound system.
++  It is safe to say 'Y' here.
++
++UML SMP support
++CONFIG_UML_SMP
++  This option enables UML SMP support.  UML implements virtual SMP by
++  allowing as many processes to run simultaneously on the host as
++  there are virtual processors configured.  Obviously, if the host is
++  a uniprocessor, those processes will timeshare, but, inside UML,
++  will appear to be running simultaneously.  If the host is a
++  multiprocessor, then UML processes may run simultaneously, depending
++  on the host scheduler.
++  CONFIG_SMP will be set to whatever this option is set to.
++  It is safe to leave this unchanged.
++
++file descriptor channel support
++CONFIG_FD_CHAN
++  This option enables support for attaching UML consoles and serial
++  lines to already set up file descriptors.  Generally, the main
++  console is attached to file descriptors 0 and 1 (stdin and stdout),
++  so it would be wise to leave this enabled unless you intend to
++  attach it to some other host device.
++
++null device channel support
++CONFIG_NULL_CHAN
++  This option enables support for attaching UML consoles and serial
++  lines to a device similar to /dev/null.  Data written to it disappears
++  and there is never any data to be read.
++
++port channel support
++CONFIG_PORT_CHAN
++  This option enables support for attaching UML consoles and serial
++  lines to host portals.  They may be accessed with 'telnet <host>
++  <port number>'.  Any number of consoles and serial lines may be
++  attached to a single portal, although what UML device you get when
++  you telnet to that portal will be unpredictable.
++  It is safe to say 'Y' here.
++
++pty channel support
++CONFIG_PTY_CHAN
++  This option enables support for attaching UML consoles and serial
++  lines to host pseudo-terminals.  Access to both traditional
++  pseudo-terminals (/dev/pty*) and pts pseudo-terminals are controlled
++  with this option.  The assignment of UML devices to host devices
++  will be announced in the kernel message log.
++  It is safe to say 'Y' here.
++
++tty channel support
++CONFIG_TTY_CHAN
++  This option enables support for attaching UML consoles and serial
++  lines to host terminals.  Access to both virtual consoles
++  (/dev/tty*) and the slave side of pseudo-terminals (/dev/ttyp* and
++  /dev/pts/*) are controlled by this option.
++  It is safe to say 'Y' here.
++
++xterm channel support
++CONFIG_XTERM_CHAN
++  This option enables support for attaching UML consoles and serial
++  lines to xterms.  Each UML device so assigned will be brought up in
++  its own xterm.
++  If you disable this option, then CONFIG_PT_PROXY will be disabled as
++  well, since UML's gdb currently requires an xterm.
++  It is safe to say 'Y' here.
++
++tty logging
++CONFIG_TTY_LOG
++  This option enables logging of all data going through pseudo-terminals
++  to the host.  This is primarily useful for honeypots, where you want
++  secure keystroke logging that can't be detected or disabled by root.
++  Say 'N' unless you are setting up a UML honeypot or otherwise know that
++  you want this option.
++
++UML real-time clock support
++CONFIG_UML_REAL_TIME_CLOCK
++  This option ties the UML clock to the host clock, so that time passes at
++  the same rate as on the host, regardless of how much CPU time the UML is
++  getting.  This should normally be enabled.  The exception would be if you're
++  debugging UML.  In this case, time spent staring at the debugger with UML
++  stopped will cause lots of timer ticks to be backed up, and UML will spent
++  lots of time calling the timer when it is finally continued.
++
+ Microtek USB scanner support
+ CONFIG_USB_MICROTEK
+   Say Y here if you want support for the Microtek X6USB and
+Index: linux-2.4.29/drivers/char/Makefile
+===================================================================
+--- linux-2.4.29.orig/drivers/char/Makefile    2005-05-03 21:09:35.000000000 +0300
++++ linux-2.4.29/drivers/char/Makefile 2005-05-03 22:28:14.000000000 +0300
+@@ -114,6 +114,12 @@
+   endif
+ endif
++ifeq ($(ARCH),um)
++  KEYMAP   =
++  KEYBD    =
++  CONSOLE  =
++endif
++
+ ifeq ($(ARCH),sh)
+   KEYMAP   =
+   KEYBD    =
+Index: linux-2.4.29/drivers/char/mem.c
+===================================================================
+--- linux-2.4.29.orig/drivers/char/mem.c       2005-05-03 21:07:25.000000000 +0300
++++ linux-2.4.29/drivers/char/mem.c    2005-05-03 22:28:14.000000000 +0300
+@@ -220,7 +220,7 @@
+       ssize_t read = 0;
+       ssize_t virtr = 0;
+       char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
+-              
++
+       if (p < (unsigned long) high_memory) {
+               read = count;
+               if (count > (unsigned long) high_memory - p)
+@@ -292,6 +292,8 @@
+                       wrote = (unsigned long) high_memory - p;
+               wrote = do_write_mem(file, (void*)p, p, buf, wrote, ppos);
++              if(wrote < 0)
++                      return(wrote);
+               p += wrote;
+               buf += wrote;
+@@ -664,6 +666,8 @@
+       write:          write_full,
+ };
++extern struct file_operations anon_file_operations;
++
+ static int memory_open(struct inode * inode, struct file * filp)
+ {
+       switch (MINOR(inode->i_rdev)) {
+@@ -693,6 +697,9 @@
+               case 9:
+                       filp->f_op = &urandom_fops;
+                       break;
++              case 10:
++                      filp->f_op = &anon_file_operations;
++                      break;
+               default:
+                       return -ENXIO;
+       }
+@@ -719,7 +726,8 @@
+       {5, "zero",    S_IRUGO | S_IWUGO,           &zero_fops},
+       {7, "full",    S_IRUGO | S_IWUGO,           &full_fops},
+       {8, "random",  S_IRUGO | S_IWUSR,           &random_fops},
+-      {9, "urandom", S_IRUGO | S_IWUSR,           &urandom_fops}
++      {9, "urandom", S_IRUGO | S_IWUSR,           &urandom_fops},
++      {10, "anon", S_IRUGO | S_IWUSR,             &anon_file_operations},
+     };
+     int i;
+Index: linux-2.4.29/drivers/char/n_tty.c
+===================================================================
+--- linux-2.4.29.orig/drivers/char/n_tty.c     2005-05-03 21:05:08.000000000 +0300
++++ linux-2.4.29/drivers/char/n_tty.c  2005-05-03 22:28:14.000000000 +0300
+@@ -25,9 +25,11 @@
+  *            who actually finally proved there really was a race.
+  *
+  * 2002/03/18   Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
+- *            waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
+- *            Also fixed a bug in BLOCKING mode where write_chan returns
+- *            EAGAIN
++ *            waiting writing processes-Sapan Bhatia <sapan@corewars.org>
++ *
++ * 2002/03/19   Fixed write_chan to stay put if console driver returns
++ *              EAGAIN and not return since it returns an EAGAIN in a 
++ *            non-blocking operation-Sapan Bhatia <sapan@corewars.org>
+  */
+ #include <linux/types.h>
+@@ -1393,9 +1395,9 @@
+               if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
+                       while (nr > 0) {
+                               ssize_t num = opost_block(tty, b, nr);
+-                              if (num < 0) {
+-                                      if (num == -EAGAIN)
+-                                              break;
++                              if (num < 0){
++                                      if(num == -EAGAIN)
++                                              break;
+                                       retval = num;
+                                       goto break_out;
+                               }
+Index: linux-2.4.29/drivers/char/tty_io.c
+===================================================================
+--- linux-2.4.29.orig/drivers/char/tty_io.c    2005-05-03 21:07:50.000000000 +0300
++++ linux-2.4.29/drivers/char/tty_io.c 2005-05-03 22:28:14.000000000 +0300
+@@ -967,6 +967,23 @@
+       tty_wakeup(tty);
+ }
++#ifdef CONFIG_TTY_LOG
++
++int (*open_log)(void *, void *) = NULL;
++int (*write_log)(int, const char *, int, void *, int) = NULL;
++void (*close_log)(int, void *) = NULL;
++
++void register_tty_logger(int (*opener)(void *, void *),
++                       int (*writer)(int, const char *, int, void *, int),
++                       void (*closer)(int, void *))
++{
++        open_log = opener;
++      write_log = writer;
++      close_log = closer;
++}
++
++#endif
++
+ static ssize_t tty_read(struct file * file, char * buf, size_t count, 
+                       loff_t *ppos)
+ {
+@@ -1012,8 +1029,13 @@
+               i = -EIO;
+       tty_ldisc_deref(ld);
+       unlock_kernel();
+-      if (i > 0)
++      if (i > 0){
+               inode->i_atime = CURRENT_TIME;
++#ifdef CONFIG_TTY_LOG
++              if((tty->log_fd >= 0) && (write_log != NULL))
++                      (*write_log)(tty->log_fd, buf, i, tty, 1);
++#endif
++      }
+       return i;
+ }
+@@ -1067,6 +1089,10 @@
+       if (written) {
+               file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
+               ret = written;
++#ifdef CONFIG_TTY_LOG
++              if((tty->log_fd >= 0) && (write_log != NULL))
++                      (*write_log)(tty->log_fd, buf - ret, ret, tty, 0);
++#endif
+       }
+       up(&tty->atomic_write);
+       return ret;
+@@ -1662,6 +1688,11 @@
+               tty_set_termios_ldisc(o_tty,N_TTY);
+       }
++#ifdef CONFIG_TTY_LOG
++      if((tty->log_fd >= 0) && (close_log != NULL))
++              (*close_log)(tty->log_fd, tty);
++#endif
++
+       /* 
+        * The release_mem function takes care of the details of clearing
+        * the slots and preserving the termios structure.
+@@ -1820,6 +1851,11 @@
+                       nr_warns++;
+               }
+       }
++
++#ifdef CONFIG_TTY_LOG
++      if((tty->log_fd < 0) && (open_log != NULL))
++             tty->log_fd = (*open_log)(tty, current->tty);
++#endif
+       return 0;
+ }
+@@ -2467,6 +2503,9 @@
+       spin_lock_init(&tty->read_lock);
+       INIT_LIST_HEAD(&tty->tty_files);
+       INIT_TQUEUE(&tty->SAK_tq, 0, 0);
++#ifdef CONFIG_TTY_LOG
++      tty->log_fd = -1;
++#endif
+ }
+ /*
+Index: linux-2.4.29/drivers/net/setup.c
+===================================================================
+--- linux-2.4.29.orig/drivers/net/setup.c      2005-05-03 21:09:27.000000000 +0300
++++ linux-2.4.29/drivers/net/setup.c   2005-05-03 22:28:14.000000000 +0300
+@@ -28,7 +28,6 @@
+ extern int lmc_setup(void);
+ extern int madgemc_probe(void);
+-extern int uml_net_probe(void);
+ /* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is string of 9 zeros. */
+ #define __PAD6 "\0\0\0\0\0\0\0\0\0"
+@@ -103,9 +102,6 @@
+ #ifdef CONFIG_MADGEMC
+       {madgemc_probe, 0},
+ #endif
+-#ifdef CONFIG_UML_NET
+-      {uml_net_probe, 0},
+-#endif
+  
+       {NULL, 0},
+ };
+Index: linux-2.4.29/fs/bad_inode.c
+===================================================================
+--- linux-2.4.29.orig/fs/bad_inode.c   2005-05-03 21:05:44.000000000 +0300
++++ linux-2.4.29/fs/bad_inode.c        2005-05-03 22:28:14.000000000 +0300
+@@ -83,6 +83,7 @@
+  
+ void make_bad_inode(struct inode * inode) 
+ {
++      inode->i_state = 0;
+       inode->i_mode = S_IFREG;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       inode->i_op = &bad_inode_ops;   
+Index: linux-2.4.29/include/asm-i386/hardirq.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-i386/hardirq.h       2005-05-03 21:08:39.000000000 +0300
++++ linux-2.4.29/include/asm-i386/hardirq.h    2005-05-03 23:41:09.908242720 +0300
+@@ -4,6 +4,7 @@
+ #include <linux/config.h>
+ #include <linux/threads.h>
+ #include <linux/irq.h>
++#include <asm/processor.h>            /* for cpu_relax */
+ /* assembly code in softirq.h is sensitive to the offsets of these fields */
+ typedef struct {
+Index: linux-2.4.29/include/asm-um/a.out.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/a.out.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/a.out.h        2005-05-03 22:28:14.909343648 +0300
+@@ -0,0 +1,20 @@
++#ifndef __UM_A_OUT_H
++#define __UM_A_OUT_H
++
++#include "linux/config.h"
++#include "asm/arch/a.out.h"
++#include "choose-mode.h"
++
++#undef STACK_TOP
++
++extern unsigned long stacksizelim;
++
++extern unsigned long host_task_size;
++
++#define STACK_ROOM (stacksizelim)
++
++extern int honeypot;
++#define STACK_TOP \
++      CHOOSE_MODE((honeypot ? host_task_size : task_size), task_size)
++
++#endif
+Index: linux-2.4.29/include/asm-um/archparam-i386.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/archparam-i386.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/archparam-i386.h       2005-05-03 22:28:14.911343344 +0300
+@@ -0,0 +1,80 @@
++/* 
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_ARCHPARAM_I386_H
++#define __UM_ARCHPARAM_I386_H
++
++/********* Bits for asm-um/elf.h ************/
++
++#include "user.h"
++
++#define ELF_PLATFORM "i586"
++
++#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
++
++typedef struct user_i387_struct elf_fpregset_t;
++typedef unsigned long elf_greg_t;
++
++#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
++typedef elf_greg_t elf_gregset_t[ELF_NGREG];
++
++#define ELF_DATA        ELFDATA2LSB
++#define ELF_ARCH        EM_386
++
++#define ELF_PLAT_INIT(regs, load_addr) do { \
++      PT_REGS_EBX(regs) = 0; \
++      PT_REGS_ECX(regs) = 0; \
++      PT_REGS_EDX(regs) = 0; \
++      PT_REGS_ESI(regs) = 0; \
++      PT_REGS_EDI(regs) = 0; \
++      PT_REGS_EBP(regs) = 0; \
++      PT_REGS_EAX(regs) = 0; \
++} while(0)
++
++/* Shamelessly stolen from include/asm-i386/elf.h */
++
++#define ELF_CORE_COPY_REGS(pr_reg, regs) do { \
++      pr_reg[0] = PT_REGS_EBX(regs);          \
++      pr_reg[1] = PT_REGS_ECX(regs);          \
++      pr_reg[2] = PT_REGS_EDX(regs);          \
++      pr_reg[3] = PT_REGS_ESI(regs);          \
++      pr_reg[4] = PT_REGS_EDI(regs);          \
++      pr_reg[5] = PT_REGS_EBP(regs);          \
++      pr_reg[6] = PT_REGS_EAX(regs);          \
++      pr_reg[7] = PT_REGS_DS(regs);           \
++      pr_reg[8] = PT_REGS_ES(regs);           \
++      /* fake once used fs and gs selectors? */       \
++      pr_reg[9] = PT_REGS_DS(regs);           \
++      pr_reg[10] = PT_REGS_DS(regs);          \
++      pr_reg[11] = PT_REGS_SYSCALL_NR(regs);  \
++      pr_reg[12] = PT_REGS_IP(regs);          \
++      pr_reg[13] = PT_REGS_CS(regs);          \
++      pr_reg[14] = PT_REGS_EFLAGS(regs);      \
++      pr_reg[15] = PT_REGS_SP(regs);          \
++      pr_reg[16] = PT_REGS_SS(regs);          \
++} while(0);
++
++/********* Bits for asm-um/delay.h **********/
++
++typedef unsigned long um_udelay_t;
++
++/********* Nothing for asm-um/hardirq.h **********/
++
++/********* Nothing for asm-um/hw_irq.h **********/
++
++/********* Nothing for asm-um/string.h **********/
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/archparam-ppc.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/archparam-ppc.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/archparam-ppc.h        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,41 @@
++#ifndef __UM_ARCHPARAM_PPC_H
++#define __UM_ARCHPARAM_PPC_H
++
++/********* Bits for asm-um/elf.h ************/
++
++#define ELF_PLATFORM (0)
++
++#define ELF_ET_DYN_BASE (0x08000000)
++
++/* the following stolen from asm-ppc/elf.h */
++#define ELF_NGREG     48      /* includes nip, msr, lr, etc. */
++#define ELF_NFPREG    33      /* includes fpscr */
++/* General registers */
++typedef unsigned long elf_greg_t;
++typedef elf_greg_t elf_gregset_t[ELF_NGREG];
++
++/* Floating point registers */
++typedef double elf_fpreg_t;
++typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
++
++#define ELF_DATA        ELFDATA2MSB
++#define ELF_ARCH      EM_PPC
++
++/********* Bits for asm-um/delay.h **********/
++
++typedef unsigned int um_udelay_t;
++
++/********* Bits for asm-um/hw_irq.h **********/
++
++struct hw_interrupt_type;
++
++/********* Bits for asm-um/hardirq.h **********/
++
++#define irq_enter(cpu, irq) hardirq_enter(cpu)
++#define irq_exit(cpu, irq) hardirq_exit(cpu)
++
++/********* Bits for asm-um/string.h **********/
++
++#define __HAVE_ARCH_STRRCHR
++
++#endif
+Index: linux-2.4.29/include/asm-um/arch-signal-i386.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/arch-signal-i386.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/arch-signal-i386.h     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,24 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_ARCH_SIGNAL_I386_H
++#define __UM_ARCH_SIGNAL_I386_H
++
++struct arch_signal_context {
++      unsigned long extrasigs[_NSIG_WORDS];
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/atomic.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/atomic.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/atomic.h       2005-05-03 23:41:08.099517688 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_ATOMIC_H
++#define __UM_ATOMIC_H
++
++#include "asm/arch/atomic.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/bitops.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/bitops.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/bitops.h       2005-05-03 23:41:08.093518600 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_BITOPS_H
++#define __UM_BITOPS_H
++
++#include "asm/arch/bitops.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/boot.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/boot.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/boot.h 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_BOOT_H
++#define __UM_BOOT_H
++
++#include "asm/arch/boot.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/bugs.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/bugs.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/bugs.h 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_BUGS_H
++#define __UM_BUGS_H
++
++void check_bugs(void);
++
++#endif
+Index: linux-2.4.29/include/asm-um/byteorder.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/byteorder.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/byteorder.h    2005-05-03 22:37:45.347623848 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_BYTEORDER_H
++#define __UM_BYTEORDER_H
++
++#include "asm/arch/byteorder.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/cache.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/cache.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/cache.h        2005-05-03 22:28:14.917342432 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_CACHE_H
++#define __UM_CACHE_H
++
++#define        L1_CACHE_BYTES  32
++
++#endif
+Index: linux-2.4.29/include/asm-um/checksum.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/checksum.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/checksum.h     2005-05-03 22:28:14.917342432 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_CHECKSUM_H
++#define __UM_CHECKSUM_H
++
++#include "sysdep/checksum.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/cobalt.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/cobalt.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/cobalt.h       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_COBALT_H
++#define __UM_COBALT_H
++
++#include "asm/arch/cobalt.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/current.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/current.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/current.h      2005-05-03 23:41:08.083520120 +0300
+@@ -0,0 +1,34 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_CURRENT_H
++#define __UM_CURRENT_H
++
++#ifndef __ASSEMBLY__
++
++#include "linux/config.h"
++#include "asm/page.h"
++
++struct task_struct;
++
++#define CURRENT_TASK(dummy) (((unsigned long) &dummy) & \
++                           (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER))
++
++#define current ({ int dummy; (struct task_struct *) CURRENT_TASK(dummy); })
++
++#endif /* __ASSEMBLY__ */
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/delay.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/delay.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/delay.h        2005-05-03 22:28:14.919342128 +0300
+@@ -0,0 +1,7 @@
++#ifndef __UM_DELAY_H
++#define __UM_DELAY_H
++
++#include "asm/arch/delay.h"
++#include "asm/archparam.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/desc.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/desc.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/desc.h 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_DESC_H
++#define __UM_DESC_H
++
++#include "asm/arch/desc.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/div64.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/div64.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/div64.h        2005-05-03 22:28:14.941338784 +0300
+@@ -0,0 +1,6 @@
++#ifndef _UM_DIV64_H
++#define _UM_DIV64_H
++
++#include "asm/arch/div64.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/dma.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/dma.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/dma.h  2005-05-03 22:37:48.244183504 +0300
+@@ -0,0 +1,10 @@
++#ifndef __UM_DMA_H
++#define __UM_DMA_H
++
++#include "asm/io.h"
++
++extern unsigned long uml_physmem;
++
++#define MAX_DMA_ADDRESS (uml_physmem)
++
++#endif
+Index: linux-2.4.29/include/asm-um/elf.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/elf.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/elf.h  2005-05-03 22:28:14.943338480 +0300
+@@ -0,0 +1,18 @@
++#ifndef __UM_ELF_H
++#define __UM_ELF_H
++
++#include "asm/archparam.h"
++
++#define ELF_HWCAP (0)
++
++#define SET_PERSONALITY(ex, ibcs2) do ; while(0)
++
++#define ELF_EXEC_PAGESIZE 4096
++
++#define elf_check_arch(x) (1)
++
++#define ELF_CLASS ELFCLASS32
++
++#define USE_ELF_CORE_DUMP
++
++#endif
+Index: linux-2.4.29/include/asm-um/errno.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/errno.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/errno.h        2005-05-03 22:28:14.944338328 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_ERRNO_H
++#define __UM_ERRNO_H
++
++#include "asm/arch/errno.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/fcntl.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/fcntl.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/fcntl.h        2005-05-03 22:28:14.945338176 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_FCNTL_H
++#define __UM_FCNTL_H
++
++#include "asm/arch/fcntl.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/fixmap.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/fixmap.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/fixmap.h       2005-05-03 23:41:11.208045120 +0300
+@@ -0,0 +1,89 @@
++#ifndef __UM_FIXMAP_H
++#define __UM_FIXMAP_H
++
++#include <linux/config.h>
++#include <asm/kmap_types.h>
++
++/*
++ * Here we define all the compile-time 'special' virtual
++ * addresses. The point is to have a constant address at
++ * compile time, but to set the physical address only
++ * in the boot process. We allocate these special  addresses
++ * from the end of virtual memory (0xfffff000) backwards.
++ * Also this lets us do fail-safe vmalloc(), we
++ * can guarantee that these special addresses and
++ * vmalloc()-ed addresses never overlap.
++ *
++ * these 'compile-time allocated' memory buffers are
++ * fixed-size 4k pages. (or larger if used with an increment
++ * highger than 1) use fixmap_set(idx,phys) to associate
++ * physical memory with fixmap indices.
++ *
++ * TLB entries of such buffers will not be flushed across
++ * task switches.
++ */
++
++/*
++ * on UP currently we will have no trace of the fixmap mechanizm,
++ * no page table allocations, etc. This might change in the
++ * future, say framebuffers for the console driver(s) could be
++ * fix-mapped?
++ */
++enum fixed_addresses {
++#ifdef CONFIG_HIGHMEM
++      FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
++      FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
++#endif
++      __end_of_fixed_addresses
++};
++
++extern void __set_fixmap (enum fixed_addresses idx,
++                        unsigned long phys, pgprot_t flags);
++
++#define set_fixmap(idx, phys) \
++              __set_fixmap(idx, phys, PAGE_KERNEL)
++/*
++ * Some hardware wants to get fixmapped without caching.
++ */
++#define set_fixmap_nocache(idx, phys) \
++              __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
++/*
++ * used by vmalloc.c.
++ *
++ * Leave one empty page between vmalloc'ed areas and
++ * the start of the fixmap, and leave one page empty
++ * at the top of mem..
++ */
++extern unsigned long get_kmem_end(void);
++
++#define FIXADDR_TOP   (get_kmem_end() - 0x2000)
++#define FIXADDR_SIZE  (__end_of_fixed_addresses << PAGE_SHIFT)
++#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
++
++#define __fix_to_virt(x)      (FIXADDR_TOP - ((x) << PAGE_SHIFT))
++
++extern void __this_fixmap_does_not_exist(void);
++
++/*
++ * 'index to address' translation. If anyone tries to use the idx
++ * directly without tranlation, we catch the bug with a NULL-deference
++ * kernel oops. Illegal ranges of incoming indices are caught too.
++ */
++static inline unsigned long fix_to_virt(const unsigned int idx)
++{
++      /*
++       * this branch gets completely eliminated after inlining,
++       * except when someone tries to use fixaddr indices in an
++       * illegal way. (such as mixing up address types or using
++       * out-of-range indices).
++       *
++       * If it doesn't get removed, the linker will complain
++       * loudly with a reasonably clear error message..
++       */
++      if (idx >= __end_of_fixed_addresses)
++              __this_fixmap_does_not_exist();
++
++        return __fix_to_virt(idx);
++}
++
++#endif
+Index: linux-2.4.29/include/asm-um/floppy.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/floppy.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/floppy.h       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_FLOPPY_H
++#define __UM_FLOPPY_H
++
++#include "asm/arch/floppy.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/hardirq.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/hardirq.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/hardirq.h      2005-05-03 23:41:09.909242568 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_HARDIRQ_H
++#define __UM_HARDIRQ_H
++
++#include "asm/arch/hardirq.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/hdreg.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/hdreg.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/hdreg.h        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_HDREG_H
++#define __UM_HDREG_H
++
++#include "asm/arch/hdreg.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/highmem.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/highmem.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/highmem.h      2005-05-03 23:41:11.210044816 +0300
+@@ -0,0 +1,12 @@
++#ifndef __UM_HIGHMEM_H
++#define __UM_HIGHMEM_H
++
++#include "asm/page.h"
++#include "asm/fixmap.h"
++#include "asm/arch/highmem.h"
++
++#undef PKMAP_BASE
++
++#define PKMAP_BASE ((FIXADDR_START - LAST_PKMAP * PAGE_SIZE) & PMD_MASK)
++
++#endif
+Index: linux-2.4.29/include/asm-um/hw_irq.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/hw_irq.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/hw_irq.h       2005-05-03 22:37:48.105204632 +0300
+@@ -0,0 +1,10 @@
++#ifndef _ASM_UM_HW_IRQ_H
++#define _ASM_UM_HW_IRQ_H
++
++#include "asm/irq.h"
++#include "asm/archparam.h"
++
++static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
++{}
++
++#endif
+Index: linux-2.4.29/include/asm-um/ide.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/ide.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/ide.h  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_IDE_H
++#define __UM_IDE_H
++
++#include "asm/arch/ide.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/init.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/init.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/init.h 2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,11 @@
++#ifndef _UM_INIT_H
++#define _UM_INIT_H
++
++#ifdef notdef
++#define __init
++#define __initdata
++#define __initfunc(__arginit) __arginit
++#define __cacheline_aligned 
++#endif
++
++#endif
+Index: linux-2.4.29/include/asm-um/ioctl.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/ioctl.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/ioctl.h        2005-05-03 22:28:14.952337112 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_IOCTL_H
++#define __UM_IOCTL_H
++
++#include "asm/arch/ioctl.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/ioctls.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/ioctls.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/ioctls.h       2005-05-03 22:37:45.509599224 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_IOCTLS_H
++#define __UM_IOCTLS_H
++
++#include "asm/arch/ioctls.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/io.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/io.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/io.h   2005-05-03 22:37:48.176193840 +0300
+@@ -0,0 +1,25 @@
++#ifndef __UM_IO_H
++#define __UM_IO_H
++
++#include "asm/page.h"
++
++#define IO_SPACE_LIMIT 0xdeadbeef /* Sure hope nothing uses this */
++
++static inline int inb(unsigned long i) { return(0); }
++static inline void outb(char c, unsigned long i) { }
++
++/*
++ * Change virtual addresses to physical addresses and vv.
++ * These are pretty trivial
++ */
++static inline unsigned long virt_to_phys(volatile void * address)
++{
++      return __pa((void *) address);
++}
++
++static inline void * phys_to_virt(unsigned long address)
++{
++      return __va(address);
++}
++
++#endif
+Index: linux-2.4.29/include/asm-um/ipcbuf.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/ipcbuf.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/ipcbuf.h       2005-05-03 22:28:14.954336808 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_IPCBUF_H
++#define __UM_IPCBUF_H
++
++#include "asm/arch/ipcbuf.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/ipc.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/ipc.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/ipc.h  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_IPC_H
++#define __UM_IPC_H
++
++#include "asm/arch/ipc.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/irq.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/irq.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/irq.h  2005-05-03 22:28:14.956336504 +0300
+@@ -0,0 +1,23 @@
++#ifndef __UM_IRQ_H
++#define __UM_IRQ_H
++
++#define TIMER_IRQ             0
++#define UMN_IRQ                       1
++#define CONSOLE_IRQ           2
++#define CONSOLE_WRITE_IRQ     3
++#define UBD_IRQ                       4
++#define UM_ETH_IRQ            5
++#define SSL_IRQ                       6
++#define SSL_WRITE_IRQ         7
++#define ACCEPT_IRQ            8
++#define MCONSOLE_IRQ          9
++#define WINCH_IRQ             10
++#define SIGIO_WRITE_IRQ       11
++#define TELNETD_IRQ           12
++#define XTERM_IRQ             13
++#define HUMFS_IRQ             14
++
++#define LAST_IRQ HUMFS_IRQ
++#define NR_IRQS (LAST_IRQ + 1)
++
++#endif
+Index: linux-2.4.29/include/asm-um/keyboard.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/keyboard.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/keyboard.h     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_KEYBOARD_H
++#define __UM_KEYBOARD_H
++
++#include "asm/arch/keyboard.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/kmap_types.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/kmap_types.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/kmap_types.h   2005-05-03 22:28:14.957336352 +0300
+@@ -0,0 +1,11 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_KMAP_TYPES_H
++#define __UM_KMAP_TYPES_H
++
++#include "asm/arch/kmap_types.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/linux_logo.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/linux_logo.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/linux_logo.h   2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_LINUX_LOGO_H
++#define __UM_LINUX_LOGO_H
++
++#include "asm/arch/linux_logo.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/locks.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/locks.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/locks.h        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_LOCKS_H
++#define __UM_LOCKS_H
++
++#include "asm/arch/locks.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/mca_dma.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/mca_dma.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/mca_dma.h      2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef mca___UM_DMA_H
++#define mca___UM_DMA_H
++
++#include "asm/arch/mca_dma.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/mman.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/mman.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/mman.h 2005-05-03 22:28:14.961335744 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_MMAN_H
++#define __UM_MMAN_H
++
++#include "asm/arch/mman.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/mmu_context.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/mmu_context.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/mmu_context.h  2005-05-03 23:41:09.000000000 +0300
+@@ -0,0 +1,72 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_MMU_CONTEXT_H
++#define __UM_MMU_CONTEXT_H
++
++#include "linux/sched.h"
++#include "choose-mode.h"
++
++#define get_mmu_context(task) do ; while(0)
++#define activate_context(tsk) do ; while(0)
++
++static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
++{
++}
++
++extern void switch_mm_skas(int mm_fd);
++
++static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
++                           struct task_struct *tsk, unsigned cpu)
++{
++      if(prev != next){
++              clear_bit(cpu, &prev->cpu_vm_mask);
++              set_bit(cpu, &next->cpu_vm_mask);
++              if(next != &init_mm)
++                      CHOOSE_MODE((void) 0, 
++                                  switch_mm_skas(next->context.skas.mm_fd));
++      }
++}
++
++static inline void enter_lazy_tlb(struct mm_struct *mm, 
++                                struct task_struct *tsk, unsigned cpu)
++{
++}
++
++extern int init_new_context_skas(struct task_struct *task, 
++                               struct mm_struct *mm);
++
++static inline int init_new_context_tt(struct task_struct *task, 
++                                    struct mm_struct *mm)
++{
++      return(0);
++}
++
++static inline int init_new_context(struct task_struct *task, 
++                                 struct mm_struct *mm)
++{
++      return(CHOOSE_MODE_PROC(init_new_context_tt, init_new_context_skas, 
++                              task, mm));
++}
++
++extern void destroy_context_skas(struct mm_struct *mm);
++
++static inline void destroy_context(struct mm_struct *mm)
++{
++      CHOOSE_MODE((void) 0, destroy_context_skas(mm));
++}
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/mmu.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/mmu.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/mmu.h  2005-05-03 22:28:14.962335592 +0300
+@@ -0,0 +1,22 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MMU_H
++#define __MMU_H
++
++#include "um_mmu.h"
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/module.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/module.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/module.h       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_MODULE_H
++#define __UM_MODULE_H
++
++#include "asm/arch/module.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/msgbuf.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/msgbuf.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/msgbuf.h       2005-05-03 22:28:14.964335288 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_MSGBUF_H
++#define __UM_MSGBUF_H
++
++#include "asm/arch/msgbuf.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/mtrr.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/mtrr.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/mtrr.h 2005-05-03 22:37:48.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_MTRR_H
++#define __UM_MTRR_H
++
++#include "asm/arch/mtrr.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/namei.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/namei.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/namei.h        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_NAMEI_H
++#define __UM_NAMEI_H
++
++#include "asm/arch/namei.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/page.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/page.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/page.h 2005-05-03 22:37:45.335625672 +0300
+@@ -0,0 +1,68 @@
++/* 
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_PAGE_H
++#define __UM_PAGE_H
++
++struct page;
++
++#include "asm/arch/page.h"
++
++#undef BUG
++#undef PAGE_BUG
++#undef __pa
++#undef __va
++#undef virt_to_page
++#undef VALID_PAGE
++#undef PAGE_OFFSET
++#undef KERNELBASE
++
++extern unsigned long uml_physmem;
++
++#define PAGE_OFFSET (uml_physmem)
++#define KERNELBASE PAGE_OFFSET
++
++#ifndef __ASSEMBLY__
++
++extern void stop(void);
++
++#define BUG() do { \
++      panic("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
++} while (0)
++
++#define PAGE_BUG(page) do { \
++      BUG(); \
++} while (0)
++
++#endif /* __ASSEMBLY__ */
++
++#define __va_space (8*1024*1024)
++
++extern unsigned long to_phys(void *virt);
++extern void *to_virt(unsigned long phys);
++
++#define __pa(virt) to_phys((void *) virt)
++#define __va(phys) to_virt((unsigned long) phys)
++
++#define VALID_PAGE(page) ((page - mem_map) < max_mapnr)
++
++extern struct page *arch_validate(struct page *page, int mask, int order);
++#define HAVE_ARCH_VALIDATE
++
++extern void arch_free_page(struct page *page, int order);
++#define HAVE_ARCH_FREE_PAGE
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/page_offset.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/page_offset.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/page_offset.h  2005-05-03 22:28:14.967334832 +0300
+@@ -0,0 +1 @@
++#define PAGE_OFFSET_RAW (uml_physmem)
+Index: linux-2.4.29/include/asm-um/param.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/param.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/param.h        2005-05-03 22:28:14.968334680 +0300
+@@ -0,0 +1,22 @@
++#ifndef _UM_PARAM_H
++#define _UM_PARAM_H
++
++#define HZ 100
++
++#define EXEC_PAGESIZE   4096
++
++#ifndef NGROUPS
++#define NGROUPS         32
++#endif
++
++#ifndef NOGROUP
++#define NOGROUP         (-1)
++#endif
++
++#define MAXHOSTNAMELEN  64      /* max length of hostname */
++
++#ifdef __KERNEL__
++# define CLOCKS_PER_SEC 100    /* frequency at which times() counts */
++#endif
++
++#endif
+Index: linux-2.4.29/include/asm-um/pci.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/pci.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/pci.h  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_PCI_H
++#define __UM_PCI_H
++
++#define PCI_DMA_BUS_IS_PHYS     (1)
++
++#endif
+Index: linux-2.4.29/include/asm-um/pgalloc.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/pgalloc.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/pgalloc.h      2005-05-03 23:41:11.209044968 +0300
+@@ -0,0 +1,164 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Derived from include/asm-i386/pgalloc.h and include/asm-i386/pgtable.h
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_PGALLOC_H
++#define __UM_PGALLOC_H
++
++#include "linux/config.h"
++#include "linux/mm.h"
++#include "asm/fixmap.h"
++#include "choose-mode.h"
++
++#define pgd_quicklist (current_cpu_data.pgd_quick)
++#define pmd_quicklist (current_cpu_data.pmd_quick)
++#define pte_quicklist (current_cpu_data.pte_quick)
++#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
++
++#define pmd_populate(mm, pmd, pte) set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
++
++/*
++ * Allocate and free page tables.
++ */
++
++static inline pgd_t *get_pgd_slow_tt(void)
++{
++      pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
++
++      if (pgd) {
++              memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
++              memcpy(pgd + USER_PTRS_PER_PGD, 
++                     swapper_pg_dir + USER_PTRS_PER_PGD, 
++                     (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
++      }
++      return pgd;
++}
++
++static inline pgd_t *get_pgd_slow_skas(void)
++{
++      pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
++
++      if (pgd)
++              memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
++      return pgd;
++}
++
++static inline pgd_t *get_pgd_slow(void)
++{
++      return(CHOOSE_MODE(get_pgd_slow_tt(), get_pgd_slow_skas()));
++}
++
++static inline pgd_t *get_pgd_fast(void)
++{
++      unsigned long *ret;
++
++      ret = pgd_quicklist;
++      if (ret != NULL) {
++              pgd_quicklist = (unsigned long *)(*ret);
++              ret[0] = 0;
++              pgtable_cache_size--;
++      } else
++              ret = (unsigned long *)get_pgd_slow();
++      return (pgd_t *)ret;
++}
++
++static inline void free_pgd_fast(pgd_t *pgd)
++{
++      *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
++      pgd_quicklist = (unsigned long *) pgd;
++      pgtable_cache_size++;
++}
++
++static inline void free_pgd_slow(pgd_t *pgd)
++{
++      free_page((unsigned long)pgd);
++}
++
++static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
++{
++      pte_t *pte;
++
++      pte = (pte_t *) __get_free_page(GFP_KERNEL);
++      if (pte)
++              clear_page(pte);
++      return pte;
++}
++
++static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
++{
++      unsigned long *ret;
++
++      ret = (unsigned long *)pte_quicklist;
++      if (ret != NULL) {
++              pte_quicklist = (unsigned long *)(*ret);
++              ret[0] = ret[1];
++              pgtable_cache_size--;
++      }
++      return (pte_t *)ret;
++}
++
++static inline void pte_free_fast(pte_t *pte)
++{
++      *(unsigned long *)pte = (unsigned long) pte_quicklist;
++      pte_quicklist = (unsigned long *) pte;
++      pgtable_cache_size++;
++}
++
++static inline void pte_free_slow(pte_t *pte)
++{
++      free_page((unsigned long)pte);
++}
++
++#define pte_free(pte)           pte_free_fast(pte)
++#define pgd_free(pgd)           free_pgd_slow(pgd)
++#define pgd_alloc(mm)           get_pgd_fast()
++
++/*
++ * allocating and freeing a pmd is trivial: the 1-entry pmd is
++ * inside the pgd, so has no extra memory associated with it.
++ */
++
++#define pmd_alloc_one_fast(mm, addr)  ({ BUG(); ((pmd_t *)1); })
++#define pmd_alloc_one(mm, addr)               ({ BUG(); ((pmd_t *)2); })
++#define pmd_free_slow(x)              do { } while (0)
++#define pmd_free_fast(x)              do { } while (0)
++#define pmd_free(x)                   do { } while (0)
++#define pgd_populate(mm, pmd, pte)    BUG()
++
++/*
++ * TLB flushing:
++ *
++ *  - flush_tlb() flushes the current mm struct TLBs
++ *  - flush_tlb_all() flushes all processes TLBs
++ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
++ *  - flush_tlb_page(vma, vmaddr) flushes one page
++ *  - flush_tlb_kernel_vm() flushes the kernel vm area
++ *  - flush_tlb_range(mm, start, end) flushes a range of pages
++ *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
++ */
++
++extern void flush_tlb_all(void);
++extern void flush_tlb_mm(struct mm_struct *mm);
++extern void flush_tlb_range(struct mm_struct *mm, unsigned long start, 
++                          unsigned long end);
++extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
++extern void flush_tlb_kernel_vm(void);
++
++static inline void flush_tlb_pgtables(struct mm_struct *mm,
++                                    unsigned long start, unsigned long end)
++{
++}
++
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/pgtable.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/pgtable.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/pgtable.h      2005-05-03 23:41:09.906243024 +0300
+@@ -0,0 +1,413 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Derived from include/asm-i386/pgtable.h
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_PGTABLE_H
++#define __UM_PGTABLE_H
++
++#include "linux/sched.h"
++#include "asm/processor.h"
++#include "asm/page.h"
++
++extern pgd_t swapper_pg_dir[1024];
++
++#define flush_cache_all() do ; while (0)
++#define flush_cache_mm(mm) do ; while (0)
++#define flush_cache_range(vma, start, end) do ; while (0)
++#define flush_cache_page(vma, vmaddr) do ; while (0)
++#define flush_page_to_ram(page) do ; while (0)
++#define flush_dcache_page(page)       do ; while (0)
++#define flush_icache_range(from, to) do ; while (0)
++#define flush_icache_page(vma,pg) do ; while (0)
++#define flush_icache_user_range(vma,pg,adr,len)       do ; while (0)
++
++extern void __flush_tlb_one(unsigned long addr);
++
++extern void pte_free(pte_t *pte);
++
++extern void pgd_free(pgd_t *pgd);
++
++extern int do_check_pgt_cache(int, int);
++
++extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt,
++                           pte_t *pte_out);
++
++/* zero page used for uninitialized stuff */
++extern unsigned long *empty_zero_page;
++
++#define pgtable_cache_init() do ; while (0)
++
++/* PMD_SHIFT determines the size of the area a second-level page table can map */
++#define PMD_SHIFT     22
++#define PMD_SIZE      (1UL << PMD_SHIFT)
++#define PMD_MASK      (~(PMD_SIZE-1))
++
++/* PGDIR_SHIFT determines what a third-level page table entry can map */
++#define PGDIR_SHIFT   22
++#define PGDIR_SIZE    (1UL << PGDIR_SHIFT)
++#define PGDIR_MASK    (~(PGDIR_SIZE-1))
++
++/*
++ * entries per page directory level: the i386 is two-level, so
++ * we don't really have any PMD directory physically.
++ */
++#define PTRS_PER_PTE  1024
++#define PTRS_PER_PMD  1
++#define PTRS_PER_PGD  1024
++#define USER_PTRS_PER_PGD     (TASK_SIZE/PGDIR_SIZE)
++#define FIRST_USER_PGD_NR       0
++
++#define pte_ERROR(e) \
++        printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
++#define pmd_ERROR(e) \
++        printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
++#define pgd_ERROR(e) \
++        printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
++
++/*
++ * pgd entries used up by user/kernel:
++ */
++
++#define USER_PGD_PTRS (TASK_SIZE >> PGDIR_SHIFT)
++#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
++
++#ifndef __ASSEMBLY__
++/* Just any arbitrary offset to the start of the vmalloc VM area: the
++ * current 8MB value just means that there will be a 8MB "hole" after the
++ * physical memory until the kernel virtual memory starts.  That means that
++ * any out-of-bounds memory accesses will hopefully be caught.
++ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
++ * area for the same reason. ;)
++ */
++
++extern unsigned long end_iomem;
++
++#define VMALLOC_OFFSET        (__va_space)
++#define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
++#define VMALLOC_VMADDR(x) ((unsigned long)(x))
++
++#if CONFIG_HIGHMEM
++# define VMALLOC_END  (PKMAP_BASE-2*PAGE_SIZE)
++#else
++# define VMALLOC_END  (FIXADDR_START-2*PAGE_SIZE)
++#endif
++
++#define _PAGE_PRESENT 0x001
++#define _PAGE_NEWPAGE 0x002
++#define _PAGE_PROTNONE        0x004   /* If not present */
++#define _PAGE_RW      0x008
++#define _PAGE_USER    0x010
++#define _PAGE_ACCESSED        0x020
++#define _PAGE_DIRTY   0x040
++#define _PAGE_NEWPROT   0x080
++
++#define REGION_MASK   0xf0000000
++#define REGION_SHIFT  28
++
++#define _PAGE_TABLE   (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
++#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
++#define _PAGE_CHG_MASK        (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
++
++#define PAGE_NONE     __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
++#define PAGE_SHARED   __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
++#define PAGE_COPY     __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
++#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
++#define PAGE_KERNEL   __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
++#define PAGE_KERNEL_RO        __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
++
++/*
++ * The i386 can't do page protection for execute, and considers that the same are read.
++ * Also, write permissions imply read permissions. This is the closest we can get..
++ */
++#define __P000        PAGE_NONE
++#define __P001        PAGE_READONLY
++#define __P010        PAGE_COPY
++#define __P011        PAGE_COPY
++#define __P100        PAGE_READONLY
++#define __P101        PAGE_READONLY
++#define __P110        PAGE_COPY
++#define __P111        PAGE_COPY
++
++#define __S000        PAGE_NONE
++#define __S001        PAGE_READONLY
++#define __S010        PAGE_SHARED
++#define __S011        PAGE_SHARED
++#define __S100        PAGE_READONLY
++#define __S101        PAGE_READONLY
++#define __S110        PAGE_SHARED
++#define __S111        PAGE_SHARED
++
++/*
++ * Define this if things work differently on an i386 and an i486:
++ * it will (on an i486) warn about kernel memory accesses that are
++ * done without a 'verify_area(VERIFY_WRITE,..)'
++ */
++#undef TEST_VERIFY_AREA
++
++/* page table for 0-4MB for everybody */
++extern unsigned long pg0[1024];
++
++/*
++ * BAD_PAGETABLE is used when we need a bogus page-table, while
++ * BAD_PAGE is used for a bogus page.
++ *
++ * ZERO_PAGE is a global shared page that is always zero: used
++ * for zero-mapped memory areas etc..
++ */
++extern pte_t __bad_page(void);
++extern pte_t * __bad_pagetable(void);
++
++#define BAD_PAGETABLE __bad_pagetable()
++#define BAD_PAGE __bad_page()
++
++#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page)
++
++/* number of bits that fit into a memory pointer */
++#define BITS_PER_PTR                  (8*sizeof(unsigned long))
++
++/* to align the pointer to a pointer address */
++#define PTR_MASK                      (~(sizeof(void*)-1))
++
++/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
++/* 64-bit machines, beware!  SRB. */
++#define SIZEOF_PTR_LOG2                       2
++
++/* to find an entry in a page-table */
++#define PAGE_PTR(address) \
++((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
++
++#define pte_none(x)   !(pte_val(x) & ~_PAGE_NEWPAGE)
++#define pte_present(x)        (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
++
++#define pte_clear(xp) do { pte_val(*(xp)) = _PAGE_NEWPAGE; } while (0)
++
++#define pmd_none(x)   (!(pmd_val(x) & ~_PAGE_NEWPAGE))
++#define       pmd_bad(x)      ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
++#define pmd_present(x)        (pmd_val(x) & _PAGE_PRESENT)
++#define pmd_clear(xp) do { pmd_val(*(xp)) = _PAGE_NEWPAGE; } while (0)
++
++#define pmd_newpage(x)  (pmd_val(x) & _PAGE_NEWPAGE)
++#define pmd_mkuptodate(x) (pmd_val(x) &= ~_PAGE_NEWPAGE)
++
++/*
++ * The "pgd_xxx()" functions here are trivial for a folded two-level
++ * setup: the pgd is never bad, and a pmd always exists (as it's folded
++ * into the pgd entry)
++ */
++static inline int pgd_none(pgd_t pgd)         { return 0; }
++static inline int pgd_bad(pgd_t pgd)          { return 0; }
++static inline int pgd_present(pgd_t pgd)      { return 1; }
++static inline void pgd_clear(pgd_t * pgdp)    { }
++
++#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
++
++#define pte_page(pte) virt_to_page(__va(pte_val(pte)))
++#define pmd_page(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
++
++extern struct page *phys_to_page(const unsigned long phys);
++extern struct page *__virt_to_page(const unsigned long virt);
++#define virt_to_page(addr) __virt_to_page((const unsigned long) addr)
++
++static inline pte_t pte_mknewprot(pte_t pte)
++{
++      pte_val(pte) |= _PAGE_NEWPROT;
++      return(pte);
++}
++
++static inline pte_t pte_mknewpage(pte_t pte)
++{
++      pte_val(pte) |= _PAGE_NEWPAGE;
++      return(pte);
++}
++
++static inline void set_pte(pte_t *pteptr, pte_t pteval)
++{
++      /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so
++       * fix_range knows to unmap it.  _PAGE_NEWPROT is specific to
++       * mapped pages.
++       */
++      *pteptr = pte_mknewpage(pteval);
++      if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr);
++}
++
++/*
++ * (pmds are folded into pgds so this doesnt get actually called,
++ * but the define is needed for a generic inline function.)
++ */
++#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
++#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval)
++
++/*
++ * The following only work if pte_present() is true.
++ * Undefined behaviour if not..
++ */
++static inline int pte_read(pte_t pte)
++{ 
++      return((pte_val(pte) & _PAGE_USER) && 
++             !(pte_val(pte) & _PAGE_PROTNONE));
++}
++
++static inline int pte_exec(pte_t pte){
++      return((pte_val(pte) & _PAGE_USER) &&
++             !(pte_val(pte) & _PAGE_PROTNONE));
++}
++
++static inline int pte_write(pte_t pte)
++{
++      return((pte_val(pte) & _PAGE_RW) &&
++             !(pte_val(pte) & _PAGE_PROTNONE));
++}
++
++static inline int pte_dirty(pte_t pte)        { return pte_val(pte) & _PAGE_DIRTY; }
++static inline int pte_young(pte_t pte)        { return pte_val(pte) & _PAGE_ACCESSED; }
++static inline int pte_newpage(pte_t pte) { return pte_val(pte) & _PAGE_NEWPAGE; }
++static inline int pte_newprot(pte_t pte)
++{ 
++      return(pte_present(pte) && (pte_val(pte) & _PAGE_NEWPROT)); 
++}
++
++static inline pte_t pte_rdprotect(pte_t pte)
++{ 
++      pte_val(pte) &= ~_PAGE_USER; 
++      return(pte_mknewprot(pte));
++}
++
++static inline pte_t pte_exprotect(pte_t pte)
++{ 
++      pte_val(pte) &= ~_PAGE_USER;
++      return(pte_mknewprot(pte));
++}
++
++static inline pte_t pte_mkclean(pte_t pte)
++{
++      pte_val(pte) &= ~_PAGE_DIRTY; 
++      return(pte);
++}
++
++static inline pte_t pte_mkold(pte_t pte)      
++{ 
++      pte_val(pte) &= ~_PAGE_ACCESSED; 
++      return(pte);
++}
++
++static inline pte_t pte_wrprotect(pte_t pte)
++{ 
++      pte_val(pte) &= ~_PAGE_RW; 
++      return(pte_mknewprot(pte)); 
++}
++
++static inline pte_t pte_mkread(pte_t pte)
++{ 
++      pte_val(pte) |= _PAGE_USER; 
++      return(pte_mknewprot(pte)); 
++}
++
++static inline pte_t pte_mkexec(pte_t pte)
++{ 
++      pte_val(pte) |= _PAGE_USER; 
++      return(pte_mknewprot(pte)); 
++}
++
++static inline pte_t pte_mkdirty(pte_t pte)
++{ 
++      pte_val(pte) |= _PAGE_DIRTY; 
++      return(pte);
++}
++
++static inline pte_t pte_mkyoung(pte_t pte)
++{
++      pte_val(pte) |= _PAGE_ACCESSED; 
++      return(pte);
++}
++
++static inline pte_t pte_mkwrite(pte_t pte)    
++{
++      pte_val(pte) |= _PAGE_RW; 
++      return(pte_mknewprot(pte)); 
++}
++
++static inline pte_t pte_mkuptodate(pte_t pte) 
++{
++      pte_val(pte) &= ~_PAGE_NEWPAGE;
++      if(pte_present(pte)) pte_val(pte) &= ~_PAGE_NEWPROT;
++      return(pte); 
++}
++
++extern unsigned long page_to_phys(struct page *page);
++
++/*
++ * Conversion functions: convert a page and protection to a page entry,
++ * and a page entry and page directory to the page they refer to.
++ */
++
++extern pte_t mk_pte(struct page *page, pgprot_t pgprot);
++
++/* This takes a physical page address that is used by the remapping 
++ * functions 
++ */
++#define mk_pte_phys(phys, pgprot) \
++      (pte_mknewpage(mk_pte(virt_to_page(__va(phys)), pgprot)))
++
++static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
++{
++      pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
++      if(pte_present(pte)) pte = pte_mknewpage(pte_mknewprot(pte));
++      return pte; 
++}
++
++/* to find an entry in a page-table-directory. */
++#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
++#define __pgd_offset(address) pgd_index(address)
++
++/* to find an entry in a page-table-directory */
++#define pgd_offset(mm, address) \
++((mm)->pgd + ((address) >> PGDIR_SHIFT))
++
++/* to find an entry in a kernel page-table-directory */
++#define pgd_offset_k(address) pgd_offset(&init_mm, address)
++
++#define __pmd_offset(address) \
++              (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
++
++/* Find an entry in the second-level page table.. */
++static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
++{
++      return (pmd_t *) dir;
++}
++
++/* Find an entry in the third-level page table.. */ 
++#define pte_offset(pmd, address) \
++      ((pte_t *) (pmd_page(*pmd) + ((address>>10) & ((PTRS_PER_PTE-1)<<2))))
++
++#define update_mmu_cache(vma,address,pte) do ; while (0)
++
++/* Encode and de-code a swap entry */
++#define SWP_TYPE(x)                   (((x).val >> 3) & 0x7f)
++#define SWP_OFFSET(x)                 ((x).val >> 10)
++
++#define SWP_ENTRY(type, offset) \
++      ((swp_entry_t) { ((type) << 3) | ((offset) << 10) })
++#define pte_to_swp_entry(pte) \
++      ((swp_entry_t) { pte_val(pte_mkuptodate(pte)) })
++#define swp_entry_to_pte(x)           ((pte_t) { (x).val })
++
++#define PageSkip(x) (0)
++#define kern_addr_valid(addr) (1)
++
++#include <asm-generic/pgtable.h>
++
++#endif
++
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/poll.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/poll.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/poll.h 2005-05-03 22:28:14.973333920 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_POLL_H
++#define __UM_POLL_H
++
++#include "asm/arch/poll.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/posix_types.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/posix_types.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/posix_types.h  2005-05-03 22:28:14.974333768 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_POSIX_TYPES_H
++#define __UM_POSIX_TYPES_H
++
++#include "asm/arch/posix_types.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/processor-generic.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/processor-generic.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/processor-generic.h    2005-05-03 23:41:08.094518448 +0300
+@@ -0,0 +1,183 @@
++/* 
++ * Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_PROCESSOR_GENERIC_H
++#define __UM_PROCESSOR_GENERIC_H
++
++struct pt_regs;
++
++struct task_struct;
++
++#include "linux/config.h"
++#include "linux/signal.h"
++#include "asm/ptrace.h"
++#include "asm/siginfo.h"
++#include "choose-mode.h"
++
++struct mm_struct;
++
++#define current_text_addr() ((void *) 0)
++
++#define cpu_relax()   do ; while (0)
++
++struct thread_struct {
++      int forking;
++      int nsyscalls;
++      struct pt_regs regs;
++      unsigned long cr2;
++      int err;
++      unsigned long trap_no;
++      int singlestep_syscall;
++      void *fault_addr;
++      void *fault_catcher;
++      struct task_struct *prev_sched;
++      unsigned long temp_stack;
++      void *exec_buf;
++      struct arch_thread arch;
++      union {
++#ifdef CONFIG_MODE_TT
++              struct {
++                      int extern_pid;
++                      int tracing;
++                      /* XXX This is really two filehandles, but they contain
++                       * lists, and list.h includes processor.h through
++                       * prefetch.h before defining struct list, so this
++                       * makes the lists' sizes unknown at this point.
++                       * So, this is a void *, and allocated separately.
++                       * Check to see if this is fixed in 2.6.
++                       */
++                      void *switch_pipe;
++                      int singlestep_syscall;
++                      int vm_seq;
++              } tt;
++#endif
++#ifdef CONFIG_MODE_SKAS
++              struct {
++                      void *switch_buf;
++                      void *fork_buf;
++                      int mm_count;
++              } skas;
++#endif
++      } mode;
++      struct {
++              int op;
++              union {
++                      struct {
++                              int pid;
++                      } fork, exec;
++                      struct {
++                              int (*proc)(void *);
++                              void *arg;
++                      } thread;
++                      struct {
++                              void (*proc)(void *);
++                              void *arg;
++                      } cb;
++              } u;
++      } request;
++};
++
++#define INIT_THREAD \
++{ \
++      .forking                = 0, \
++      .nsyscalls              = 0, \
++        .regs                 = EMPTY_REGS, \
++      .cr2                    = 0, \
++      .err                    = 0, \
++      .fault_addr             = NULL, \
++      .prev_sched             = NULL, \
++      .temp_stack             = 0, \
++      .exec_buf               = NULL, \
++      .arch                   = INIT_ARCH_THREAD, \
++      .request                = { 0 } \
++}
++
++#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE)
++
++typedef struct {
++      unsigned long seg;
++} mm_segment_t;
++
++extern struct task_struct *alloc_task_struct(void);
++extern void free_task_struct(struct task_struct *task);
++
++#define get_task_struct(tsk)      atomic_inc(&virt_to_page(tsk)->count)
++
++extern void release_thread(struct task_struct *);
++extern int arch_kernel_thread(int (*fn)(void *), void * arg, 
++                            unsigned long flags);
++extern void dump_thread(struct pt_regs *regs, struct user *u);
++
++extern unsigned long thread_saved_pc(struct thread_struct *t);
++
++static inline void mm_copy_segments(struct mm_struct *from_mm, 
++                                  struct mm_struct *new_mm)
++{
++}
++
++static inline void copy_segments(struct task_struct *p, 
++                               struct mm_struct *new_mm)
++{
++}
++
++static inline void release_segments(struct mm_struct *mm)
++{
++}
++
++#define init_task     (init_task_union.task)
++#define init_stack    (init_task_union.stack)
++
++/*
++ * User space process size: 3GB (default).
++ */
++extern unsigned long task_size;
++
++#define TASK_SIZE     (task_size)
++
++/* This decides where the kernel will search for a free chunk of vm
++ * space during mmap's.
++ */
++#define TASK_UNMAPPED_BASE    (0x40000000)
++
++extern void start_thread(struct pt_regs *regs, unsigned long entry, 
++                       unsigned long stack);
++
++struct cpuinfo_um {
++      unsigned long loops_per_jiffy;
++      unsigned long *pgd_quick;
++      unsigned long *pmd_quick;
++      unsigned long *pte_quick;
++      unsigned long pgtable_cache_sz;  
++      int ipi_pipe[2];
++};
++
++extern struct cpuinfo_um boot_cpu_data;
++
++#define my_cpu_data           cpu_data[smp_processor_id()]
++
++#ifdef CONFIG_SMP
++extern struct cpuinfo_um cpu_data[];
++#define current_cpu_data cpu_data[smp_processor_id()]
++#else
++#define cpu_data (&boot_cpu_data)
++#define current_cpu_data boot_cpu_data
++#endif
++
++#define KSTK_EIP(tsk) (PT_REGS_IP(&tsk->thread.regs))
++#define KSTK_ESP(tsk) (PT_REGS_SP(&tsk->thread.regs))
++#define get_wchan(p) (0)
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/processor-i386.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/processor-i386.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/processor-i386.h       2005-05-03 23:41:08.095518296 +0300
+@@ -0,0 +1,35 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_PROCESSOR_I386_H
++#define __UM_PROCESSOR_I386_H
++
++extern int cpu_has_xmm;
++extern int cpu_has_cmov;
++
++struct arch_thread {
++      unsigned long debugregs[8];
++      int debugregs_seq;
++};
++
++#define INIT_ARCH_THREAD { .debugregs                 = { [ 0 ... 7 ] = 0 }, \
++                           .debugregs_seq     = 0 }
++
++#include "asm/arch/user.h"
++
++#include "asm/processor-generic.h"
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/processor-ppc.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/processor-ppc.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/processor-ppc.h        2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,15 @@
++#ifndef __UM_PROCESSOR_PPC_H
++#define __UM_PROCESSOR_PPC_H
++
++#if defined(__ASSEMBLY__)
++
++#define CONFIG_ALL_PPC
++#include "arch/processor.h"
++
++#else
++
++#include "asm/processor-generic.h"
++
++#endif
++
++#endif
+Index: linux-2.4.29/include/asm-um/ptrace-generic.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/ptrace-generic.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/ptrace-generic.h       2005-05-03 23:41:08.084519968 +0300
+@@ -0,0 +1,74 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_PTRACE_GENERIC_H
++#define __UM_PTRACE_GENERIC_H
++
++#ifndef __ASSEMBLY__
++
++#include "linux/config.h"
++
++#include "asm/current.h"
++
++#define pt_regs pt_regs_subarch
++#define show_regs show_regs_subarch
++
++#include "asm/arch/ptrace.h"
++
++#undef pt_regs
++#undef show_regs
++#undef user_mode
++#undef instruction_pointer
++
++#include "sysdep/ptrace.h"
++#include "skas_ptrace.h"
++
++struct pt_regs {
++      union uml_pt_regs regs;
++};
++
++#define EMPTY_REGS { regs : EMPTY_UML_PT_REGS }
++
++#define PT_REGS_IP(r) UPT_IP(&(r)->regs)
++#define PT_REGS_SP(r) UPT_SP(&(r)->regs)
++
++#define PT_REG(r, reg) UPT_REG(&(r)->regs, reg)
++#define PT_REGS_SET(r, reg, val) UPT_SET(&(r)->regs, reg, val)
++
++#define PT_REGS_SET_SYSCALL_RETURN(r, res) \
++      UPT_SET_SYSCALL_RETURN(&(r)->regs, res)
++#define PT_REGS_RESTART_SYSCALL(r) UPT_RESTART_SYSCALL(&(r)->regs)
++
++#define PT_REGS_SYSCALL_NR(r) UPT_SYSCALL_NR(&(r)->regs)
++
++#define PT_REGS_SC(r) UPT_SC(&(r)->regs)
++
++struct task_struct;
++
++extern unsigned long getreg(struct task_struct *child, int regno);
++extern int putreg(struct task_struct *child, int regno, unsigned long value);
++extern int get_fpregs(unsigned long buf, struct task_struct *child);
++extern int set_fpregs(unsigned long buf, struct task_struct *child);
++extern int get_fpxregs(unsigned long buf, struct task_struct *child);
++extern int set_fpxregs(unsigned long buf, struct task_struct *tsk);
++
++extern void show_regs(struct pt_regs *regs);
++
++#define INIT_TASK_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE)
++
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/ptrace-i386.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/ptrace-i386.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/ptrace-i386.h  2005-05-03 23:41:08.085519816 +0300
+@@ -0,0 +1,46 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_PTRACE_I386_H
++#define __UM_PTRACE_I386_H
++
++#include "sysdep/ptrace.h"
++#include "asm/ptrace-generic.h"
++
++#define PT_REGS_EAX(r) UPT_EAX(&(r)->regs)
++#define PT_REGS_EBX(r) UPT_EBX(&(r)->regs)
++#define PT_REGS_ECX(r) UPT_ECX(&(r)->regs)
++#define PT_REGS_EDX(r) UPT_EDX(&(r)->regs)
++#define PT_REGS_ESI(r) UPT_ESI(&(r)->regs)
++#define PT_REGS_EDI(r) UPT_EDI(&(r)->regs)
++#define PT_REGS_EBP(r) UPT_EBP(&(r)->regs)
++
++#define PT_REGS_CS(r) UPT_CS(&(r)->regs)
++#define PT_REGS_SS(r) UPT_SS(&(r)->regs)
++#define PT_REGS_DS(r) UPT_DS(&(r)->regs)
++#define PT_REGS_ES(r) UPT_ES(&(r)->regs)
++#define PT_REGS_FS(r) UPT_FS(&(r)->regs)
++#define PT_REGS_GS(r) UPT_GS(&(r)->regs)
++
++#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
++
++#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_EAX(r)
++#define PT_REGS_SYSCALL_RET(r) PT_REGS_EAX(r)
++#define PT_FIX_EXEC_STACK(sp) do ; while(0)
++
++#define user_mode(r) UPT_IS_USER(&(r)->regs)
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/resource.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/resource.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/resource.h     2005-05-03 22:28:14.980332856 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_RESOURCE_H
++#define __UM_RESOURCE_H
++
++#include "asm/arch/resource.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/rwlock.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/rwlock.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/rwlock.h       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_RWLOCK_H
++#define __UM_RWLOCK_H
++
++#include "asm/arch/rwlock.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/rwsem.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/rwsem.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/rwsem.h        2005-05-03 23:41:08.109516168 +0300
+@@ -0,0 +1,10 @@
++#ifndef __UM_RWSEM_H__
++#define __UM_RWSEM_H__
++
++#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
++#define __builtin_expect(exp,c) (exp)
++#endif
++
++#include "asm/arch/rwsem.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/scatterlist.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/scatterlist.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/scatterlist.h  2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_SCATTERLIST_H
++#define __UM_SCATTERLIST_H
++
++#include "asm/arch/scatterlist.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/segment.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/segment.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/segment.h      2005-05-03 22:28:14.983332400 +0300
+@@ -0,0 +1,4 @@
++#ifndef __UM_SEGMENT_H
++#define __UM_SEGMENT_H
++
++#endif
+Index: linux-2.4.29/include/asm-um/semaphore.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/semaphore.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/semaphore.h    2005-05-03 23:41:08.110516016 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_SEMAPHORE_H
++#define __UM_SEMAPHORE_H
++
++#include "asm/arch/semaphore.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/sembuf.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/sembuf.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/sembuf.h       2005-05-03 22:28:14.984332248 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_SEMBUF_H
++#define __UM_SEMBUF_H
++
++#include "asm/arch/sembuf.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/serial.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/serial.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/serial.h       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_SERIAL_H
++#define __UM_SERIAL_H
++
++#include "asm/arch/serial.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/shmbuf.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/shmbuf.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/shmbuf.h       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_SHMBUF_H
++#define __UM_SHMBUF_H
++
++#include "asm/arch/shmbuf.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/shmparam.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/shmparam.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/shmparam.h     2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_SHMPARAM_H
++#define __UM_SHMPARAM_H
++
++#include "asm/arch/shmparam.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/sigcontext-generic.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/sigcontext-generic.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/sigcontext-generic.h   2005-05-03 22:28:14.987331792 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_SIGCONTEXT_GENERIC_H
++#define __UM_SIGCONTEXT_GENERIC_H
++
++#include "asm/arch/sigcontext.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/sigcontext-i386.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/sigcontext-i386.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/sigcontext-i386.h      2005-05-03 22:28:14.988331640 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_SIGCONTEXT_I386_H
++#define __UM_SIGCONTEXT_I386_H
++
++#include "asm/sigcontext-generic.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/sigcontext-ppc.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/sigcontext-ppc.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/sigcontext-ppc.h       2005-05-03 22:28:14.000000000 +0300
+@@ -0,0 +1,10 @@
++#ifndef __UM_SIGCONTEXT_PPC_H
++#define __UM_SIGCONTEXT_PPC_H
++
++#define pt_regs sys_pt_regs
++
++#include "asm/sigcontext-generic.h"
++
++#undef pt_regs
++
++#endif
+Index: linux-2.4.29/include/asm-um/siginfo.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/siginfo.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/siginfo.h      2005-05-03 23:41:08.092518752 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_SIGINFO_H
++#define __UM_SIGINFO_H
++
++#include "asm/arch/siginfo.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/signal.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/signal.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/signal.h       2005-05-03 23:41:08.090519056 +0300
+@@ -0,0 +1,22 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_SIGNAL_H
++#define __UM_SIGNAL_H
++
++#include "asm/arch/signal.h"
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/smp.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/smp.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/smp.h  2005-05-03 23:41:09.801258984 +0300
+@@ -0,0 +1,19 @@
++#ifndef __UM_SMP_H
++#define __UM_SMP_H
++
++#ifdef CONFIG_SMP
++
++#include "linux/config.h"
++#include "asm/current.h"
++
++#define smp_processor_id() (current->processor)
++#define cpu_logical_map(n) (n)
++#define cpu_number_map(n) (n)
++#define PROC_CHANGE_PENALTY   15 /* Pick a number, any number */
++extern int hard_smp_processor_id(void);
++extern unsigned long cpu_online_map;
++#define NO_PROC_ID -1
++
++#endif
++
++#endif
+Index: linux-2.4.29/include/asm-um/smplock.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/smplock.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/smplock.h      2005-05-03 23:41:09.912242112 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_SMPLOCK_H
++#define __UM_SMPLOCK_H
++
++#include "asm/arch/smplock.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/socket.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/socket.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/socket.h       2005-05-03 22:37:45.384618224 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_SOCKET_H
++#define __UM_SOCKET_H
++
++#include "asm/arch/socket.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/sockios.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/sockios.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/sockios.h      2005-05-03 22:28:14.994330728 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_SOCKIOS_H
++#define __UM_SOCKIOS_H
++
++#include "asm/arch/sockios.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/softirq.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/softirq.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/softirq.h      2005-05-03 23:41:09.910242416 +0300
+@@ -0,0 +1,13 @@
++#ifndef __UM_SOFTIRQ_H
++#define __UM_SOFTIRQ_H
++
++#include "linux/smp.h"
++#include "asm/system.h"
++#include "asm/processor.h"
++
++/* A gratuitous name change */
++#define i386_bh_lock um_bh_lock
++#include "asm/arch/softirq.h"
++#undef i386_bh_lock
++
++#endif
+Index: linux-2.4.29/include/asm-um/spinlock.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/spinlock.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/spinlock.h     2005-05-03 23:41:08.101517384 +0300
+@@ -0,0 +1,10 @@
++#ifndef __UM_SPINLOCK_H
++#define __UM_SPINLOCK_H
++
++#include "linux/config.h"
++
++#ifdef CONFIG_SMP
++#include "asm/arch/spinlock.h"
++#endif
++
++#endif
+Index: linux-2.4.29/include/asm-um/statfs.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/statfs.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/statfs.h       2005-05-03 23:41:08.104516928 +0300
+@@ -0,0 +1,6 @@
++#ifndef _UM_STATFS_H
++#define _UM_STATFS_H
++
++#include "asm/arch/statfs.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/stat.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/stat.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/stat.h 2005-05-03 22:28:14.997330272 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_STAT_H
++#define __UM_STAT_H
++
++#include "asm/arch/stat.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/string.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/string.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/string.h       2005-05-03 22:28:14.998330120 +0300
+@@ -0,0 +1,7 @@
++#ifndef __UM_STRING_H
++#define __UM_STRING_H
++
++#include "asm/arch/string.h"
++#include "asm/archparam.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/system-generic.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/system-generic.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/system-generic.h       2005-05-03 23:41:08.098517840 +0300
+@@ -0,0 +1,50 @@
++#ifndef __UM_SYSTEM_GENERIC_H
++#define __UM_SYSTEM_GENERIC_H
++
++#include "asm/arch/system.h"
++
++#undef prepare_to_switch
++#undef switch_to
++#undef __save_flags
++#undef save_flags
++#undef __restore_flags
++#undef restore_flags
++#undef __cli
++#undef __sti
++#undef cli
++#undef sti
++#undef local_irq_save
++#undef local_irq_restore
++#undef local_irq_disable
++#undef local_irq_enable
++
++#define prepare_to_switch() do ; while(0)
++
++void *_switch_to(void *prev, void *next);
++
++#define switch_to(prev, next, last) prev = _switch_to(prev, next)
++
++extern int get_signals(void);
++extern int set_signals(int enable);
++extern void block_signals(void);
++extern void unblock_signals(void);
++
++#define local_irq_save(flags) do { (flags) = set_signals(0); } while(0)
++
++#define local_irq_restore(flags) do { set_signals(flags); } while(0)
++
++#define local_irq_enable() unblock_signals()
++#define local_irq_disable() block_signals()
++
++#define __sti() unblock_signals()
++#define sti() unblock_signals()
++#define __cli() block_signals()
++#define cli() block_signals()
++
++#define __save_flags(x) do { (x) = get_signals(); } while(0)
++#define save_flags(x) __save_flags(x)
++
++#define __restore_flags(x) local_irq_restore(x)
++#define restore_flags(x) __restore_flags(x)
++
++#endif
+Index: linux-2.4.29/include/asm-um/system-i386.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/system-i386.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/system-i386.h  2005-05-03 23:41:08.098517840 +0300
+@@ -0,0 +1,8 @@
++#ifndef __UM_SYSTEM_I386_H
++#define __UM_SYSTEM_I386_H
++
++#include "asm/system-generic.h"
++
++#define __HAVE_ARCH_CMPXCHG 1
++
++#endif
+Index: linux-2.4.29/include/asm-um/system-ppc.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/system-ppc.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/system-ppc.h   2005-05-03 22:28:15.000000000 +0300
+@@ -0,0 +1,12 @@
++#ifndef __UM_SYSTEM_PPC_H
++#define __UM_SYSTEM_PPC_H
++
++#define _switch_to _ppc_switch_to
++
++#include "asm/arch/system.h"
++
++#undef _switch_to
++ 
++#include "asm/system-generic.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/termbits.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/termbits.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/termbits.h     2005-05-03 22:37:45.506599680 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_TERMBITS_H
++#define __UM_TERMBITS_H
++
++#include "asm/arch/termbits.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/termios.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/termios.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/termios.h      2005-05-03 22:37:45.512598768 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_TERMIOS_H
++#define __UM_TERMIOS_H
++
++#include "asm/arch/termios.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/timex.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/timex.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/timex.h        2005-05-03 23:41:09.799259288 +0300
+@@ -0,0 +1,18 @@
++#ifndef __UM_TIMEX_H
++#define __UM_TIMEX_H
++
++#include "linux/time.h"
++
++typedef unsigned long cycles_t;
++
++#define cacheflush_time (0)
++
++static inline cycles_t get_cycles (void)
++{
++      return 0;
++}
++
++#define vxtime_lock()         do ; while (0)
++#define vxtime_unlock()               do ; while (0)
++
++#endif
+Index: linux-2.4.29/include/asm-um/tlb.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/tlb.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/tlb.h  2005-05-03 22:28:15.000000000 +0300
+@@ -0,0 +1 @@
++#include <asm-generic/tlb.h>
+Index: linux-2.4.29/include/asm-um/types.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/types.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/types.h        2005-05-03 22:28:15.006328904 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_TYPES_H
++#define __UM_TYPES_H
++
++#include "asm/arch/types.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/uaccess.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/uaccess.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/uaccess.h      2005-05-03 23:41:09.913241960 +0300
+@@ -0,0 +1,99 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __UM_UACCESS_H
++#define __UM_UACCESS_H
++
++#include "linux/sched.h"
++
++#define VERIFY_READ 0
++#define VERIFY_WRITE 1
++
++/*
++ * The fs value determines whether argument validity checking should be
++ * performed or not.  If get_fs() == USER_DS, checking is performed, with
++ * get_fs() == KERNEL_DS, checking is bypassed.
++ *
++ * For historical reasons, these macros are grossly misnamed.
++ */
++
++#define MAKE_MM_SEG(s)        ((mm_segment_t) { (s) })
++
++#define KERNEL_DS     MAKE_MM_SEG(0xFFFFFFFF)
++#define USER_DS               MAKE_MM_SEG(TASK_SIZE)
++
++#define get_ds()      (KERNEL_DS)
++#define get_fs()      (current->addr_limit)
++#define set_fs(x)     (current->addr_limit = (x))
++
++#define segment_eq(a, b) ((a).seg == (b).seg)
++
++#include "um_uaccess.h"
++
++#define __copy_from_user(to, from, n) copy_from_user(to, from, n)
++
++#define __copy_to_user(to, from, n) copy_to_user(to, from, n)
++
++#define __get_user(x, ptr) \
++({ \
++        const __typeof__(ptr) __private_ptr = ptr; \
++        __typeof__(*(__private_ptr)) __private_val; \
++        int __private_ret = -EFAULT; \
++        (x) = 0; \
++      if (__copy_from_user(&__private_val, (__private_ptr), \
++          sizeof(*(__private_ptr))) == 0) {\
++              (x) = (__typeof__(*(__private_ptr))) __private_val; \
++              __private_ret = 0; \
++      } \
++        __private_ret; \
++}) 
++
++#define get_user(x, ptr) \
++({ \
++        const __typeof__((*ptr)) *private_ptr = (ptr); \
++        (access_ok(VERIFY_READ, private_ptr, sizeof(*private_ptr)) ? \
++       __get_user(x, private_ptr) : ((x) = 0, -EFAULT)); \
++})
++
++#define __put_user(x, ptr) \
++({ \
++        __typeof__(ptr) __private_ptr = ptr; \
++        __typeof__(*(__private_ptr)) __private_val; \
++        int __private_ret = -EFAULT; \
++        __private_val = (__typeof__(*(__private_ptr))) (x); \
++        if (__copy_to_user((__private_ptr), &__private_val, \
++                         sizeof(*(__private_ptr))) == 0) { \
++              __private_ret = 0; \
++      } \
++        __private_ret; \
++})
++
++#define put_user(x, ptr) \
++({ \
++        __typeof__(*(ptr)) *private_ptr = (ptr); \
++        (access_ok(VERIFY_WRITE, private_ptr, sizeof(*private_ptr)) ? \
++       __put_user(x, private_ptr) : -EFAULT); \
++})
++
++#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
++
++struct exception_table_entry
++{
++        unsigned long insn;
++      unsigned long fixup;
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/ucontext.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/ucontext.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/ucontext.h     2005-05-03 22:28:15.008328600 +0300
+@@ -0,0 +1,6 @@
++#ifndef _ASM_UM_UCONTEXT_H
++#define _ASM_UM_UCONTEXT_H
++
++#include "asm/arch/ucontext.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/unaligned.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/unaligned.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/unaligned.h    2005-05-03 22:28:15.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_UNALIGNED_H
++#define __UM_UNALIGNED_H
++
++#include "asm/arch/unaligned.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/unistd.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/unistd.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/unistd.h       2005-05-03 23:41:11.206045424 +0300
+@@ -0,0 +1,121 @@
++/* 
++ * Copyright (C) 2000, 2001  Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef _UM_UNISTD_H_
++#define _UM_UNISTD_H_
++
++#include "linux/resource.h"
++#include "asm/uaccess.h"
++
++extern long sys_open(const char *filename, int flags, int mode);
++extern long sys_dup(unsigned int fildes);
++extern long sys_close(unsigned int fd);
++extern int um_execve(const char *file, char *const argv[], char *const env[]);
++extern long sys_setsid(void);
++extern long sys_waitpid(pid_t pid, unsigned int * stat_addr, int options);
++extern long sys_wait4(pid_t pid,unsigned int *stat_addr, int options, 
++                    struct rusage *ru);
++extern long sys_mount(char *dev_name, char *dir_name, char *type, 
++                    unsigned long flags, void *data);
++extern long sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, 
++                     struct timeval *tvp);
++extern long sys_lseek(unsigned int fildes, unsigned long offset, int whence);
++extern long sys_read(unsigned int fildes, char *buf, int len);
++extern long sys_write(unsigned int fildes, char *buf, int len);
++
++#ifdef __KERNEL_SYSCALLS__
++
++#define KERNEL_CALL(ret_t, sys, args...)      \
++      mm_segment_t fs = get_fs();             \
++      ret_t ret;                              \
++      set_fs(KERNEL_DS);                      \
++      ret = sys(args);                        \
++      set_fs(fs);                             \
++      if (ret >= 0)                           \
++              return ret;                     \
++      errno = -(long)ret;                     \
++      return -1;
++
++static inline long open(const char *pathname, int flags, int mode) 
++{
++      KERNEL_CALL(int, sys_open, pathname, flags, mode)
++}
++
++static inline long dup(unsigned int fd)
++{
++      KERNEL_CALL(int, sys_dup, fd);
++}
++
++static inline long close(unsigned int fd)
++{
++      KERNEL_CALL(int, sys_close, fd);
++}
++
++static inline int execve(const char *filename, char *const argv[], 
++                       char *const envp[])
++{
++      KERNEL_CALL(int, um_execve, filename, argv, envp);
++}
++
++static inline long waitpid(pid_t pid, unsigned int *status, int options)
++{
++      KERNEL_CALL(pid_t, sys_wait4, pid, status, options, NULL)
++}
++
++static inline pid_t wait(int *status)
++{
++      KERNEL_CALL(pid_t, sys_wait4, -1, status, 0, NULL)
++}
++
++static inline pid_t setsid(void)
++{
++      KERNEL_CALL(pid_t, sys_setsid)
++}
++
++static inline long lseek(unsigned int fd, off_t offset, unsigned int whence)
++{
++      KERNEL_CALL(long, sys_lseek, fd, offset, whence)
++}
++
++static inline int read(unsigned int fd, char * buf, int len)
++{
++      KERNEL_CALL(int, sys_read, fd, buf, len)
++}
++
++static inline int write(unsigned int fd, char * buf, int len)
++{
++      KERNEL_CALL(int, sys_write, fd, buf, len)
++}
++
++#endif
++
++/* Save the value of __KERNEL_SYSCALLS__, undefine it, include the underlying
++ * arch's unistd.h for the system call numbers, and restore the old 
++ * __KERNEL_SYSCALLS__.
++ */
++
++#ifdef __KERNEL_SYSCALLS__
++#define __SAVE_KERNEL_SYSCALLS__ __KERNEL_SYSCALLS__
++#endif
++
++#undef __KERNEL_SYSCALLS__
++#include "asm/arch/unistd.h"
++
++#ifdef __KERNEL_SYSCALLS__
++#define __KERNEL_SYSCALLS__ __SAVE_KERNEL_SYSCALLS__
++#endif
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/asm-um/user.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/user.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/user.h 2005-05-03 23:43:26.305507184 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_USER_H
++#define __UM_USER_H
++
++#include "asm/arch/user.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/vga.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/vga.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/vga.h  2005-05-03 22:28:15.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_VGA_H
++#define __UM_VGA_H
++
++#include "asm/arch/vga.h"
++
++#endif
+Index: linux-2.4.29/include/asm-um/xor.h
+===================================================================
+--- linux-2.4.29.orig/include/asm-um/xor.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/asm-um/xor.h  2005-05-03 22:28:15.000000000 +0300
+@@ -0,0 +1,6 @@
++#ifndef __UM_XOR_H
++#define __UM_XOR_H
++
++#include "asm-generic/xor.h"
++
++#endif
+Index: linux-2.4.29/include/linux/blk.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/blk.h      2005-05-03 21:09:03.000000000 +0300
++++ linux-2.4.29/include/linux/blk.h   2005-05-03 23:41:26.547713136 +0300
+@@ -320,6 +320,24 @@
+ #define DEVICE_REQUEST do_ida_request
+ #define DEVICE_NR(device) (MINOR(device) >> 4)
++#elif (MAJOR_NR == UBD_MAJOR)
++
++#define DEVICE_NAME "User-mode block device"
++#define DEVICE_INTR do_ubd
++#define DEVICE_REQUEST do_ubd_request
++#define DEVICE_NR(device) (MINOR(device) >> UBD_SHIFT)
++#define DEVICE_ON(device)
++#define DEVICE_OFF(device)
++
++#elif (MAJOR_NR == COW_MAJOR)
++
++#define DEVICE_NAME "COW device"
++#define DEVICE_INTR do_cow
++#define DEVICE_REQUEST do_cow_request
++#define DEVICE_NR(device) (MINOR(device) >> COW_SHIFT)
++#define DEVICE_ON(device)
++#define DEVICE_OFF(device)
++
+ #endif /* MAJOR_NR == whatever */
+ /* provide DEVICE_xxx defaults, if not explicitly defined
+Index: linux-2.4.29/include/linux/fs.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/fs.h       2005-05-03 21:06:01.000000000 +0300
++++ linux-2.4.29/include/linux/fs.h    2005-05-03 23:56:00.359873496 +0300
+@@ -322,6 +322,8 @@
+ #include <linux/ncp_fs_i.h>
+ #include <linux/proc_fs_i.h>
+ #include <linux/usbdev_fs_i.h>
++#include <linux/hostfs_fs_i.h>
++#include <linux/hppfs_fs_i.h>
+ #include <linux/jffs2_fs_i.h>
+ #include <linux/cramfs_fs_sb.h>
+@@ -518,7 +520,9 @@
+               struct proc_inode_info          proc_i;
+               struct socket                   socket_i;
+               struct usbdev_inode_info        usbdev_i;
+-              struct jffs2_inode_info         jffs2_i;
++              struct hostfs_inode_info        hostfs_i;
++              struct hppfs_inode_info         hppfs_i;
++              struct jffs2_inode_info         jffs2_i;
+               void                            *generic_ip;
+       } u;
+ };
+@@ -866,6 +870,8 @@
+       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 *);
++      void (*munmap) (struct file *, struct vm_area_struct *, 
++                      unsigned long start, unsigned long len);
+       int (*open) (struct inode *, struct file *);
+       int (*flush) (struct file *);
+       int (*release) (struct inode *, struct file *);
+Index: linux-2.4.29/include/linux/ghash.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/ghash.h    2005-05-03 21:09:50.000000000 +0300
++++ linux-2.4.29/include/linux/ghash.h 2005-05-03 22:28:15.000000000 +0300
+@@ -153,6 +153,26 @@
+       return NULL;\
+ }
++/* LINKAGE - empty or "static", depending on whether you want the definitions to
++ *    be public or not
++ * NAME - a string to stick in names to make this hash table type distinct from
++ *    any others
++ * HASHSIZE - number of buckets
++ * TYPE - type of data contained in the buckets - must be a structure, one 
++ *    field is of type NAME_ptrs, another is the hash key
++ * PTRS - TYPE must contain a field of type NAME_ptrs, PTRS is the name of that
++ *    field
++ * KEYTYPE - type of the key field within TYPE
++ * KEY - name of the key field within TYPE
++ * KEYCMP - pointer to function that compares KEYTYPEs to each other - the
++ *    prototype is int KEYCMP(KEYTYPE, KEYTYPE), it returns zero for equal, 
++ *    non-zero for not equal
++ * HASHFN - the hash function - the prototype is int HASHFN(KEYTYPE),
++ *    it returns a number in the range 0 ... HASHSIZE - 1
++ * Call DEF_HASH_STRUCTS, define your hash table as a NAME_table, then call
++ * DEF_HASH.
++ */
++
+ #define DEF_HASH_STRUCTS(NAME,HASHSIZE,TYPE) \
+ \
+ struct NAME##_table {\
+@@ -165,7 +185,7 @@
+       TYPE * prev_hash;\
+ };
+-#define DEF_HASH(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\
++#define DEF_HASH(LINKAGE,NAME,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,HASHFN)\
+ \
+ LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+ {\
+@@ -206,12 +226,10 @@
+ \
+ LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
+ {\
+-      int ix = hashfn(pos);\
++      int ix = HASHFN(pos);\
+       TYPE * ptr = tbl->hashtable[ix];\
+       while(ptr && KEYCMP(ptr->KEY, pos))\
+               ptr = ptr->PTRS.next_hash;\
+-      if(ptr && !KEYEQ(ptr->KEY, pos))\
+-              ptr = NULL;\
+       return ptr;\
+ }
+Index: linux-2.4.29/include/linux/hostfs_fs_i.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/hostfs_fs_i.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/linux/hostfs_fs_i.h   2005-05-03 22:28:15.053321760 +0300
+@@ -0,0 +1,25 @@
++#ifndef _HOSTFS_FS_I
++#define _HOSTFS_FS_I
++
++#include "filehandle.h"
++
++struct externfs_file_ops;
++
++struct hostfs_inode_info {
++      struct externfs_file_ops *ops;
++      struct file_handle *fh;
++      int mode;
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/linux/hppfs_fs_i.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/hppfs_fs_i.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/linux/hppfs_fs_i.h    2005-05-03 22:28:15.054321608 +0300
+@@ -0,0 +1,19 @@
++#ifndef _HPPFS_FS_I
++#define _HPPFS_FS_I
++
++struct hppfs_inode_info {
++      struct dentry *proc_dentry;
++};
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/include/linux/kernel.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/kernel.h   2005-05-03 21:04:57.000000000 +0300
++++ linux-2.4.29/include/linux/kernel.h        2005-05-03 23:41:08.088519360 +0300
+@@ -49,7 +49,7 @@
+ # define ATTRIB_NORET  __attribute__((noreturn))
+ # define NORET_AND     noreturn,
+-#ifdef __i386__
++#if defined(__i386__) || defined(UM_FASTCALL)
+ #define FASTCALL(x)   x __attribute__((regparm(3)))
+ #define fastcall      __attribute__((regparm(3)))
+ #else
+Index: linux-2.4.29/include/linux/kernel_stat.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/kernel_stat.h      2005-05-03 21:09:36.000000000 +0300
++++ linux-2.4.29/include/linux/kernel_stat.h   2005-05-03 23:41:09.913241960 +0300
+@@ -12,7 +12,7 @@
+  * used by rstatd/perfmeter
+  */
+-#define DK_MAX_MAJOR 16
++#define DK_MAX_MAJOR 99
+ #define DK_MAX_DISK 16
+ struct kernel_stat {
+Index: linux-2.4.29/include/linux/mm.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/mm.h       2005-05-03 21:05:15.000000000 +0300
++++ linux-2.4.29/include/linux/mm.h    2005-05-03 23:55:59.724970016 +0300
+@@ -441,6 +441,18 @@
+ extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist));
+ extern struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order);
++#ifndef HAVE_ARCH_VALIDATE
++static inline struct page *arch_validate(struct page *page, 
++                                       unsigned int gfp_mask, int order)
++{
++        return(page);
++}
++#endif
++
++#ifndef HAVE_ARCH_FREE_PAGE
++static inline void arch_free_page(struct page *page, int order) { }
++#endif
++
+ static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order)
+ {
+       /*
+@@ -448,7 +460,7 @@
+        */
+       if (order >= MAX_ORDER)
+               return NULL;
+-      return _alloc_pages(gfp_mask, order);
++      return arch_validate(_alloc_pages(gfp_mask, order), gfp_mask, order);
+ }
+ #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
+@@ -508,6 +520,9 @@
+ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
+               int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
++extern long do_mprotect(struct mm_struct *mm, unsigned long start, 
++                      size_t len, unsigned long prot);
++
+ /*
+  * On a two-level page table, this ends up being trivial. Thus the
+  * inlining and the symmetry break with pte_alloc() that does all
+@@ -555,9 +570,10 @@
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+-      unsigned long len, unsigned long prot,
+-      unsigned long flag, unsigned long pgoff);
++extern unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file *file, 
++                                 unsigned long addr, unsigned long len,
++                                 unsigned long prot, unsigned long flag,
++                                 unsigned long pgoff);
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+       unsigned long len, unsigned long prot,
+@@ -567,7 +583,8 @@
+       if ((offset + PAGE_ALIGN(len)) < offset)
+               goto out;
+       if (!(offset & ~PAGE_MASK))
+-              ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
++              ret = do_mmap_pgoff(current->mm, file, addr, len, prot, flag, 
++                                  offset >> PAGE_SHIFT);
+ out:
+       return ret;
+ }
+Index: linux-2.4.29/include/linux/proc_mm.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/proc_mm.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/include/linux/proc_mm.h       2005-05-03 23:46:00.225107848 +0300
+@@ -0,0 +1,48 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include "linux/sched.h"
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++      unsigned long addr;
++      unsigned long len;
++      unsigned long prot;
++      unsigned long flags;
++      unsigned long fd;
++      unsigned long offset;
++};
++
++struct mm_munmap {
++      unsigned long addr;
++      unsigned long len;      
++};
++
++struct mm_mprotect {
++      unsigned long addr;
++      unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++      int op;
++      union {
++              struct mm_mmap mmap;
++              struct mm_munmap munmap;
++              struct mm_mprotect mprotect;
++              int copy_segments;
++      } u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++#endif
+Index: linux-2.4.29/include/linux/shmem_fs.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/shmem_fs.h 2005-05-03 21:09:04.000000000 +0300
++++ linux-2.4.29/include/linux/shmem_fs.h      2005-05-03 22:28:15.082317352 +0300
+@@ -22,6 +22,8 @@
+       unsigned long           next_index;
+       swp_entry_t             i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */
+       void                  **i_indirect; /* indirect blocks */
++      unsigned long           map_direct[SHMEM_NR_DIRECT];
++      void                  **map_indirect;
+       unsigned long           swapped;    /* data pages assigned to swap */
+       unsigned long           flags;
+       struct list_head        list;
+Index: linux-2.4.29/include/linux/tty.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/tty.h      2005-05-03 21:07:23.000000000 +0300
++++ linux-2.4.29/include/linux/tty.h   2005-05-03 23:41:09.901243784 +0300
+@@ -310,6 +310,9 @@
+       spinlock_t read_lock;
+       /* If the tty has a pending do_SAK, queue it here - akpm */
+       struct tq_struct SAK_tq;
++#ifdef CONFIG_TTY_LOG
++        int log_fd;
++#endif
+ };
+ /* tty magic number */
+@@ -368,6 +371,7 @@
+ extern int specialix_init(void);
+ extern int espserial_init(void);
+ extern int macserial_init(void);
++extern int stdio_init(void);
+ extern int a2232board_init(void);
+ extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
+@@ -434,5 +438,7 @@
+ extern int vt_ioctl(struct tty_struct *tty, struct file * file,
+                   unsigned int cmd, unsigned long arg);
++extern void stdio_console_init(void);
++
+ #endif /* __KERNEL__ */
+ #endif
+Index: linux-2.4.29/init/do_mounts.c
+===================================================================
+--- linux-2.4.29.orig/init/do_mounts.c 2005-05-03 21:09:10.000000000 +0300
++++ linux-2.4.29/init/do_mounts.c      2005-05-03 22:28:15.000000000 +0300
+@@ -154,6 +154,22 @@
+       { "pf",         0x2f00 },
+       { "apblock", APBLOCK_MAJOR << 8},
+       { "ddv", DDV_MAJOR << 8},
++      { "ubd0", UBD_MAJOR << 8 | 0 << 4},
++      { "ubda", UBD_MAJOR << 8 | 0 << 4},
++      { "ubd1", UBD_MAJOR << 8 | 1 << 4},
++      { "ubdb", UBD_MAJOR << 8 | 1 << 4},
++      { "ubd2", UBD_MAJOR << 8 | 2 << 4},
++      { "ubdc", UBD_MAJOR << 8 | 2 << 4},
++      { "ubd3", UBD_MAJOR << 8 | 3 << 4},
++      { "ubdd", UBD_MAJOR << 8 | 3 << 4},
++      { "ubd4", UBD_MAJOR << 8 | 4 << 4},
++      { "ubde", UBD_MAJOR << 8 | 4 << 4},
++      { "ubd5", UBD_MAJOR << 8 | 5 << 4},
++      { "ubdf", UBD_MAJOR << 8 | 5 << 4},
++      { "ubd6", UBD_MAJOR << 8 | 6 << 4},
++      { "ubdg", UBD_MAJOR << 8 | 6 << 4},
++      { "ubd7", UBD_MAJOR << 8 | 7 << 4},
++      { "ubdh", UBD_MAJOR << 8 | 7 << 4},
+       { "jsfd",    JSFD_MAJOR << 8},
+ #if defined(CONFIG_ARCH_S390)
+       { "dasda", (DASD_MAJOR << MINORBITS) },
+Index: linux-2.4.29/kernel/panic.c
+===================================================================
+--- linux-2.4.29.orig/kernel/panic.c   2005-05-03 21:09:35.000000000 +0300
++++ linux-2.4.29/kernel/panic.c        2005-05-03 22:28:15.000000000 +0300
+@@ -74,7 +74,7 @@
+       smp_send_stop();
+ #endif
+-      notifier_call_chain(&panic_notifier_list, 0, NULL);
++      notifier_call_chain(&panic_notifier_list, 0, buf);
+       if (panic_timeout > 0)
+       {
+Index: linux-2.4.29/MAINTAINERS
+===================================================================
+--- linux-2.4.29.orig/MAINTAINERS      2005-05-03 21:07:57.000000000 +0300
++++ linux-2.4.29/MAINTAINERS   2005-05-03 22:28:15.000000000 +0300
+@@ -2120,6 +2120,14 @@
+ L:    linux-usb-devel@lists.sourceforge.net
+ W:    http://usb.in.tum.de
+ S:    Maintained
++
++USER-MODE PORT
++P:    Jeff Dike
++M:    jdike@karaya.com
++L:    user-mode-linux-devel@lists.sourceforge.net
++L:    user-mode-linux-user@lists.sourceforge.net
++W:    http://user-mode-linux.sourceforge.net
++S:    Maintained
+       
+ USB "USBNET" DRIVER
+ P:    David Brownell
+Index: linux-2.4.29/Makefile
+===================================================================
+--- linux-2.4.29.orig/Makefile 2005-05-03 21:08:14.000000000 +0300
++++ linux-2.4.29/Makefile      2005-05-03 22:28:15.000000000 +0300
+@@ -5,7 +5,15 @@
+ KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
++# SUBARCH tells the usermode build what the underlying arch is.  That is set
++# first, and if a usermode build is happening, the "ARCH=um" on the command
++# line overrides the setting of ARCH below.  If a native build is happening,
++# then ARCH is assigned, getting whatever value it gets normally, and 
++# SUBARCH is subsequently ignored.
++
++SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
++ARCH := $(SUBARCH)
++
+ KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g")
+ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
+Index: linux-2.4.29/mm/Makefile
+===================================================================
+--- linux-2.4.29.orig/mm/Makefile      2005-05-03 21:08:06.000000000 +0300
++++ linux-2.4.29/mm/Makefile   2005-05-03 22:28:15.000000000 +0300
+@@ -17,5 +17,6 @@
+           shmem.o
+ obj-$(CONFIG_HIGHMEM) += highmem.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+ include $(TOPDIR)/Rules.make
+Index: linux-2.4.29/mm/mmap.c
+===================================================================
+--- linux-2.4.29.orig/mm/mmap.c        2005-05-03 21:07:59.000000000 +0300
++++ linux-2.4.29/mm/mmap.c     2005-05-03 22:28:15.000000000 +0300
+@@ -391,10 +391,11 @@
+       return 0;
+ }
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len,
+-      unsigned long prot, unsigned long flags, unsigned long pgoff)
++unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file * file, 
++                          unsigned long addr, unsigned long len,
++                          unsigned long prot, unsigned long flags, 
++                          unsigned long pgoff)
+ {
+-      struct mm_struct * mm = current->mm;
+       struct vm_area_struct * vma, * prev;
+       unsigned int vm_flags;
+       int correct_wcount = 0;
+@@ -1000,6 +1001,11 @@
+               remove_shared_vm_struct(mpnt);
+               mm->map_count--;
++              if((mpnt->vm_file != NULL) && (mpnt->vm_file->f_op != NULL) &&
++                 (mpnt->vm_file->f_op->munmap != NULL))
++                      mpnt->vm_file->f_op->munmap(mpnt->vm_file, mpnt, st, 
++                                                  size);
++
+               zap_page_range(mm, st, size);
+               /*
+Index: linux-2.4.29/mm/mprotect.c
+===================================================================
+--- linux-2.4.29.orig/mm/mprotect.c    2005-05-03 21:06:44.000000000 +0300
++++ linux-2.4.29/mm/mprotect.c 2005-05-03 22:28:15.000000000 +0300
+@@ -264,7 +264,8 @@
+       return 0;
+ }
+-asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long do_mprotect(struct mm_struct *mm, unsigned long start, size_t len, 
++               unsigned long prot)
+ {
+       unsigned long nstart, end, tmp;
+       struct vm_area_struct * vma, * next, * prev;
+@@ -281,9 +282,9 @@
+       if (end == start)
+               return 0;
+-      down_write(&current->mm->mmap_sem);
++      down_write(&mm->mmap_sem);
+-      vma = find_vma_prev(current->mm, start, &prev);
++      vma = find_vma_prev(mm, start, &prev);
+       error = -ENOMEM;
+       if (!vma || vma->vm_start > start)
+               goto out;
+@@ -332,6 +333,11 @@
+               prev->vm_mm->map_count--;
+       }
+ out:
+-      up_write(&current->mm->mmap_sem);
++      up_write(&mm->mmap_sem);
+       return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++        return(do_mprotect(current->mm, start, len, prot));
++}
+Index: linux-2.4.29/mm/page_alloc.c
+===================================================================
+--- linux-2.4.29.orig/mm/page_alloc.c  2005-05-03 21:05:16.000000000 +0300
++++ linux-2.4.29/mm/page_alloc.c       2005-05-03 22:28:15.000000000 +0300
+@@ -116,6 +116,7 @@
+       struct page *base;
+       zone_t *zone;
++      arch_free_page(page, order);
+       /*
+        * Yes, think what happens when other parts of the kernel take 
+        * a reference to a page in order to pin it for io. -ben
+Index: linux-2.4.29/mm/proc_mm.c
+===================================================================
+--- linux-2.4.29.orig/mm/proc_mm.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.29/mm/proc_mm.c  2005-05-03 22:28:15.000000000 +0300
+@@ -0,0 +1,173 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/init.h"
++#include "linux/proc_fs.h"
++#include "linux/proc_mm.h"
++#include "linux/file.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++      struct mm_struct *ret = ERR_PTR(-EBADF);
++      struct file *file;
++
++      file = fget(fd);
++      if (!file)
++              goto out;
++
++      ret = ERR_PTR(-EINVAL);
++      if(file->f_op != &proc_mm_fops)
++              goto out_fput;
++
++      ret = file->private_data;
++ out_fput:
++      fput(file);
++ out:
++      return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr, 
++                   unsigned long len, unsigned long prot, 
++                   unsigned long flags, unsigned long fd,
++                   unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++                           size_t count, loff_t *ppos)
++{
++      struct mm_struct *mm = file->private_data;
++      struct proc_mm_op req;
++      int n, ret;
++
++      if(count > sizeof(req))
++              return(-EINVAL);
++
++      n = copy_from_user(&req, buffer, count);
++      if(n != 0)
++              return(-EFAULT);
++
++      ret = count;
++      switch(req.op){
++      case MM_MMAP: {
++              struct mm_mmap *map = &req.u.mmap;
++
++              ret = do_mmap2(mm, map->addr, map->len, map->prot, 
++                             map->flags, map->fd, map->offset >> PAGE_SHIFT);
++              if((ret & ~PAGE_MASK) == 0)
++                      ret = count;
++      
++              break;
++      }
++      case MM_MUNMAP: {
++              struct mm_munmap *unmap = &req.u.munmap;
++
++              down_write(&mm->mmap_sem);
++              ret = do_munmap(mm, unmap->addr, unmap->len);
++              up_write(&mm->mmap_sem);
++
++              if(ret == 0)
++                      ret = count;
++              break;
++      }
++      case MM_MPROTECT: {
++              struct mm_mprotect *protect = &req.u.mprotect;
++
++              ret = do_mprotect(mm, protect->addr, protect->len, 
++                                protect->prot);
++              if(ret == 0)
++                      ret = count;
++              break;
++      }
++
++      case MM_COPY_SEGMENTS: {
++              struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++              if(IS_ERR(from)){
++                      ret = PTR_ERR(from);
++                      break;
++              }
++
++              mm_copy_segments(from, mm);
++              break;
++      }
++      default:
++              ret = -EINVAL;
++              break;
++      }
++
++      return(ret);
++}
++
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++      struct mm_struct *mm = mm_alloc();
++      int ret;
++
++      ret = -ENOMEM;
++      if(mm == NULL)
++              goto out_mem;
++
++      ret = init_new_context(current, mm);
++      if(ret)
++              goto out_free;
++
++      spin_lock(&mmlist_lock);
++      list_add(&mm->mmlist, &current->mm->mmlist);
++      mmlist_nr++;
++      spin_unlock(&mmlist_lock);
++
++      file->private_data = mm;
++
++      return(0);
++
++ out_free:
++      mmput(mm);
++ out_mem:
++      return(ret);
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++      struct mm_struct *mm = file->private_data;
++
++      mmput(mm);
++      return(0);
++}
++
++static struct file_operations proc_mm_fops = {
++      .open           = open_proc_mm,
++      .release        = release_proc_mm,
++      .write          = write_proc_mm,
++};
++
++static int make_proc_mm(void)
++{
++      struct proc_dir_entry *ent;
++
++      ent = create_proc_entry("mm", 0222, &proc_root);
++      if(ent == NULL){
++              printk("make_proc_mm : Failed to register /proc/mm\n");
++              return(0);
++      }
++      ent->proc_fops = &proc_mm_fops;
++
++      return(0);
++}
++
++__initcall(make_proc_mm);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.4.29/mm/shmem.c
+===================================================================
+--- linux-2.4.29.orig/mm/shmem.c       2005-05-03 21:06:51.000000000 +0300
++++ linux-2.4.29/mm/shmem.c    2005-05-03 22:28:15.000000000 +0300
+@@ -128,16 +128,17 @@
+  *                   +-> 48-51
+  *                   +-> 52-55
+  */
+-static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long index, unsigned long *page)
++static void *shmem_block(unsigned long index, unsigned long *page,
++                       unsigned long *direct, void ***indirect)
+ {
+       unsigned long offset;
+       void **dir;
+       if (index < SHMEM_NR_DIRECT)
+-              return info->i_direct+index;
+-      if (!info->i_indirect) {
++              return direct+index;
++      if (!*indirect) {
+               if (page) {
+-                      info->i_indirect = (void **) *page;
++                      *indirect = (void **) *page;
+                       *page = 0;
+               }
+               return NULL;                    /* need another page */
+@@ -146,7 +147,7 @@
+       index -= SHMEM_NR_DIRECT;
+       offset = index % ENTRIES_PER_PAGE;
+       index /= ENTRIES_PER_PAGE;
+-      dir = info->i_indirect;
++      dir = *indirect;
+       if (index >= ENTRIES_PER_PAGE/2) {
+               index -= ENTRIES_PER_PAGE/2;
+@@ -169,7 +170,21 @@
+               *dir = (void *) *page;
+               *page = 0;
+       }
+-      return (swp_entry_t *) *dir + offset;
++      return (unsigned long **) *dir + offset;
++}
++
++static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long index, unsigned long *page)
++{
++      return((swp_entry_t *) shmem_block(index, page, 
++                                         (unsigned long *) info->i_direct, 
++                                         &info->i_indirect));
++}
++
++static unsigned long *shmem_map_count(struct shmem_inode_info *info, 
++                                    unsigned long index, unsigned long *page)
++{
++      return((unsigned long *) shmem_block(index, page, info->map_direct, 
++                                           &info->map_indirect));
+ }
+ /*
+@@ -847,6 +862,7 @@
+       ops = &shmem_vm_ops;
+       if (!S_ISREG(inode->i_mode))
+               return -EACCES;
++
+       UPDATE_ATIME(inode);
+       vma->vm_ops = ops;
+       return 0;
+@@ -1750,4 +1766,125 @@
+       return 0;
+ }
++static int adjust_map_counts(struct shmem_inode_info *info, 
++                           unsigned long offset, unsigned long len, 
++                           int adjust)
++{
++      unsigned long idx, i, *count, page = 0;
++
++      spin_lock(&info->lock);
++      offset >>= PAGE_SHIFT;
++      len >>= PAGE_SHIFT;
++      for(i = 0; i < len; i++){
++              idx = (i + offset) >> (PAGE_CACHE_SHIFT - PAGE_SHIFT);
++
++              while((count = shmem_map_count(info, idx, &page)) == NULL){
++                      spin_unlock(&info->lock);
++                      page = get_zeroed_page(GFP_KERNEL);
++                      if(page == 0)
++                              return(-ENOMEM);
++                      spin_lock(&info->lock);
++              }
++
++              if(page != 0)
++                      free_page(page);
++
++              *count += adjust;
++      }
++      spin_unlock(&info->lock);
++      return(0);
++}
++
+ EXPORT_SYMBOL(shmem_file_setup);
++
++struct file_operations anon_file_operations;
++
++static int anon_mmap(struct file *file, struct vm_area_struct *vma)
++{
++        struct file *new;
++      struct inode *inode;
++      loff_t size = vma->vm_end - vma->vm_start;
++      int err;
++
++      if(file->private_data == NULL){
++              new = shmem_file_setup("dev/anon", size);
++              if(IS_ERR(new))
++                      return(PTR_ERR(new));
++
++              new->f_op = &anon_file_operations;
++              file->private_data = new;
++      }
++      
++      if (vma->vm_file)
++              fput(vma->vm_file);
++      vma->vm_file = file->private_data;
++      get_file(vma->vm_file);
++
++      inode = vma->vm_file->f_dentry->d_inode;
++      err = adjust_map_counts(SHMEM_I(inode), vma->vm_pgoff, size, 1);
++      if(err)
++              return(err);
++
++      vma->vm_ops = &shmem_vm_ops;
++      return 0;
++}
++
++static void anon_munmap(struct file *file, struct vm_area_struct *vma, 
++                      unsigned long start, unsigned long len)
++{
++      struct inode *inode = file->f_dentry->d_inode;
++      struct shmem_inode_info *info = SHMEM_I(inode);
++      pgd_t *pgd;
++      pmd_t *pmd;
++      pte_t *pte;
++      struct page *page;
++      unsigned long addr, idx, *count;
++
++      for(addr = start; addr < start + len; addr += PAGE_SIZE){
++              idx = (addr - vma->vm_start + vma->vm_pgoff);
++              idx >>= PAGE_CACHE_SHIFT;
++
++              count = shmem_map_count(info, idx, NULL);
++              BUG_ON(count == NULL);
++
++              (*count)--;
++              if(*count > 0)
++                      continue;
++
++              pgd = pgd_offset(vma->vm_mm, addr);
++              if(pgd_none(*pgd))
++                      continue;
++
++              pmd = pmd_offset(pgd, addr);
++              if(pmd_none(*pmd))
++                      continue;
++
++              pte = pte_offset(pmd, addr);
++              if(!pte_present(*pte)) /* XXX need to handle swapped pages */
++                      continue;
++
++              *pte = pte_mkclean(*pte);
++
++              page = pte_page(*pte);
++              LockPage(page);
++              lru_cache_del(page);
++              ClearPageDirty(page);
++              remove_inode_page(page);
++              UnlockPage(page);
++
++              page_cache_release(page);
++      }
++}
++
++int anon_release(struct inode *inode, struct file *file)
++{
++      if(file->private_data != NULL)
++              fput(file->private_data);
++      return(0);
++}
++
++struct file_operations anon_file_operations = {
++      .mmap           = anon_mmap,
++      .munmap         = anon_munmap,
++      .release        = anon_release,
++};
diff --git a/lustre/kernel_patches/patches/vfs_intent-2.4.29-vanilla.patch b/lustre/kernel_patches/patches/vfs_intent-2.4.29-vanilla.patch
new file mode 100644 (file)
index 0000000..f19fbd4
--- /dev/null
@@ -0,0 +1,1833 @@
+Index: linux-2.4.29/fs/dcache.c
+===================================================================
+--- linux-2.4.29.orig/fs/dcache.c      2005-04-07 18:52:37.000000000 +0300
++++ linux-2.4.29/fs/dcache.c   2005-04-07 19:14:06.000000000 +0300
+@@ -184,6 +184,13 @@
+               spin_unlock(&dcache_lock);
+               return 0;
+       }
++
++      /* network invalidation by Lustre */
++      if (dentry->d_flags & DCACHE_LUSTRE_INVALID) {
++              spin_unlock(&dcache_lock);
++              return 0;
++      }
++
+       /*
+        * Check whether to do a partial shrink_dcache
+        * to get rid of unused child entries.
+@@ -836,13 +843,19 @@
+  * Adds a dentry to the hash according to its name.
+  */
+  
+-void d_rehash(struct dentry * entry)
++void __d_rehash(struct dentry * entry, int lock)
+ {
+       struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash);
+       if (!list_empty(&entry->d_hash)) BUG();
+-      spin_lock(&dcache_lock);
++      if (lock) spin_lock(&dcache_lock);
+       list_add(&entry->d_hash, list);
+-      spin_unlock(&dcache_lock);
++      if (lock) spin_unlock(&dcache_lock);
++}
++EXPORT_SYMBOL(__d_rehash);
++
++void d_rehash(struct dentry * entry)
++{
++      __d_rehash(entry, 1);
+ }
+ #define do_switch(x,y) do { \
+Index: linux-2.4.29/fs/exec.c
+===================================================================
+--- linux-2.4.29.orig/fs/exec.c        2005-04-07 18:53:19.000000000 +0300
++++ linux-2.4.29/fs/exec.c     2005-04-07 19:14:06.000000000 +0300
+@@ -112,8 +112,10 @@
+       struct file * file;
+       struct nameidata nd;
+       int error;
++      struct lookup_intent it = { .it_op = IT_OPEN,
++                                  .it_flags = FMODE_READ|FMODE_EXEC };
+-      error = user_path_walk(library, &nd);
++      error = user_path_walk_it(library, &nd, &it);
+       if (error)
+               goto out;
+@@ -125,7 +127,8 @@
+       if (error)
+               goto exit;
+-      file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
++      file = dentry_open_it(nd.dentry, nd.mnt, O_RDONLY, &it);
++      intent_release(&it);
+       error = PTR_ERR(file);
+       if (IS_ERR(file))
+               goto out;
+@@ -378,8 +381,10 @@
+       struct inode *inode;
+       struct file *file;
+       int err = 0;
++      struct lookup_intent it = { .it_op = IT_OPEN,
++                                  .it_flags = FMODE_READ|FMODE_EXEC };
+-      err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd);
++      err = path_lookup_it(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd, &it);
+       file = ERR_PTR(err);
+       if (!err) {
+               inode = nd.dentry->d_inode;
+@@ -391,7 +396,8 @@
+                               err = -EACCES;
+                       file = ERR_PTR(err);
+                       if (!err) {
+-                              file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
++                              file = dentry_open_it(nd.dentry, nd.mnt, O_RDONLY, &it);
++                              intent_release(&it);
+                               if (!IS_ERR(file)) {
+                                       err = deny_write_access(file);
+                                       if (err) {
+@@ -403,6 +409,7 @@
+                               return file;
+                       }
+               }
++              intent_release(&it);
+               path_release(&nd);
+       }
+       goto out;
+@@ -1163,7 +1170,7 @@
+               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;
+       retval = binfmt->core_dump(signr, regs, file);
+Index: linux-2.4.29/fs/namei.c
+===================================================================
+--- linux-2.4.29.orig/fs/namei.c       2005-04-07 18:53:14.000000000 +0300
++++ linux-2.4.29/fs/namei.c    2005-05-03 17:23:44.139922792 +0300
+@@ -94,6 +94,13 @@
+  * XEmacs seems to be relying on it...
+  */
++void intent_release(struct lookup_intent *it)
++{
++      if (it && it->it_op_release)
++              it->it_op_release(it);
++
++}
++
+ /* In order to reduce some races, while at the same time doing additional
+  * checking and hopefully speeding things up, we copy filenames to the
+  * kernel data space before using them..
+@@ -260,10 +267,19 @@
+  * Internal lookup() using the new generic dcache.
+  * SMP-safe
+  */
+-static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags)
++static struct dentry *cached_lookup(struct dentry *parent, struct qstr *name,
++                                  int flags, struct lookup_intent *it)
+ {
+       struct dentry * dentry = d_lookup(parent, name);
++      if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if (!dentry->d_op->d_revalidate_it(dentry, flags, it) &&
++                  !d_invalidate(dentry)) {
++                      dput(dentry);
++                      dentry = NULL;
++              }
++              return dentry;
++      } else
+       if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
+               if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {
+                       dput(dentry);
+@@ -281,11 +297,15 @@
+  * make sure that nobody added the entry to the dcache in the meantime..
+  * SMP-safe
+  */
+-static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, int flags)
++static struct dentry *real_lookup(struct dentry *parent, struct qstr *name,
++                                int flags, struct lookup_intent *it)
+ {
+       struct dentry * result;
+       struct inode *dir = parent->d_inode;
++      int counter = 0;
++again:
++      counter++;
+       down(&dir->i_sem);
+       /*
+        * First re-do the cached lookup just in case it was created
+@@ -300,6 +320,9 @@
+               result = ERR_PTR(-ENOMEM);
+               if (dentry) {
+                       lock_kernel();
++                      if (dir->i_op->lookup_it)
++                              result = dir->i_op->lookup_it(dir, dentry, it, flags);
++                      else
+                       result = dir->i_op->lookup(dir, dentry);
+                       unlock_kernel();
+                       if (result)
+@@ -321,6 +344,15 @@
+                       dput(result);
+                       result = ERR_PTR(-ENOENT);
+               }
++      } else if (result->d_op && result->d_op->d_revalidate_it) {
++              if (!result->d_op->d_revalidate_it(result, flags, it) &&
++                  !d_invalidate(result)) {
++                      dput(result);
++                      if (counter > 10)
++                              result = ERR_PTR(-ESTALE);
++                      if (!IS_ERR(result))
++                              goto again;
++              }
+       }
+       return result;
+ }
+@@ -332,7 +364,8 @@
+  * Without that kind of total limit, nasty chains of consecutive
+  * symlinks can cause almost arbitrarily long lookups. 
+  */
+-static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
++static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd,
++                               struct lookup_intent *it)
+ {
+       int err;
+       if (current->link_count >= 5)
+@@ -346,10 +379,12 @@
+       current->link_count++;
+       current->total_link_count++;
+       UPDATE_ATIME(dentry->d_inode);
++      nd->intent = it;
+       err = dentry->d_inode->i_op->follow_link(dentry, nd);
+       current->link_count--;
+       return err;
+ loop:
++      intent_release(it);
+       path_release(nd);
+       return -ELOOP;
+ }
+@@ -447,7 +482,8 @@
+  *
+  * We expect 'base' to be positive and a directory.
+  */
+-int fastcall link_path_walk(const char * name, struct nameidata *nd)
++int fastcall link_path_walk_it(const char * name, struct nameidata *nd,
++                          struct lookup_intent *it)
+ {
+       struct dentry *dentry;
+       struct inode *inode;
+@@ -520,9 +556,9 @@
+                               break;
+               }
+               /* This does the actual lookups.. */
+-              dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
++              dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE, NULL);
+               if (!dentry) {
+-                      dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
++                      dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE, NULL);
+                       err = PTR_ERR(dentry);
+                       if (IS_ERR(dentry))
+                               break;
+@@ -540,7 +576,7 @@
+                       goto out_dput;
+               if (inode->i_op->follow_link) {
+-                      err = do_follow_link(dentry, nd);
++                      err = do_follow_link(dentry, nd, NULL);
+                       dput(dentry);
+                       if (err)
+                               goto return_err;
+@@ -556,7 +592,7 @@
+                       nd->dentry = dentry;
+               }
+               err = -ENOTDIR; 
+-              if (!inode->i_op->lookup)
++              if (!inode->i_op->lookup && !inode->i_op->lookup_it)
+                       break;
+               continue;
+               /* here ends the main loop */
+@@ -583,9 +619,9 @@
+                       if (err < 0)
+                               break;
+               }
+-              dentry = cached_lookup(nd->dentry, &this, nd->flags);
++              dentry = cached_lookup(nd->dentry, &this, nd->flags, it);
+               if (!dentry) {
+-                      dentry = real_lookup(nd->dentry, &this, nd->flags);
++                      dentry = real_lookup(nd->dentry, &this, nd->flags, it);
+                       err = PTR_ERR(dentry);
+                       if (IS_ERR(dentry))
+                               break;
+@@ -595,7 +631,7 @@
+               inode = dentry->d_inode;
+               if ((lookup_flags & LOOKUP_FOLLOW)
+                   && inode && inode->i_op && inode->i_op->follow_link) {
+-                      err = do_follow_link(dentry, nd);
++                      err = do_follow_link(dentry, nd, it);
+                       dput(dentry);
+                       if (err)
+                               goto return_err;
+@@ -609,7 +645,8 @@
+                       goto no_inode;
+               if (lookup_flags & LOOKUP_DIRECTORY) {
+                       err = -ENOTDIR; 
+-                      if (!inode->i_op || !inode->i_op->lookup)
++                      if (!inode->i_op ||
++                          (!inode->i_op->lookup && !inode->i_op->lookup_it))
+                               break;
+               }
+               goto return_base;
+@@ -635,6 +672,34 @@
+                * Check the cached dentry for staleness.
+                */
+               dentry = nd->dentry;
++              if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) {
++                      err = -ESTALE;
++                      if (!dentry->d_op->d_revalidate_it(dentry, 0, it)) {
++                              struct dentry *new;
++                              err = permission(dentry->d_parent->d_inode,
++                                               MAY_EXEC);
++                              if (err)
++                                      break;
++                              new = real_lookup(dentry->d_parent,
++                                                &dentry->d_name, 0, it);
++                              if (IS_ERR(new)) {
++                                      err = PTR_ERR(new);
++                                      break;
++                              }
++                              d_invalidate(dentry);
++                              dput(dentry);
++                              nd->dentry = new;
++                      }
++                      if (!nd->dentry->d_inode)
++                              goto no_inode;
++                      if (lookup_flags & LOOKUP_DIRECTORY) {
++                              err = -ENOTDIR; 
++                              if (!nd->dentry->d_inode->i_op ||
++                                  (!nd->dentry->d_inode->i_op->lookup &&
++                                   !nd->dentry->d_inode->i_op->lookup_it))
++                                      break;
++                      }
++              } else
+               if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
+                       err = -ESTALE;
+                       if (!dentry->d_op->d_revalidate(dentry, 0)) {
+@@ -648,15 +713,28 @@
+               dput(dentry);
+               break;
+       }
++      if (err)
++              intent_release(it);
+       path_release(nd);
+ return_err:
+       return err;
+ }
++int link_path_walk(const char * name, struct nameidata *nd)
++{
++      return link_path_walk_it(name, nd, NULL);
++}
++
++int path_walk_it(const char * name, struct nameidata *nd, struct lookup_intent *it)
++{
++      current->total_link_count = 0;
++      return link_path_walk_it(name, nd, it);
++}
++
+ int fastcall path_walk(const char * name, struct nameidata *nd)
+ {
+       current->total_link_count = 0;
+-      return link_path_walk(name, nd);
++      return link_path_walk_it(name, nd, NULL);
+ }
+ /* SMP-safe */
+@@ -741,6 +819,16 @@
+ }
+ /* SMP-safe */
++int path_lookup_it(const char *path, unsigned flags, struct nameidata *nd,
++                 struct lookup_intent *it)
++{
++      int error = 0;
++      if (path_init(path, flags, nd))
++              error = path_walk_it(path, nd, it);
++      return error;
++}
++
++/* SMP-safe */
+ int fastcall path_lookup(const char *path, unsigned flags, struct nameidata *nd)
+ {
+       int error = 0;
+@@ -755,6 +843,7 @@
+ {
+       nd->last_type = LAST_ROOT; /* if there are only slashes... */
+       nd->flags = flags;
++      nd->intent = NULL;
+       if (*name=='/')
+               return walk_init_root(name,nd);
+       read_lock(&current->fs->lock);
+@@ -769,7 +858,8 @@
+  * needs parent already locked. Doesn't follow mounts.
+  * SMP-safe.
+  */
+-struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
++struct dentry * lookup_hash_it(struct qstr *name, struct dentry * base,
++                             struct lookup_intent *it)
+ {
+       struct dentry * dentry;
+       struct inode *inode;
+@@ -792,13 +882,16 @@
+                       goto out;
+       }
+-      dentry = cached_lookup(base, name, 0);
++      dentry = cached_lookup(base, name, 0, it);
+       if (!dentry) {
+               struct dentry *new = d_alloc(base, name);
+               dentry = ERR_PTR(-ENOMEM);
+               if (!new)
+                       goto out;
+               lock_kernel();
++              if (inode->i_op->lookup_it)
++                      dentry = inode->i_op->lookup_it(inode, new, it, 0);
++              else
+               dentry = inode->i_op->lookup(inode, new);
+               unlock_kernel();
+               if (!dentry)
+@@ -810,6 +903,12 @@
+       return dentry;
+ }
++struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
++{
++      return lookup_hash_it(name, base, NULL);
++}
++
++
+ /* SMP-safe */
+ struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
+ {
+@@ -831,7 +930,7 @@
+       }
+       this.hash = end_name_hash(hash);
+-      return lookup_hash(&this, base);
++      return lookup_hash_it(&this, base, NULL);
+ access:
+       return ERR_PTR(-EACCES);
+ }
+@@ -862,6 +961,23 @@
+       return err;
+ }
++int __user_walk_it(const char *name, unsigned flags, struct nameidata *nd,
++                 struct lookup_intent *it)
++{
++      char *tmp;
++      int err;
++
++      tmp = getname(name);
++      err = PTR_ERR(tmp);
++      if (!IS_ERR(tmp)) {
++              err = 0;
++              if (path_init(tmp, flags, nd))
++                      err = path_walk_it(tmp, nd, it);
++              putname(tmp);
++      }
++      return err;
++}
++
+ /*
+  * It's inline, so penalty for filesystems that don't use sticky bit is
+  * minimal.
+@@ -957,7 +1073,8 @@
+       return retval;
+ }
+-int vfs_create(struct inode *dir, struct dentry *dentry, int mode)
++static int vfs_create_it(struct inode *dir, struct dentry *dentry, int mode,
++                       struct lookup_intent *it)
+ {
+       int error;
+@@ -970,12 +1087,15 @@
+               goto exit_lock;
+       error = -EACCES;        /* shouldn't it be ENOSYS? */
+-      if (!dir->i_op || !dir->i_op->create)
++      if (!dir->i_op || (!dir->i_op->create && !dir->i_op->create_it))
+               goto exit_lock;
+       DQUOT_INIT(dir);
+       lock_kernel();
+-      error = dir->i_op->create(dir, dentry, mode);
++      if (dir->i_op->create_it)
++              error = dir->i_op->create_it(dir, dentry, mode, it);
++      else
++              error = dir->i_op->create(dir, dentry, mode);
+       unlock_kernel();
+ exit_lock:
+       up(&dir->i_zombie);
+@@ -984,6 +1104,11 @@
+       return error;
+ }
++int vfs_create(struct inode *dir, struct dentry *dentry, int mode)
++{
++      return vfs_create_it(dir, dentry, mode, NULL);
++}
++
+ /*
+  *    open_namei()
+  *
+@@ -998,7 +1123,8 @@
+  * for symlinks (where the permissions are checked later).
+  * SMP-safe
+  */
+-int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
++int open_namei_it(const char *pathname, int flag, int mode,
++                struct nameidata *nd, struct lookup_intent *it)
+ {
+       int acc_mode, error = 0;
+       struct inode *inode;
+@@ -1008,11 +1134,14 @@
+       acc_mode = ACC_MODE(flag);
++      if (it)
++              it->it_flags = flag;
++
+       /*
+        * The simplest case - just a plain lookup.
+        */
+       if (!(flag & O_CREAT)) {
+-              error = path_lookup(pathname, lookup_flags(flag), nd);
++              error = path_lookup_it(pathname, lookup_flags(flag), nd, it);
+               if (error)
+                       return error;
+               dentry = nd->dentry;
+@@ -1022,6 +1151,10 @@
+       /*
+        * Create - we need to know the parent.
+        */
++      if (it) {
++              it->it_create_mode = mode;
++              it->it_op |= IT_CREAT;
++      }
+       error = path_lookup(pathname, LOOKUP_PARENT, nd);
+       if (error)
+               return error;
+@@ -1037,7 +1170,7 @@
+       dir = nd->dentry;
+       down(&dir->d_inode->i_sem);
+-      dentry = lookup_hash(&nd->last, nd->dentry);
++      dentry = lookup_hash_it(&nd->last, nd->dentry, it);
+ do_last:
+       error = PTR_ERR(dentry);
+@@ -1046,10 +1179,11 @@
+               goto exit;
+       }
++      it->it_create_mode = mode;
+       /* Negative dentry, just create the file */
+       if (!dentry->d_inode) {
+-              error = vfs_create(dir->d_inode, dentry,
+-                                 mode & ~current->fs->umask);
++              error = vfs_create_it(dir->d_inode, dentry,
++                                 mode & ~current->fs->umask, it);
+               up(&dir->d_inode->i_sem);
+               dput(nd->dentry);
+               nd->dentry = dentry;
+@@ -1153,7 +1287,7 @@
+               if (!error) {
+                       DQUOT_INIT(inode);
+                       
+-                      error = do_truncate(dentry, 0);
++                      error = do_truncate(dentry, 0, 1);
+               }
+               put_write_access(inode);
+               if (error)
+@@ -1165,8 +1299,10 @@
+       return 0;
+ exit_dput:
++      intent_release(it);
+       dput(dentry);
+ exit:
++      intent_release(it);
+       path_release(nd);
+       return error;
+@@ -1185,7 +1321,10 @@
+        * are done. Procfs-like symlinks just set LAST_BIND.
+        */
+       UPDATE_ATIME(dentry->d_inode);
++      nd->intent = it;
+       error = dentry->d_inode->i_op->follow_link(dentry, nd);
++      if (error)
++              intent_release(it);
+       dput(dentry);
+       if (error)
+               return error;
+@@ -1207,13 +1346,20 @@
+       }
+       dir = nd->dentry;
+       down(&dir->d_inode->i_sem);
+-      dentry = lookup_hash(&nd->last, nd->dentry);
++      dentry = lookup_hash_it(&nd->last, nd->dentry, it);
+       putname(nd->last.name);
+       goto do_last;
+ }
++int open_namei(const char *pathname, int flag, int mode, struct nameidata *nd)
++{
++      return open_namei_it(pathname, flag, mode, nd, NULL);
++}
++
++
+ /* SMP-safe */
+-static struct dentry *lookup_create(struct nameidata *nd, int is_dir)
++static struct dentry *lookup_create(struct nameidata *nd, int is_dir,
++                                  struct lookup_intent *it)
+ {
+       struct dentry *dentry;
+@@ -1221,7 +1367,7 @@
+       dentry = ERR_PTR(-EEXIST);
+       if (nd->last_type != LAST_NORM)
+               goto fail;
+-      dentry = lookup_hash(&nd->last, nd->dentry);
++      dentry = lookup_hash_it(&nd->last, nd->dentry, it);
+       if (IS_ERR(dentry))
+               goto fail;
+       if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
+@@ -1277,7 +1423,20 @@
+       error = path_lookup(tmp, LOOKUP_PARENT, &nd);
+       if (error)
+               goto out;
+-      dentry = lookup_create(&nd, 0);
++
++      if (nd.last_type != LAST_NORM) {
++              error = -EEXIST;
++              goto out2;
++      }
++      if (nd.dentry->d_inode->i_op->mknod_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++              error = op->mknod_raw(&nd, mode, dev);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto out2;
++      }
++
++      dentry = lookup_create(&nd, 0, NULL);
+       error = PTR_ERR(dentry);
+       mode &= ~current->fs->umask;
+@@ -1298,6 +1457,7 @@
+               dput(dentry);
+       }
+       up(&nd.dentry->d_inode->i_sem);
++out2:
+       path_release(&nd);
+ out:
+       putname(tmp);
+@@ -1345,7 +1505,18 @@
+               error = path_lookup(tmp, LOOKUP_PARENT, &nd);
+               if (error)
+                       goto out;
+-              dentry = lookup_create(&nd, 1);
++              if (nd.last_type != LAST_NORM) {
++                      error = -EEXIST;
++                      goto out2;
++              }
++              if (nd.dentry->d_inode->i_op->mkdir_raw) {
++                      struct inode_operations *op = nd.dentry->d_inode->i_op;
++                      error = op->mkdir_raw(&nd, mode);
++                      /* the file system wants to use normal vfs path now */
++                      if (error != -EOPNOTSUPP)
++                              goto out2;
++              }
++              dentry = lookup_create(&nd, 1, NULL);
+               error = PTR_ERR(dentry);
+               if (!IS_ERR(dentry)) {
+                       error = vfs_mkdir(nd.dentry->d_inode, dentry,
+@@ -1353,6 +1524,7 @@
+                       dput(dentry);
+               }
+               up(&nd.dentry->d_inode->i_sem);
++out2:
+               path_release(&nd);
+ out:
+               putname(tmp);
+@@ -1453,8 +1625,16 @@
+                       error = -EBUSY;
+                       goto exit1;
+       }
++      if (nd.dentry->d_inode->i_op->rmdir_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++
++              error = op->rmdir_raw(&nd);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto exit1;
++      }
+       down(&nd.dentry->d_inode->i_sem);
+-      dentry = lookup_hash(&nd.last, nd.dentry);
++      dentry = lookup_hash_it(&nd.last, nd.dentry, NULL);
+       error = PTR_ERR(dentry);
+       if (!IS_ERR(dentry)) {
+               error = vfs_rmdir(nd.dentry->d_inode, dentry);
+@@ -1512,8 +1692,15 @@
+       error = -EISDIR;
+       if (nd.last_type != LAST_NORM)
+               goto exit1;
++      if (nd.dentry->d_inode->i_op->unlink_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++              error = op->unlink_raw(&nd);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto exit1;
++      }
+       down(&nd.dentry->d_inode->i_sem);
+-      dentry = lookup_hash(&nd.last, nd.dentry);
++      dentry = lookup_hash_it(&nd.last, nd.dentry, NULL);
+       error = PTR_ERR(dentry);
+       if (!IS_ERR(dentry)) {
+               /* Why not before? Because we want correct error value */
+@@ -1580,15 +1767,27 @@
+               error = path_lookup(to, LOOKUP_PARENT, &nd);
+               if (error)
+                       goto out;
+-              dentry = lookup_create(&nd, 0);
++              if (nd.last_type != LAST_NORM) {
++                      error = -EEXIST;
++                      goto out2;
++              }
++              if (nd.dentry->d_inode->i_op->symlink_raw) {
++                      struct inode_operations *op = nd.dentry->d_inode->i_op;
++                      error = op->symlink_raw(&nd, from);
++                      /* the file system wants to use normal vfs path now */
++                      if (error != -EOPNOTSUPP)
++                              goto out2;
++              }
++              dentry = lookup_create(&nd, 0, NULL);
+               error = PTR_ERR(dentry);
+               if (!IS_ERR(dentry)) {
+                       error = vfs_symlink(nd.dentry->d_inode, dentry, from);
+                       dput(dentry);
+               }
+               up(&nd.dentry->d_inode->i_sem);
++      out2:
+               path_release(&nd);
+-out:
++      out:
+               putname(to);
+       }
+       putname(from);
+@@ -1664,7 +1863,18 @@
+               error = -EXDEV;
+               if (old_nd.mnt != nd.mnt)
+                       goto out_release;
+-              new_dentry = lookup_create(&nd, 0);
++              if (nd.last_type != LAST_NORM) {
++                      error = -EEXIST;
++                      goto out_release;
++              }
++              if (nd.dentry->d_inode->i_op->link_raw) {
++                      struct inode_operations *op = nd.dentry->d_inode->i_op;
++                      error = op->link_raw(&old_nd, &nd);
++                      /* the file system wants to use normal vfs path now */
++                      if (error != -EOPNOTSUPP)
++                              goto out_release;
++              }
++              new_dentry = lookup_create(&nd, 0, NULL);
+               error = PTR_ERR(new_dentry);
+               if (!IS_ERR(new_dentry)) {
+                       error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
+@@ -1708,7 +1918,7 @@
+  *       locking].
+  */
+ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
+-             struct inode *new_dir, struct dentry *new_dentry)
++                 struct inode *new_dir, struct dentry *new_dentry)
+ {
+       int error;
+       struct inode *target;
+@@ -1787,7 +1997,7 @@
+ }
+ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
+-             struct inode *new_dir, struct dentry *new_dentry)
++                   struct inode *new_dir, struct dentry *new_dentry)
+ {
+       int error;
+@@ -1875,9 +2085,18 @@
+       if (newnd.last_type != LAST_NORM)
+               goto exit2;
++      if (old_dir->d_inode->i_op->rename_raw) {
++              lock_kernel();
++              error = old_dir->d_inode->i_op->rename_raw(&oldnd, &newnd);
++              unlock_kernel();
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto exit2;
++      }
++
+       double_lock(new_dir, old_dir);
+-      old_dentry = lookup_hash(&oldnd.last, old_dir);
++      old_dentry = lookup_hash_it(&oldnd.last, old_dir, NULL);
+       error = PTR_ERR(old_dentry);
+       if (IS_ERR(old_dentry))
+               goto exit3;
+@@ -1893,16 +2112,16 @@
+               if (newnd.last.name[newnd.last.len])
+                       goto exit4;
+       }
+-      new_dentry = lookup_hash(&newnd.last, new_dir);
++      new_dentry = lookup_hash_it(&newnd.last, new_dir, NULL);
+       error = PTR_ERR(new_dentry);
+       if (IS_ERR(new_dentry))
+               goto exit4;
++
+       lock_kernel();
+       error = vfs_rename(old_dir->d_inode, old_dentry,
+                                  new_dir->d_inode, new_dentry);
+       unlock_kernel();
+-
+       dput(new_dentry);
+ exit4:
+       dput(old_dentry);
+@@ -1953,20 +2172,26 @@
+ }
+ static inline int
+-__vfs_follow_link(struct nameidata *nd, const char *link)
++__vfs_follow_link(struct nameidata *nd, const char *link,
++                struct lookup_intent *it)
+ {
+       int res = 0;
+       char *name;
+       if (IS_ERR(link))
+               goto fail;
++      if (it == NULL)
++              it = nd->intent;
++      else if (it != nd->intent)
++              printk("it != nd->intent: tell phil@clusterfs.com\n");
++
+       if (*link == '/') {
+               path_release(nd);
+               if (!walk_init_root(link, nd))
+                       /* weird __emul_prefix() stuff did it */
+                       goto out;
+       }
+-      res = link_path_walk(link, nd);
++      res = link_path_walk_it(link, nd, it);
+ out:
+       if (current->link_count || res || nd->last_type!=LAST_NORM)
+               return res;
+@@ -1990,7 +2215,13 @@
+ int vfs_follow_link(struct nameidata *nd, const char *link)
+ {
+-      return __vfs_follow_link(nd, link);
++      return __vfs_follow_link(nd, link, NULL);
++}
++
++int vfs_follow_link_it(struct nameidata *nd, const char *link,
++                     struct lookup_intent *it)
++{
++      return __vfs_follow_link(nd, link, it);
+ }
+ /* get the link contents into pagecache */
+@@ -2032,7 +2263,7 @@
+ {
+       struct page *page = NULL;
+       char *s = page_getlink(dentry, &page);
+-      int res = __vfs_follow_link(nd, s);
++      int res = __vfs_follow_link(nd, s, NULL);
+       if (page) {
+               kunmap(page);
+               page_cache_release(page);
+Index: linux-2.4.29/fs/namespace.c
+===================================================================
+--- linux-2.4.29.orig/fs/namespace.c   2005-04-07 18:54:11.000000000 +0300
++++ linux-2.4.29/fs/namespace.c        2005-04-07 19:14:06.000000000 +0300
+@@ -98,6 +98,7 @@
+ {
+       old_nd->dentry = mnt->mnt_mountpoint;
+       old_nd->mnt = mnt->mnt_parent;
++      UNPIN(old_nd->dentry, old_nd->mnt, 1);
+       mnt->mnt_parent = mnt;
+       mnt->mnt_mountpoint = mnt->mnt_root;
+       list_del_init(&mnt->mnt_child);
+@@ -109,6 +110,7 @@
+ {
+       mnt->mnt_parent = mntget(nd->mnt);
+       mnt->mnt_mountpoint = dget(nd->dentry);
++      PIN(nd->dentry, nd->mnt, 1);
+       list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry));
+       list_add_tail(&mnt->mnt_child, &nd->mnt->mnt_mounts);
+       nd->dentry->d_mounted++;
+@@ -488,14 +490,17 @@
+ {
+       struct nameidata old_nd;
+       struct vfsmount *mnt = NULL;
++      struct lookup_intent it = { .it_op = IT_GETATTR };
+       int err = mount_is_safe(nd);
+       if (err)
+               return err;
+       if (!old_name || !*old_name)
+               return -EINVAL;
+-      err = path_lookup(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd);
+-      if (err)
++      err = path_lookup_it(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd, &it);
++      if (err) {
++              intent_release(&it);
+               return err;
++      }
+       down_write(&current->namespace->sem);
+       err = -EINVAL;
+@@ -518,6 +523,7 @@
+       }
+       up_write(&current->namespace->sem);
++      intent_release(&it);
+       path_release(&old_nd);
+       return err;
+ }
+@@ -701,6 +707,7 @@
+                 unsigned long flags, void *data_page)
+ {
+       struct nameidata nd;
++      struct lookup_intent it = { .it_op = IT_GETATTR };
+       int retval = 0;
+       int mnt_flags = 0;
+@@ -728,10 +735,11 @@
+       flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
+       /* ... and get the mountpoint */
+-      retval = path_lookup(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd);
+-      if (retval)
++      retval = path_lookup_it(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd, &it);
++      if (retval) {
++              intent_release(&it);
+               return retval;
+-
++      }
+       if (flags & MS_REMOUNT)
+               retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
+                                   data_page);
+@@ -742,6 +750,8 @@
+       else
+               retval = do_add_mount(&nd, type_page, flags, mnt_flags,
+                                     dev_name, data_page);
++
++      intent_release(&it);
+       path_release(&nd);
+       return retval;
+ }
+@@ -907,6 +917,8 @@
+ {
+       struct vfsmount *tmp;
+       struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
++      struct lookup_intent new_it = { .it_op = IT_GETATTR };
++      struct lookup_intent old_it = { .it_op = IT_GETATTR };
+       int error;
+       if (!capable(CAP_SYS_ADMIN))
+@@ -914,14 +926,14 @@
+       lock_kernel();
+-      error = __user_walk(new_root, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd);
++      error = __user_walk_it(new_root, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd, &new_it);
+       if (error)
+               goto out0;
+       error = -EINVAL;
+       if (!check_mnt(new_nd.mnt))
+               goto out1;
+-      error = __user_walk(put_old, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd);
++      error = __user_walk_it(put_old, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd, &old_it);
+       if (error)
+               goto out1;
+@@ -976,8 +988,10 @@
+       up(&old_nd.dentry->d_inode->i_zombie);
+       up_write(&current->namespace->sem);
+       path_release(&user_nd);
++      intent_release(&old_it);
+       path_release(&old_nd);
+ out1:
++      intent_release(&new_it);
+       path_release(&new_nd);
+ out0:
+       unlock_kernel();
+Index: linux-2.4.29/fs/open.c
+===================================================================
+--- linux-2.4.29.orig/fs/open.c        2005-04-07 18:52:27.000000000 +0300
++++ linux-2.4.29/fs/open.c     2005-04-07 19:14:06.000000000 +0300
+@@ -19,6 +19,8 @@
+ #include <asm/uaccess.h>
+ #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
++extern int path_walk_it(const char *name, struct nameidata *nd,
++                      struct lookup_intent *it);
+ int vfs_statfs(struct super_block *sb, struct statfs *buf)
+ {
+@@ -95,9 +97,10 @@
+       write_unlock(&files->file_lock);
+ }
+-int do_truncate(struct dentry *dentry, loff_t length)
++int do_truncate(struct dentry *dentry, loff_t length, int called_from_open)
+ {
+       struct inode *inode = dentry->d_inode;
++      struct inode_operations *op = dentry->d_inode->i_op;
+       int error;
+       struct iattr newattrs;
+@@ -109,7 +112,13 @@
+       down(&inode->i_sem);
+       newattrs.ia_size = length;
+       newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+-      error = notify_change(dentry, &newattrs);
++      if (called_from_open)
++              newattrs.ia_valid |= ATTR_FROM_OPEN;
++      if (op->setattr_raw) {
++              newattrs.ia_valid |= ATTR_RAW;
++              error = op->setattr_raw(inode, &newattrs);
++      } else
++              error = notify_change(dentry, &newattrs);
+       up(&inode->i_sem);
+       up_write(&inode->i_alloc_sem);
+       return error;
+@@ -120,12 +129,13 @@
+       struct nameidata nd;
+       struct inode * inode;
+       int error;
++      struct lookup_intent it = { .it_op = IT_GETATTR };
+       error = -EINVAL;
+       if (length < 0) /* sorry, but loff_t says... */
+               goto out;
+-      error = user_path_walk(path, &nd);
++      error = user_path_walk_it(path, &nd, &it);
+       if (error)
+               goto out;
+       inode = nd.dentry->d_inode;
+@@ -165,11 +175,13 @@
+       error = locks_verify_truncate(inode, NULL, length);
+       if (!error) {
+               DQUOT_INIT(inode);
+-              error = do_truncate(nd.dentry, length);
++              intent_release(&it);
++              error = do_truncate(nd.dentry, length, 0);
+       }
+       put_write_access(inode);
+ dput_and_out:
++      intent_release(&it);
+       path_release(&nd);
+ out:
+       return error;
+@@ -217,7 +229,7 @@
+       error = locks_verify_truncate(inode, file, length);
+       if (!error)
+-              error = do_truncate(dentry, length);
++              error = do_truncate(dentry, length, 0);
+ out_putf:
+       fput(file);
+ out:
+@@ -262,11 +274,13 @@
+       struct inode * inode;
+       struct iattr newattrs;
+-      error = user_path_walk(filename, &nd);
++      error = user_path_walk_it(filename, &nd, NULL);
+       if (error)
+               goto out;
+       inode = nd.dentry->d_inode;
++      /* this is safe without a Lustre lock because it only depends
++         on the super block */
+       error = -EROFS;
+       if (IS_RDONLY(inode))
+               goto dput_and_out;
+@@ -284,7 +298,20 @@
+                       goto dput_and_out;
+               newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
+-      } else {
++      } 
++
++
++      if (inode->i_op->setattr_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++ 
++              newattrs.ia_valid |= ATTR_RAW;
++              error = op->setattr_raw(inode, &newattrs);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto dput_and_out;
++      }
++ 
++      if (!times) {
+               error = -EACCES;
+               if (IS_IMMUTABLE(inode))
+                       goto dput_and_out;
+@@ -312,12 +339,14 @@
+       struct inode * inode;
+       struct iattr newattrs;
+-      error = user_path_walk(filename, &nd);
++      error = user_path_walk_it(filename, &nd, NULL);
+       if (error)
+               goto out;
+       inode = nd.dentry->d_inode;
++      /* this is safe without a Lustre lock because it only depends
++         on the super block */
+       error = -EROFS;
+       if (IS_RDONLY(inode))
+               goto dput_and_out;
+@@ -335,7 +364,19 @@
+               newattrs.ia_atime = times[0].tv_sec;
+               newattrs.ia_mtime = times[1].tv_sec;
+               newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
+-      } else {
++      }
++
++      if (inode->i_op->setattr_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++ 
++              newattrs.ia_valid |= ATTR_RAW;
++              error = op->setattr_raw(inode, &newattrs);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto dput_and_out;
++      }
++
++      if (!utimes) {
+               error = -EACCES;
+               if (IS_IMMUTABLE(inode))
+                       goto dput_and_out;
+@@ -362,6 +403,7 @@
+       int old_fsuid, old_fsgid;
+       kernel_cap_t old_cap;
+       int res;
++      struct lookup_intent it = { .it_op = IT_GETATTR };
+       if (mode & ~S_IRWXO)    /* where's F_OK, X_OK, W_OK, R_OK? */
+               return -EINVAL;
+@@ -379,13 +421,14 @@
+       else
+               current->cap_effective = current->cap_permitted;
+-      res = user_path_walk(filename, &nd);
++      res = user_path_walk_it(filename, &nd, &it);
+       if (!res) {
+               res = permission(nd.dentry->d_inode, mode);
+               /* SuS v2 requires we report a read only fs too */
+               if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)
+                  && !special_file(nd.dentry->d_inode->i_mode))
+                       res = -EROFS;
++              intent_release(&it);
+               path_release(&nd);
+       }
+@@ -400,8 +443,9 @@
+ {
+       int error;
+       struct nameidata nd;
++      struct lookup_intent it = { .it_op = IT_GETATTR };
+-      error = __user_walk(filename,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd);
++      error = __user_walk_it(filename,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd, &it);
+       if (error)
+               goto out;
+@@ -412,6 +456,7 @@
+       set_fs_pwd(current->fs, nd.mnt, nd.dentry);
+ dput_and_out:
++      intent_release(&it);
+       path_release(&nd);
+ out:
+       return error;
+@@ -451,9 +496,10 @@
+ {
+       int error;
+       struct nameidata nd;
++      struct lookup_intent it = { .it_op = IT_GETATTR };
+-      error = __user_walk(filename, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
+-                    LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
++      error = __user_walk_it(filename, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
++                             LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd, &it);
+       if (error)
+               goto out;
+@@ -469,39 +515,56 @@
+       set_fs_altroot();
+       error = 0;
+ dput_and_out:
++      intent_release(&it);
+       path_release(&nd);
+ out:
+       return error;
+ }
+-asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
++int chmod_common(struct dentry *dentry, mode_t mode)
+ {
+-      struct inode * inode;
+-      struct dentry * dentry;
+-      struct file * file;
+-      int err = -EBADF;
++      struct inode *inode = dentry->d_inode;
+       struct iattr newattrs;
++      int err = -EROFS;
+-      file = fget(fd);
+-      if (!file)
++      if (IS_RDONLY(inode))
+               goto out;
+-      dentry = file->f_dentry;
+-      inode = dentry->d_inode;
++      if (inode->i_op->setattr_raw) {
++              newattrs.ia_mode = mode;
++              newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
++              newattrs.ia_valid |= ATTR_RAW;
++              err = inode->i_op->setattr_raw(inode, &newattrs);
++              /* the file system wants to use normal vfs path now */
++              if (err != -EOPNOTSUPP)
++                      goto out;
++      }
+-      err = -EROFS;
+-      if (IS_RDONLY(inode))
+-              goto out_putf;
+       err = -EPERM;
+       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+-              goto out_putf;
++              goto out;
++
+       if (mode == (mode_t) -1)
+               mode = inode->i_mode;
+       newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
+       newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
+       err = notify_change(dentry, &newattrs);
+-out_putf:
++out:
++      return err;
++}
++
++asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
++{
++      struct file * file;
++      int err = -EBADF;
++
++      file = fget(fd);
++      if (!file)
++              goto out;
++
++      err = chmod_common(file->f_dentry, mode);
++
+       fput(file);
+ out:
+       return err;
+@@ -510,30 +573,14 @@
+ asmlinkage long sys_chmod(const char * filename, mode_t mode)
+ {
+       struct nameidata nd;
+-      struct inode * inode;
+       int error;
+-      struct iattr newattrs;
+       error = user_path_walk(filename, &nd);
+       if (error)
+               goto out;
+-      inode = nd.dentry->d_inode;
+-
+-      error = -EROFS;
+-      if (IS_RDONLY(inode))
+-              goto dput_and_out;
+-
+-      error = -EPERM;
+-      if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+-              goto dput_and_out;
+-      if (mode == (mode_t) -1)
+-              mode = inode->i_mode;
+-      newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
+-      newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
+-      error = notify_change(nd.dentry, &newattrs);
++      error = chmod_common(nd.dentry, mode);
+-dput_and_out:
+       path_release(&nd);
+ out:
+       return error;
+@@ -553,6 +600,20 @@
+       error = -EROFS;
+       if (IS_RDONLY(inode))
+               goto out;
++
++      if (inode->i_op->setattr_raw) {
++              struct inode_operations *op = dentry->d_inode->i_op;
++
++              newattrs.ia_uid = user;
++              newattrs.ia_gid = group;
++              newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;
++              newattrs.ia_valid |= ATTR_RAW;
++              error = op->setattr_raw(inode, &newattrs);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      return error;
++      }
++
+       error = -EPERM;
+       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+               goto out;
+@@ -657,6 +718,7 @@
+ {
+       int namei_flags, error;
+       struct nameidata nd;
++      struct lookup_intent it = { .it_op = IT_OPEN };
+       namei_flags = flags;
+       if ((namei_flags+1) & O_ACCMODE)
+@@ -664,14 +726,15 @@
+       if (namei_flags & O_TRUNC)
+               namei_flags |= 2;
+-      error = open_namei(filename, namei_flags, mode, &nd);
+-      if (!error)
+-              return dentry_open(nd.dentry, nd.mnt, flags);
++      error = open_namei_it(filename, namei_flags, mode, &nd, &it);
++      if (error)
++              return ERR_PTR(error);
+-      return ERR_PTR(error);
++      return dentry_open_it(nd.dentry, nd.mnt, flags, &it);
+ }
+-struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
++struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
++                          int flags, struct lookup_intent *it)
+ {
+       struct file * f;
+       struct inode *inode;
+@@ -708,12 +771,15 @@
+       }
+       if (f->f_op && f->f_op->open) {
++              f->f_it = it;
+               error = f->f_op->open(inode,f);
++              f->f_it = NULL;
+               if (error)
+                       goto cleanup_all;
+       }
+       f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
++      intent_release(it);
+       return f;
+ cleanup_all:
+@@ -728,11 +794,17 @@
+ cleanup_file:
+       put_filp(f);
+ cleanup_dentry:
++      intent_release(it);
+       dput(dentry);
+       mntput(mnt);
+       return ERR_PTR(error);
+ }
++struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
++{
++      return dentry_open_it(dentry, mnt, flags, NULL);
++}
++
+ /*
+  * Find an empty file descriptor entry, and mark it busy.
+  */
+Index: linux-2.4.29/fs/stat.c
+===================================================================
+--- linux-2.4.29.orig/fs/stat.c        2005-04-07 18:52:47.000000000 +0300
++++ linux-2.4.29/fs/stat.c     2005-04-07 19:14:06.000000000 +0300
+@@ -17,10 +17,12 @@
+  * Revalidate the inode. This is required for proper NFS attribute caching.
+  */
+ static __inline__ int
+-do_revalidate(struct dentry *dentry)
++do_revalidate(struct dentry *dentry, struct lookup_intent *it)
+ {
+       struct inode * inode = dentry->d_inode;
+-      if (inode->i_op && inode->i_op->revalidate)
++      if (inode->i_op && inode->i_op->revalidate_it)
++              return inode->i_op->revalidate_it(dentry, it);
++      else if (inode->i_op && inode->i_op->revalidate)
+               return inode->i_op->revalidate(dentry);
+       return 0;
+ }
+@@ -141,13 +143,15 @@
+ asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
+ {
+       struct nameidata nd;
++      struct lookup_intent it = { .it_op = IT_GETATTR };
+       int error;
+-      error = user_path_walk(filename, &nd);
++      error = user_path_walk_it(filename, &nd, &it);
+       if (!error) {
+-              error = do_revalidate(nd.dentry);
++              error = do_revalidate(nd.dentry, &it);
+               if (!error)
+                       error = cp_old_stat(nd.dentry->d_inode, statbuf);
++              intent_release(&it);
+               path_release(&nd);
+       }
+       return error;
+@@ -157,13 +161,15 @@
+ asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
+ {
+       struct nameidata nd;
++      struct lookup_intent it = { .it_op = IT_GETATTR };
+       int error;
+-      error = user_path_walk(filename, &nd);
++      error = user_path_walk_it(filename, &nd, &it);
+       if (!error) {
+-              error = do_revalidate(nd.dentry);
++              error = do_revalidate(nd.dentry, &it);
+               if (!error)
+                       error = cp_new_stat(nd.dentry->d_inode, statbuf);
++              intent_release(&it);
+               path_release(&nd);
+       }
+       return error;
+@@ -178,13 +184,15 @@
+ asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
+ {
+       struct nameidata nd;
++      struct lookup_intent it = { .it_op = IT_GETATTR };
+       int error;
+-      error = user_path_walk_link(filename, &nd);
++      error = user_path_walk_link_it(filename, &nd, &it);
+       if (!error) {
+-              error = do_revalidate(nd.dentry);
++              error = do_revalidate(nd.dentry, &it);
+               if (!error)
+                       error = cp_old_stat(nd.dentry->d_inode, statbuf);
++              intent_release(&it);
+               path_release(&nd);
+       }
+       return error;
+@@ -195,13 +203,15 @@
+ asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
+ {
+       struct nameidata nd;
++      struct lookup_intent it = { .it_op = IT_GETATTR };
+       int error;
+-      error = user_path_walk_link(filename, &nd);
++      error = user_path_walk_link_it(filename, &nd, &it);
+       if (!error) {
+-              error = do_revalidate(nd.dentry);
++              error = do_revalidate(nd.dentry, &it);
+               if (!error)
+                       error = cp_new_stat(nd.dentry->d_inode, statbuf);
++              intent_release(&it);
+               path_release(&nd);
+       }
+       return error;
+@@ -222,7 +232,7 @@
+       if (f) {
+               struct dentry * dentry = f->f_dentry;
+-              err = do_revalidate(dentry);
++              err = do_revalidate(dentry, NULL);
+               if (!err)
+                       err = cp_old_stat(dentry->d_inode, statbuf);
+               fput(f);
+@@ -241,7 +251,7 @@
+       if (f) {
+               struct dentry * dentry = f->f_dentry;
+-              err = do_revalidate(dentry);
++              err = do_revalidate(dentry, NULL);
+               if (!err)
+                       err = cp_new_stat(dentry->d_inode, statbuf);
+               fput(f);
+@@ -263,7 +273,7 @@
+               error = -EINVAL;
+               if (inode->i_op && inode->i_op->readlink &&
+-                  !(error = do_revalidate(nd.dentry))) {
++                  !(error = do_revalidate(nd.dentry, NULL))) {
+                       UPDATE_ATIME(inode);
+                       error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
+               }
+@@ -339,12 +349,14 @@
+ {
+       struct nameidata nd;
+       int error;
++      struct lookup_intent it = { .it_op = IT_GETATTR };
+-      error = user_path_walk(filename, &nd);
++      error = user_path_walk_it(filename, &nd, &it);
+       if (!error) {
+-              error = do_revalidate(nd.dentry);
++              error = do_revalidate(nd.dentry, &it);
+               if (!error)
+                       error = cp_new_stat64(nd.dentry->d_inode, statbuf);
++              intent_release(&it);
+               path_release(&nd);
+       }
+       return error;
+@@ -354,12 +366,14 @@
+ {
+       struct nameidata nd;
+       int error;
++      struct lookup_intent it = { .it_op = IT_GETATTR };
+-      error = user_path_walk_link(filename, &nd);
++      error = user_path_walk_link_it(filename, &nd, &it);
+       if (!error) {
+-              error = do_revalidate(nd.dentry);
++              error = do_revalidate(nd.dentry, &it);
+               if (!error)
+                       error = cp_new_stat64(nd.dentry->d_inode, statbuf);
++              intent_release(&it);
+               path_release(&nd);
+       }
+       return error;
+@@ -374,7 +388,7 @@
+       if (f) {
+               struct dentry * dentry = f->f_dentry;
+-              err = do_revalidate(dentry);
++              err = do_revalidate(dentry, NULL);
+               if (!err)
+                       err = cp_new_stat64(dentry->d_inode, statbuf);
+               fput(f);
+Index: linux-2.4.29/include/linux/dcache.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/dcache.h   2005-04-07 18:55:17.000000000 +0300
++++ linux-2.4.29/include/linux/dcache.h        2005-04-07 19:14:06.000000000 +0300
+@@ -6,6 +6,51 @@
+ #include <asm/atomic.h>
+ #include <linux/mount.h>
+ #include <linux/kernel.h>
++#include <linux/string.h>
++
++#define IT_OPEN     0x0001
++#define IT_CREAT    0x0002
++#define IT_READDIR  0x0004
++#define IT_GETATTR  0x0008
++#define IT_LOOKUP   0x0010
++#define IT_UNLINK   0x0020
++#define IT_GETXATTR 0x0040
++#define IT_EXEC     0x0080
++#define IT_PIN      0x0100
++
++#define IT_FL_LOCKED   0x0001
++#define IT_FL_FOLLOWED 0x0002 /* set by vfs_follow_link */
++
++#define INTENT_MAGIC 0x19620323
++
++
++struct lustre_intent_data {
++      int       it_disposition;
++      int       it_status;
++      __u64     it_lock_handle;
++      void     *it_data;
++      int       it_lock_mode;
++      int it_int_flags;
++};
++struct lookup_intent {
++      int     it_magic;
++      void    (*it_op_release)(struct lookup_intent *);
++      int     it_op;
++      int     it_flags;
++      int     it_create_mode;
++      union {
++              struct lustre_intent_data lustre;
++      } d;
++};
++
++static inline void intent_init(struct lookup_intent *it, int op, int flags)
++{
++      memset(it, 0, sizeof(*it));
++      it->it_magic = INTENT_MAGIC;
++      it->it_op = op;
++      it->it_flags = flags;
++}
++
+ /*
+  * linux/include/linux/dcache.h
+@@ -91,8 +136,22 @@
+       int (*d_delete)(struct dentry *);
+       void (*d_release)(struct dentry *);
+       void (*d_iput)(struct dentry *, struct inode *);
++      int (*d_revalidate_it)(struct dentry *, int, struct lookup_intent *);
++      void (*d_pin)(struct dentry *, struct vfsmount * , int);
++      void (*d_unpin)(struct dentry *, struct vfsmount *, int);
+ };
++#define PIN(de,mnt,flag)  if (de && de->d_op && de->d_op->d_pin) \
++                              de->d_op->d_pin(de, mnt, flag);
++#define UNPIN(de,mnt,flag)  if (de && de->d_op && de->d_op->d_unpin) \
++                              de->d_op->d_unpin(de, mnt, flag);
++
++
++/* defined in fs/namei.c */
++extern void intent_release(struct lookup_intent *it);
++/* defined in fs/dcache.c */
++extern void __d_rehash(struct dentry * entry, int lock);
++
+ /* the dentry parameter passed to d_hash and d_compare is the parent
+  * directory of the entries to be compared. It is used in case these
+  * functions need any directory specific information for determining
+@@ -124,6 +183,7 @@
+                                        * s_nfsd_free_path semaphore will be down
+                                        */
+ #define DCACHE_REFERENCED     0x0008  /* Recently used, don't discard. */
++#define DCACHE_LUSTRE_INVALID 0x0010  /* Lustre invalidated */
+ extern spinlock_t dcache_lock;
+Index: linux-2.4.29/include/linux/fs.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/fs.h       2005-04-07 18:59:19.000000000 +0300
++++ linux-2.4.29/include/linux/fs.h    2005-05-03 17:06:23.738087912 +0300
+@@ -73,6 +73,7 @@
+ #define FMODE_READ 1
+ #define FMODE_WRITE 2
++#define FMODE_EXEC 4
+ #define READ 0
+ #define WRITE 1
+@@ -340,6 +341,9 @@
+ #define ATTR_MTIME_SET        256
+ #define ATTR_FORCE    512     /* Not a change, but a change it */
+ #define ATTR_ATTR_FLAG        1024
++#define ATTR_RAW      0x0800  /* file system, not vfs will massage attrs */
++#define ATTR_FROM_OPEN        0x1000  /* called from open path, ie O_TRUNC */
++#define ATTR_CTIME_SET        0x2000
+ /*
+  * This is the Inode Attributes structure, used for notify_change().  It
+@@ -478,6 +482,7 @@
+       struct pipe_inode_info  *i_pipe;
+       struct block_device     *i_bdev;
+       struct char_device      *i_cdev;
++      void                    *i_filterdata;
+       unsigned long           i_dnotify_mask; /* Directory notify events */
+       struct dnotify_struct   *i_dnotify; /* for directory notifications */
+@@ -580,6 +585,7 @@
+       /* needed for tty driver, and maybe others */
+       void                    *private_data;
++      struct lookup_intent    *f_it;
+       /* preallocated helper kiobuf to speedup O_DIRECT */
+       struct kiobuf           *f_iobuf;
+@@ -700,6 +706,7 @@
+       struct qstr last;
+       unsigned int flags;
+       int last_type;
++      struct lookup_intent *intent;
+ };
+ /*
+@@ -820,7 +827,8 @@
+ 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 *);
+-extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
++int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
++             struct inode *new_dir, struct dentry *new_dentry);
+ /*
+  * File types
+@@ -880,21 +888,32 @@
+ struct inode_operations {
+       int (*create) (struct inode *,struct dentry *,int);
++      int (*create_it) (struct inode *,struct dentry *,int, struct lookup_intent *);
+       struct dentry * (*lookup) (struct inode *,struct dentry *);
++      struct dentry * (*lookup_it) (struct inode *,struct dentry *, struct lookup_intent *, int flags);
+       int (*link) (struct dentry *,struct inode *,struct dentry *);
++      int (*link_raw) (struct nameidata *,struct nameidata *);
+       int (*unlink) (struct inode *,struct dentry *);
++      int (*unlink_raw) (struct nameidata *);
+       int (*symlink) (struct inode *,struct dentry *,const char *);
++      int (*symlink_raw) (struct nameidata *,const char *);
+       int (*mkdir) (struct inode *,struct dentry *,int);
++      int (*mkdir_raw) (struct nameidata *,int);
+       int (*rmdir) (struct inode *,struct dentry *);
++      int (*rmdir_raw) (struct nameidata *);
+       int (*mknod) (struct inode *,struct dentry *,int,int);
++      int (*mknod_raw) (struct nameidata *,int,dev_t);
+       int (*rename) (struct inode *, struct dentry *,
+                       struct inode *, struct dentry *);
++      int (*rename_raw) (struct nameidata *, struct nameidata *);
+       int (*readlink) (struct dentry *, char *,int);
+       int (*follow_link) (struct dentry *, struct nameidata *);
+       void (*truncate) (struct inode *);
+       int (*permission) (struct inode *, int);
+       int (*revalidate) (struct dentry *);
++      int (*revalidate_it) (struct dentry *, struct lookup_intent *);
+       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);
+@@ -1091,10 +1110,14 @@
+ 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);
++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 *);
+@@ -1385,6 +1408,7 @@
+ 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(path_lookup(const char *, unsigned, struct nameidata *));
+@@ -1396,6 +1420,8 @@
+ 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 __inode_init_once(struct inode *);
+@@ -1539,6 +1565,8 @@
+ 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;
+Index: linux-2.4.29/include/linux/fs_struct.h
+===================================================================
+--- linux-2.4.29.orig/include/linux/fs_struct.h        2005-04-07 18:54:22.000000000 +0300
++++ linux-2.4.29/include/linux/fs_struct.h     2005-04-07 19:14:06.000000000 +0300
+@@ -34,10 +34,12 @@
+       write_lock(&fs->lock);
+       old_root = fs->root;
+       old_rootmnt = fs->rootmnt;
++      PIN(dentry, mnt, 1);
+       fs->rootmnt = mntget(mnt);
+       fs->root = dget(dentry);
+       write_unlock(&fs->lock);
+       if (old_root) {
++              UNPIN(old_root, old_rootmnt, 1);
+               dput(old_root);
+               mntput(old_rootmnt);
+       }
+@@ -57,10 +59,12 @@
+       write_lock(&fs->lock);
+       old_pwd = fs->pwd;
+       old_pwdmnt = fs->pwdmnt;
++      PIN(dentry, mnt, 0);
+       fs->pwdmnt = mntget(mnt);
+       fs->pwd = dget(dentry);
+       write_unlock(&fs->lock);
+       if (old_pwd) {
++              UNPIN(old_pwd, old_pwdmnt, 0);
+               dput(old_pwd);
+               mntput(old_pwdmnt);
+       }
+Index: linux-2.4.29/kernel/exit.c
+===================================================================
+--- linux-2.4.29.orig/kernel/exit.c    2005-04-07 18:53:09.000000000 +0300
++++ linux-2.4.29/kernel/exit.c 2005-04-07 19:14:06.000000000 +0300
+@@ -238,11 +238,14 @@
+ {
+       /* No need to hold fs->lock if we are killing it */
+       if (atomic_dec_and_test(&fs->count)) {
++              UNPIN(fs->pwd, fs->pwdmnt, 0);
++              UNPIN(fs->root, fs->rootmnt, 1);
+               dput(fs->root);
+               mntput(fs->rootmnt);
+               dput(fs->pwd);
+               mntput(fs->pwdmnt);
+               if (fs->altroot) {
++                      UNPIN(fs->altroot, fs->altrootmnt, 1);
+                       dput(fs->altroot);
+                       mntput(fs->altrootmnt);
+               }
+Index: linux-2.4.29/kernel/fork.c
+===================================================================
+--- linux-2.4.29.orig/kernel/fork.c    2005-04-07 18:52:37.000000000 +0300
++++ linux-2.4.29/kernel/fork.c 2005-04-07 19:14:06.000000000 +0300
+@@ -388,10 +388,13 @@
+               fs->umask = old->umask;
+               read_lock(&old->lock);
+               fs->rootmnt = mntget(old->rootmnt);
++              PIN(old->pwd, old->pwdmnt, 0);
++              PIN(old->root, old->rootmnt, 1);
+               fs->root = dget(old->root);
+               fs->pwdmnt = mntget(old->pwdmnt);
+               fs->pwd = dget(old->pwd);
+               if (old->altroot) {
++                      PIN(old->altroot, old->altrootmnt, 1);
+                       fs->altrootmnt = mntget(old->altrootmnt);
+                       fs->altroot = dget(old->altroot);
+               } else {
+Index: linux-2.4.29/kernel/ksyms.c
+===================================================================
+--- linux-2.4.29.orig/kernel/ksyms.c   2005-04-07 18:59:19.000000000 +0300
++++ linux-2.4.29/kernel/ksyms.c        2005-04-07 19:14:06.000000000 +0300
+@@ -284,6 +284,7 @@
+ EXPORT_SYMBOL(mark_page_accessed);
+ EXPORT_SYMBOL(vfs_readlink);
+ EXPORT_SYMBOL(vfs_follow_link);
++EXPORT_SYMBOL(vfs_follow_link_it);
+ EXPORT_SYMBOL(page_readlink);
+ EXPORT_SYMBOL(page_follow_link);
+ EXPORT_SYMBOL(page_symlink_inode_operations);
diff --git a/lustre/kernel_patches/series/vanilla-2.4.29 b/lustre/kernel_patches/series/vanilla-2.4.29
new file mode 100644 (file)
index 0000000..53a248c
--- /dev/null
@@ -0,0 +1,44 @@
+uml-patch-2.4.29-1.patch
+uml-2.4.20-do_mmap_pgoff-fix.patch
+uml-export-end_iomem.patch
+configurable-x86-stack-2.4.20.patch
+configurable-x86_64-2.4.21.patch
+dev_read_only_2.4.20-rh.patch
+exports_2.4.20-rh-hp.patch
+lustre_version.patch
+vfs_intent-2.4.29-vanilla.patch 
+invalidate_show-2.4.29.patch
+export-truncate.patch
+iod-stock-exports-2.4.22.patch 
+ext3-htree-2.4.29.patch
+linux-2.4.29-xattr-0.8.54.patch 
+ext3-orphan_lock-2.4.22-rh.patch
+ext3-noread-2.4.20.patch
+ext3-delete_thread-2.4.29.patch 
+extN-wantedi.patch
+ext3-san-2.4.20.patch
+ext3-map_inode_page.patch
+ext3-error-export.patch
+iopen-2.4.20.patch
+tcp-zero-copy-2.4.22-rh.patch
+jbd-dont-account-blocks-twice.patch
+jbd-commit-tricks.patch
+ext3-no-write-super-chaos.patch
+add_page_private.patch
+nfs_export_kernel-2.4.29.patch 
+ext3-raw-lookup.patch
+ext3-ea-in-inode-2.4.29.patch
+listman-2.4.20.patch
+ext3-trusted_ea-2.4.20.patch
+ext3-xattr-ptr-arith-fix.patch
+3.5G-address-space-2.4.22-vanilla.patch
+procfs-ndynamic-2.4.patch
+ext3-truncate-buffer-head.patch
+inode-max-readahead-2.4.24.patch
+ext3-extents-2.4.29.patch
+ext3-extents-asyncdel-2.4.24.patch
+export_num_siblings.patch
+ext3-nlinks-2.4.24.patch
+export-show_task-2.4-vanilla.patch 
+export-zap-page-range.patch
+remove-suid-2.4-rhel.patch