Whamcloud - gitweb
Land b1_2 onto HEAD (20040317_2319)
authoradilger <adilger>
Thu, 18 Mar 2004 07:19:06 +0000 (07:19 +0000)
committeradilger <adilger>
Thu, 18 Mar 2004 07:19:06 +0000 (07:19 +0000)
b=2939, b=2325, b=2059 (partial), b=2925, b=2399, b=2517

47 files changed:
lustre/ChangeLog
lustre/include/linux/lustre_fsfilt.h
lustre/include/linux/obd.h
lustre/kernel_patches/patches/dcache_refcount_debug.patch [new file with mode: 0644]
lustre/kernel_patches/patches/ext3-pdirops-2.4.20-chaos.patch [new file with mode: 0644]
lustre/kernel_patches/patches/inode-max-readahead-2.4.24.patch [new file with mode: 0644]
lustre/kernel_patches/patches/iopen-2.4.20.patch
lustre/kernel_patches/patches/iopen-2.4.21-chaos.patch
lustre/kernel_patches/patches/iopen-2.6.3-mm4.patch
lustre/kernel_patches/patches/linux-2.6.3-CITI_NFS4_ALL.patch
lustre/kernel_patches/patches/lustre_version.patch
lustre/kernel_patches/patches/vfs_intent-2.4.18-18-chaos65.patch
lustre/kernel_patches/patches/vfs_intent-2.4.19-pre1.patch
lustre/kernel_patches/patches/vfs_intent-2.4.19-suse.patch
lustre/kernel_patches/patches/vfs_intent-2.4.20-hp.patch
lustre/kernel_patches/patches/vfs_intent-2.4.20-rh.patch
lustre/kernel_patches/patches/vfs_intent-2.4.20-vanilla.patch
lustre/kernel_patches/patches/vfs_intent-2.4.21-chaos.patch
lustre/kernel_patches/patches/vfs_intent-2.4.21-suse2.patch
lustre/kernel_patches/patches/vfs_intent-2.4.22-rh.patch
lustre/kernel_patches/series/chaos-2.4.21
lustre/kernel_patches/series/hp-pnnl-2.4.20
lustre/kernel_patches/series/rh-2.4.20
lustre/kernel_patches/series/vanilla-2.4.24
lustre/liblustre/namei.c
lustre/llite/Makefile.am
lustre/llite/Makefile.mk
lustre/llite/file.c
lustre/llite/sysctl.c [deleted file]
lustre/lvfs/.cvsignore
lustre/lvfs/Makefile.am
lustre/lvfs/fsfilt_ext3.c
lustre/lvfs/fsfilt_extN.c [deleted file]
lustre/lvfs/fsfilt_reiserfs.c
lustre/mds/mds_fs.c
lustre/mds/mds_open.c
lustre/mds/mds_reint.c
lustre/mds/mds_unlink_open.c
lustre/obdclass/class_obd.c
lustre/obdclass/llog_lvfs.c
lustre/obdfilter/filter.c
lustre/obdfilter/filter_io.c
lustre/obdfilter/filter_lvb.c
lustre/ptlrpc/llog_server.c
lustre/ptlrpc/recover.c
lustre/tests/replay-ost-single.sh
lustre/tests/sanity.sh

index c80989f..0eb3b7f 100644 (file)
@@ -19,8 +19,13 @@ tbd  Cluster File Systems, Inc. <info@clusterfs.com>
        - mds_reint_create() should take same inode create lock (2926)
        - correct journal credits calculated for CANCEL_UNLINK_LOG (2931)
        - don't close files for self_export to avoid uninitialized obd (2936)
-        - let lustre could be mounted with the same name for node and mds (2939)
-       
+       - allow MDS with the same name as client node (2939)
+       - hold dentry reference for closed log files for unlink (2325)
+       - reserve space for all logs during transactions (2059)
+       - don't evict page beyond end of stripe extent (2925)
+       - don't oops on a deleted current working directory (2399)
+       - handle hard links to targets without a parent properly (2517)
+
 2004-03-04  Cluster File Systems, Inc. <info@clusterfs.com>
        * version 1.2.0
        * bug fixes
index 3f3421a..40e9914 100644 (file)
@@ -28,6 +28,7 @@
 #ifdef __KERNEL__
 
 #include <linux/obd.h>
+#include <linux/obd_class.h>
 
 typedef void (*fsfilt_cb_t)(struct obd_device *obd, __u64 last_rcvd,
                             void *data, int error);
@@ -41,10 +42,11 @@ struct fsfilt_operations {
         struct list_head fs_list;
         struct module *fs_owner;
         char   *fs_type;
-        void   *(* fs_start)(struct inode *inode, int op, void *desc_private);
+        void   *(* fs_start)(struct inode *inode, int op, void *desc_private,
+                             int logs);
         void   *(* fs_brw_start)(int objcount, struct fsfilt_objinfo *fso,
                                  int niocount, struct niobuf_local *nb,
-                                 void *desc_private);
+                                 void *desc_private, int logs);
         int     (* fs_commit)(struct inode *inode, void *handle,int force_sync);
         int     (* fs_commit_async)(struct inode *inode, void *handle,
                                         void **wait_handle);
@@ -72,6 +74,7 @@ struct fsfilt_operations {
                                     int force_sync);
         int     (* fs_read_record)(struct file *, void *, int size, loff_t *);
         int     (* fs_setup)(struct super_block *sb);
+        int     (* fs_get_op_len)(int, struct fsfilt_objinfo *, int);
 };
 
 extern int fsfilt_register_ops(struct fsfilt_operations *fs_ops);
@@ -88,24 +91,23 @@ extern void fsfilt_put_ops(struct fsfilt_operations *fs_ops);
 #define FSFILT_OP_MKNOD          7
 #define FSFILT_OP_SETATTR        8
 #define FSFILT_OP_LINK           9
-#define FSFILT_OP_CREATE_LOG    10
-#define FSFILT_OP_UNLINK_LOG    11
-#define FSFILT_OP_CANCEL_UNLINK_LOG    12
+#define FSFILT_OP_CANCEL_UNLINK 10
 
-static inline void *fsfilt_start(struct obd_device *obd, struct inode *inode,
-                                 int op, struct obd_trans_info *oti)
+static inline void *fsfilt_start_log(struct obd_device *obd,
+                                     struct inode *inode, int op,
+                                     struct obd_trans_info *oti, int logs)
 {
         unsigned long now = jiffies;
         void *parent_handle = oti ? oti->oti_handle : NULL;
-        void *handle = obd->obd_fsops->fs_start(inode, op, parent_handle);
-        CDEBUG(D_INFO, "started handle %p (%p)\n", handle, parent_handle);
+        void *handle = obd->obd_fsops->fs_start(inode, op, parent_handle, logs);
+        CDEBUG(D_HA, "started handle %p (%p)\n", handle, parent_handle);
 
         if (oti != NULL) {
                 if (parent_handle == NULL) {
                         oti->oti_handle = handle;
                 } else if (handle != parent_handle) {
                         CERROR("mismatch: parent %p, handle %p, oti %p\n",
-                               parent_handle, handle, oti->oti_handle);
+                               parent_handle, handle, oti);
                         LBUG();
                 }
         }
@@ -114,17 +116,22 @@ static inline void *fsfilt_start(struct obd_device *obd, struct inode *inode,
         return handle;
 }
 
-static inline void *fsfilt_brw_start(struct obd_device *obd, int objcount,
-                                     struct fsfilt_objinfo *fso, int niocount,
-                                     struct niobuf_local *nb,
-                                     struct obd_trans_info *oti)
+static inline void *fsfilt_start(struct obd_device *obd, struct inode *inode,
+                                 int op, struct obd_trans_info *oti)
+{
+        return fsfilt_start_log(obd, inode, op, oti, 0);
+}
+
+static inline void *fsfilt_brw_start_log(struct obd_device *obd,
+                                         int objcount,
+                                         struct fsfilt_objinfo *fso,
+                                         int niocount, struct niobuf_local *nb,
+                                         struct obd_trans_info *oti, int logs)
 {
         unsigned long now = jiffies;
         void *parent_handle = oti ? oti->oti_handle : NULL;
-        void *handle;
-
-        handle = obd->obd_fsops->fs_brw_start(objcount, fso, niocount, nb,
-                                              parent_handle);
+        void *handle = obd->obd_fsops->fs_brw_start(objcount, fso, niocount, nb,
+                                                    parent_handle, logs);
         CDEBUG(D_HA, "started handle %p (%p)\n", handle, parent_handle);
 
         if (oti != NULL) {
@@ -132,41 +139,53 @@ static inline void *fsfilt_brw_start(struct obd_device *obd, int objcount,
                         oti->oti_handle = handle;
                 } else if (handle != parent_handle) {
                         CERROR("mismatch: parent %p, handle %p, oti %p\n",
-                               parent_handle, handle, oti->oti_handle);
+                               parent_handle, handle, oti);
                         LBUG();
                 }
         }
         if (time_after(jiffies, now + 15 * HZ))
                 CERROR("long journal start time %lus\n", (jiffies - now) / HZ);
+
         return handle;
 }
 
+static inline void *fsfilt_brw_start(struct obd_device *obd, int objcount,
+                                     struct fsfilt_objinfo *fso, int niocount,
+                                     struct niobuf_local *nb,
+                                     struct obd_trans_info *oti)
+{
+        return fsfilt_brw_start_log(obd, objcount, fso, niocount, nb, oti, 0);
+}
+
 static inline int fsfilt_commit(struct obd_device *obd, struct inode *inode,
                                 void *handle, int force_sync)
 {
         unsigned long now = jiffies;
         int rc = obd->obd_fsops->fs_commit(inode, handle, force_sync);
-        CDEBUG(D_INFO, "committing handle %p\n", handle);
+        CDEBUG(D_HA, "committing handle %p\n", handle);
+
         if (time_after(jiffies, now + 15 * HZ))
                 CERROR("long journal start time %lus\n", (jiffies - now) / HZ);
+
         return rc;
 }
 
 static inline int fsfilt_commit_async(struct obd_device *obd,
-                                         struct inode *inode,
-                                         void *handle,
-                                         void **wait_handle)
+                                      struct inode *inode, void *handle,
+                                      void **wait_handle)
 {
         unsigned long now = jiffies;
         int rc = obd->obd_fsops->fs_commit_async(inode, handle, wait_handle);
+
         CDEBUG(D_HA, "committing handle %p (async)\n", *wait_handle);
         if (time_after(jiffies, now + 15 * HZ))
                 CERROR("long journal start time %lus\n", (jiffies - now) / HZ);
+
         return rc;
 }
 
-static inline int fsfilt_commit_wait(struct obd_device *obd, struct inode *inode,
-                                        void *handle)
+static inline int fsfilt_commit_wait(struct obd_device *obd,
+                                     struct inode *inode, void *handle)
 {
         unsigned long now = jiffies;
         int rc = obd->obd_fsops->fs_commit_wait(inode, handle);
@@ -217,8 +236,8 @@ static inline int fsfilt_add_journal_cb(struct obd_device *obd, __u64 last_rcvd,
                                         void *handle, fsfilt_cb_t cb_func,
                                         void *cb_data)
 {
-        return obd->obd_fsops->fs_add_journal_cb(obd, last_rcvd, handle,
-                                                 cb_func, cb_data);
+        return obd->obd_fsops->fs_add_journal_cb(obd, last_rcvd,
+                                                 handle, cb_func, cb_data);
 }
 
 /* very similar to obd_statfs(), but caller already holds obd_osfs_lock */
index 9da934f..fb2da73 100644 (file)
@@ -479,10 +479,10 @@ struct obd_device {
         __u64                  obd_last_committed;
         struct fsfilt_operations *obd_fsops;
         spinlock_t              obd_osfs_lock;
-        struct llog_ctxt        *obd_llog_ctxt[LLOG_MAX_CTXTS];
         struct obd_statfs       obd_osfs;
         unsigned long           obd_osfs_age;
         struct obd_run_ctxt     obd_ctxt;
+        struct llog_ctxt        *obd_llog_ctxt[LLOG_MAX_CTXTS];
         struct obd_device       *obd_observer;
         struct obd_export       *obd_self_export;
 
diff --git a/lustre/kernel_patches/patches/dcache_refcount_debug.patch b/lustre/kernel_patches/patches/dcache_refcount_debug.patch
new file mode 100644 (file)
index 0000000..0eddc23
--- /dev/null
@@ -0,0 +1,24 @@
+--- ./fs/dcache.c.orig 2004-01-30 14:54:45.000000000 -0700
++++ ./fs/dcache.c      2004-02-20 14:49:18.000000000 -0700
+@@ -348,8 +348,20 @@
+               dentry_stat.nr_unused--;
+               /* Unused dentry with a count? */
+-              if (atomic_read(&dentry->d_count))
++              if (atomic_read(&dentry->d_count)) {
++                      struct inode *inode = dentry->d_inode;
++                      printk(KERN_CRIT "dentry %*s %p->%lu/%u(%p/%s) ct %d\n",
++                             dentry->d_name.len, dentry->d_name.name, dentry,
++                             inode ? inode->i_ino : 0,
++                             inode ? inode->i_generation : 0, inode,
++                             inode ? inode->i_sb ?
++                                      inode->i_sb->s_type->name : "" : "",
++                             atomic_read(&dentry->d_count));
++                      spin_unlock(&dcache_lock);
++                      set_task_state(current, TASK_UNINTERRUPTIBLE);
++                      schedule();
+                       BUG();
++              }
+               prune_one_dentry(dentry);
+               if (!--count)
diff --git a/lustre/kernel_patches/patches/ext3-pdirops-2.4.20-chaos.patch b/lustre/kernel_patches/patches/ext3-pdirops-2.4.20-chaos.patch
new file mode 100644 (file)
index 0000000..28badd6
--- /dev/null
@@ -0,0 +1,1248 @@
+ fs/ext3/ialloc.c          |    3 
+ fs/ext3/inode.c           |    3 
+ fs/ext3/namei.c           |  582 +++++++++++++++++++++++++++++++++++++---------
+ fs/ext3/super.c           |   14 +
+ include/linux/ext3_fs.h   |    1 
+ include/linux/ext3_fs_i.h |    6 
+ 6 files changed, 500 insertions(+), 109 deletions(-)
+
+Index: linux-2.4.20/fs/ext3/namei.c
+===================================================================
+--- linux-2.4.20.orig/fs/ext3/namei.c  Wed Mar 17 15:37:09 2004
++++ linux-2.4.20/fs/ext3/namei.c       Wed Mar 17 15:37:56 2004
+@@ -51,6 +51,9 @@
+ {
+       struct buffer_head *bh;
++      /* with parallel dir operations all appends
++       * have to be serialized -bzzz */
++      down(&EXT3_I(inode)->i_append_sem);
+       *block = inode->i_size >> inode->i_sb->s_blocksize_bits;
+       if ((bh = ext3_bread(handle, inode, *block, 1, err))) {
+@@ -58,6 +61,8 @@
+               EXT3_I(inode)->i_disksize = inode->i_size;
+               ext3_journal_get_write_access(handle,bh);
+       }
++      up(&EXT3_I(inode)->i_append_sem);
++      
+       return bh;
+ }
+@@ -134,6 +139,8 @@
+       struct buffer_head *bh;
+       struct dx_entry *entries;
+       struct dx_entry *at;
++      unsigned long leaf;
++      unsigned int curidx;
+ };
+ struct dx_map_entry
+@@ -142,6 +149,30 @@
+       u32 offs;
+ };
++/* FIXME: this should be reworked using bb_spin_lock
++ * introduced in -mm tree
++ */
++#define BH_DXLock     25
++
++static inline void dx_lock_bh(struct buffer_head volatile *bh)
++{
++#ifdef CONFIG_SMP
++        while (test_and_set_bit(BH_DXLock, &bh->b_state)) {
++                while (test_bit(BH_DXLock, &bh->b_state))
++                        cpu_relax();
++        }
++#endif
++}
++
++static inline void dx_unlock_bh(struct buffer_head *bh)
++{
++#ifdef CONFIG_SMP
++        smp_mb__before_clear_bit();
++        clear_bit(BH_DXLock, &bh->b_state);
++#endif
++}
++
++
+ #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);
+@@ -153,7 +184,7 @@
+ 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,
++static struct dx_frame *dx_probe(struct qstr *name,
+                                struct inode *dir,
+                                struct dx_hash_info *hinfo,
+                                struct dx_frame *frame,
+@@ -165,15 +196,18 @@
+ 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 void dx_insert_block (struct inode *, struct dx_frame *, u32, u32, u32);
+ 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);
++                     struct ext3_dir_entry_2 **res_dir, int *err,
++                     int rwlock, void **lock);
+ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
+                            struct inode *inode);
++static inline void *ext3_lock_htree(struct inode *, unsigned long, int);
++static inline void ext3_unlock_htree(struct inode *, void *);
+ /*
+  * Future: use high four bits of block for coalesce-on-delete flags
+@@ -306,6 +340,94 @@
+ #endif /* DX_DEBUG */
+ /*
++ * dx_find_position
++ *
++ * search position of specified hash in index
++ *
++ */
++
++struct dx_entry * dx_find_position(struct dx_entry * entries, u32 hash)
++{
++      struct dx_entry *p, *q, *m;
++      int count;
++
++      count = dx_get_count(entries);
++      p = entries + 1;
++      q = entries + count - 1;
++      while (p <= q)
++      {
++              m = p + (q - p)/2;
++              if (dx_get_hash(m) > hash)
++                      q = m - 1;
++              else
++                      p = m + 1;
++      }
++      return p - 1;
++}
++
++/*
++ * returns 1 if path is unchanged
++ */
++int dx_check_path(struct dx_frame *frame, u32 hash)
++{
++      struct dx_entry *p;
++      int ret = 1;
++
++      dx_lock_bh(frame->bh);
++      p = dx_find_position(frame->entries, hash);
++      if (frame->leaf != dx_get_block(p))
++              ret = 0;
++      dx_unlock_bh(frame->bh);
++      
++      return ret;
++}
++
++/*
++ * 0 - changed
++ * 1 - hasn't changed
++ */
++static int
++dx_check_full_path(struct dx_frame *frames, struct dx_hash_info *hinfo)
++{
++      struct dx_entry *p;
++      struct dx_frame *frame = frames;
++      u32 leaf;
++
++      /* check first level */
++      dx_lock_bh(frame->bh);
++      p = dx_find_position(frame->entries, hinfo->hash);
++      leaf = dx_get_block(p);
++      dx_unlock_bh(frame->bh);
++      
++      if (leaf != frame->leaf) 
++              return 0;
++      
++      /* is there 2nd level? */
++      frame++;
++      if (frame->bh == NULL)
++              return 1;
++
++      /* check second level */
++      dx_lock_bh(frame->bh);
++
++      /* probably 1st level got changed, check it */
++      if (!dx_check_path(frames, hinfo->hash)) {
++              /* path changed */
++              dx_unlock_bh(frame->bh);
++              return 0;
++      }
++
++      p = dx_find_position(frame->entries, hinfo->hash);
++      leaf = dx_get_block(p);
++      dx_unlock_bh(frame->bh);
++      
++      if (leaf != frame->leaf)
++              return 0;
++
++      return 1;
++}
++
++/*
+  * Probe for a directory leaf block to search.
+  *
+  * dx_probe can return ERR_BAD_DX_DIR, which means there was a format
+@@ -315,19 +437,20 @@
+  * back to userspace.
+  */
+ static struct dx_frame *
+-dx_probe(struct dentry *dentry, struct inode *dir,
++dx_probe(struct qstr *name, 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;
++      unsigned indirect;
++      struct dx_entry *at, *entries;
+       struct dx_root *root;
+       struct buffer_head *bh;
+       struct dx_frame *frame = frame_in;
+       u32 hash;
++      unsigned int curidx;
+       frame->bh = NULL;
+-      if (dentry)
+-              dir = dentry->d_parent->d_inode;
++      frame[1].bh = NULL;
++
+       if (!(bh = ext3_bread (NULL,dir, 0, 0, err)))
+               goto fail;
+       root = (struct dx_root *) bh->b_data;
+@@ -343,8 +466,8 @@
+       }
+       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);
++      if (name)
++              ext3fs_dirhash(name->name, name->len, hinfo);
+       hash = hinfo->hash;
+       if (root->info.unused_flags & 1) {
+@@ -356,7 +479,19 @@
+               goto fail;
+       }
++repeat:
++      curidx = 0;
++      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));
++      dx_lock_bh(bh);
++      /* indirect must be initialized under bh lock because
++       * 2nd level creation procedure may change it and dx_probe()
++       * will suggest htree is still single-level -bzzz */
+       if ((indirect = root->info.indirect_levels) > 1) {
++              dx_unlock_bh(bh);
+               ext3_warning(dir->i_sb, __FUNCTION__,
+                            "Unimplemented inode hash depth: %#06x",
+                            root->info.indirect_levels);
+@@ -364,56 +499,46 @@
+               *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)));
++              at = dx_find_position(entries, hinfo->hash);
++              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)))
++              frame->curidx = curidx;
++              frame->leaf = dx_get_block(at);
++              if (!indirect--) {
++                      dx_unlock_bh(bh);
++                      return frame;
++              }
++              
++              /* step into next htree level */
++              curidx = dx_get_block(at);
++              dx_unlock_bh(bh);
++              if (!(bh = ext3_bread (NULL,dir, frame->leaf, 0, err)))
+                       goto fail2;
++              
++              dx_lock_bh(bh);
++              /* splitting may change root index block and move
++               * hash we're looking for into another index block
++               * so, we have to check this situation and repeat
++               * from begining if path got changed -bzzz */
++              if (!dx_check_path(frame, hash)) {
++                      dx_unlock_bh(bh);
++                      bh = frame->bh;
++                      indirect++;
++                      goto repeat;
++              }
++              
+               at = entries = ((struct dx_node *) bh->b_data)->entries;
+               assert (dx_get_limit(entries) == dx_node_limit (dir));
+               frame++;
+       }
++      dx_unlock_bh(bh);
+ fail2:
+       while (frame >= frame_in) {
+               brelse(frame->bh);
+@@ -427,8 +552,7 @@
+ {
+       if (frames[0].bh == NULL)
+               return;
+-
+-      if (((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels)
++      if (frames[1].bh != NULL)
+               brelse(frames[1].bh);
+       brelse(frames[0].bh);
+ }
+@@ -470,8 +594,10 @@
+        * nodes need to be read.
+        */
+       while (1) {
+-              if (++(p->at) < p->entries + dx_get_count(p->entries))
++              if (++(p->at) < p->entries + dx_get_count(p->entries)) {
++                      p->leaf = dx_get_block(p->at);
+                       break;
++              }
+               if (p == frames)
+                       return 0;
+               num_frames++;
+@@ -497,13 +623,17 @@
+        * block so no check is necessary
+        */
+       while (num_frames--) {
+-              if (!(bh = ext3_bread(NULL, dir, dx_get_block(p->at),
+-                                    0, err)))
++              u32 idx;
++              
++              idx = p->leaf = dx_get_block(p->at);
++              if (!(bh = ext3_bread(NULL, dir, idx, 0, err)))
+                       return -1; /* Failure */
+               p++;
+               brelse (p->bh);
+               p->bh = bh;
+               p->at = p->entries = ((struct dx_node *) bh->b_data)->entries;
++              p->curidx = idx;
++              p->leaf = dx_get_block(p->at);
+       }
+       return 1;
+ }
+@@ -543,7 +673,7 @@
+       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);
++      frame = dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, frames, &err);
+       if (!frame)
+               return err;
+@@ -625,7 +755,8 @@
+                       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));
++              de = (struct ext3_dir_entry_2 *)((char*)de +
++                              le16_to_cpu(de->rec_len));
+       }
+       return count;
+ }
+@@ -658,7 +789,8 @@
+       } while(more);
+ }
+-static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block)
++static void dx_insert_block(struct inode *dir, struct dx_frame *frame,
++                      u32 hash, u32 block, u32 idx)
+ {
+       struct dx_entry *entries = frame->entries;
+       struct dx_entry *old = frame->at, *new = old + 1;
+@@ -670,6 +802,7 @@
+       dx_set_hash(new, hash);
+       dx_set_block(new, block);
+       dx_set_count(entries, count + 1);
++      
+ }
+ #endif
+@@ -752,7 +885,8 @@
+       
+ static struct buffer_head * ext3_find_entry (struct dentry *dentry,
+-                                      struct ext3_dir_entry_2 ** res_dir)
++                                      struct ext3_dir_entry_2 ** res_dir,
++                                      int rwlock, void **lock)
+ {
+       struct super_block * sb;
+       struct buffer_head * bh_use[NAMEI_RA_SIZE];
+@@ -768,6 +902,7 @@
+       int namelen;
+       const u8 *name;
+       unsigned blocksize;
++      int do_not_use_dx = 0;
+       *res_dir = NULL;
+       sb = dir->i_sb;
+@@ -776,9 +911,10 @@
+       name = dentry->d_name.name;
+       if (namelen > EXT3_NAME_LEN)
+               return NULL;
++repeat:
+ #ifdef CONFIG_EXT3_INDEX
+       if (is_dx(dir)) {
+-              bh = ext3_dx_find_entry(dentry, res_dir, &err);
++              bh = ext3_dx_find_entry(dentry, res_dir, &err, rwlock, lock);
+               /*
+                * On success, or if the error was file not found,
+                * return.  Otherwise, fall back to doing a search the
+@@ -787,8 +923,14 @@
+               if (bh || (err != ERR_BAD_DX_DIR))
+                       return bh;
+               dxtrace(printk("ext3_find_entry: dx failed, falling back\n"));
++              do_not_use_dx = 1;
+       }
+ #endif
++      *lock = ext3_lock_htree(dir, 0, rwlock);
++      if (is_dx(dir) && !do_not_use_dx) {
++              ext3_unlock_htree(dir, *lock);
++              goto repeat;
++      }
+       nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb);
+       start = EXT3_I(dir)->i_dir_start_lookup;
+       if (start >= nblocks)
+@@ -860,12 +1002,17 @@
+       /* Clean up the read-ahead blocks */
+       for (; ra_ptr < ra_max; ra_ptr++)
+               brelse (bh_use[ra_ptr]);
++      if (!ret) {
++              ext3_unlock_htree(dir, *lock);
++              *lock = NULL;
++      }
+       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 ext3_dir_entry_2 **res_dir, int *err,
++                     int rwlock, void **lock)
+ {
+       struct super_block * sb;
+       struct dx_hash_info     hinfo;
+@@ -880,11 +1027,22 @@
+       struct inode *dir = dentry->d_parent->d_inode;
+       
+       sb = dir->i_sb;
+-      if (!(frame = dx_probe (dentry, 0, &hinfo, frames, err)))
++repeat:
++      if (!(frame = dx_probe (&dentry->d_name, dir, &hinfo, frames, err)))
+               return NULL;
++      
++      *lock = ext3_lock_htree(dir, frame->leaf, rwlock);
++      /* while locking leaf we just found may get splitted
++       * so, we need another leaf. check this */
++      if (!dx_check_full_path(frames, &hinfo)) {
++              ext3_unlock_htree(dir, *lock);
++              dx_release(frames);
++              goto repeat;
++      }
++
+       hash = hinfo.hash;
+       do {
+-              block = dx_get_block(frame->at);
++              block = frame->leaf;
+               if (!(bh = ext3_bread (NULL,dir, block, 0, err)))
+                       goto errout;
+               de = (struct ext3_dir_entry_2 *) bh->b_data;
+@@ -918,6 +1076,8 @@
+       *err = -ENOENT;
+ errout:
+       dxtrace(printk("%s not found\n", name));
++      ext3_unlock_htree(dir, *lock);
++      *lock = NULL;
+       dx_release (frames);
+       return NULL;
+ }
+@@ -928,6 +1088,7 @@
+       struct inode * inode;
+       struct ext3_dir_entry_2 * de;
+       struct buffer_head * bh;
++    void *lock = NULL;
+       if (dentry->d_name.len > EXT3_NAME_LEN)
+               return ERR_PTR(-ENAMETOOLONG);
+@@ -935,10 +1096,11 @@
+       if (ext3_check_for_iopen(dir, dentry))
+               return NULL;
+-      bh = ext3_find_entry(dentry, &de);
++      bh = ext3_find_entry(dentry, &de, 0, &lock);
+       inode = NULL;
+       if (bh) {
+               unsigned long ino = le32_to_cpu(de->inode);
++              ext3_unlock_htree(dir, lock);
+               brelse (bh);
+               inode = iget(dir->i_sb, ino);
+@@ -975,7 +1137,8 @@
+       unsigned rec_len = 0;
+       while (count--) {
+-              struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *) (from + map->offs);
++              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 = rec_len;
+@@ -988,7 +1151,8 @@
+ 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;
++      struct ext3_dir_entry_2 *next, *to, *prev;
++      struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *) base;
+       unsigned rec_len = 0;
+       prev = to = de;
+@@ -1010,7 +1174,8 @@
+ 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)
++                      struct dx_hash_info *hinfo, void **target,
++                      int *error)
+ {
+       unsigned blocksize = dir->i_sb->s_blocksize;
+       unsigned count, continued;
+@@ -1057,23 +1222,30 @@
+       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));
+-
++              frame->leaf, 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));
++      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? */
++      *target = NULL;
+       if (hinfo->hash >= hash2)
+       {
+               swap(*bh, bh2);
+               de = de2;
+-      }
+-      dx_insert_block (frame, hash2 + continued, newblock);
++
++              /* entry will be stored into new block
++               * we have to lock it before add_dirent_to_buf */
++              *target = ext3_lock_htree(dir, newblock, 1);
++      }
++      dx_lock_bh(frame->bh);
++      dx_insert_block (dir, frame, hash2 + continued, newblock, frame->curidx);
++      dx_unlock_bh(frame->bh);
+       err = ext3_journal_dirty_metadata (handle, bh2);
+       if (err)
+               goto journal_error;
+@@ -1147,7 +1319,8 @@
+       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);
++              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;
+@@ -1205,7 +1378,8 @@
+       unsigned        blocksize;
+       struct dx_hash_info hinfo;
+       u32             block;
+-              
++      void            *lock, *new_lock;
++
+       blocksize =  dir->i_sb->s_blocksize;
+       dxtrace(printk("Creating index\n"));
+       retval = ext3_journal_get_write_access(handle, bh);
+@@ -1216,7 +1390,6 @@
+       }
+       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);
+@@ -1224,6 +1397,8 @@
+       }
+       data1 = bh2->b_data;
++      lock = ext3_lock_htree(dir, block, 1);
++
+       /* 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 + de->rec_len);
+@@ -1253,13 +1428,25 @@
+       frame->entries = entries;
+       frame->at = entries;
+       frame->bh = bh;
++      frame->curidx = 0;
++      frame->leaf = 0;
++      frame[1].bh = NULL;
+       bh = bh2;
+-      de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
++      de = do_split(handle,dir, &bh, frame, &hinfo, &new_lock, &retval);
+       dx_release (frames);
+       if (!(de))
+-              return retval;
++              goto cleanup;
++
++      retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
++cleanup:
++      if (new_lock)
++              ext3_unlock_htree(dir, new_lock);
++      /* we mark directory indexed in order to
++       * avoid races while htree being created -bzzz */
++      EXT3_I(dir)->i_flags |= EXT3_INDEX_FL;
++      ext3_unlock_htree(dir, lock);
+-      return add_dirent_to_buf(handle, dentry, inode, de, bh);
++      return retval;
+ }
+ #endif
+@@ -1288,11 +1475,13 @@
+       unsigned blocksize;
+       unsigned nlen, rlen;
+       u32 block, blocks;
++      void *lock;
+       sb = dir->i_sb;
+       blocksize = sb->s_blocksize;
+       if (!dentry->d_name.len)
+               return -EINVAL;
++repeat:
+ #ifdef CONFIG_EXT3_INDEX
+       if (is_dx(dir)) {
+               retval = ext3_dx_add_entry(handle, dentry, inode);
+@@ -1303,36 +1492,53 @@
+               ext3_mark_inode_dirty(handle, dir);
+       }
+ #endif
++      lock = ext3_lock_htree(dir, 0, 1);
++      if (is_dx(dir)) {
++              /* we got lock for block 0
++               * probably previous holder of the lock
++               * created htree -bzzz */
++              ext3_unlock_htree(dir, lock);
++              goto repeat;
++      }
++      
+       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)
++              if(!bh) {
++                      ext3_unlock_htree(dir, lock);
+                       return retval;
++              }
+               retval = add_dirent_to_buf(handle, dentry, inode, 0, bh);
+-              if (retval != -ENOSPC)
++              if (retval != -ENOSPC) {
++                      ext3_unlock_htree(dir, lock);
+                       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);
++                  EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX)) {
++                      retval = make_indexed_dir(handle, dentry, inode, bh);
++                      ext3_unlock_htree(dir, lock);
++                      return retval;
++              }
+ #endif
+               brelse(bh);
+       }
+       bh = ext3_append(handle, dir, &block, &retval);
+-      if (!bh)
++      if (!bh) {
++              ext3_unlock_htree(dir, lock);
+               return retval;
++      }
+       de = (struct ext3_dir_entry_2 *) bh->b_data;
+       de->inode = 0;
+       de->rec_len = cpu_to_le16(rlen = blocksize);
+       nlen = 0;
+-      return add_dirent_to_buf(handle, dentry, inode, de, bh);
++      retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
++      ext3_unlock_htree(dir, lock);
++      return retval;
+ }
+ #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)
+ {
+@@ -1344,15 +1550,28 @@
+       struct super_block * sb = dir->i_sb;
+       struct ext3_dir_entry_2 *de;
+       int err;
+-
+-      frame = dx_probe(dentry, 0, &hinfo, frames, &err);
++      int curidx;
++      void *idx_lock, *leaf_lock, *newleaf_lock;
++      
++repeat:
++      frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err);
+       if (!frame)
+               return err;
+-      entries = frame->entries;
+-      at = frame->at;
+-      if (!(bh = ext3_bread(handle,dir, dx_get_block(frame->at), 0, &err)))
++      /* we're going to chage leaf, so lock it first */
++      leaf_lock = ext3_lock_htree(dir, frame->leaf, 1);
++
++      /* while locking leaf we just found may get splitted
++       * so we need to check this */
++      if (!dx_check_full_path(frames, &hinfo)) {
++              ext3_unlock_htree(dir, leaf_lock);
++              dx_release(frames);
++              goto repeat;
++      }
++      if (!(bh = ext3_bread(handle,dir, frame->leaf, 0, &err))) {
++              printk("can't ext3_bread(%d) = %d\n", (int) frame->leaf, err);
+               goto cleanup;
++      }
+       BUFFER_TRACE(bh, "get_write_access");
+       err = ext3_journal_get_write_access(handle, bh);
+@@ -1365,6 +1584,35 @@
+               goto cleanup;
+       }
++      /* our leaf has no enough space. hence, we have to
++       * split it. so lock index for this leaf first */
++      curidx = frame->curidx;
++      idx_lock = ext3_lock_htree(dir, curidx, 1);
++
++      /* now check did path get changed? */
++      dx_release(frames);
++
++      frame = dx_probe(&dentry->d_name, dentry->d_parent->d_inode,
++                      &hinfo, frames, &err);
++      if (!frame) {
++              /* FIXME: error handling here */
++              brelse(bh);
++              ext3_unlock_htree(dir, idx_lock);
++              return err;
++      }
++      
++      if (frame->curidx != curidx) {
++              /* path has been changed. we have to drop old lock
++               * and repeat */
++              brelse(bh);
++              ext3_unlock_htree(dir, idx_lock);
++              ext3_unlock_htree(dir, leaf_lock);
++              dx_release(frames);
++              goto repeat;
++      }
++      entries = frame->entries;
++      at = frame->at;
++
+       /* 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)));
+@@ -1376,7 +1624,8 @@
+               struct dx_entry *entries2;
+               struct dx_node *node2;
+               struct buffer_head *bh2;
+-
++              void *nb_lock;
++              
+               if (levels && (dx_get_count(frames->entries) ==
+                              dx_get_limit(frames->entries))) {
+                       ext3_warning(sb, __FUNCTION__,
+@@ -1387,6 +1636,7 @@
+               bh2 = ext3_append (handle, dir, &newblock, &err);
+               if (!(bh2))
+                       goto cleanup;
++              nb_lock = ext3_lock_htree(dir, newblock, 1);
+               node2 = (struct dx_node *)(bh2->b_data);
+               entries2 = node2->entries;
+               node2->fake.rec_len = cpu_to_le16(sb->s_blocksize);
+@@ -1398,27 +1648,73 @@
+               if (levels) {
+                       unsigned icount1 = icount/2, icount2 = icount - icount1;
+                       unsigned hash2 = dx_get_hash(entries + icount1);
++                      void *ri_lock;
++
++                      /* we have to protect root htree index against
++                       * another dx_add_entry() which would want to
++                       * split it too -bzzz */
++                      ri_lock = ext3_lock_htree(dir, 0, 1);
++
++                      /* as root index block blocked we must repeat
++                       * searching for current position of our 2nd index -bzzz */
++                      dx_lock_bh(frame->bh);
++                      frames->at = dx_find_position(frames->entries, hinfo.hash);
++                      dx_unlock_bh(frame->bh);
++                      
+                       dxtrace(printk("Split index %i/%i\n", icount1, icount2));
+-                              
+-                      BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */
++      
++                      BUFFER_TRACE(frame->bh, "get_write_access");
+                       err = ext3_journal_get_write_access(handle,
+                                                            frames[0].bh);
+                       if (err)
+                               goto journal_error;
+-                              
++                      
++                      /* copy index into new one */
+                       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) {
++                              /* unlock index we won't use */
++                              ext3_unlock_htree(dir, idx_lock);
++                              idx_lock = nb_lock;
+                               frame->at = at = at - entries - icount1 + entries2;
+-                              frame->entries = entries = entries2;
++                              frame->entries = entries2;
++                              frame->curidx = curidx = newblock;
+                               swap(frame->bh, bh2);
++                      } else {
++                              /* we'll use old index,so new one may be freed */
++                              ext3_unlock_htree(dir, nb_lock);
+                       }
+-                      dx_insert_block (frames + 0, hash2, newblock);
++              
++                      /* NOTE: very subtle piece of code
++                       * competing dx_probe() may find 2nd level index in root
++                       * index, then we insert new index here and set new count
++                       * in that 2nd level index. so, dx_probe() may see 2nd
++                       * level index w/o hash it looks for. the solution is
++                       * to check root index after we locked just founded 2nd
++                       * level index -bzzz */
++                      dx_lock_bh(frames[0].bh);
++                      dx_insert_block (dir, frames + 0, hash2, newblock, 0);
++                      dx_unlock_bh(frames[0].bh);
++                      
++                      /* now old and new 2nd level index blocks contain
++                       * all pointers, so dx_probe() may find it in the both.
++                       * it's OK -bzzz */
++                      
++                      dx_lock_bh(frame->bh);
++                      dx_set_count(entries, icount1);
++                      dx_unlock_bh(frame->bh);
++
++                      /* now old 2nd level index block points to first half
++                       * of leafs. it's importand that dx_probe() must
++                       * check root index block for changes under
++                       * dx_lock_bh(frame->bh) -bzzz */
++
++                      ext3_unlock_htree(dir, ri_lock);
++              
+                       dxtrace(dx_show_index ("node", frames[1].entries));
+                       dxtrace(dx_show_index ("node",
+                              ((struct dx_node *) bh2->b_data)->entries));
+@@ -1427,38 +1723,61 @@
+                               goto journal_error;
+                       brelse (bh2);
+               } else {
++                      unsigned long leaf = frame->leaf;
++
+                       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_lock_bh(frames[0].bh);
+                       dx_set_count(entries, 1);
+                       dx_set_block(entries + 0, newblock);
+                       ((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1;
++                      dx_unlock_bh(frames[0].bh);
+                       /* Add new access path frame */
+                       frame = frames + 1;
+                       frame->at = at = at - entries + entries2;
+                       frame->entries = entries = entries2;
+                       frame->bh = bh2;
++                      frame->curidx = newblock;
++                      frame->leaf = leaf;
+                       err = ext3_journal_get_write_access(handle,
+                                                            frame->bh);
+                       if (err)
+                               goto journal_error;
++
++                      /* first level index was root. it's already initialized */
++                      /* we my unlock it now */
++                      ext3_unlock_htree(dir, idx_lock);
++
++                      /* current index is just created 2nd level index */
++                      curidx = newblock;
++                      idx_lock = nb_lock;
+               }
+               ext3_journal_dirty_metadata(handle, frames[0].bh);
+       }
+-      de = do_split(handle, dir, &bh, frame, &hinfo, &err);
++      de = do_split(handle, dir, &bh, frame, &hinfo, &newleaf_lock, &err);
+       if (!de)
+               goto cleanup;
++
++      /* index splitted */
++      ext3_unlock_htree(dir, idx_lock);
++      
+       err = add_dirent_to_buf(handle, dentry, inode, de, bh);
++
++      if (newleaf_lock)
++              ext3_unlock_htree(dir, newleaf_lock);
++      
+       bh = 0;
+       goto cleanup;
+       
+ journal_error:
+       ext3_std_error(dir->i_sb, err);
+ cleanup:
++      ext3_unlock_htree(dir, leaf_lock);
+       if (bh)
+               brelse(bh);
+       dx_release(frames);
+@@ -1902,6 +2221,7 @@
+       struct buffer_head * bh;
+       struct ext3_dir_entry_2 * de;
+       handle_t *handle;
++      void *lock;
+       handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
+       if (IS_ERR(handle)) {
+@@ -1909,7 +2229,7 @@
+       }
+       retval = -ENOENT;
+-      bh = ext3_find_entry (dentry, &de);
++      bh = ext3_find_entry (dentry, &de, 1, &lock);
+       if (!bh)
+               goto end_rmdir;
+@@ -1920,14 +2240,19 @@
+       DQUOT_INIT(inode);
+       retval = -EIO;
+-      if (le32_to_cpu(de->inode) != inode->i_ino)
++      if (le32_to_cpu(de->inode) != inode->i_ino) {
++              ext3_unlock_htree(dir, lock);
+               goto end_rmdir;
++      }
+       retval = -ENOTEMPTY;
+-      if (!empty_dir (inode))
++      if (!empty_dir (inode)) {
++              ext3_unlock_htree(dir, lock);
+               goto end_rmdir;
++      }
+       retval = ext3_delete_entry(handle, dir, de, bh);
++      ext3_unlock_htree(dir, lock);
+       if (retval)
+               goto end_rmdir;
+       if (inode->i_nlink != 2)
+@@ -1956,6 +2281,7 @@
+       struct buffer_head * bh;
+       struct ext3_dir_entry_2 * de;
+       handle_t *handle;
++      void *lock;
+       handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
+       if (IS_ERR(handle)) {
+@@ -1966,7 +2292,7 @@
+               handle->h_sync = 1;
+       retval = -ENOENT;
+-      bh = ext3_find_entry (dentry, &de);
++      bh = ext3_find_entry (dentry, &de, 1, &lock);
+       if (!bh)
+               goto end_unlink;
+@@ -1974,8 +2300,10 @@
+       DQUOT_INIT(inode);
+       retval = -EIO;
+-      if (le32_to_cpu(de->inode) != inode->i_ino)
++      if (le32_to_cpu(de->inode) != inode->i_ino) {
++              ext3_unlock_htree(dir, lock);
+               goto end_unlink;
++      }
+       
+       if (!inode->i_nlink) {
+               ext3_warning (inode->i_sb, "ext3_unlink",
+@@ -1984,6 +2312,7 @@
+               inode->i_nlink = 1;
+       }
+       retval = ext3_delete_entry(handle, dir, de, bh);
++      ext3_unlock_htree(dir, lock);
+       if (retval)
+               goto end_unlink;
+       dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+@@ -2121,6 +2450,7 @@
+       struct buffer_head * old_bh, * new_bh, * dir_bh;
+       struct ext3_dir_entry_2 * old_de, * new_de;
+       int retval;
++      void *lock1 = NULL, *lock2 = NULL, *lock3 = NULL;
+       old_bh = new_bh = dir_bh = NULL;
+@@ -2133,7 +2463,10 @@
+       if (IS_SYNC(old_dir) || IS_SYNC(new_dir))
+               handle->h_sync = 1;
+-      old_bh = ext3_find_entry (old_dentry, &old_de);
++      if (old_dentry->d_parent == new_dentry->d_parent)
++              down(&EXT3_I(old_dentry->d_parent->d_inode)->i_rename_sem);
++
++      old_bh = ext3_find_entry (old_dentry, &old_de, 1, &lock1 /* FIXME */);
+       /*
+        *  Check for inode number is _not_ due to possible IO errors.
+        *  We might rmdir the source, keep it as pwd of some process
+@@ -2146,7 +2479,7 @@
+               goto end_rename;
+       new_inode = new_dentry->d_inode;
+-      new_bh = ext3_find_entry (new_dentry, &new_de);
++      new_bh = ext3_find_entry (new_dentry, &new_de, 1, &lock2 /* FIXME */);
+       if (new_bh) {
+               if (!new_inode) {
+                       brelse (new_bh);
+@@ -2209,7 +2542,7 @@
+               struct buffer_head *old_bh2;
+               struct ext3_dir_entry_2 *old_de2;
+               
+-              old_bh2 = ext3_find_entry(old_dentry, &old_de2);
++              old_bh2 = ext3_find_entry(old_dentry, &old_de2, 1, &lock3 /* FIXME */);
+               if (old_bh2) {
+                       retval = ext3_delete_entry(handle, old_dir,
+                                                  old_de2, old_bh2);
+@@ -2252,6 +2585,14 @@
+       retval = 0;
+ end_rename:
++      if (lock1)
++              ext3_unlock_htree(old_dentry->d_parent->d_inode, lock1);
++      if (lock2)
++              ext3_unlock_htree(new_dentry->d_parent->d_inode, lock2);
++      if (lock3)
++              ext3_unlock_htree(old_dentry->d_parent->d_inode, lock3);
++      if (old_dentry->d_parent == new_dentry->d_parent)
++              up(&EXT3_I(old_dentry->d_parent->d_inode)->i_rename_sem);
+       brelse (dir_bh);
+       brelse (old_bh);
+       brelse (new_bh);
+@@ -2260,6 +2601,29 @@
+ }
+ /*
++ * this locking primitives are used to protect parts
++ * of dir's htree. protection unit is block: leaf or index
++ */
++static inline void *ext3_lock_htree(struct inode *dir,
++                                      unsigned long value, int rwlock)
++{
++      void *lock;
++      
++      if (!test_opt(dir->i_sb, PDIROPS))
++              return NULL;
++      lock = dynlock_lock(&EXT3_I(dir)->i_htree_lock, value, 1, GFP_KERNEL);
++      return lock;
++}
++
++static inline void ext3_unlock_htree(struct inode *dir,
++                                      void *lock)
++{
++      if (!test_opt(dir->i_sb, PDIROPS) || !lock)
++              return;
++      dynlock_unlock(&EXT3_I(dir)->i_htree_lock, lock);
++}
++
++/*
+  * directories can handle most operations...
+  */
+ struct inode_operations ext3_dir_inode_operations = {
+Index: linux-2.4.20/fs/ext3/super.c
+===================================================================
+--- linux-2.4.20.orig/fs/ext3/super.c  Wed Mar 17 15:37:09 2004
++++ linux-2.4.20/fs/ext3/super.c       Wed Mar 17 15:37:10 2004
+@@ -796,6 +796,8 @@
+                               return 0;
+                       }
+               }
++              else if (!strcmp (this_char, "pdirops"))
++                      set_opt (sbi->s_mount_opt, PDIROPS);
+               else if (!strcmp (this_char, "grpid") ||
+                        !strcmp (this_char, "bsdgroups"))
+                       set_opt (*mount_options, GRPID);
+@@ -822,6 +824,9 @@
+                       if (want_numeric(value, "sb", sb_block))
+                               return 0;
+               }
++              else if (!strcmp (this_char, "pdirops")) {
++                      set_opt (sbi->s_mount_opt, PDIROPS);
++              }
+ #ifdef CONFIG_JBD_DEBUG
+               else if (!strcmp (this_char, "ro-after")) {
+                       unsigned long v;
+@@ -985,6 +990,10 @@
+               ext3_check_inodes_bitmap (sb);
+       }
+ #endif
++#ifdef S_PDIROPS
++      if (test_opt (sb, PDIROPS))
++              sb->s_flags |= S_PDIROPS;
++#endif
+       setup_ro_after(sb);
+       return res;
+ }
+@@ -1484,6 +1493,11 @@
+               test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered":
+               "writeback");
++      if (test_opt(sb, PDIROPS)) {
++              printk (KERN_INFO "EXT3-fs: mounted filesystem with parallel dirops\n");
++              sb->s_flags |= S_PDIROPS;
++      }
++              
+       return sb;
+ failed_mount3:
+Index: linux-2.4.20/fs/ext3/inode.c
+===================================================================
+--- linux-2.4.20.orig/fs/ext3/inode.c  Wed Mar 17 15:37:09 2004
++++ linux-2.4.20/fs/ext3/inode.c       Wed Mar 17 15:37:10 2004
+@@ -2435,6 +2435,9 @@
+       } else if (S_ISDIR(inode->i_mode)) {
+               inode->i_op = &ext3_dir_inode_operations;
+               inode->i_fop = &ext3_dir_operations;
++              dynlock_init(&EXT3_I(inode)->i_htree_lock);
++              sema_init(&EXT3_I(inode)->i_rename_sem, 1);
++              sema_init(&EXT3_I(inode)->i_append_sem, 1);
+       } else if (S_ISLNK(inode->i_mode)) {
+               if (ext3_inode_is_fast_symlink(inode))
+                       inode->i_op = &ext3_fast_symlink_inode_operations;
+Index: linux-2.4.20/fs/ext3/ialloc.c
+===================================================================
+--- linux-2.4.20.orig/fs/ext3/ialloc.c Wed Mar 17 15:37:09 2004
++++ linux-2.4.20/fs/ext3/ialloc.c      Wed Mar 17 15:37:10 2004
+@@ -601,6 +601,9 @@
+               return ERR_PTR(-EDQUOT);
+       }
+       ext3_debug ("allocating inode %lu\n", inode->i_ino);
++      dynlock_init(&EXT3_I(inode)->i_htree_lock);
++      sema_init(&EXT3_I(inode)->i_rename_sem, 1);
++      sema_init(&EXT3_I(inode)->i_append_sem, 1);
+       return inode;
+ fail:
+Index: linux-2.4.20/include/linux/ext3_fs.h
+===================================================================
+--- linux-2.4.20.orig/include/linux/ext3_fs.h  Wed Mar 17 15:37:09 2004
++++ linux-2.4.20/include/linux/ext3_fs.h       Wed Mar 17 15:37:10 2004
+@@ -306,6 +306,7 @@
+ /*
+  * Mount flags
+  */
++#define EXT3_MOUNT_PDIROPS            0x800000/* Parallel dir operations */
+ #define EXT3_MOUNT_CHECK              0x0001  /* Do mount-time checks */
+ #define EXT3_MOUNT_GRPID              0x0004  /* Create files with directory's group */
+ #define EXT3_MOUNT_DEBUG              0x0008  /* Some debugging messages */
+Index: linux-2.4.20/include/linux/ext3_fs_i.h
+===================================================================
+--- linux-2.4.20.orig/include/linux/ext3_fs_i.h        Thu Nov 22 11:46:19 2001
++++ linux-2.4.20/include/linux/ext3_fs_i.h     Wed Mar 17 15:37:10 2004
+@@ -17,6 +17,7 @@
+ #define _LINUX_EXT3_FS_I
+ #include <linux/rwsem.h>
++#include <linux/dynlocks.h>
+ /*
+  * second extended file system inode data in memory
+@@ -73,6 +74,11 @@
+        * by other means, so we have truncate_sem.
+        */
+       struct rw_semaphore truncate_sem;
++
++      /* following fields for parallel directory operations -bzzz */
++      struct dynlock i_htree_lock;
++      struct semaphore i_append_sem;
++      struct semaphore i_rename_sem;
+ };
+ #endif        /* _LINUX_EXT3_FS_I */
diff --git a/lustre/kernel_patches/patches/inode-max-readahead-2.4.24.patch b/lustre/kernel_patches/patches/inode-max-readahead-2.4.24.patch
new file mode 100644 (file)
index 0000000..9203859
--- /dev/null
@@ -0,0 +1,22 @@
+--- linux-2.4.24-l32/mm/filemap.c.inode_ramax  2004-03-14 13:16:21.000000000 -0800
++++ linux-2.4.24-l32/mm/filemap.c      2004-03-16 10:57:14.000000000 -0800
+@@ -1226,6 +1226,8 @@
+ static inline int get_max_readahead(struct inode * inode)
+ {
++      if (inode->i_mapping->a_ops->max_readahead)
++              return inode->i_mapping->a_ops->max_readahead(inode);
+       if (!inode->i_dev || !max_readahead[MAJOR(inode->i_dev)])
+               return vm_max_readahead;
+       return max_readahead[MAJOR(inode->i_dev)][MINOR(inode->i_dev)];
+--- linux-2.4.24-l32/include/linux/fs.h.inode_ramax    2004-03-14 13:15:49.000000000 -0800
++++ linux-2.4.24-l32/include/linux/fs.h        2004-03-15 11:56:56.000000000 -0800
+@@ -410,6 +410,8 @@
+ #define KERNEL_HAS_DIRECT_FILEIO /* Unfortunate kludge due to lack of foresight */
+       int (*direct_fileIO)(int, struct file *, struct kiobuf *, unsigned long, int);
+       void (*removepage)(struct page *); /* called when page gets removed from the inode */
++#define KERNEL_HAS_AS_MAX_READAHEAD
++      int (*max_readahead)(struct inode *);
+ };
+ struct address_space {
index 8800e1f..f409533 100644 (file)
@@ -8,10 +8,10 @@
  include/linux/ext3_fs.h            |    2 
  8 files changed, 318 insertions(+), 2 deletions(-)
 
-Index: linux-2.4.22-uml/Documentation/filesystems/ext2.txt
+Index: lum/Documentation/filesystems/ext2.txt
 ===================================================================
---- linux-2.4.22-uml.orig/Documentation/filesystems/ext2.txt   2001-07-11 16:44:45.000000000 -0600
-+++ linux-2.4.22-uml/Documentation/filesystems/ext2.txt        2004-01-30 14:18:10.000000000 -0700
+--- lum.orig/Documentation/filesystems/ext2.txt        2001-07-11 16:44:45.000000000 -0600
++++ lum/Documentation/filesystems/ext2.txt     2004-03-09 16:46:38.000000000 -0700
 @@ -35,6 +35,22 @@
  
  sb=n                          Use alternate superblock at this location.
@@ -35,10 +35,10 @@ Index: linux-2.4.22-uml/Documentation/filesystems/ext2.txt
  grpquota,noquota,quota,usrquota       Quota options are silently ignored by ext2.
  
  
-Index: linux-2.4.22-uml/fs/ext3/Makefile
+Index: lum/fs/ext3/Makefile
 ===================================================================
---- linux-2.4.22-uml.orig/fs/ext3/Makefile     2004-01-30 14:17:58.000000000 -0700
-+++ linux-2.4.22-uml/fs/ext3/Makefile  2004-01-30 14:18:10.000000000 -0700
+--- lum.orig/fs/ext3/Makefile  2004-01-30 14:54:50.000000000 -0700
++++ lum/fs/ext3/Makefile       2004-03-09 16:46:39.000000000 -0700
 @@ -11,7 +11,7 @@
  
  export-objs := ext3-exports.o
@@ -48,10 +48,10 @@ Index: linux-2.4.22-uml/fs/ext3/Makefile
                ioctl.o namei.o super.o symlink.o hash.o ext3-exports.o
  obj-m    := $(O_TARGET)
  
-Index: linux-2.4.22-uml/fs/ext3/inode.c
+Index: lum/fs/ext3/inode.c
 ===================================================================
---- linux-2.4.22-uml.orig/fs/ext3/inode.c      2004-01-30 14:17:59.000000000 -0700
-+++ linux-2.4.22-uml/fs/ext3/inode.c   2004-01-30 14:18:10.000000000 -0700
+--- lum.orig/fs/ext3/inode.c   2004-01-30 14:54:55.000000000 -0700
++++ lum/fs/ext3/inode.c        2004-03-09 16:46:41.000000000 -0700
 @@ -31,6 +31,7 @@
  #include <linux/highuid.h>
  #include <linux/quotaops.h>
@@ -70,11 +70,11 @@ Index: linux-2.4.22-uml/fs/ext3/inode.c
        if(ext3_get_inode_loc(inode, &iloc))
                goto bad_inode;
        bh = iloc.bh;
-Index: linux-2.4.22-uml/fs/ext3/iopen.c
+Index: lum/fs/ext3/iopen.c
 ===================================================================
---- linux-2.4.22-uml.orig/fs/ext3/iopen.c      2004-01-30 14:18:10.000000000 -0700
-+++ linux-2.4.22-uml/fs/ext3/iopen.c   2004-01-30 14:18:10.000000000 -0700
-@@ -0,0 +1,258 @@
+--- lum.orig/fs/ext3/iopen.c   2004-03-09 16:46:37.000000000 -0700
++++ lum/fs/ext3/iopen.c        2004-03-09 16:48:03.000000000 -0700
+@@ -0,0 +1,282 @@
 +/*
 + * linux/fs/ext3/iopen.c
 + *
@@ -211,13 +211,24 @@ Index: linux-2.4.22-uml/fs/ext3/iopen.c
 +
 +/* This function is spliced into ext3_lookup and does the move of a
 + * disconnected dentry (if it exists) to a connected dentry.
-+ * Caller must hold dcache_lock.
 + */
-+struct dentry *iopen_connect_dentry(struct dentry *de, struct inode *inode)
++struct dentry *iopen_connect_dentry(struct dentry *dentry, struct inode *inode,
++                                  int rehash)
 +{
 +      struct dentry *tmp, *goal = NULL;
 +      struct list_head *lp;
 +
++      /* verify this dentry is really new */
++      assert(dentry->d_inode == NULL);
++      assert(list_empty(&dentry->d_alias));           /* d_instantiate */
++      if (rehash)
++              assert(list_empty(&dentry->d_hash));    /* d_rehash */
++      assert(list_empty(&dentry->d_subdirs));
++
++      spin_lock(&dcache_lock);
++      if (!inode)
++              goto do_rehash;
++
 +      /* preferrably return a connected dentry */
 +      list_for_each(lp, &inode->i_dentry) {
 +              tmp = list_entry(lp, struct dentry, d_alias);
@@ -231,27 +242,40 @@ Index: linux-2.4.22-uml/fs/ext3/iopen.c
 +      }
 +
 +      if (!goal)
-+              return NULL;
++              goto do_instantiate;
 +
 +      /* Move the goal to the de hash queue - like d_move() */
 +      goal->d_flags &= ~DCACHE_NFSD_DISCONNECTED;
 +      list_del_init(&goal->d_hash);
 +
 +      list_del(&goal->d_child);
-+      list_del(&de->d_child);
++      list_del(&dentry->d_child);
 +
 +      /* Switch the parents and the names.. */
-+      switch_names(goal, de);
-+      do_switch(goal->d_parent, de->d_parent);
-+      do_switch(goal->d_name.len, de->d_name.len);
-+      do_switch(goal->d_name.hash, de->d_name.hash);
++      switch_names(goal, dentry);
++      do_switch(goal->d_parent, dentry->d_parent);
++      do_switch(goal->d_name.len, dentry->d_name.len);
++      do_switch(goal->d_name.hash, dentry->d_name.hash);
 +
 +      /* And add them back to the (new) parent lists */
 +      list_add(&goal->d_child, &goal->d_parent->d_subdirs);
-+      list_add(&de->d_child, &de->d_parent->d_subdirs);
++      list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
 +      __d_rehash(goal, 0);
++      spin_unlock(&dcache_lock);
++      iput(inode);
 +
 +      return goal;
++
++      /* d_add(), but don't drop dcache_lock before adding dentry to inode */
++do_instantiate:
++      list_add(&dentry->d_alias, &inode->i_dentry);   /* d_instantiate */
++      dentry->d_inode = inode;
++do_rehash:
++      if (rehash)
++              __d_rehash(dentry, 0);                  /* d_rehash */
++      spin_unlock(&dcache_lock);
++
++      return NULL;
 +}
 +
 +/*
@@ -333,10 +357,10 @@ Index: linux-2.4.22-uml/fs/ext3/iopen.c
 +
 +      return 1;
 +}
-Index: linux-2.4.22-uml/fs/ext3/iopen.h
+Index: lum/fs/ext3/iopen.h
 ===================================================================
---- linux-2.4.22-uml.orig/fs/ext3/iopen.h      2004-01-30 14:18:10.000000000 -0700
-+++ linux-2.4.22-uml/fs/ext3/iopen.h   2004-01-30 14:18:10.000000000 -0700
+--- lum.orig/fs/ext3/iopen.h   2004-03-09 16:46:37.000000000 -0700
++++ lum/fs/ext3/iopen.h        2004-03-09 16:48:03.000000000 -0700
 @@ -0,0 +1,15 @@
 +/*
 + * iopen.h
@@ -351,12 +375,12 @@ Index: linux-2.4.22-uml/fs/ext3/iopen.h
 +
 +extern int ext3_check_for_iopen(struct inode *dir, struct dentry *dentry);
 +extern int ext3_iopen_get_inode(struct inode *inode);
-+extern struct dentry *iopen_connect_dentry(struct dentry *de,
-+                                         struct inode *inode);
-Index: linux-2.4.22-uml/fs/ext3/namei.c
++extern struct dentry *iopen_connect_dentry(struct dentry *dentry,
++                                         struct inode *inode, int rehash);
+Index: lum/fs/ext3/namei.c
 ===================================================================
---- linux-2.4.22-uml.orig/fs/ext3/namei.c      2004-01-30 14:17:59.000000000 -0700
-+++ linux-2.4.22-uml/fs/ext3/namei.c   2004-01-30 14:19:44.000000000 -0700
+--- lum.orig/fs/ext3/namei.c   2004-01-30 14:54:53.000000000 -0700
++++ lum/fs/ext3/namei.c        2004-03-09 16:49:25.000000000 -0700
 @@ -35,7 +35,7 @@
  #include <linux/string.h>
  #include <linux/locks.h>
@@ -366,12 +390,7 @@ Index: linux-2.4.22-uml/fs/ext3/namei.c
  
  /*
   * define how far ahead to read directories while searching them.
-@@ -927,10 +927,14 @@
-       struct inode * inode;
-       struct ext3_dir_entry_2 * de;
-       struct buffer_head * bh;
-+      struct dentry *alternate = NULL;
+@@ -931,6 +931,9 @@
        if (dentry->d_name.len > EXT3_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
  
@@ -381,41 +400,67 @@ Index: linux-2.4.22-uml/fs/ext3/namei.c
        bh = ext3_find_entry(dentry, &de);
        inode = NULL;
        if (bh) {
-@@ -942,7 +946,28 @@
+@@ -942,8 +945,8 @@
                        return ERR_PTR(-EACCES);
                }
        }
 -      d_add(dentry, inode);
+-      return NULL;
 +
-+      /* verify this dentry is really new */
-+      assert(!dentry->d_inode);
-+      assert(list_empty(&dentry->d_alias));           /* d_instantiate */
-+      assert(list_empty(&dentry->d_hash));            /* d_rehash */
-+      assert(list_empty(&dentry->d_subdirs));
-+
-+      spin_lock(&dcache_lock);
-+      if (inode && (alternate = iopen_connect_dentry(dentry, inode))) {
-+              spin_unlock(&dcache_lock);
-+              iput(inode);
-+              return alternate;
++      return iopen_connect_dentry(dentry, inode, 1);
+ }
+ #define S_SHIFT 12
+@@ -1932,10 +1935,6 @@
+                             inode->i_nlink);
+       inode->i_version = ++event;
+       inode->i_nlink = 0;
+-      /* There's no need to set i_disksize: the fact that i_nlink is
+-       * zero will ensure that the right thing happens during any
+-       * recovery. */
+-      inode->i_size = 0;
+       ext3_orphan_add(handle, inode);
+       dir->i_nlink--;
+       inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+@@ -2086,6 +2085,23 @@
+       return err;
+ }
++/* Like ext3_add_nondir() except for call to iopen_connect_dentry */
++static int ext3_add_link(handle_t *handle, struct dentry *dentry,
++                       struct inode *inode)
++{
++      int err = ext3_add_entry(handle, dentry, inode);
++      if (!err) {
++              err = ext3_mark_inode_dirty(handle, inode);
++              if (err == 0) {
++                      (void)iopen_connect_dentry(dentry, inode, 0);
++                      return 0;
++              }
 +      }
++      ext3_dec_count(handle, inode);
++      iput(inode);
++      return err;
++}
 +
-+      /* d_add(), but don't drop dcache_lock before adding dentry to inode */
-+      if (inode)                                      /* d_instantiate */
-+              list_add(&dentry->d_alias, &inode->i_dentry);
-+      dentry->d_inode = inode;
-+
-+      __d_rehash(dentry, 0);                          /* d_rehash */
-+      spin_unlock(&dcache_lock);
-+
-       return NULL;
- }
+ static int ext3_link (struct dentry * old_dentry,
+               struct inode * dir, struct dentry *dentry)
+ {
+@@ -2113,7 +2129,8 @@
+       ext3_inc_count(handle, inode);
+       atomic_inc(&inode->i_count);
  
-Index: linux-2.4.22-uml/fs/ext3/super.c
+-      err = ext3_add_nondir(handle, dentry, inode);
++      err = ext3_add_link(handle, dentry, inode);
++      ext3_orphan_del(handle, inode);
+       ext3_journal_stop(handle, dir);
+       return err;
+ }
+Index: lum/fs/ext3/super.c
 ===================================================================
---- linux-2.4.22-uml.orig/fs/ext3/super.c      Sun Nov 16 01:19:22 2003
-+++ linux-2.4.22-uml/fs/ext3/super.c   Sun Nov 16 01:27:31 2003
-@@ -839,6 +839,18 @@
+--- lum.orig/fs/ext3/super.c   2004-01-30 14:54:53.000000000 -0700
++++ lum/fs/ext3/super.c        2004-03-09 16:46:45.000000000 -0700
+@@ -742,6 +742,18 @@
                         || !strcmp (this_char, "quota")
                         || !strcmp (this_char, "usrquota"))
                        /* Don't do anything ;-) */ ;
@@ -434,10 +479,10 @@ Index: linux-2.4.22-uml/fs/ext3/super.c
                else if (!strcmp (this_char, "journal")) {
                        /* @@@ FIXME */
                        /* Eventually we will want to be able to create
-Index: linux-2.4.22-uml/include/linux/ext3_fs.h
+Index: lum/include/linux/ext3_fs.h
 ===================================================================
---- linux-2.4.22-uml.orig/include/linux/ext3_fs.h      2004-01-30 14:17:59.000000000 -0700
-+++ linux-2.4.22-uml/include/linux/ext3_fs.h   2004-01-30 14:18:10.000000000 -0700
+--- lum.orig/include/linux/ext3_fs.h   2004-01-30 14:54:53.000000000 -0700
++++ lum/include/linux/ext3_fs.h        2004-03-09 16:46:46.000000000 -0700
 @@ -322,6 +322,8 @@
  #define EXT3_MOUNT_UPDATE_JOURNAL     0x1000  /* Update the journal format */
  #define EXT3_MOUNT_NO_UID32           0x2000  /* Disable 32-bit UIDs */
index 16bde95..62bd8e1 100644 (file)
@@ -8,11 +8,11 @@
  include/linux/ext3_fs.h            |    2 
  8 files changed, 318 insertions(+), 2 deletions(-)
 
-Index: linux-2.4.21-chaos/Documentation/filesystems/ext2.txt
+Index: linux-ia64/Documentation/filesystems/ext2.txt
 ===================================================================
---- linux-2.4.21-chaos.orig/Documentation/filesystems/ext2.txt 2002-05-08 01:53:59.000000000 +0400
-+++ linux-2.4.21-chaos/Documentation/filesystems/ext2.txt      2003-12-12 16:19:04.000000000 +0300
-@@ -35,6 +35,22 @@
+--- linux-ia64.orig/Documentation/filesystems/ext2.txt 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/Documentation/filesystems/ext2.txt      2004-03-17 18:03:15.000000000 -0800
+@@ -35,6 +35,22 @@ resgid=n                    The group ID which may use th
  
  sb=n                          Use alternate superblock at this location.
  
@@ -35,11 +35,11 @@ Index: linux-2.4.21-chaos/Documentation/filesystems/ext2.txt
  grpquota,noquota,quota,usrquota       Quota options are silently ignored by ext2.
  
  
-Index: linux-2.4.21-chaos/fs/ext3/Makefile
+Index: linux-ia64/fs/ext3/Makefile
 ===================================================================
---- linux-2.4.21-chaos.orig/fs/ext3/Makefile   2003-12-12 16:18:36.000000000 +0300
-+++ linux-2.4.21-chaos/fs/ext3/Makefile        2003-12-12 16:19:04.000000000 +0300
-@@ -11,7 +11,7 @@
+--- linux-ia64.orig/fs/ext3/Makefile   2004-03-17 18:03:14.000000000 -0800
++++ linux-ia64/fs/ext3/Makefile        2004-03-17 18:03:15.000000000 -0800
+@@ -11,7 +11,7 @@ O_TARGET := ext3.o
  
  export-objs := ext3-exports.o
  
@@ -48,10 +48,10 @@ Index: linux-2.4.21-chaos/fs/ext3/Makefile
                ioctl.o namei.o super.o symlink.o hash.o ext3-exports.o
  obj-m    := $(O_TARGET)
  
-Index: linux-2.4.21-chaos/fs/ext3/inode.c
+Index: linux-ia64/fs/ext3/inode.c
 ===================================================================
---- linux-2.4.21-chaos.orig/fs/ext3/inode.c    2003-12-12 16:19:02.000000000 +0300
-+++ linux-2.4.21-chaos/fs/ext3/inode.c 2003-12-12 16:19:05.000000000 +0300
+--- linux-ia64.orig/fs/ext3/inode.c    2004-03-17 18:03:15.000000000 -0800
++++ linux-ia64/fs/ext3/inode.c 2004-03-17 18:10:36.000000000 -0800
 @@ -34,6 +34,7 @@
  #include <linux/highuid.h>
  #include <linux/quotaops.h>
@@ -60,7 +60,7 @@ Index: linux-2.4.21-chaos/fs/ext3/inode.c
  
  /*
   * SEARCH_FROM_ZERO forces each block allocation to search from the start
-@@ -2430,6 +2431,9 @@
+@@ -2430,6 +2431,9 @@ void ext3_read_inode(struct inode * inod
        struct buffer_head *bh;
        int block;
        
@@ -70,21 +70,14 @@ Index: linux-2.4.21-chaos/fs/ext3/inode.c
        if(ext3_get_inode_loc(inode, &iloc))
                goto bad_inode;
        bh = iloc.bh;
-Index: linux-2.4.21-chaos/fs/ext3/iopen.c
+Index: linux-ia64/fs/ext3/iopen.c
 ===================================================================
---- linux-2.4.21-chaos.orig/fs/ext3/iopen.c    2003-01-30 13:24:37.000000000 +0300
-+++ linux-2.4.21-chaos/fs/ext3/iopen.c 2003-12-12 16:19:05.000000000 +0300
-@@ -0,0 +1,258 @@
-+/*
-+ * linux/fs/ext3/iopen.c
-+ *
-+ * Special support for open by inode number
-+ *
-+ * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu).
-+ *
-+ * This file may be redistributed under the terms of the GNU General
-+ * Public License.
-+ *
+--- linux-ia64.orig/fs/ext3/iopen.c    2004-03-17 18:02:08.000000000 -0800
++++ linux-ia64/fs/ext3/iopen.c 2004-03-17 18:10:58.000000000 -0800
+@@ -8,3 +8,275 @@
+  * This file may be redistributed under the terms of the GNU General
+  * Public License.
+  *
 + *
 + * Invariants:
 + *   - there is only ever a single DCACHE_NFSD_DISCONNECTED dentry alias
@@ -211,13 +204,24 @@ Index: linux-2.4.21-chaos/fs/ext3/iopen.c
 +
 +/* This function is spliced into ext3_lookup and does the move of a
 + * disconnected dentry (if it exists) to a connected dentry.
-+ * Caller must hold dcache_lock.
 + */
-+struct dentry *iopen_connect_dentry(struct dentry *de, struct inode *inode)
++struct dentry *iopen_connect_dentry(struct dentry *dentry, struct inode *inode,
++                                  int rehash)
 +{
 +      struct dentry *tmp, *goal = NULL;
 +      struct list_head *lp;
 +
++      /* verify this dentry is really new */
++      assert(dentry->d_inode == NULL);
++      assert(list_empty(&dentry->d_alias));           /* d_instantiate */
++      if (rehash)
++              assert(list_empty(&dentry->d_hash));    /* d_rehash */
++      assert(list_empty(&dentry->d_subdirs));
++
++      spin_lock(&dcache_lock);
++      if (!inode)
++              goto do_rehash;
++
 +      /* preferrably return a connected dentry */
 +      list_for_each(lp, &inode->i_dentry) {
 +              tmp = list_entry(lp, struct dentry, d_alias);
@@ -231,27 +235,40 @@ Index: linux-2.4.21-chaos/fs/ext3/iopen.c
 +      }
 +
 +      if (!goal)
-+              return NULL;
++              goto do_instantiate;
 +
 +      /* Move the goal to the de hash queue - like d_move() */
 +      goal->d_flags &= ~DCACHE_NFSD_DISCONNECTED;
 +      list_del_init(&goal->d_hash);
 +
 +      list_del(&goal->d_child);
-+      list_del(&de->d_child);
++      list_del(&dentry->d_child);
 +
 +      /* Switch the parents and the names.. */
-+      switch_names(goal, de);
-+      do_switch(goal->d_parent, de->d_parent);
-+      do_switch(goal->d_name.len, de->d_name.len);
-+      do_switch(goal->d_name.hash, de->d_name.hash);
++      switch_names(goal, dentry);
++      do_switch(goal->d_parent, dentry->d_parent);
++      do_switch(goal->d_name.len, dentry->d_name.len);
++      do_switch(goal->d_name.hash, dentry->d_name.hash);
 +
 +      /* And add them back to the (new) parent lists */
 +      list_add(&goal->d_child, &goal->d_parent->d_subdirs);
-+      list_add(&de->d_child, &de->d_parent->d_subdirs);
++      list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
 +      __d_rehash(goal, 0);
++      spin_unlock(&dcache_lock);
++      iput(inode);
 +
 +      return goal;
++
++      /* d_add(), but don't drop dcache_lock before adding dentry to inode */
++do_instantiate:
++      list_add(&dentry->d_alias, &inode->i_dentry);   /* d_instantiate */
++      dentry->d_inode = inode;
++do_rehash:
++      if (rehash)
++              __d_rehash(dentry, 0);                  /* d_rehash */
++      spin_unlock(&dcache_lock);
++
++      return NULL;
 +}
 +
 +/*
@@ -333,10 +350,10 @@ Index: linux-2.4.21-chaos/fs/ext3/iopen.c
 +
 +      return 1;
 +}
-Index: linux-2.4.21-chaos/fs/ext3/iopen.h
+Index: linux-ia64/fs/ext3/iopen.h
 ===================================================================
---- linux-2.4.21-chaos.orig/fs/ext3/iopen.h    2003-01-30 13:24:37.000000000 +0300
-+++ linux-2.4.21-chaos/fs/ext3/iopen.h 2003-12-12 16:19:05.000000000 +0300
+--- linux-ia64.orig/fs/ext3/iopen.h    2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/fs/ext3/iopen.h 2004-03-17 18:03:15.000000000 -0800
 @@ -0,0 +1,15 @@
 +/*
 + * iopen.h
@@ -351,12 +368,12 @@ Index: linux-2.4.21-chaos/fs/ext3/iopen.h
 +
 +extern int ext3_check_for_iopen(struct inode *dir, struct dentry *dentry);
 +extern int ext3_iopen_get_inode(struct inode *inode);
-+extern struct dentry *iopen_connect_dentry(struct dentry *de,
-+                                         struct inode *inode);
-Index: linux-2.4.21-chaos/fs/ext3/namei.c
++extern struct dentry *iopen_connect_dentry(struct dentry *dentry,
++                                         struct inode *inode, int rehash);
+Index: linux-ia64/fs/ext3/namei.c
 ===================================================================
---- linux-2.4.21-chaos.orig/fs/ext3/namei.c    2003-12-12 16:18:59.000000000 +0300
-+++ linux-2.4.21-chaos/fs/ext3/namei.c 2003-12-12 16:19:05.000000000 +0300
+--- linux-ia64.orig/fs/ext3/namei.c    2004-03-17 18:03:15.000000000 -0800
++++ linux-ia64/fs/ext3/namei.c 2004-03-17 18:10:35.000000000 -0800
 @@ -36,7 +36,7 @@
  #include <linux/string.h>
  #include <linux/locks.h>
@@ -366,12 +383,7 @@ Index: linux-2.4.21-chaos/fs/ext3/namei.c
  
  /*
   * define how far ahead to read directories while searching them.
-@@ -922,10 +922,14 @@
-       struct inode * inode;
-       struct ext3_dir_entry_2 * de;
-       struct buffer_head * bh;
-+      struct dentry *alternate = NULL;
+@@ -932,6 +932,9 @@ static struct dentry *ext3_lookup(struct
        if (dentry->d_name.len > EXT3_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
  
@@ -381,41 +393,67 @@ Index: linux-2.4.21-chaos/fs/ext3/namei.c
        bh = ext3_find_entry(dentry, &de);
        inode = NULL;
        if (bh) {
-@@ -943,7 +948,28 @@
+@@ -943,8 +946,8 @@ static struct dentry *ext3_lookup(struct
                        return ERR_PTR(-EACCES);
                }
        }
 -      d_add(dentry, inode);
+-      return NULL;
 +
-+      /* verify this dentry is really new */
-+      assert(!dentry->d_inode);
-+      assert(list_empty(&dentry->d_alias));           /* d_instantiate */
-+      assert(list_empty(&dentry->d_hash));            /* d_rehash */
-+      assert(list_empty(&dentry->d_subdirs));
-+
-+      spin_lock(&dcache_lock);
-+      if (inode && (alternate = iopen_connect_dentry(dentry, inode))) {
-+              spin_unlock(&dcache_lock);
-+              iput(inode);
-+              return alternate;
++      return iopen_connect_dentry(dentry, inode, 1);
+ }
+ #define S_SHIFT 12
+@@ -1935,10 +1938,6 @@ static int ext3_rmdir (struct inode * di
+                             inode->i_nlink);
+       inode->i_version = ++event;
+       inode->i_nlink = 0;
+-      /* There's no need to set i_disksize: the fact that i_nlink is
+-       * zero will ensure that the right thing happens during any
+-       * recovery. */
+-      inode->i_size = 0;
+       ext3_orphan_add(handle, inode);
+       dir->i_nlink--;
+       inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+@@ -2057,6 +2056,23 @@ out_stop:
+       return err;
+ }
++/* Like ext3_add_nondir() except for call to iopen_connect_dentry */
++static int ext3_add_link(handle_t *handle, struct dentry *dentry,
++                       struct inode *inode)
++{
++      int err = ext3_add_entry(handle, dentry, inode);
++      if (!err) {
++              err = ext3_mark_inode_dirty(handle, inode);
++              if (err == 0) {
++                      (void)iopen_connect_dentry(dentry, inode, 0);
++                      return 0;
++              }
 +      }
++      ext3_dec_count(handle, inode);
++      iput(inode);
++      return err;
++}
 +
-+      /* d_add(), but don't drop dcache_lock before adding dentry to inode */
-+      if (inode)                                      /* d_instantiate */
-+              list_add(&dentry->d_alias, &inode->i_dentry);
-+      dentry->d_inode = inode;
-+
-+      __d_rehash(dentry, 0);                          /* d_rehash */
-+      spin_unlock(&dcache_lock);
-+
-       return NULL;
- }
+ static int ext3_link (struct dentry * old_dentry,
+               struct inode * dir, struct dentry *dentry)
+ {
+@@ -2084,7 +2100,8 @@ static int ext3_link (struct dentry * ol
+       ext3_inc_count(handle, inode);
+       atomic_inc(&inode->i_count);
  
-Index: linux-2.4.21-chaos/fs/ext3/super.c
+-      err = ext3_add_nondir(handle, dentry, inode);
++      err = ext3_add_link(handle, dentry, inode);
++      ext3_orphan_del(handle, inode);
+       ext3_journal_stop(handle, dir);
+       return err;
+ }
+Index: linux-ia64/fs/ext3/super.c
 ===================================================================
---- linux-2.4.21-chaos.orig/fs/ext3/super.c    2003-12-12 16:18:51.000000000 +0300
-+++ linux-2.4.21-chaos/fs/ext3/super.c 2003-12-12 16:19:05.000000000 +0300
-@@ -890,6 +890,18 @@
+--- linux-ia64.orig/fs/ext3/super.c    2004-03-17 18:03:14.000000000 -0800
++++ linux-ia64/fs/ext3/super.c 2004-03-17 18:10:35.000000000 -0800
+@@ -891,6 +891,18 @@ static int parse_options (char * options
                         || !strcmp (this_char, "quota")
                         || !strcmp (this_char, "usrquota"))
                        /* Don't do anything ;-) */ ;
@@ -434,11 +472,11 @@ Index: linux-2.4.21-chaos/fs/ext3/super.c
                else if (!strcmp (this_char, "journal")) {
                        /* @@@ FIXME */
                        /* Eventually we will want to be able to create
-Index: linux-2.4.21-chaos/include/linux/ext3_fs.h
+Index: linux-ia64/include/linux/ext3_fs.h
 ===================================================================
---- linux-2.4.21-chaos.orig/include/linux/ext3_fs.h    2003-12-12 16:19:01.000000000 +0300
-+++ linux-2.4.21-chaos/include/linux/ext3_fs.h 2003-12-12 16:19:05.000000000 +0300
-@@ -328,6 +328,8 @@
+--- linux-ia64.orig/include/linux/ext3_fs.h    2004-03-17 18:03:15.000000000 -0800
++++ linux-ia64/include/linux/ext3_fs.h 2004-03-17 18:03:15.000000000 -0800
+@@ -328,6 +328,8 @@ struct ext3_inode {
  #define EXT3_MOUNT_XATTR_USER         0x4000  /* Extended user attributes */
  #define EXT3_MOUNT_POSIX_ACL          0x8000  /* POSIX Access Control Lists */
  #define EXT3_MOUNT_ASYNCDEL           0x20000 /* Delayed deletion */
index 79b1f17..5500320 100644 (file)
@@ -15,7 +15,7 @@ Index: linux-2.6.3-mm4/Documentation/filesystems/ext2.txt
  
  sb=n                          Use alternate superblock at this location.
  
-+iopen                         Makes an invisible pseudo-directory called 
++iopen                         Makes an invisible pseudo-directory called
 +                              __iopen__ available in the root directory
 +                              of the filesystem.  Allows open-by-inode-
 +                              number.  i.e., inode 3145 can be accessed
@@ -59,16 +59,14 @@ Index: linux-2.6.3-mm4/fs/ext3/iopen.c
 ===================================================================
 --- linux-2.6.3-mm4.orig/fs/ext3/iopen.c       2004-03-08 14:58:44.413198848 +0800
 +++ linux-2.6.3-mm4/fs/ext3/iopen.c    2004-03-08 14:58:44.576174072 +0800
-@@ -0,0 +1,223 @@
-+
-+
+@@ -0,0 +1,218 @@
 +/*
 + * linux/fs/ext3/iopen.c
 + *
 + * Special support for open by inode number
 + *
 + * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu).
-+ * 
++ *
 + * This file may be redistributed under the terms of the GNU General
 + * Public License.
 + */
@@ -90,12 +88,13 @@ Index: linux-2.6.3-mm4/fs/ext3/iopen.c
 +/*
 + * This implements looking up an inode by number.
 + */
-+static struct dentry *iopen_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
++static struct dentry *iopen_lookup(struct inode *dir, struct dentry *dentry,
++                                 struct nameidata *nd)
 +{
 +      struct inode * inode;
 +      unsigned long ino;
-+        struct list_head *lp;
-+        struct dentry *alternate;
++      struct list_head *lp;
++      struct dentry *alternate;
 +      char buf[IOPEN_NAME_LEN];
 +      
 +      if (dentry->d_name.len >= IOPEN_NAME_LEN)
@@ -111,10 +110,7 @@ Index: linux-2.6.3-mm4/fs/ext3/iopen.c
 +      else
 +              ino = simple_strtoul(buf, 0, 0);
 +
-+      if ((ino != EXT3_ROOT_INO &&
-+           //ino != EXT3_ACL_IDX_INO &&
-+           //ino != EXT3_ACL_DATA_INO &&
-+           ino < EXT3_FIRST_INO(dir->i_sb)) ||
++      if ((ino != EXT3_ROOT_INO && ino < EXT3_FIRST_INO(dir->i_sb)) ||
 +          ino > le32_to_cpu(EXT3_SB(dir->i_sb)->s_es->s_inodes_count))
 +              return ERR_PTR(-ENOENT);
 +
@@ -126,24 +122,24 @@ Index: linux-2.6.3-mm4/fs/ext3/iopen.c
 +              return ERR_PTR(-ENOENT);
 +      }
 +
-+        /* preferrably return a connected dentry */
-+        spin_lock(&dcache_lock);
-+        list_for_each(lp, &inode->i_dentry) {
-+                alternate = list_entry(lp, struct dentry, d_alias);
-+                assert(!(alternate->d_flags & DCACHE_DISCONNECTED));
-+        }
-+
-+        if (!list_empty(&inode->i_dentry)) {
-+                alternate = list_entry(inode->i_dentry.next, 
-+                                       struct dentry, d_alias);
-+                dget_locked(alternate);
-+                alternate->d_vfs_flags |= DCACHE_REFERENCED;
-+                iput(inode);
-+                spin_unlock(&dcache_lock);
-+                return alternate;
-+        }
-+        dentry->d_flags |= DCACHE_DISCONNECTED;
-+        spin_unlock(&dcache_lock);
++      /* preferrably return a connected dentry */
++      spin_lock(&dcache_lock);
++      list_for_each(lp, &inode->i_dentry) {
++              alternate = list_entry(lp, struct dentry, d_alias);
++              assert(!(alternate->d_flags & DCACHE_DISCONNECTED));
++      }
++
++      if (!list_empty(&inode->i_dentry)) {
++              alternate = list_entry(inode->i_dentry.next,
++                                     struct dentry, d_alias);
++              dget_locked(alternate);
++              alternate->d_vfs_flags |= DCACHE_REFERENCED;
++              iput(inode);
++              spin_unlock(&dcache_lock);
++              return alternate;
++      }
++      dentry->d_flags |= DCACHE_DISCONNECTED;
++      spin_unlock(&dcache_lock);
 +
 +      d_add(dentry, inode);
 +      return NULL;
@@ -157,7 +153,7 @@ Index: linux-2.6.3-mm4/fs/ext3/iopen.c
 +{
 +      const unsigned char *old_name, *new_name;
 +
-+      memcpy(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN); 
++      memcpy(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN);
 +      old_name = target->d_name.name;
 +      new_name = dentry->d_name.name;
 +      if (old_name == target->d_iname)
@@ -171,37 +167,36 @@ Index: linux-2.6.3-mm4/fs/ext3/iopen.c
 +
 +struct dentry *iopen_connect_dentry(struct dentry *de, struct inode *inode)
 +{
-+        struct dentry *tmp, *goal = NULL;
-+        struct list_head *lp;
-+
-+        /* preferrably return a connected dentry */
-+        spin_lock(&dcache_lock);
-+        /* verify this dentry is really new */
-+        assert(!de->d_inode);
-+        assert(list_empty(&de->d_subdirs));
-+        assert(list_empty(&de->d_alias));
-+
-+
-+        list_for_each(lp, &inode->i_dentry) {
-+                tmp = list_entry(lp, struct dentry, d_alias);
-+                if (tmp->d_flags & DCACHE_DISCONNECTED) {
-+                        assert(tmp->d_alias.next == &inode->i_dentry);
-+                        assert(tmp->d_alias.prev == &inode->i_dentry);
-+                        goal = tmp;
-+                        dget_locked(goal);
-+                        break;
-+                }
-+        }
-+        spin_unlock(&dcache_lock);
-+
-+        if (!goal)
-+                return NULL; 
-+
-+        goal->d_flags &= ~DCACHE_DISCONNECTED;
++      struct dentry *tmp, *goal = NULL;
++      struct list_head *lp;
++
++      /* preferrably return a connected dentry */
++      spin_lock(&dcache_lock);
++      /* verify this dentry is really new */
++      assert(!de->d_inode);
++      assert(list_empty(&de->d_subdirs));
++      assert(list_empty(&de->d_alias));
++
++      list_for_each(lp, &inode->i_dentry) {
++              tmp = list_entry(lp, struct dentry, d_alias);
++              if (tmp->d_flags & DCACHE_DISCONNECTED) {
++                      assert(tmp->d_alias.next == &inode->i_dentry);
++                      assert(tmp->d_alias.prev == &inode->i_dentry);
++                      goal = tmp;
++                      dget_locked(goal);
++                      break;
++              }
++      }
++      spin_unlock(&dcache_lock);
++
++      if (!goal)
++              return NULL;
++
++      goal->d_flags &= ~DCACHE_DISCONNECTED;
 +      d_rehash(de);
 +      d_move(goal, de);
 +
-+        return goal;
++      return goal;
 +}
 +
 +/*
@@ -243,7 +238,7 @@ Index: linux-2.6.3-mm4/fs/ext3/iopen.c
 +
 +      inode = iget(dir->i_sb, EXT3_BAD_INO);
 +
-+      if (!inode) 
++      if (!inode)
 +              return 0;
 +      d_add(dentry, inode);
 +      return 1;
@@ -272,7 +267,7 @@ Index: linux-2.6.3-mm4/fs/ext3/iopen.c
 +      EXT3_I(inode)->i_dtime = 0;
 +      inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size
 +                                       * (for stat), not the fs block
-+                                       * size */  
++                                       * size */
 +      inode->i_blocks = 0;
 +      inode->i_version = 1;
 +      inode->i_generation = 0;
@@ -292,9 +287,9 @@ Index: linux-2.6.3-mm4/fs/ext3/iopen.h
 + * iopen.h
 + *
 + * Special support for opening files by inode number.
-+ * 
++ *
 + * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu).
-+ * 
++ *
 + * This file may be redistributed under the terms of the GNU General
 + * Public License.
 + */
@@ -320,13 +315,13 @@ Index: linux-2.6.3-mm4/fs/ext3/namei.c
  #endif
  
 +struct dentry *iopen_connect_dentry(struct dentry *de, struct inode *inode);
-+ 
++
  static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
  {
        struct inode * inode;
        struct ext3_dir_entry_2 * de;
        struct buffer_head * bh;
-+      struct dentry *alternate = NULL;
++      struct dentry *alternate = NULL;
  
        if (dentry->d_name.len > EXT3_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
index 16e191b..726957c 100644 (file)
@@ -5336,7 +5336,7 @@ diff -puN /dev/null include/linux/sunrpc/svcauth_gss.h
 + * Bruce Fields <bfields@umich.edu>
 + * Copyright (c) 2002 The Regents of the Unviersity of Michigan
 + *
-+ * $Id: linux-2.6.3-CITI_NFS4_ALL.patch,v 1.2 2004/03/17 01:04:13 nic Exp $
++ * Id: linux-2.6.3-CITI_NFS4_ALL.patch,v 1.2.4.1 2004/03/17 23:55:23 adilger Exp $
 + *
 + */
 +
index 86f514b..7ebb838 100644 (file)
@@ -7,6 +7,6 @@
 --- /dev/null  Fri Aug 30 17:31:37 2002
 +++ linux-2.4.18-18.8.0-l12-braam/include/linux/lustre_version.h       Thu Feb 13 07:58:33 2003
 @@ -0,0 +1 @@
-+#define LUSTRE_KERNEL_VERSION 32
++#define LUSTRE_KERNEL_VERSION 34
 
 _
index e29ae29..41c2772 100644 (file)
 +                                                &dentry->d_name, 0, NULL);
 +                              d_invalidate(dentry);
 +                              dput(dentry);
-+                              if (IS_ERR(new)) { 
++                              if (IS_ERR(new)) {
 +                                      err = PTR_ERR(new);
 +                                      break;
 +                              }
index 5fbd0fc..7c4ea56 100644 (file)
@@ -453,7 +453,7 @@ Index: linux-2.4.19-pre1/fs/namei.c
 +                                                &dentry->d_name, 0, NULL);
 +                              d_invalidate(dentry);
 +                              dput(dentry);
-+                              if (IS_ERR(new)) { 
++                              if (IS_ERR(new)) {
 +                                      err = PTR_ERR(new);
 +                                      break;
 +                              }
index 6b6027a..7741be4 100644 (file)
@@ -436,7 +436,7 @@ Index: linux-2.4.19.SuSE/fs/namei.c
 +                                                &dentry->d_name, 0, NULL);
 +                              d_invalidate(dentry);
 +                              dput(dentry);
-+                              if (IS_ERR(new)) { 
++                              if (IS_ERR(new)) {
 +                                      err = PTR_ERR(new);
 +                                      break;
 +                              }
index 082b8b7..8585701 100644 (file)
  kernel/ksyms.c            |    1 
  13 files changed, 591 insertions(+), 133 deletions(-)
 
---- linux-2.4.20-hp4-pnnl13/fs/exec.c~vfs_intent-2.4.20-hp     2003-09-13 15:19:27.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/exec.c   2003-09-14 17:33:51.000000000 +0400
-@@ -116,8 +116,10 @@ asmlinkage long sys_uselib(const char * 
+Index: linux/fs/exec.c
+===================================================================
+--- linux.orig/fs/exec.c       Wed Mar 17 13:00:38 2004
++++ linux/fs/exec.c    Wed Mar 17 13:11:25 2004
+@@ -115,8 +115,10 @@
        struct file * file;
        struct nameidata nd;
        int error;
@@ -27,7 +29,7 @@
        if (error)
                goto out;
  
-@@ -129,7 +131,8 @@ asmlinkage long sys_uselib(const char * 
+@@ -128,7 +130,8 @@
        if (error)
                goto exit;
  
@@ -37,7 +39,7 @@
        error = PTR_ERR(file);
        if (IS_ERR(file))
                goto out;
-@@ -372,8 +375,10 @@ struct file *open_exec(const char *name)
+@@ -371,8 +374,10 @@
        struct inode *inode;
        struct file *file;
        int err = 0;
@@ -49,7 +51,7 @@
        file = ERR_PTR(err);
        if (!err) {
                inode = nd.dentry->d_inode;
-@@ -385,7 +390,8 @@ struct file *open_exec(const char *name)
+@@ -384,7 +389,8 @@
                                err = -EACCES;
                        file = ERR_PTR(err);
                        if (!err) {
@@ -59,7 +61,7 @@
                                if (!IS_ERR(file)) {
                                        err = deny_write_access(file);
                                        if (err) {
-@@ -397,6 +403,7 @@ out:
+@@ -396,6 +402,7 @@
                                return file;
                        }
                }
@@ -67,7 +69,7 @@
                path_release(&nd);
        }
        goto out;
-@@ -1128,7 +1135,7 @@ int do_coredump(long signr, struct pt_re
+@@ -1120,7 +1127,7 @@
                goto close_fail;
        if (!file->f_op->write)
                goto close_fail;
                goto close_fail;
  
        retval = binfmt->core_dump(signr, regs, file);
---- linux-2.4.20-hp4-pnnl13/fs/dcache.c~vfs_intent-2.4.20-hp   2002-11-29 02:53:15.000000000 +0300
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/dcache.c 2003-09-14 17:33:51.000000000 +0400
-@@ -181,6 +181,13 @@ int d_invalidate(struct dentry * dentry)
+Index: linux/fs/dcache.c
+===================================================================
+--- linux.orig/fs/dcache.c     Thu Nov 28 18:53:15 2002
++++ linux/fs/dcache.c  Wed Mar 17 13:11:25 2004
+@@ -181,6 +181,13 @@
                spin_unlock(&dcache_lock);
                return 0;
        }
@@ -92,7 +96,7 @@
        /*
         * Check whether to do a partial shrink_dcache
         * to get rid of unused child entries.
-@@ -830,13 +837,19 @@ void d_delete(struct dentry * dentry)
+@@ -830,13 +837,19 @@
   * Adds a dentry to the hash according to its name.
   */
   
  }
  
  #define do_switch(x,y) do { \
---- linux-2.4.20-hp4-pnnl13/fs/namespace.c~vfs_intent-2.4.20-hp        2002-11-29 02:53:15.000000000 +0300
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/namespace.c      2003-09-14 17:33:51.000000000 +0400
-@@ -99,6 +99,7 @@ static void detach_mnt(struct vfsmount *
+Index: linux/fs/namespace.c
+===================================================================
+--- linux.orig/fs/namespace.c  Thu Nov 28 18:53:15 2002
++++ linux/fs/namespace.c       Wed Mar 17 13:11:25 2004
+@@ -99,6 +99,7 @@
  {
        old_nd->dentry = mnt->mnt_mountpoint;
        old_nd->mnt = mnt->mnt_parent;
        mnt->mnt_parent = mnt;
        mnt->mnt_mountpoint = mnt->mnt_root;
        list_del_init(&mnt->mnt_child);
-@@ -110,6 +111,7 @@ static void attach_mnt(struct vfsmount *
+@@ -110,6 +111,7 @@
  {
        mnt->mnt_parent = mntget(nd->mnt);
        mnt->mnt_mountpoint = dget(nd->dentry);
        list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry));
        list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts);
        nd->dentry->d_mounted++;
-@@ -485,14 +487,17 @@ static int do_loopback(struct nameidata 
+@@ -485,14 +487,17 @@
  {
        struct nameidata old_nd;
        struct vfsmount *mnt = NULL;
  
        down_write(&current->namespace->sem);
        err = -EINVAL;
-@@ -515,6 +520,7 @@ static int do_loopback(struct nameidata 
+@@ -515,6 +520,7 @@
        }
  
        up_write(&current->namespace->sem);
        path_release(&old_nd);
        return err;
  }
-@@ -698,6 +704,7 @@ long do_mount(char * dev_name, char * di
+@@ -698,6 +704,7 @@
                  unsigned long flags, void *data_page)
  {
        struct nameidata nd;
        int retval = 0;
        int mnt_flags = 0;
  
-@@ -722,10 +729,11 @@ long do_mount(char * dev_name, char * di
+@@ -722,10 +729,11 @@
        flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
  
        /* ... and get the mountpoint */
        if (flags & MS_REMOUNT)
                retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
                                    data_page);
-@@ -736,6 +744,8 @@ long do_mount(char * dev_name, char * di
+@@ -736,6 +744,8 @@
        else
                retval = do_add_mount(&nd, type_page, flags, mnt_flags,
                                      dev_name, data_page);
        path_release(&nd);
        return retval;
  }
-@@ -901,6 +911,8 @@ asmlinkage long sys_pivot_root(const cha
+@@ -901,6 +911,8 @@
  {
        struct vfsmount *tmp;
        struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
        int error;
  
        if (!capable(CAP_SYS_ADMIN))
-@@ -908,14 +920,14 @@ asmlinkage long sys_pivot_root(const cha
+@@ -908,14 +920,14 @@
  
        lock_kernel();
  
        if (error)
                goto out1;
  
-@@ -970,8 +982,10 @@ out2:
+@@ -970,8 +982,10 @@
        up(&old_nd.dentry->d_inode->i_zombie);
        up_write(&current->namespace->sem);
        path_release(&user_nd);
        path_release(&new_nd);
  out0:
        unlock_kernel();
---- linux-2.4.20-hp4-pnnl13/fs/namei.c~vfs_intent-2.4.20-hp    2003-09-13 15:19:23.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/namei.c  2003-09-14 17:33:51.000000000 +0400
+Index: linux/fs/namei.c
+===================================================================
+--- linux.orig/fs/namei.c      Wed Mar 17 13:00:37 2004
++++ linux/fs/namei.c   Wed Mar 17 13:12:31 2004
 @@ -94,6 +94,13 @@
   * XEmacs seems to be relying on 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 @@ void path_release(struct nameidata *nd)
+@@ -260,10 +267,19 @@
   * Internal lookup() using the new generic dcache.
   * SMP-safe
   */
        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 @@ static struct dentry * cached_lookup(str
+@@ -281,11 +297,15 @@
   * make sure that nobody added the entry to the dcache in the meantime..
   * SMP-safe
   */
        down(&dir->i_sem);
        /*
         * First re-do the cached lookup just in case it was created
-@@ -300,6 +320,9 @@ static struct dentry * real_lookup(struc
+@@ -300,6 +320,9 @@
                result = ERR_PTR(-ENOMEM);
                if (dentry) {
                        lock_kernel();
                        result = dir->i_op->lookup(dir, dentry);
                        unlock_kernel();
                        if (result)
-@@ -321,6 +344,15 @@ static struct dentry * real_lookup(struc
+@@ -321,6 +344,15 @@
                        dput(result);
                        result = ERR_PTR(-ENOENT);
                }
        }
        return result;
  }
-@@ -332,7 +364,8 @@ static struct dentry * real_lookup(struc
+@@ -332,7 +364,8 @@
   * Without that kind of total limit, nasty chains of consecutive
   * symlinks can cause almost arbitrarily long lookups. 
   */
  {
        int err;
        if (current->link_count >= 5)
-@@ -346,10 +379,18 @@ static inline int do_follow_link(struct 
+@@ -346,10 +379,18 @@
        current->link_count++;
        current->total_link_count++;
        UPDATE_ATIME(dentry->d_inode);
        path_release(nd);
        return -ELOOP;
  }
-@@ -379,15 +420,26 @@ int follow_up(struct vfsmount **mnt, str
+@@ -379,15 +420,26 @@
        return __follow_up(mnt, dentry);
  }
  
                dput(*dentry);
                mntput(mounted->mnt_parent);
                *dentry = dget(mounted->mnt_root);
-@@ -399,7 +451,7 @@ static inline int __follow_down(struct v
+@@ -399,7 +451,7 @@
  
  int follow_down(struct vfsmount **mnt, struct dentry **dentry)
  {
  }
   
  static inline void follow_dotdot(struct nameidata *nd)
-@@ -435,7 +487,7 @@ static inline void follow_dotdot(struct 
+@@ -435,7 +487,7 @@
                mntput(nd->mnt);
                nd->mnt = parent;
        }
                ;
  }
  
-@@ -447,7 +499,8 @@ static inline void follow_dotdot(struct 
+@@ -447,7 +499,8 @@
   *
   * We expect 'base' to be positive and a directory.
   */
  {
        struct dentry *dentry;
        struct inode *inode;
-@@ -520,15 +573,15 @@ int link_path_walk(const char * name, st
+@@ -520,15 +573,15 @@
                                break;
                }
                /* This does the actual lookups.. */
                        ;
  
                err = -ENOENT;
-@@ -540,7 +593,7 @@ int link_path_walk(const char * name, st
+@@ -540,7 +593,7 @@
                        goto out_dput;
  
                if (inode->i_op->follow_link) {
                        dput(dentry);
                        if (err)
                                goto return_err;
-@@ -556,7 +609,7 @@ int link_path_walk(const char * name, st
+@@ -556,7 +609,7 @@
                        nd->dentry = dentry;
                }
                err = -ENOTDIR; 
                        break;
                continue;
                /* here ends the main loop */
-@@ -583,19 +636,19 @@ last_component:
+@@ -583,19 +636,19 @@
                        if (err < 0)
                                break;
                }
                        dput(dentry);
                        if (err)
                                goto return_err;
-@@ -609,7 +662,8 @@ last_component:
+@@ -609,7 +662,8 @@
                        goto no_inode;
                if (lookup_flags & LOOKUP_DIRECTORY) {
                        err = -ENOTDIR; 
                                break;
                }
                goto return_base;
-@@ -633,6 +687,25 @@ return_reval:
+@@ -633,6 +687,27 @@
                 * Check the cached dentry for staleness.
                 */
                dentry = nd->dentry;
 +                                                &dentry->d_name, 0, NULL);
 +                              d_invalidate(dentry);
 +                              dput(dentry);
-+                              if (IS_ERR(new)) { 
++                              if (IS_ERR(new)) {
 +                                      err = PTR_ERR(new);
 +                                      break;
 +                              }
 +                              nd->dentry = new;
 +                      }
++                      if (!nd->dentry->d_inode)
++                              goto no_inode;
 +              } else
                if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
                        err = -ESTALE;
                        if (!dentry->d_op->d_revalidate(dentry, 0)) {
-@@ -646,15 +719,28 @@ out_dput:
+@@ -646,15 +721,28 @@
                dput(dentry);
                break;
        }
  }
  
  /* SMP-safe */
-@@ -739,6 +825,17 @@ walk_init_root(const char *name, struct 
+@@ -739,6 +827,17 @@
  }
  
  /* SMP-safe */
  int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
  {
        int error = 0;
-@@ -753,6 +850,7 @@ int path_init(const char *name, unsigned
+@@ -753,6 +852,7 @@
  {
        nd->last_type = LAST_ROOT; /* if there are only slashes... */
        nd->flags = flags;
        if (*name=='/')
                return walk_init_root(name,nd);
        read_lock(&current->fs->lock);
-@@ -767,7 +865,8 @@ int path_init(const char *name, unsigned
+@@ -767,7 +867,8 @@
   * needs parent already locked. Doesn't follow mounts.
   * SMP-safe.
   */
  {
        struct dentry * dentry;
        struct inode *inode;
-@@ -790,13 +889,16 @@ struct dentry * lookup_hash(struct qstr 
+@@ -790,13 +891,16 @@
                        goto out;
        }
  
                dentry = inode->i_op->lookup(inode, new);
                unlock_kernel();
                if (!dentry)
-@@ -808,6 +910,12 @@ out:
+@@ -808,6 +912,12 @@
        return dentry;
  }
  
  /* SMP-safe */
  struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
  {
-@@ -829,7 +937,7 @@ struct dentry * lookup_one_len(const cha
+@@ -829,7 +939,7 @@
        }
        this.hash = end_name_hash(hash);
  
  access:
        return ERR_PTR(-EACCES);
  }
-@@ -860,6 +968,23 @@ int __user_walk(const char *name, unsign
+@@ -860,6 +970,23 @@
        return err;
  }
  
  /*
   * It's inline, so penalty for filesystems that don't use sticky bit is
   * minimal.
-@@ -955,7 +1080,8 @@ static inline int lookup_flags(unsigned 
+@@ -955,7 +1082,8 @@
        return retval;
  }
  
  {
        int error;
  
-@@ -968,12 +1094,15 @@ int vfs_create(struct inode *dir, struct
+@@ -968,12 +1096,15 @@
                goto exit_lock;
  
        error = -EACCES;        /* shouldn't it be ENOSYS? */
        unlock_kernel();
  exit_lock:
        up(&dir->i_zombie);
-@@ -982,6 +1111,11 @@ exit_lock:
+@@ -982,6 +1113,11 @@
        return error;
  }
  
  /*
   *    open_namei()
   *
-@@ -996,7 +1130,8 @@ exit_lock:
+@@ -996,7 +1132,8 @@
   * for symlinks (where the permissions are checked later).
   * SMP-safe
   */
  {
        int acc_mode, error = 0;
        struct inode *inode;
-@@ -1006,11 +1141,14 @@ int open_namei(const char * pathname, in
+@@ -1006,11 +1143,14 @@
  
        acc_mode = ACC_MODE(flag);
  
                if (error)
                        return error;
                dentry = nd->dentry;
-@@ -1020,6 +1158,10 @@ int open_namei(const char * pathname, in
+@@ -1020,6 +1160,10 @@
        /*
         * Create - we need to know the parent.
         */
        error = path_lookup(pathname, LOOKUP_PARENT, nd);
        if (error)
                return error;
-@@ -1035,7 +1177,7 @@ int open_namei(const char * pathname, in
+@@ -1035,7 +1179,7 @@
  
        dir = nd->dentry;
        down(&dir->d_inode->i_sem);
  
  do_last:
        error = PTR_ERR(dentry);
-@@ -1044,11 +1186,12 @@ do_last:
+@@ -1044,11 +1188,12 @@
                goto exit;
        }
  
                up(&dir->d_inode->i_sem);
                dput(nd->dentry);
                nd->dentry = dentry;
-@@ -1073,7 +1216,7 @@ do_last:
+@@ -1073,7 +1218,7 @@
                error = -ELOOP;
                if (flag & O_NOFOLLOW)
                        goto exit_dput;
        }
        error = -ENOENT;
        if (!dentry->d_inode)
-@@ -1152,7 +1295,7 @@ ok:
+@@ -1152,7 +1297,7 @@
                if (!error) {
                        DQUOT_INIT(inode);
                        
                }
                put_write_access(inode);
                if (error)
-@@ -1164,8 +1307,10 @@ ok:
+@@ -1164,8 +1309,10 @@
        return 0;
  
  exit_dput:
        path_release(nd);
        return error;
  
-@@ -1184,7 +1329,16 @@ do_link:
+@@ -1184,7 +1331,16 @@
         * are done. Procfs-like symlinks just set LAST_BIND.
         */
        UPDATE_ATIME(dentry->d_inode);
        dput(dentry);
        if (error)
                return error;
-@@ -1206,13 +1360,20 @@ do_link:
+@@ -1206,13 +1362,20 @@
        }
        dir = nd->dentry;
        down(&dir->d_inode->i_sem);
  {
        struct dentry *dentry;
  
-@@ -1220,7 +1381,7 @@ static struct dentry *lookup_create(stru
+@@ -1220,7 +1383,7 @@
        dentry = ERR_PTR(-EEXIST);
        if (nd->last_type != LAST_NORM)
                goto fail;
        if (IS_ERR(dentry))
                goto fail;
        if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
-@@ -1276,7 +1437,16 @@ asmlinkage long sys_mknod(const char * f
+@@ -1276,7 +1439,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);
        error = PTR_ERR(dentry);
  
        if (!IS_POSIXACL(nd.dentry->d_inode))
-@@ -1298,6 +1468,7 @@ asmlinkage long sys_mknod(const char * f
+@@ -1298,6 +1474,7 @@
                dput(dentry);
        }
        up(&nd.dentry->d_inode->i_sem);
        path_release(&nd);
  out:
        putname(tmp);
-@@ -1345,7 +1516,14 @@ asmlinkage long sys_mkdir(const char * p
+@@ -1345,7 +1522,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);
                error = PTR_ERR(dentry);
                if (!IS_ERR(dentry)) {
                        if (!IS_POSIXACL(nd.dentry->d_inode))
-@@ -1354,6 +1532,7 @@ asmlinkage long sys_mkdir(const char * p
+@@ -1354,6 +1542,7 @@
                        dput(dentry);
                }
                up(&nd.dentry->d_inode->i_sem);
                path_release(&nd);
  out:
                putname(tmp);
-@@ -1454,8 +1633,16 @@ asmlinkage long sys_rmdir(const char * p
+@@ -1454,8 +1643,16 @@
                        error = -EBUSY;
                        goto exit1;
        }
        error = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
                error = vfs_rmdir(nd.dentry->d_inode, dentry);
-@@ -1513,8 +1700,15 @@ asmlinkage long sys_unlink(const char * 
+@@ -1513,8 +1710,15 @@
        error = -EISDIR;
        if (nd.last_type != LAST_NORM)
                goto exit1;
        error = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
                /* Why not before? Because we want correct error value */
-@@ -1581,15 +1775,23 @@ asmlinkage long sys_symlink(const char *
+@@ -1581,15 +1785,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);
                putname(to);
        }
        putname(from);
-@@ -1665,7 +1867,14 @@ asmlinkage long sys_link(const char * ol
+@@ -1665,7 +1881,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);
                error = PTR_ERR(new_dentry);
                if (!IS_ERR(new_dentry)) {
                        error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
-@@ -1709,7 +1918,7 @@ exit:
+@@ -1709,7 +1936,7 @@
   *       locking].
   */
  int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
  {
        int error;
        struct inode *target;
-@@ -1788,7 +1997,7 @@ out_unlock:
+@@ -1788,7 +2015,7 @@
  }
  
  int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
  {
        int error;
  
-@@ -1876,9 +2085,18 @@ static inline int do_rename(const char *
+@@ -1876,9 +2103,18 @@
        if (newnd.last_type != LAST_NORM)
                goto exit2;
  
        error = PTR_ERR(old_dentry);
        if (IS_ERR(old_dentry))
                goto exit3;
-@@ -1894,16 +2112,16 @@ static inline int do_rename(const char *
+@@ -1894,16 +2130,16 @@
                if (newnd.last.name[newnd.last.len])
                        goto exit4;
        }
        dput(new_dentry);
  exit4:
        dput(old_dentry);
-@@ -1954,20 +2172,28 @@ out:
+@@ -1954,20 +2190,28 @@
  }
  
  static inline int
  out:
        if (current->link_count || res || nd->last_type!=LAST_NORM)
                return res;
-@@ -1989,7 +2215,13 @@ fail:
+@@ -1989,7 +2233,13 @@
  
  int vfs_follow_link(struct nameidata *nd, const char *link)
  {
  }
  
  /* get the link contents into pagecache */
-@@ -2031,7 +2263,7 @@ int page_follow_link(struct dentry *dent
+@@ -2031,7 +2281,7 @@
  {
        struct page *page = NULL;
        char *s = page_getlink(dentry, &page);
        if (page) {
                kunmap(page);
                page_cache_release(page);
---- linux-2.4.20-hp4-pnnl13/fs/open.c~vfs_intent-2.4.20-hp     2002-11-29 02:53:15.000000000 +0300
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/open.c   2003-09-14 17:33:51.000000000 +0400
+Index: linux/fs/open.c
+===================================================================
+--- linux.orig/fs/open.c       Thu Nov 28 18:53:15 2002
++++ linux/fs/open.c    Wed Mar 17 13:11:25 2004
 @@ -19,6 +19,8 @@
  #include <asm/uaccess.h>
  
  
  int vfs_statfs(struct super_block *sb, struct statfs *buf)
  {
-@@ -95,9 +97,10 @@ void fd_install(unsigned int fd, struct 
+@@ -95,9 +97,10 @@
        write_unlock(&files->file_lock);
  }
  
        int error;
        struct iattr newattrs;
  
-@@ -108,7 +111,13 @@ int do_truncate(struct dentry *dentry, l
+@@ -108,7 +111,13 @@
        down(&inode->i_sem);
        newattrs.ia_size = length;
        newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
        up(&inode->i_sem);
        return error;
  }
-@@ -118,12 +127,13 @@ static inline long do_sys_truncate(const
+@@ -118,12 +127,13 @@
        struct nameidata nd;
        struct inode * inode;
        int error;
        if (error)
                goto out;
        inode = nd.dentry->d_inode;
-@@ -163,11 +173,13 @@ static inline long do_sys_truncate(const
+@@ -163,11 +173,13 @@
        error = locks_verify_truncate(inode, NULL, length);
        if (!error) {
                DQUOT_INIT(inode);
        path_release(&nd);
  out:
        return error;
-@@ -215,7 +227,7 @@ static inline long do_sys_ftruncate(unsi
+@@ -215,7 +227,7 @@
  
        error = locks_verify_truncate(inode, file, length);
        if (!error)
  out_putf:
        fput(file);
  out:
-@@ -260,11 +272,13 @@ asmlinkage long sys_utime(char * filenam
+@@ -260,11 +272,13 @@
        struct inode * inode;
        struct iattr newattrs;
  
        error = -EROFS;
        if (IS_RDONLY(inode))
                goto dput_and_out;
-@@ -279,11 +293,25 @@ asmlinkage long sys_utime(char * filenam
+@@ -279,11 +293,25 @@
                        goto dput_and_out;
  
                newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
        error = notify_change(nd.dentry, &newattrs);
  dput_and_out:
        path_release(&nd);
-@@ -304,12 +332,14 @@ asmlinkage long sys_utimes(char * filena
+@@ -304,12 +332,14 @@
        struct inode * inode;
        struct iattr newattrs;
  
        error = -EROFS;
        if (IS_RDONLY(inode))
                goto dput_and_out;
-@@ -324,7 +354,20 @@ asmlinkage long sys_utimes(char * filena
+@@ -324,7 +354,20 @@
                newattrs.ia_atime = times[0].tv_sec;
                newattrs.ia_mtime = times[1].tv_sec;
                newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
                if (current->fsuid != inode->i_uid &&
                    (error = permission(inode,MAY_WRITE)) != 0)
                        goto dput_and_out;
-@@ -347,6 +390,7 @@ asmlinkage long sys_access(const char * 
+@@ -347,6 +390,7 @@
        int old_fsuid, old_fsgid;
        kernel_cap_t old_cap;
        int res;
  
        if (mode & ~S_IRWXO)    /* where's F_OK, X_OK, W_OK, R_OK? */
                return -EINVAL;
-@@ -364,13 +408,14 @@ asmlinkage long sys_access(const char * 
+@@ -364,13 +408,14 @@
        else
                current->cap_effective = current->cap_permitted;
  
                path_release(&nd);
        }
  
-@@ -385,8 +430,9 @@ asmlinkage long sys_chdir(const char * f
+@@ -385,8 +430,9 @@
  {
        int error;
        struct nameidata nd;
        if (error)
                goto out;
  
-@@ -397,6 +443,7 @@ asmlinkage long sys_chdir(const char * f
+@@ -397,6 +443,7 @@
        set_fs_pwd(current->fs, nd.mnt, nd.dentry);
  
  dput_and_out:
        path_release(&nd);
  out:
        return error;
-@@ -436,9 +483,10 @@ asmlinkage long sys_chroot(const char * 
+@@ -436,9 +483,10 @@
  {
        int error;
        struct nameidata nd;
        if (error)
                goto out;
  
-@@ -454,39 +502,56 @@ asmlinkage long sys_chroot(const char * 
+@@ -454,39 +502,56 @@
        set_fs_altroot();
        error = 0;
  dput_and_out:
        fput(file);
  out:
        return err;
-@@ -495,30 +560,14 @@ out:
+@@ -495,30 +560,14 @@
  asmlinkage long sys_chmod(const char * filename, mode_t mode)
  {
        struct nameidata nd;
        path_release(&nd);
  out:
        return error;
-@@ -538,6 +587,20 @@ static int chown_common(struct dentry * 
+@@ -538,6 +587,20 @@
        error = -EROFS;
        if (IS_RDONLY(inode))
                goto out;
        error = -EPERM;
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
                goto out;
-@@ -642,6 +705,7 @@ struct file *filp_open(const char * file
+@@ -642,6 +705,7 @@
  {
        int namei_flags, error;
        struct nameidata nd;
  
        namei_flags = flags;
        if ((namei_flags+1) & O_ACCMODE)
-@@ -649,14 +713,15 @@ struct file *filp_open(const char * file
+@@ -649,14 +713,15 @@
        if (namei_flags & O_TRUNC)
                namei_flags |= 2;
  
  {
        struct file * f;
        struct inode *inode;
-@@ -693,12 +758,15 @@ struct file *dentry_open(struct dentry *
+@@ -693,12 +758,15 @@
        }
  
        if (f->f_op && f->f_op->open) {
        return f;
  
  cleanup_all:
-@@ -713,11 +781,17 @@ cleanup_all:
+@@ -713,11 +781,17 @@
  cleanup_file:
        put_filp(f);
  cleanup_dentry:
  /*
   * Find an empty file descriptor entry, and mark it busy.
   */
---- linux-2.4.20-hp4-pnnl13/fs/stat.c~vfs_intent-2.4.20-hp     2001-09-14 03:04:43.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/stat.c   2003-09-14 17:34:07.000000000 +0400
-@@ -17,10 +17,14 @@
+Index: linux/fs/stat.c
+===================================================================
+--- linux.orig/fs/stat.c       Thu Sep 13 19:04:43 2001
++++ linux/fs/stat.c    Wed Mar 17 13:12:31 2004
+@@ -17,10 +17,12 @@
   * Revalidate the inode. This is required for proper NFS attribute caching.
   */
  static __inline__ int
  {
        struct inode * inode = dentry->d_inode;
 -      if (inode->i_op && inode->i_op->revalidate)
-+      if (!inode)
-+              return -ENOENT;
 +      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;
  }
-@@ -135,13 +139,15 @@ static int cp_new_stat(struct inode * in
+@@ -135,13 +137,15 @@
  asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
  {
        struct nameidata nd;
                path_release(&nd);
        }
        return error;
-@@ -151,13 +157,15 @@ asmlinkage long sys_stat(char * filename
+@@ -151,13 +155,15 @@
  asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
  {
        struct nameidata nd;
                path_release(&nd);
        }
        return error;
-@@ -172,13 +180,15 @@ asmlinkage long sys_newstat(char * filen
+@@ -172,13 +178,15 @@
  asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
  {
        struct nameidata nd;
                path_release(&nd);
        }
        return error;
-@@ -189,13 +199,15 @@ asmlinkage long sys_lstat(char * filenam
+@@ -189,13 +197,15 @@
  asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
  {
        struct nameidata nd;
                path_release(&nd);
        }
        return error;
-@@ -216,7 +228,7 @@ asmlinkage long sys_fstat(unsigned int f
+@@ -216,7 +226,7 @@
        if (f) {
                struct dentry * dentry = f->f_dentry;
  
                if (!err)
                        err = cp_old_stat(dentry->d_inode, statbuf);
                fput(f);
-@@ -235,7 +247,7 @@ asmlinkage long sys_newfstat(unsigned in
+@@ -235,7 +245,7 @@
        if (f) {
                struct dentry * dentry = f->f_dentry;
  
                if (!err)
                        err = cp_new_stat(dentry->d_inode, statbuf);
                fput(f);
-@@ -257,7 +269,7 @@ asmlinkage long sys_readlink(const char 
+@@ -257,7 +267,7 @@
  
                error = -EINVAL;
                if (inode->i_op && inode->i_op->readlink &&
                        UPDATE_ATIME(inode);
                        error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
                }
-@@ -333,12 +345,14 @@ asmlinkage long sys_stat64(char * filena
+@@ -333,12 +343,14 @@
  {
        struct nameidata nd;
        int error;
                path_release(&nd);
        }
        return error;
-@@ -348,12 +362,14 @@ asmlinkage long sys_lstat64(char * filen
+@@ -348,12 +360,14 @@
  {
        struct nameidata nd;
        int error;
                path_release(&nd);
        }
        return error;
-@@ -368,7 +384,7 @@ asmlinkage long sys_fstat64(unsigned lon
+@@ -368,7 +382,7 @@
        if (f) {
                struct dentry * dentry = f->f_dentry;
  
                if (!err)
                        err = cp_new_stat64(dentry->d_inode, statbuf);
                fput(f);
---- linux-2.4.20-hp4-pnnl13/fs/proc/base.c~vfs_intent-2.4.20-hp        2003-09-13 15:19:19.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/proc/base.c      2003-09-14 17:33:51.000000000 +0400
-@@ -481,6 +481,9 @@ static int proc_pid_follow_link(struct d
+Index: linux/fs/proc/base.c
+===================================================================
+--- linux.orig/fs/proc/base.c  Wed Mar 17 13:00:35 2004
++++ linux/fs/proc/base.c       Wed Mar 17 13:11:25 2004
+@@ -481,6 +481,9 @@
  
        error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt);
        nd->last_type = LAST_BIND;
  out:
        return error;
  }
---- linux-2.4.20-hp4-pnnl13/include/linux/dcache.h~vfs_intent-2.4.20-hp        2002-11-29 02:53:15.000000000 +0300
-+++ linux-2.4.20-hp4-pnnl13-alexey/include/linux/dcache.h      2003-09-14 17:33:51.000000000 +0400
+Index: linux/include/linux/dcache.h
+===================================================================
+--- linux.orig/include/linux/dcache.h  Thu Nov 28 18:53:15 2002
++++ linux/include/linux/dcache.h       Wed Mar 17 13:11:25 2004
 @@ -6,6 +6,51 @@
  #include <asm/atomic.h>
  #include <linux/mount.h>
  
  /*
   * linux/include/linux/dcache.h
-@@ -91,8 +136,22 @@ struct dentry_operations {
+@@ -91,8 +136,22 @@
        int (*d_delete)(struct dentry *);
        void (*d_release)(struct dentry *);
        void (*d_iput)(struct dentry *, struct inode *);
  /* 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 @@ d_iput:            no              no              yes
+@@ -124,6 +183,7 @@
                                         * s_nfsd_free_path semaphore will be down
                                         */
  #define DCACHE_REFERENCED     0x0008  /* Recently used, don't discard. */
  
  extern spinlock_t dcache_lock;
  
---- linux-2.4.20-hp4-pnnl13/include/linux/fs.h~vfs_intent-2.4.20-hp    2003-09-14 17:33:50.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/include/linux/fs.h  2003-09-14 17:33:51.000000000 +0400
-@@ -73,6 +73,7 @@ extern int leases_enable, dir_notify_ena
+Index: linux/include/linux/fs.h
+===================================================================
+--- linux.orig/include/linux/fs.h      Wed Mar 17 13:11:23 2004
++++ linux/include/linux/fs.h   Wed Mar 17 13:11:31 2004
+@@ -73,6 +73,7 @@
  
  #define FMODE_READ 1
  #define FMODE_WRITE 2
  
  #define READ 0
  #define WRITE 1
-@@ -340,6 +341,9 @@ extern void set_bh_page(struct buffer_he
+@@ -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
  
  /*
   * This is the Inode Attributes structure, used for notify_change().  It
-@@ -474,6 +478,7 @@ struct inode {
+@@ -474,6 +478,7 @@
        struct pipe_inode_info  *i_pipe;
        struct block_device     *i_bdev;
        struct char_device      *i_cdev;
  
        unsigned long           i_dnotify_mask; /* Directory notify events */
        struct dnotify_struct   *i_dnotify; /* for directory notifications */
-@@ -576,6 +581,7 @@ struct file {
+@@ -576,6 +581,7 @@
  
        /* needed for tty driver, and maybe others */
        void                    *private_data;
  
        /* preallocated helper kiobuf to speedup O_DIRECT */
        struct kiobuf           *f_iobuf;
-@@ -697,6 +703,7 @@ struct nameidata {
+@@ -697,6 +703,7 @@
        struct qstr last;
        unsigned int flags;
        int last_type;
  };
  
  /*
-@@ -817,7 +824,8 @@ extern int vfs_symlink(struct inode *, s
+@@ -817,7 +824,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 *);
  
  /*
   * File types
-@@ -877,21 +885,32 @@ struct file_operations {
+@@ -877,21 +885,32 @@
  
  struct inode_operations {
        int (*create) (struct inode *,struct dentry *,int);
        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);
-@@ -1088,10 +1107,14 @@ static inline int get_lease(struct inode
+@@ -1088,10 +1107,14 @@
  
  asmlinkage long sys_open(const char *, int, int);
  asmlinkage long sys_close(unsigned int);      /* yes, it's really unsigned */
  extern int filp_close(struct file *, fl_owner_t id);
  extern char * getname(const char *);
  
-@@ -1353,6 +1376,7 @@ typedef int (*read_actor_t)(read_descrip
+@@ -1354,6 +1377,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(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 *));
-@@ -1364,6 +1388,8 @@ extern struct dentry * lookup_one_len(co
+@@ -1365,6 +1389,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_link_it(name,nd,it) __user_walk_it(name, LOOKUP_POSITIVE, nd, it)
  
  extern void inode_init_once(struct inode *);
- extern void iput(struct inode *);
-@@ -1499,6 +1525,8 @@ extern struct file_operations generic_ro
+ extern void _inode_init_once(struct inode *);
+@@ -1503,6 +1529,8 @@
  
  extern int vfs_readlink(struct dentry *, char *, int, const char *);
  extern int vfs_follow_link(struct nameidata *, const char *);
  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;
---- linux-2.4.20-hp4-pnnl13/include/linux/fs_struct.h~vfs_intent-2.4.20-hp     2001-07-14 02:10:44.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/include/linux/fs_struct.h   2003-09-14 17:33:51.000000000 +0400
-@@ -34,10 +34,12 @@ static inline void set_fs_root(struct fs
+Index: linux/include/linux/fs_struct.h
+===================================================================
+--- linux.orig/include/linux/fs_struct.h       Fri Jul 13 18:10:44 2001
++++ linux/include/linux/fs_struct.h    Wed Mar 17 13:11:25 2004
+@@ -34,10 +34,12 @@
        write_lock(&fs->lock);
        old_root = fs->root;
        old_rootmnt = fs->rootmnt;
                dput(old_root);
                mntput(old_rootmnt);
        }
-@@ -57,10 +59,12 @@ static inline void set_fs_pwd(struct fs_
+@@ -57,10 +59,12 @@
        write_lock(&fs->lock);
        old_pwd = fs->pwd;
        old_pwdmnt = fs->pwdmnt;
                dput(old_pwd);
                mntput(old_pwdmnt);
        }
---- linux-2.4.20-hp4-pnnl13/kernel/ksyms.c~vfs_intent-2.4.20-hp        2003-09-14 17:33:50.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/kernel/ksyms.c      2003-09-14 17:33:51.000000000 +0400
-@@ -296,6 +296,7 @@ EXPORT_SYMBOL(read_cache_page);
+Index: linux/kernel/ksyms.c
+===================================================================
+--- linux.orig/kernel/ksyms.c  Wed Mar 17 13:11:23 2004
++++ linux/kernel/ksyms.c       Wed Mar 17 13:11:25 2004
+@@ -315,6 +315,7 @@
  EXPORT_SYMBOL(set_page_dirty);
  EXPORT_SYMBOL(vfs_readlink);
  EXPORT_SYMBOL(vfs_follow_link);
  EXPORT_SYMBOL(page_readlink);
  EXPORT_SYMBOL(page_follow_link);
  EXPORT_SYMBOL(page_symlink_inode_operations);
---- linux-2.4.20-hp4-pnnl13/kernel/fork.c~vfs_intent-2.4.20-hp 2003-09-13 15:19:27.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/kernel/fork.c       2003-09-14 17:33:51.000000000 +0400
-@@ -388,10 +388,13 @@ static inline struct fs_struct *__copy_f
+Index: linux/kernel/fork.c
+===================================================================
+--- linux.orig/kernel/fork.c   Wed Mar 17 13:00:38 2004
++++ linux/kernel/fork.c        Wed Mar 17 13:11:25 2004
+@@ -387,10 +387,13 @@
                fs->umask = old->umask;
                read_lock(&old->lock);
                fs->rootmnt = mntget(old->rootmnt);
                        fs->altrootmnt = mntget(old->altrootmnt);
                        fs->altroot = dget(old->altroot);
                } else {
---- linux-2.4.20-hp4-pnnl13/kernel/exit.c~vfs_intent-2.4.20-hp 2003-09-13 15:19:27.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/kernel/exit.c       2003-09-14 17:33:51.000000000 +0400
-@@ -239,11 +239,14 @@ static inline void __put_fs_struct(struc
+Index: linux/kernel/exit.c
+===================================================================
+--- linux.orig/kernel/exit.c   Wed Mar 17 13:00:38 2004
++++ linux/kernel/exit.c        Wed Mar 17 13:11:25 2004
+@@ -239,11 +239,14 @@
  {
        /* No need to hold fs->lock if we are killing it */
        if (atomic_dec_and_test(&fs->count)) {
                        dput(fs->altroot);
                        mntput(fs->altrootmnt);
                }
-
-_
index f9096db..409c8f0 100644 (file)
  kernel/ksyms.c            |    1 
  13 files changed, 578 insertions(+), 129 deletions(-)
 
---- linux-2.4.20-rh-20.9/fs/dcache.c~vfs_intent-2.4.20-rh      2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/dcache.c    2003-09-14 17:34:53.000000000 +0400
-@@ -186,6 +186,13 @@ int d_invalidate(struct dentry * dentry)
+Index: linux-2.4.20/fs/dcache.c
+===================================================================
+--- linux-2.4.20.orig/fs/dcache.c      Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/fs/dcache.c   Wed Mar 17 13:57:11 2004
+@@ -186,6 +186,13 @@
                spin_unlock(&dcache_lock);
                return 0;
        }
@@ -29,7 +31,7 @@
        /*
         * Check whether to do a partial shrink_dcache
         * to get rid of unused child entries.
-@@ -841,13 +848,19 @@ void d_delete(struct dentry * dentry)
+@@ -841,13 +848,19 @@
   * Adds a dentry to the hash according to its name.
   */
   
  }
  
  #define do_switch(x,y) do { \
---- linux-2.4.20-rh-20.9/fs/exec.c~vfs_intent-2.4.20-rh        2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/exec.c      2003-09-14 17:34:53.000000000 +0400
-@@ -114,8 +114,10 @@ asmlinkage long sys_uselib(const char * 
+Index: linux-2.4.20/fs/exec.c
+===================================================================
+--- linux-2.4.20.orig/fs/exec.c        Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/fs/exec.c     Wed Mar 17 13:57:11 2004
+@@ -114,8 +114,10 @@
        struct file * file;
        struct nameidata nd;
        int error;
@@ -66,7 +70,7 @@
        if (error)
                goto out;
  
-@@ -127,7 +129,8 @@ asmlinkage long sys_uselib(const char * 
+@@ -127,7 +129,8 @@
        if (error)
                goto exit;
  
@@ -76,7 +80,7 @@
        error = PTR_ERR(file);
        if (IS_ERR(file))
                goto out;
-@@ -382,8 +385,10 @@ struct file *open_exec(const char *name)
+@@ -382,8 +385,10 @@
        struct inode *inode;
        struct file *file;
        int err = 0;
@@ -88,7 +92,7 @@
        file = ERR_PTR(err);
        if (!err) {
                inode = nd.dentry->d_inode;
-@@ -395,7 +400,8 @@ struct file *open_exec(const char *name)
+@@ -395,7 +400,8 @@
                                err = -EACCES;
                        file = ERR_PTR(err);
                        if (!err) {
                                if (!IS_ERR(file)) {
                                        err = deny_write_access(file);
                                        if (err) {
-@@ -407,6 +413,7 @@ out:
+@@ -407,6 +413,7 @@
                                return file;
                        }
                }
                path_release(&nd);
        }
        goto out;
-@@ -1296,7 +1303,7 @@ int do_coredump(long signr, int exit_cod
+@@ -1296,7 +1303,7 @@
                goto close_fail;
        if (!file->f_op->write)
                goto close_fail;
                goto close_fail;
  
        retval = binfmt->core_dump(signr, regs, file);
---- linux-2.4.20-rh-20.9/fs/namei.c~vfs_intent-2.4.20-rh       2003-09-13 19:34:25.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/namei.c     2003-09-14 17:34:53.000000000 +0400
+Index: linux-2.4.20/fs/namei.c
+===================================================================
+--- linux-2.4.20.orig/fs/namei.c       Wed Mar 17 13:57:03 2004
++++ linux-2.4.20/fs/namei.c    Wed Mar 17 13:58:01 2004
 @@ -94,6 +94,13 @@
   * XEmacs seems to be relying on 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 @@ void path_release(struct nameidata *nd)
+@@ -260,10 +267,19 @@
   * Internal lookup() using the new generic dcache.
   * SMP-safe
   */
        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 @@ static struct dentry * cached_lookup(str
+@@ -281,11 +297,15 @@
   * make sure that nobody added the entry to the dcache in the meantime..
   * SMP-safe
   */
        down(&dir->i_sem);
        /*
         * First re-do the cached lookup just in case it was created
-@@ -300,6 +320,9 @@ static struct dentry * real_lookup(struc
+@@ -300,6 +320,9 @@
                result = ERR_PTR(-ENOMEM);
                if (dentry) {
                        lock_kernel();
                        result = dir->i_op->lookup(dir, dentry);
                        unlock_kernel();
                        if (result)
-@@ -321,6 +344,15 @@ static struct dentry * real_lookup(struc
+@@ -321,6 +344,15 @@
                        dput(result);
                        result = ERR_PTR(-ENOENT);
                }
        }
        return result;
  }
-@@ -334,7 +366,8 @@ int max_recursive_link = 5;
+@@ -334,7 +366,8 @@
   * Without that kind of total limit, nasty chains of consecutive
   * symlinks can cause almost arbitrarily long lookups. 
   */
  {
        int err;
        if (current->link_count >= max_recursive_link)
-@@ -348,10 +381,18 @@ static inline int do_follow_link(struct 
+@@ -348,10 +381,18 @@
        current->link_count++;
        current->total_link_count++;
        UPDATE_ATIME(dentry->d_inode);
        path_release(nd);
        return -ELOOP;
  }
-@@ -381,15 +422,26 @@ int follow_up(struct vfsmount **mnt, str
+@@ -381,15 +422,26 @@
        return __follow_up(mnt, dentry);
  }
  
                dput(*dentry);
                mntput(mounted->mnt_parent);
                *dentry = dget(mounted->mnt_root);
-@@ -401,7 +453,7 @@ static inline int __follow_down(struct v
+@@ -401,7 +453,7 @@
  
  int follow_down(struct vfsmount **mnt, struct dentry **dentry)
  {
  }
   
  static inline void follow_dotdot(struct nameidata *nd)
-@@ -437,7 +489,7 @@ static inline void follow_dotdot(struct 
+@@ -437,7 +489,7 @@
                mntput(nd->mnt);
                nd->mnt = parent;
        }
                ;
  }
  
-@@ -449,7 +501,8 @@ static inline void follow_dotdot(struct 
+@@ -449,7 +501,8 @@
   *
   * We expect 'base' to be positive and a directory.
   */
  {
        struct dentry *dentry;
        struct inode *inode;
-@@ -526,19 +579,18 @@ int link_path_walk(const char * name, st
+@@ -526,19 +579,18 @@
                                break;
                }
                /* This does the actual lookups.. */
  
                err = -ENOENT;
                inode = dentry->d_inode;
-@@ -549,7 +601,7 @@ int link_path_walk(const char * name, st
+@@ -549,7 +601,7 @@
                        goto out_dput;
  
                if (inode->i_op->follow_link) {
                        dput(dentry);
                        if (err)
                                goto return_err;
-@@ -565,7 +617,7 @@ int link_path_walk(const char * name, st
+@@ -565,7 +617,7 @@
                        nd->dentry = dentry;
                }
                err = -ENOTDIR; 
                        break;
                continue;
                /* here ends the main loop */
-@@ -592,22 +644,22 @@ last_component:
+@@ -592,22 +644,22 @@
                        if (err < 0)
                                break;
                }
                        dput(dentry);
                        if (err)
                                goto return_err;
-@@ -621,7 +673,8 @@ last_component:
+@@ -621,7 +673,8 @@
                        goto no_inode;
                if (lookup_flags & LOOKUP_DIRECTORY) {
                        err = -ENOTDIR; 
                                break;
                }
                goto return_base;
-@@ -645,6 +698,25 @@ return_reval:
+@@ -645,6 +698,27 @@
                 * Check the cached dentry for staleness.
                 */
                dentry = nd->dentry;
 +                              }
 +                              nd->dentry = new;
 +                      }
++                      if (!nd->dentry->d_inode)
++                              goto no_inode;
 +              } else
                if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
                        err = -ESTALE;
                        if (!dentry->d_op->d_revalidate(dentry, 0)) {
-@@ -658,15 +730,28 @@ out_dput:
+@@ -658,15 +732,28 @@
                dput(dentry);
                break;
        }
  }
  
  /* SMP-safe */
-@@ -751,6 +836,17 @@ walk_init_root(const char *name, struct 
+@@ -751,6 +838,17 @@
  }
  
  /* SMP-safe */
  int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
  {
        int error = 0;
-@@ -765,6 +861,7 @@ int path_init(const char *name, unsigned
+@@ -765,6 +863,7 @@
  {
        nd->last_type = LAST_ROOT; /* if there are only slashes... */
        nd->flags = flags;
        if (*name=='/')
                return walk_init_root(name,nd);
        read_lock(&current->fs->lock);
-@@ -779,7 +876,8 @@ int path_init(const char *name, unsigned
+@@ -779,7 +878,8 @@
   * needs parent already locked. Doesn't follow mounts.
   * SMP-safe.
   */
  {
        struct dentry * dentry;
        struct inode *inode;
-@@ -802,13 +900,16 @@ struct dentry * lookup_hash(struct qstr 
+@@ -802,13 +902,16 @@
                        goto out;
        }
  
                dentry = inode->i_op->lookup(inode, new);
                unlock_kernel();
                if (!dentry)
-@@ -820,6 +921,12 @@ out:
+@@ -820,6 +923,12 @@
        return dentry;
  }
  
  /* SMP-safe */
  struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
  {
-@@ -841,7 +948,7 @@ struct dentry * lookup_one_len(const cha
+@@ -841,7 +950,7 @@
        }
        this.hash = end_name_hash(hash);
  
  access:
        return ERR_PTR(-EACCES);
  }
-@@ -872,6 +979,23 @@ int __user_walk(const char *name, unsign
+@@ -872,6 +981,23 @@
        return err;
  }
  
  /*
   * It's inline, so penalty for filesystems that don't use sticky bit is
   * minimal.
-@@ -969,7 +1093,8 @@ static inline int lookup_flags(unsigned 
+@@ -969,7 +1095,8 @@
        return retval;
  }
  
  {
        int error;
  
-@@ -982,12 +1107,15 @@ int vfs_create(struct inode *dir, struct
+@@ -982,12 +1109,15 @@
                goto exit_lock;
  
        error = -EACCES;        /* shouldn't it be ENOSYS? */
        unlock_kernel();
  exit_lock:
        up(&dir->i_zombie);
-@@ -996,6 +1124,11 @@ exit_lock:
+@@ -996,6 +1126,11 @@
        return error;
  }
  
  /*
   *    open_namei()
   *
-@@ -1010,7 +1143,8 @@ exit_lock:
+@@ -1010,7 +1145,8 @@
   * for symlinks (where the permissions are checked later).
   * SMP-safe
   */
  {
        int acc_mode, error = 0;
        struct inode *inode;
-@@ -1020,11 +1154,14 @@ int open_namei(const char * pathname, in
+@@ -1020,11 +1156,14 @@
  
        acc_mode = ACC_MODE(flag);
  
                if (error)
                        return error;
                dentry = nd->dentry;
-@@ -1034,6 +1171,10 @@ int open_namei(const char * pathname, in
+@@ -1034,6 +1173,10 @@
        /*
         * Create - we need to know the parent.
         */
        error = path_lookup(pathname, LOOKUP_PARENT, nd);
        if (error)
                return error;
-@@ -1049,7 +1190,7 @@ int open_namei(const char * pathname, in
+@@ -1049,7 +1192,7 @@
  
        dir = nd->dentry;
        down(&dir->d_inode->i_sem);
  
  do_last:
        error = PTR_ERR(dentry);
-@@ -1058,10 +1199,11 @@ do_last:
+@@ -1058,10 +1201,11 @@
                goto exit;
        }
  
                up(&dir->d_inode->i_sem);
                dput(nd->dentry);
                nd->dentry = dentry;
-@@ -1086,7 +1228,7 @@ do_last:
+@@ -1086,7 +1230,7 @@
                error = -ELOOP;
                if (flag & O_NOFOLLOW)
                        goto exit_dput;
        }
        error = -ENOENT;
        if (!dentry->d_inode)
-@@ -1165,7 +1307,7 @@ ok:
+@@ -1165,7 +1309,7 @@
                if (!error) {
                        DQUOT_INIT(inode);
                        
                }
                put_write_access(inode);
                if (error)
-@@ -1177,8 +1319,10 @@ ok:
+@@ -1177,8 +1321,10 @@
        return 0;
  
  exit_dput:
        path_release(nd);
        return error;
  
-@@ -1197,7 +1341,16 @@ do_link:
+@@ -1197,7 +1343,16 @@
         * are done. Procfs-like symlinks just set LAST_BIND.
         */
        UPDATE_ATIME(dentry->d_inode);
        dput(dentry);
        if (error)
                return error;
-@@ -1219,13 +1372,20 @@ do_link:
+@@ -1219,13 +1374,20 @@
        }
        dir = nd->dentry;
        down(&dir->d_inode->i_sem);
  {
        struct dentry *dentry;
  
-@@ -1233,7 +1393,7 @@ static struct dentry *lookup_create(stru
+@@ -1233,7 +1395,7 @@
        dentry = ERR_PTR(-EEXIST);
        if (nd->last_type != LAST_NORM)
                goto fail;
        if (IS_ERR(dentry))
                goto fail;
        if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
-@@ -1289,7 +1449,16 @@ asmlinkage long sys_mknod(const char * f
+@@ -1289,7 +1451,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);
        error = PTR_ERR(dentry);
  
        mode &= ~current->fs->umask;
-@@ -1310,6 +1479,7 @@ asmlinkage long sys_mknod(const char * f
+@@ -1310,6 +1485,7 @@
                dput(dentry);
        }
        up(&nd.dentry->d_inode->i_sem);
        path_release(&nd);
  out:
        putname(tmp);
-@@ -1357,7 +1527,14 @@ asmlinkage long sys_mkdir(const char * p
+@@ -1357,7 +1533,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);
                error = PTR_ERR(dentry);
                if (!IS_ERR(dentry)) {
                        error = vfs_mkdir(nd.dentry->d_inode, dentry,
-@@ -1365,6 +1542,7 @@ asmlinkage long sys_mkdir(const char * p
+@@ -1365,6 +1552,7 @@
                        dput(dentry);
                }
                up(&nd.dentry->d_inode->i_sem);
                path_release(&nd);
  out:
                putname(tmp);
-@@ -1465,8 +1643,16 @@ asmlinkage long sys_rmdir(const char * p
+@@ -1465,8 +1653,16 @@
                        error = -EBUSY;
                        goto exit1;
        }
        error = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
                error = vfs_rmdir(nd.dentry->d_inode, dentry);
-@@ -1524,8 +1710,15 @@ asmlinkage long sys_unlink(const char * 
+@@ -1524,8 +1720,15 @@
        error = -EISDIR;
        if (nd.last_type != LAST_NORM)
                goto exit1;
        error = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
                /* Why not before? Because we want correct error value */
-@@ -1592,15 +1785,23 @@ asmlinkage long sys_symlink(const char *
+@@ -1592,15 +1795,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);
                putname(to);
        }
        putname(from);
-@@ -1676,7 +1877,14 @@ asmlinkage long sys_link(const char * ol
+@@ -1676,7 +1891,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);
                error = PTR_ERR(new_dentry);
                if (!IS_ERR(new_dentry)) {
                        error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
-@@ -1720,7 +1928,7 @@ exit:
+@@ -1720,7 +1946,7 @@
   *       locking].
   */
  int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
  {
        int error;
        struct inode *target;
-@@ -1799,7 +2007,7 @@ out_unlock:
+@@ -1799,7 +2025,7 @@
  }
  
  int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
  {
        int error;
  
-@@ -1887,9 +2095,18 @@ static inline int do_rename(const char *
+@@ -1887,9 +2113,18 @@
        if (newnd.last_type != LAST_NORM)
                goto exit2;
  
        error = PTR_ERR(old_dentry);
        if (IS_ERR(old_dentry))
                goto exit3;
-@@ -1905,16 +2122,16 @@ static inline int do_rename(const char *
+@@ -1905,16 +2140,16 @@
                if (newnd.last.name[newnd.last.len])
                        goto exit4;
        }
        dput(new_dentry);
  exit4:
        dput(old_dentry);
-@@ -1965,20 +2182,28 @@ out:
+@@ -1965,20 +2200,28 @@
  }
  
  static inline int
  out:
        if (current->link_count || res || nd->last_type!=LAST_NORM)
                return res;
-@@ -2002,7 +2227,13 @@ fail:
+@@ -2002,7 +2245,13 @@
  
  int vfs_follow_link(struct nameidata *nd, const char *link)
  {
  }
  
  /* get the link contents into pagecache */
-@@ -2044,7 +2275,7 @@ int page_follow_link(struct dentry *dent
+@@ -2044,7 +2293,7 @@
  {
        struct page *page = NULL;
        char *s = page_getlink(dentry, &page);
        if (page) {
                kunmap(page);
                page_cache_release(page);
---- linux-2.4.20-rh-20.9/fs/namespace.c~vfs_intent-2.4.20-rh   2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/namespace.c 2003-09-14 17:34:53.000000000 +0400
-@@ -99,6 +99,7 @@ static void detach_mnt(struct vfsmount *
+Index: linux-2.4.20/fs/namespace.c
+===================================================================
+--- linux-2.4.20.orig/fs/namespace.c   Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/fs/namespace.c        Wed Mar 17 13:57:11 2004
+@@ -99,6 +99,7 @@
  {
        old_nd->dentry = mnt->mnt_mountpoint;
        old_nd->mnt = mnt->mnt_parent;
        mnt->mnt_parent = mnt;
        mnt->mnt_mountpoint = mnt->mnt_root;
        list_del_init(&mnt->mnt_child);
-@@ -110,6 +111,7 @@ static void attach_mnt(struct vfsmount *
+@@ -110,6 +111,7 @@
  {
        mnt->mnt_parent = mntget(nd->mnt);
        mnt->mnt_mountpoint = dget(nd->dentry);
        list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry));
        list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts);
        nd->dentry->d_mounted++;
-@@ -485,14 +487,17 @@ static int do_loopback(struct nameidata 
+@@ -485,14 +487,17 @@
  {
        struct nameidata old_nd;
        struct vfsmount *mnt = NULL;
  
        down_write(&current->namespace->sem);
        err = -EINVAL;
-@@ -515,6 +520,7 @@ static int do_loopback(struct nameidata 
+@@ -515,6 +520,7 @@
        }
  
        up_write(&current->namespace->sem);
        path_release(&old_nd);
        return err;
  }
-@@ -698,6 +704,7 @@ long do_mount(char * dev_name, char * di
+@@ -698,6 +704,7 @@
                  unsigned long flags, void *data_page)
  {
        struct nameidata nd;
        int retval = 0;
        int mnt_flags = 0;
  
-@@ -722,10 +729,11 @@ long do_mount(char * dev_name, char * di
+@@ -722,10 +729,11 @@
        flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
  
        /* ... and get the mountpoint */
        if (flags & MS_REMOUNT)
                retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
                                    data_page);
-@@ -736,6 +744,8 @@ long do_mount(char * dev_name, char * di
+@@ -736,6 +744,8 @@
        else
                retval = do_add_mount(&nd, type_page, flags, mnt_flags,
                                      dev_name, data_page);
        path_release(&nd);
        return retval;
  }
-@@ -901,6 +911,8 @@ asmlinkage long sys_pivot_root(const cha
+@@ -901,6 +911,8 @@
  {
        struct vfsmount *tmp;
        struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
        int error;
  
        if (!capable(CAP_SYS_ADMIN))
-@@ -908,14 +920,14 @@ asmlinkage long sys_pivot_root(const cha
+@@ -908,14 +920,14 @@
  
        lock_kernel();
  
        if (error)
                goto out1;
  
-@@ -970,8 +982,10 @@ out2:
+@@ -970,8 +982,10 @@
        up(&old_nd.dentry->d_inode->i_zombie);
        up_write(&current->namespace->sem);
        path_release(&user_nd);
        path_release(&new_nd);
  out0:
        unlock_kernel();
---- linux-2.4.20-rh-20.9/fs/open.c~vfs_intent-2.4.20-rh        2003-09-13 19:34:25.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/open.c      2003-09-14 17:34:53.000000000 +0400
+Index: linux-2.4.20/fs/open.c
+===================================================================
+--- linux-2.4.20.orig/fs/open.c        Wed Mar 17 13:57:03 2004
++++ linux-2.4.20/fs/open.c     Wed Mar 17 13:57:11 2004
 @@ -19,6 +19,8 @@
  #include <asm/uaccess.h>
  
  
  int vfs_statfs(struct super_block *sb, struct statfs *buf)
  {
-@@ -95,9 +97,10 @@ void fd_install(unsigned int fd, struct 
+@@ -95,9 +97,10 @@
        write_unlock(&files->file_lock);
  }
  
        int error;
        struct iattr newattrs;
  
-@@ -108,7 +111,13 @@ int do_truncate(struct dentry *dentry, l
+@@ -108,7 +111,13 @@
        down(&inode->i_sem);
        newattrs.ia_size = length;
        newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
        up(&inode->i_sem);
        return error;
  }
-@@ -118,12 +127,13 @@ static inline long do_sys_truncate(const
+@@ -118,12 +127,13 @@
        struct nameidata nd;
        struct inode * inode;
        int error;
        if (error)
                goto out;
        inode = nd.dentry->d_inode;
-@@ -163,11 +173,13 @@ static inline long do_sys_truncate(const
+@@ -163,11 +173,13 @@
        error = locks_verify_truncate(inode, NULL, length);
        if (!error) {
                DQUOT_INIT(inode);
        path_release(&nd);
  out:
        return error;
-@@ -215,7 +227,7 @@ static inline long do_sys_ftruncate(unsi
+@@ -215,7 +227,7 @@
  
        error = locks_verify_truncate(inode, file, length);
        if (!error)
  out_putf:
        fput(file);
  out:
-@@ -260,11 +272,13 @@ asmlinkage long sys_utime(char * filenam
+@@ -260,11 +272,13 @@
        struct inode * inode;
        struct iattr newattrs;
  
        error = -EROFS;
        if (IS_RDONLY(inode))
                goto dput_and_out;
-@@ -279,11 +293,25 @@ asmlinkage long sys_utime(char * filenam
+@@ -279,11 +293,25 @@
                        goto dput_and_out;
  
                newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
        error = notify_change(nd.dentry, &newattrs);
  dput_and_out:
        path_release(&nd);
-@@ -304,12 +332,14 @@ asmlinkage long sys_utimes(char * filena
+@@ -304,12 +332,14 @@
        struct inode * inode;
        struct iattr newattrs;
  
        error = -EROFS;
        if (IS_RDONLY(inode))
                goto dput_and_out;
-@@ -324,7 +354,20 @@ asmlinkage long sys_utimes(char * filena
+@@ -324,7 +354,20 @@
                newattrs.ia_atime = times[0].tv_sec;
                newattrs.ia_mtime = times[1].tv_sec;
                newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
                if (current->fsuid != inode->i_uid &&
                    (error = permission(inode,MAY_WRITE)) != 0)
                        goto dput_and_out;
-@@ -347,6 +390,7 @@ asmlinkage long sys_access(const char * 
+@@ -347,6 +390,7 @@
        int old_fsuid, old_fsgid;
        kernel_cap_t old_cap;
        int res;
  
        if (mode & ~S_IRWXO)    /* where's F_OK, X_OK, W_OK, R_OK? */
                return -EINVAL;
-@@ -364,13 +408,14 @@ asmlinkage long sys_access(const char * 
+@@ -364,13 +408,14 @@
        else
                current->cap_effective = current->cap_permitted;
  
                path_release(&nd);
        }
  
-@@ -385,8 +430,9 @@ asmlinkage long sys_chdir(const char * f
+@@ -385,8 +430,9 @@
  {
        int error;
        struct nameidata nd;
        if (error)
                goto out;
  
-@@ -397,6 +443,7 @@ asmlinkage long sys_chdir(const char * f
+@@ -397,6 +443,7 @@
        set_fs_pwd(current->fs, nd.mnt, nd.dentry);
  
  dput_and_out:
        path_release(&nd);
  out:
        return error;
-@@ -436,9 +483,10 @@ asmlinkage long sys_chroot(const char * 
+@@ -436,9 +483,10 @@
  {
        int error;
        struct nameidata nd;
        if (error)
                goto out;
  
-@@ -454,39 +502,56 @@ asmlinkage long sys_chroot(const char * 
+@@ -454,39 +502,56 @@
        set_fs_altroot();
        error = 0;
  dput_and_out:
        fput(file);
  out:
        return err;
-@@ -495,30 +560,14 @@ out:
+@@ -495,30 +560,14 @@
  asmlinkage long sys_chmod(const char * filename, mode_t mode)
  {
        struct nameidata nd;
        path_release(&nd);
  out:
        return error;
-@@ -538,6 +587,20 @@ static int chown_common(struct dentry * 
+@@ -538,6 +587,20 @@
        error = -EROFS;
        if (IS_RDONLY(inode))
                goto out;
        error = -EPERM;
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
                goto out;
-@@ -642,8 +705,9 @@ struct file *filp_open(const char * file
+@@ -642,8 +705,9 @@
  {
        int namei_flags, error;
        struct nameidata nd;
  
        namei_flags = flags;
        if ((namei_flags+1) & O_ACCMODE)
-@@ -651,14 +715,15 @@ struct file *filp_open(const char * file
+@@ -651,14 +715,15 @@
        if (namei_flags & O_TRUNC)
                namei_flags |= 2;
  
  {
        struct file * f;
        struct inode *inode;
-@@ -695,12 +760,15 @@ struct file *dentry_open(struct dentry *
+@@ -695,12 +760,15 @@
        }
  
        if (f->f_op && f->f_op->open) {
        return f;
  
  cleanup_all:
-@@ -715,11 +783,17 @@ cleanup_all:
+@@ -715,11 +783,17 @@
  cleanup_file:
        put_filp(f);
  cleanup_dentry:
  /*
   * Find an empty file descriptor entry, and mark it busy.
   */
---- linux-2.4.20-rh-20.9/fs/proc/base.c~vfs_intent-2.4.20-rh   2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/proc/base.c 2003-09-14 17:34:53.000000000 +0400
-@@ -494,6 +494,9 @@ static int proc_pid_follow_link(struct d
+Index: linux-2.4.20/fs/proc/base.c
+===================================================================
+--- linux-2.4.20.orig/fs/proc/base.c   Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/fs/proc/base.c        Wed Mar 17 13:57:11 2004
+@@ -494,6 +494,9 @@
  
        error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt);
        nd->last_type = LAST_BIND;
  out:
        return error;
  }
---- linux-2.4.20-rh-20.9/fs/stat.c~vfs_intent-2.4.20-rh        2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/stat.c      2003-09-14 17:35:10.000000000 +0400
-@@ -17,10 +17,14 @@
+Index: linux-2.4.20/fs/stat.c
+===================================================================
+--- linux-2.4.20.orig/fs/stat.c        Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/fs/stat.c     Wed Mar 17 13:58:01 2004
+@@ -17,10 +17,12 @@
   * Revalidate the inode. This is required for proper NFS attribute caching.
   */
  static __inline__ int
  {
        struct inode * inode = dentry->d_inode;
 -      if (inode->i_op && inode->i_op->revalidate)
-+      if (!inode)
-+              return -ENOENT;
 +      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;
  }
-@@ -32,13 +36,13 @@ static inline nlink_t user_nlink(struct 
+@@ -32,13 +34,13 @@
        return inode->i_nlink;
  }
  
        if (res)
                return res;
  
-@@ -111,10 +115,12 @@ int vfs_stat(char *name, struct kstat *s
+@@ -111,10 +113,12 @@
  {
        struct nameidata nd;
        int error;
                path_release(&nd);
        }
        return error;
-@@ -124,10 +130,12 @@ int vfs_lstat(char *name, struct kstat *
+@@ -124,10 +128,12 @@
  {
        struct nameidata nd;
        int error;
                path_release(&nd);
        }
        return error;
-@@ -139,7 +147,7 @@ int vfs_fstat(unsigned int fd, struct ks
+@@ -139,7 +145,7 @@
        int error = -EBADF;
  
        if (f) {
                fput(f);
        }
        return error;
-@@ -286,7 +294,7 @@ asmlinkage long sys_readlink(const char 
+@@ -286,7 +292,7 @@
  
                error = -EINVAL;
                if (inode->i_op && inode->i_op->readlink &&
                        UPDATE_ATIME(inode);
                        error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
                }
---- linux-2.4.20-rh-20.9/include/linux/dcache.h~vfs_intent-2.4.20-rh   2003-09-13 19:34:28.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/include/linux/dcache.h 2003-09-14 17:34:53.000000000 +0400
+Index: linux-2.4.20/include/linux/dcache.h
+===================================================================
+--- linux-2.4.20.orig/include/linux/dcache.h   Wed Mar 17 13:57:04 2004
++++ linux-2.4.20/include/linux/dcache.h        Wed Mar 17 13:57:11 2004
 @@ -6,6 +6,51 @@
  #include <asm/atomic.h>
  #include <linux/mount.h>
  
  /*
   * linux/include/linux/dcache.h
-@@ -96,8 +141,22 @@ struct dentry_operations {
+@@ -96,8 +141,22 @@
        int (*d_delete)(struct dentry *);
        void (*d_release)(struct dentry *);
        void (*d_iput)(struct dentry *, struct inode *);
  /* 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
-@@ -129,6 +188,7 @@ d_iput:            no              no              yes
+@@ -129,6 +188,7 @@
                                         * s_nfsd_free_path semaphore will be down
                                         */
  #define DCACHE_REFERENCED     0x0008  /* Recently used, don't discard. */
  
  extern spinlock_t dcache_lock;
  
---- linux-2.4.20-rh-20.9/include/linux/fs.h~vfs_intent-2.4.20-rh       2003-09-14 17:34:50.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/include/linux/fs.h     2003-09-14 17:34:53.000000000 +0400
-@@ -73,6 +73,7 @@ extern int leases_enable, dir_notify_ena
+Index: linux-2.4.20/include/linux/fs.h
+===================================================================
+--- linux-2.4.20.orig/include/linux/fs.h       Wed Mar 17 13:57:11 2004
++++ linux-2.4.20/include/linux/fs.h    Wed Mar 17 13:57:11 2004
+@@ -73,6 +73,7 @@
  
  #define FMODE_READ 1
  #define FMODE_WRITE 2
  
  #define READ 0
  #define WRITE 1
-@@ -338,6 +339,9 @@ extern void set_bh_page(struct buffer_he
+@@ -338,6 +339,9 @@
  #define ATTR_MTIME_SET        256
  #define ATTR_FORCE    512     /* Not a change, but a change it */
  #define ATTR_ATTR_FLAG        1024
  
  /*
   * This is the Inode Attributes structure, used for notify_change().  It
-@@ -473,6 +477,7 @@ struct inode {
+@@ -473,6 +477,7 @@
        struct pipe_inode_info  *i_pipe;
        struct block_device     *i_bdev;
        struct char_device      *i_cdev;
  
        unsigned long           i_dnotify_mask; /* Directory notify events */
        struct dnotify_struct   *i_dnotify; /* for directory notifications */
-@@ -575,6 +580,7 @@ struct file {
+@@ -575,6 +580,7 @@
  
        /* needed for tty driver, and maybe others */
        void                    *private_data;
  
        /* preallocated helper kiobuf to speedup O_DIRECT */
        struct kiobuf           *f_iobuf;
-@@ -702,6 +708,7 @@ struct nameidata {
+@@ -702,6 +708,7 @@
        struct qstr last;
        unsigned int flags;
        int last_type;
  };
  
  /*
-@@ -822,7 +829,8 @@ extern int vfs_symlink(struct inode *, s
+@@ -822,7 +829,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 *);
  
  /*
   * File types
-@@ -882,21 +890,32 @@ struct file_operations {
+@@ -882,21 +890,32 @@
  
  struct inode_operations {
        int (*create) (struct inode *,struct dentry *,int);
        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);
-@@ -1092,10 +1111,14 @@ static inline int get_lease(struct inode
+@@ -1092,10 +1111,14 @@
  
  asmlinkage long sys_open(const char *, int, int);
  asmlinkage long sys_close(unsigned int);      /* yes, it's really unsigned */
  extern int filp_close(struct file *, fl_owner_t id);
  extern char * getname(const char *);
  
-@@ -1386,6 +1409,7 @@ typedef int (*read_actor_t)(read_descrip
+@@ -1386,6 +1409,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(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 *));
-@@ -1397,6 +1421,8 @@ extern struct dentry * lookup_one_len(co
+@@ -1397,6 +1421,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)
  
  extern void inode_init_once(struct inode *);
  extern void iput(struct inode *);
-@@ -1504,6 +1530,8 @@ extern struct file_operations generic_ro
+@@ -1504,6 +1530,8 @@
  
  extern int vfs_readlink(struct dentry *, char *, int, const char *);
  extern int vfs_follow_link(struct nameidata *, const char *);
  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;
---- linux-2.4.20-rh-20.9/include/linux/fs_struct.h~vfs_intent-2.4.20-rh        2003-09-13 19:34:19.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/include/linux/fs_struct.h      2003-09-14 17:34:53.000000000 +0400
-@@ -37,10 +37,12 @@ static inline void set_fs_root(struct fs
+Index: linux-2.4.20/include/linux/fs_struct.h
+===================================================================
+--- linux-2.4.20.orig/include/linux/fs_struct.h        Wed Mar 17 13:57:02 2004
++++ linux-2.4.20/include/linux/fs_struct.h     Wed Mar 17 13:57:11 2004
+@@ -37,10 +37,12 @@
        write_lock(&fs->lock);
        old_root = fs->root;
        old_rootmnt = fs->rootmnt;
                dput(old_root);
                mntput(old_rootmnt);
        }
-@@ -60,10 +62,12 @@ static inline void set_fs_pwd(struct fs_
+@@ -60,10 +62,12 @@
        write_lock(&fs->lock);
        old_pwd = fs->pwd;
        old_pwdmnt = fs->pwdmnt;
                dput(old_pwd);
                mntput(old_pwdmnt);
        }
---- linux-2.4.20-rh-20.9/kernel/ksyms.c~vfs_intent-2.4.20-rh   2003-09-14 17:34:51.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/kernel/ksyms.c 2003-09-14 17:34:53.000000000 +0400
-@@ -298,6 +298,7 @@ EXPORT_SYMBOL(read_cache_page);
+Index: linux-2.4.20/kernel/ksyms.c
+===================================================================
+--- linux-2.4.20.orig/kernel/ksyms.c   Wed Mar 17 13:57:11 2004
++++ linux-2.4.20/kernel/ksyms.c        Wed Mar 17 13:57:11 2004
+@@ -297,6 +297,7 @@
  EXPORT_SYMBOL(set_page_dirty);
  EXPORT_SYMBOL(vfs_readlink);
  EXPORT_SYMBOL(vfs_follow_link);
  EXPORT_SYMBOL(page_readlink);
  EXPORT_SYMBOL(page_follow_link);
  EXPORT_SYMBOL(page_symlink_inode_operations);
---- linux-2.4.20-rh-20.9/kernel/fork.c~vfs_intent-2.4.20-rh    2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/kernel/fork.c  2003-09-14 17:34:53.000000000 +0400
-@@ -440,10 +440,13 @@ static inline struct fs_struct *__copy_f
+Index: linux-2.4.20/kernel/fork.c
+===================================================================
+--- linux-2.4.20.orig/kernel/fork.c    Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/kernel/fork.c Wed Mar 17 13:57:11 2004
+@@ -440,10 +440,13 @@
                fs->umask = old->umask;
                read_lock(&old->lock);
                fs->rootmnt = mntget(old->rootmnt);
                        fs->altrootmnt = mntget(old->altrootmnt);
                        fs->altroot = dget(old->altroot);
                } else {
---- linux-2.4.20-rh-20.9/kernel/exit.c~vfs_intent-2.4.20-rh    2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/kernel/exit.c  2003-09-14 17:34:53.000000000 +0400
-@@ -345,11 +345,14 @@ static inline void __put_fs_struct(struc
+Index: linux-2.4.20/kernel/exit.c
+===================================================================
+--- linux-2.4.20.orig/kernel/exit.c    Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/kernel/exit.c Wed Mar 17 13:57:11 2004
+@@ -345,11 +345,14 @@
  {
        /* No need to hold fs->lock if we are killing it */
        if (atomic_dec_and_test(&fs->count)) {
                        dput(fs->altroot);
                        mntput(fs->altrootmnt);
                }
-
-_
index 7d83b5e..1ef0b01 100644 (file)
  kernel/ksyms.c            |    1 
  12 files changed, 558 insertions(+), 128 deletions(-)
 
---- linux-2.4.20-vanilla/fs/exec.c~vfs_intent-2.4.20-vanilla   2003-05-16 05:29:12.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/fs/exec.c      2003-09-17 21:05:04.000000000 +0400
-@@ -107,8 +107,10 @@ asmlinkage long sys_uselib(const char * 
+Index: linux-2.4.24/fs/exec.c
+===================================================================
+--- linux-2.4.24.orig/fs/exec.c        Fri Nov 28 10:26:21 2003
++++ linux-2.4.24/fs/exec.c     Wed Mar 17 17:36:14 2004
+@@ -112,8 +112,10 @@ asmlinkage long sys_uselib(const char * 
        struct file * file;
        struct nameidata nd;
        int error;
@@ -26,7 +28,7 @@
        if (error)
                goto out;
  
-@@ -120,7 +122,8 @@ asmlinkage long sys_uselib(const char * 
+@@ -125,7 +127,8 @@ asmlinkage long sys_uselib(const char * 
        if (error)
                goto exit;
  
@@ -36,7 +38,7 @@
        error = PTR_ERR(file);
        if (IS_ERR(file))
                goto out;
-@@ -363,8 +366,10 @@ struct file *open_exec(const char *name)
+@@ -374,8 +377,10 @@ struct file *open_exec(const char *name)
        struct inode *inode;
        struct file *file;
        int err = 0;
@@ -48,7 +50,7 @@
        file = ERR_PTR(err);
        if (!err) {
                inode = nd.dentry->d_inode;
-@@ -376,7 +381,8 @@ struct file *open_exec(const char *name)
+@@ -387,7 +392,8 @@ struct file *open_exec(const char *name)
                                err = -EACCES;
                        file = ERR_PTR(err);
                        if (!err) {
@@ -58,7 +60,7 @@
                                if (!IS_ERR(file)) {
                                        err = deny_write_access(file);
                                        if (err) {
-@@ -388,6 +394,7 @@ out:
+@@ -399,6 +405,7 @@ out:
                                return file;
                        }
                }
@@ -66,7 +68,7 @@
                path_release(&nd);
        }
        goto out;
-@@ -989,7 +996,7 @@ int do_coredump(long signr, struct pt_re
+@@ -1132,7 +1139,7 @@ int do_coredump(long signr, struct pt_re
                goto close_fail;
        if (!file->f_op->write)
                goto close_fail;
                goto close_fail;
  
        retval = binfmt->core_dump(signr, regs, file);
---- linux-2.4.20-vanilla/fs/dcache.c~vfs_intent-2.4.20-vanilla 2003-05-16 05:29:12.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/fs/dcache.c    2003-09-17 21:05:04.000000000 +0400
+Index: linux-2.4.24/fs/dcache.c
+===================================================================
+--- linux-2.4.24.orig/fs/dcache.c      Fri Jun 13 07:51:37 2003
++++ linux-2.4.24/fs/dcache.c   Wed Mar 17 17:36:14 2004
 @@ -181,6 +181,13 @@ int d_invalidate(struct dentry * dentry)
                spin_unlock(&dcache_lock);
                return 0;
  }
  
  #define do_switch(x,y) do { \
---- linux-2.4.20-vanilla/fs/namespace.c~vfs_intent-2.4.20-vanilla      2003-05-16 05:29:12.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/fs/namespace.c 2003-09-17 21:05:04.000000000 +0400
-@@ -99,6 +99,7 @@ static void detach_mnt(struct vfsmount *
+Index: linux-2.4.24/fs/namespace.c
+===================================================================
+--- linux-2.4.24.orig/fs/namespace.c   Fri Nov 28 10:26:21 2003
++++ linux-2.4.24/fs/namespace.c        Wed Mar 17 17:36:14 2004
+@@ -98,6 +98,7 @@ static void detach_mnt(struct vfsmount *
  {
        old_nd->dentry = mnt->mnt_mountpoint;
        old_nd->mnt = mnt->mnt_parent;
        mnt->mnt_parent = mnt;
        mnt->mnt_mountpoint = mnt->mnt_root;
        list_del_init(&mnt->mnt_child);
-@@ -110,6 +111,7 @@ static void attach_mnt(struct vfsmount *
+@@ -109,6 +110,7 @@ static void attach_mnt(struct vfsmount *
  {
        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(&mnt->mnt_child, &nd->mnt->mnt_mounts);
+       list_add_tail(&mnt->mnt_child, &nd->mnt->mnt_mounts);
        nd->dentry->d_mounted++;
-@@ -485,14 +487,17 @@ static int do_loopback(struct nameidata 
+@@ -488,14 +490,17 @@ static int do_loopback(struct nameidata 
  {
        struct nameidata old_nd;
        struct vfsmount *mnt = NULL;
  
        down_write(&current->namespace->sem);
        err = -EINVAL;
-@@ -515,6 +520,7 @@ static int do_loopback(struct nameidata 
+@@ -518,6 +523,7 @@ static int do_loopback(struct nameidata 
        }
  
        up_write(&current->namespace->sem);
        path_release(&old_nd);
        return err;
  }
-@@ -698,6 +704,7 @@ long do_mount(char * dev_name, char * di
+@@ -701,6 +707,7 @@ long do_mount(char * dev_name, char * di
                  unsigned long flags, void *data_page)
  {
        struct nameidata nd;
        int retval = 0;
        int mnt_flags = 0;
  
-@@ -722,10 +729,11 @@ long do_mount(char * dev_name, char * di
+@@ -725,10 +732,11 @@ long do_mount(char * dev_name, char * di
        flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
  
        /* ... and get the mountpoint */
        if (flags & MS_REMOUNT)
                retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
                                    data_page);
-@@ -736,6 +744,8 @@ long do_mount(char * dev_name, char * di
+@@ -739,6 +747,8 @@ long do_mount(char * dev_name, char * di
        else
                retval = do_add_mount(&nd, type_page, flags, mnt_flags,
                                      dev_name, data_page);
        path_release(&nd);
        return retval;
  }
-@@ -901,6 +911,8 @@ asmlinkage long sys_pivot_root(const cha
+@@ -904,6 +914,8 @@ asmlinkage long sys_pivot_root(const cha
  {
        struct vfsmount *tmp;
        struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
        int error;
  
        if (!capable(CAP_SYS_ADMIN))
-@@ -908,14 +920,14 @@ asmlinkage long sys_pivot_root(const cha
+@@ -911,14 +923,14 @@ asmlinkage long sys_pivot_root(const cha
  
        lock_kernel();
  
        if (error)
                goto out1;
  
-@@ -970,8 +982,10 @@ out2:
+@@ -973,8 +985,10 @@ out2:
        up(&old_nd.dentry->d_inode->i_zombie);
        up_write(&current->namespace->sem);
        path_release(&user_nd);
        path_release(&new_nd);
  out0:
        unlock_kernel();
---- linux-2.4.20-vanilla/fs/namei.c~vfs_intent-2.4.20-vanilla  2003-05-16 05:29:12.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/fs/namei.c     2003-09-17 21:05:04.000000000 +0400
+Index: linux-2.4.24/fs/namei.c
+===================================================================
+--- linux-2.4.24.orig/fs/namei.c       Mon Aug 25 04:44:43 2003
++++ linux-2.4.24/fs/namei.c    Wed Mar 17 17:36:52 2004
 @@ -94,6 +94,13 @@
   * XEmacs seems to be relying on it...
   */
                                break;
                }
                goto return_base;
-@@ -633,6 +670,25 @@ return_reval:
+@@ -635,6 +672,27 @@ return_reval:
                 * Check the cached dentry for staleness.
                 */
                dentry = nd->dentry;
 +                                                &dentry->d_name, 0, NULL);
 +                              d_invalidate(dentry);
 +                              dput(dentry);
-+                              if (IS_ERR(new)) { 
++                              if (IS_ERR(new)) {
 +                                      err = PTR_ERR(new);
 +                                      break;
 +                              }
 +                              nd->dentry = new;
 +                      }
++                      if (!nd->dentry->d_inode)
++                              goto no_inode;
 +              } else
                if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
                        err = -ESTALE;
                        if (!dentry->d_op->d_revalidate(dentry, 0)) {
-@@ -646,15 +702,28 @@ out_dput:
+@@ -648,15 +706,28 @@ out_dput:
                dput(dentry);
                break;
        }
  }
  
  /* SMP-safe */
-@@ -739,6 +808,17 @@ walk_init_root(const char *name, struct 
+@@ -741,6 +812,17 @@ walk_init_root(const char *name, struct 
  }
  
  /* SMP-safe */
  int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
  {
        int error = 0;
-@@ -753,6 +833,7 @@ int path_init(const char *name, unsigned
+@@ -755,6 +837,7 @@ int path_init(const char *name, unsigned
  {
        nd->last_type = LAST_ROOT; /* if there are only slashes... */
        nd->flags = flags;
        if (*name=='/')
                return walk_init_root(name,nd);
        read_lock(&current->fs->lock);
-@@ -767,7 +848,8 @@ int path_init(const char *name, unsigned
+@@ -769,7 +852,8 @@ int path_init(const char *name, unsigned
   * needs parent already locked. Doesn't follow mounts.
   * SMP-safe.
   */
  {
        struct dentry * dentry;
        struct inode *inode;
-@@ -790,13 +872,16 @@ struct dentry * lookup_hash(struct qstr 
+@@ -792,13 +876,16 @@ struct dentry * lookup_hash(struct qstr 
                        goto out;
        }
  
                dentry = inode->i_op->lookup(inode, new);
                unlock_kernel();
                if (!dentry)
-@@ -808,6 +893,12 @@ out:
+@@ -810,6 +897,12 @@ out:
        return dentry;
  }
  
  /* SMP-safe */
  struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
  {
-@@ -829,7 +920,7 @@ struct dentry * lookup_one_len(const cha
+@@ -831,7 +924,7 @@ struct dentry * lookup_one_len(const cha
        }
        this.hash = end_name_hash(hash);
  
  access:
        return ERR_PTR(-EACCES);
  }
-@@ -860,6 +951,23 @@ int __user_walk(const char *name, unsign
+@@ -862,6 +955,23 @@ int __user_walk(const char *name, unsign
        return err;
  }
  
  /*
   * It's inline, so penalty for filesystems that don't use sticky bit is
   * minimal.
-@@ -955,7 +1063,8 @@ static inline int lookup_flags(unsigned 
+@@ -957,7 +1067,8 @@ static inline int lookup_flags(unsigned 
        return retval;
  }
  
  {
        int error;
  
-@@ -968,12 +1077,15 @@ int vfs_create(struct inode *dir, struct
+@@ -970,12 +1081,15 @@ int vfs_create(struct inode *dir, struct
                goto exit_lock;
  
        error = -EACCES;        /* shouldn't it be ENOSYS? */
        unlock_kernel();
  exit_lock:
        up(&dir->i_zombie);
-@@ -982,6 +1094,11 @@ exit_lock:
+@@ -984,6 +1098,11 @@ exit_lock:
        return error;
  }
  
  /*
   *    open_namei()
   *
-@@ -996,7 +1113,8 @@ exit_lock:
+@@ -998,7 +1117,8 @@ exit_lock:
   * for symlinks (where the permissions are checked later).
   * SMP-safe
   */
  {
        int acc_mode, error = 0;
        struct inode *inode;
-@@ -1006,11 +1124,14 @@ int open_namei(const char * pathname, in
+@@ -1008,11 +1128,14 @@ int open_namei(const char * pathname, in
  
        acc_mode = ACC_MODE(flag);
  
                if (error)
                        return error;
                dentry = nd->dentry;
-@@ -1020,6 +1141,10 @@ int open_namei(const char * pathname, in
+@@ -1022,6 +1145,10 @@ int open_namei(const char * pathname, in
        /*
         * Create - we need to know the parent.
         */
        error = path_lookup(pathname, LOOKUP_PARENT, nd);
        if (error)
                return error;
-@@ -1035,7 +1160,7 @@ int open_namei(const char * pathname, in
+@@ -1037,7 +1164,7 @@ int open_namei(const char * pathname, in
  
        dir = nd->dentry;
        down(&dir->d_inode->i_sem);
  
  do_last:
        error = PTR_ERR(dentry);
-@@ -1044,10 +1169,11 @@ do_last:
+@@ -1046,10 +1173,11 @@ do_last:
                goto exit;
        }
  
                up(&dir->d_inode->i_sem);
                dput(nd->dentry);
                nd->dentry = dentry;
-@@ -1151,7 +1277,7 @@ ok:
+@@ -1153,7 +1281,7 @@ ok:
                if (!error) {
                        DQUOT_INIT(inode);
                        
                }
                put_write_access(inode);
                if (error)
-@@ -1163,8 +1289,10 @@ ok:
+@@ -1165,8 +1293,10 @@ ok:
        return 0;
  
  exit_dput:
        path_release(nd);
        return error;
  
-@@ -1183,7 +1311,10 @@ do_link:
+@@ -1185,7 +1315,10 @@ do_link:
         * are done. Procfs-like symlinks just set LAST_BIND.
         */
        UPDATE_ATIME(dentry->d_inode);
        dput(dentry);
        if (error)
                return error;
-@@ -1205,13 +1336,20 @@ do_link:
+@@ -1207,13 +1340,20 @@ do_link:
        }
        dir = nd->dentry;
        down(&dir->d_inode->i_sem);
  {
        struct dentry *dentry;
  
-@@ -1219,7 +1357,7 @@ static struct dentry *lookup_create(stru
+@@ -1221,7 +1361,7 @@ static struct dentry *lookup_create(stru
        dentry = ERR_PTR(-EEXIST);
        if (nd->last_type != LAST_NORM)
                goto fail;
        if (IS_ERR(dentry))
                goto fail;
        if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
-@@ -1275,7 +1413,16 @@ asmlinkage long sys_mknod(const char * f
+@@ -1277,7 +1417,20 @@ asmlinkage long sys_mknod(const char * f
        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);
        error = PTR_ERR(dentry);
  
        mode &= ~current->fs->umask;
-@@ -1296,6 +1443,7 @@ asmlinkage long sys_mknod(const char * f
+@@ -1298,6 +1451,7 @@ asmlinkage long sys_mknod(const char * f
                dput(dentry);
        }
        up(&nd.dentry->d_inode->i_sem);
        path_release(&nd);
  out:
        putname(tmp);
-@@ -1343,7 +1491,14 @@ asmlinkage long sys_mkdir(const char * p
+@@ -1345,7 +1499,18 @@ asmlinkage long sys_mkdir(const char * p
                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);
                error = PTR_ERR(dentry);
                if (!IS_ERR(dentry)) {
                        error = vfs_mkdir(nd.dentry->d_inode, dentry,
-@@ -1351,6 +1506,7 @@ asmlinkage long sys_mkdir(const char * p
+@@ -1353,6 +1518,7 @@ asmlinkage long sys_mkdir(const char * p
                        dput(dentry);
                }
                up(&nd.dentry->d_inode->i_sem);
                path_release(&nd);
  out:
                putname(tmp);
-@@ -1451,8 +1607,16 @@ asmlinkage long sys_rmdir(const char * p
+@@ -1453,8 +1619,16 @@ asmlinkage long sys_rmdir(const char * p
                        error = -EBUSY;
                        goto exit1;
        }
        error = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
                error = vfs_rmdir(nd.dentry->d_inode, dentry);
-@@ -1510,8 +1674,15 @@ asmlinkage long sys_unlink(const char * 
+@@ -1512,8 +1686,15 @@ asmlinkage long sys_unlink(const char * 
        error = -EISDIR;
        if (nd.last_type != LAST_NORM)
                goto exit1;
        error = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
                /* Why not before? Because we want correct error value */
-@@ -1578,15 +1749,23 @@ asmlinkage long sys_symlink(const char *
+@@ -1580,15 +1761,27 @@ asmlinkage long sys_symlink(const char *
                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);
                putname(to);
        }
        putname(from);
-@@ -1662,7 +1841,14 @@ asmlinkage long sys_link(const char * ol
+@@ -1664,7 +1857,18 @@ asmlinkage long sys_link(const char * ol
                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);
                error = PTR_ERR(new_dentry);
                if (!IS_ERR(new_dentry)) {
                        error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
-@@ -1706,7 +1892,7 @@ exit:
+@@ -1708,7 +1912,7 @@ exit:
   *       locking].
   */
  int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
  {
        int error;
        struct inode *target;
-@@ -1785,7 +1971,7 @@ out_unlock:
+@@ -1787,7 +1991,7 @@ out_unlock:
  }
  
  int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
  {
        int error;
  
-@@ -1873,9 +2059,18 @@ static inline int do_rename(const char *
+@@ -1875,9 +2079,18 @@ static inline int do_rename(const char *
        if (newnd.last_type != LAST_NORM)
                goto exit2;
  
        error = PTR_ERR(old_dentry);
        if (IS_ERR(old_dentry))
                goto exit3;
-@@ -1891,16 +2086,16 @@ static inline int do_rename(const char *
+@@ -1893,16 +2106,16 @@ static inline int do_rename(const char *
                if (newnd.last.name[newnd.last.len])
                        goto exit4;
        }
        dput(new_dentry);
  exit4:
        dput(old_dentry);
-@@ -1951,20 +2146,26 @@ out:
+@@ -1953,20 +2166,26 @@ out:
  }
  
  static inline int
  out:
        if (current->link_count || res || nd->last_type!=LAST_NORM)
                return res;
-@@ -1986,7 +2187,13 @@ fail:
+@@ -1990,7 +2209,13 @@ fail:
  
  int vfs_follow_link(struct nameidata *nd, const char *link)
  {
  }
  
  /* get the link contents into pagecache */
-@@ -2028,7 +2235,7 @@ int page_follow_link(struct dentry *dent
+@@ -2032,7 +2257,7 @@ int page_follow_link(struct dentry *dent
  {
        struct page *page = NULL;
        char *s = page_getlink(dentry, &page);
        if (page) {
                kunmap(page);
                page_cache_release(page);
---- linux-2.4.20-vanilla/fs/open.c~vfs_intent-2.4.20-vanilla   2003-05-16 05:29:13.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/fs/open.c      2003-09-17 21:05:04.000000000 +0400
+Index: linux-2.4.24/fs/open.c
+===================================================================
+--- linux-2.4.24.orig/fs/open.c        Mon Aug 25 04:44:43 2003
++++ linux-2.4.24/fs/open.c     Wed Mar 17 17:36:14 2004
 @@ -19,6 +19,8 @@
  #include <asm/uaccess.h>
  
        int error;
        struct iattr newattrs;
  
-@@ -108,7 +111,13 @@ int do_truncate(struct dentry *dentry, l
+@@ -109,7 +112,13 @@ int do_truncate(struct dentry *dentry, l
        down(&inode->i_sem);
        newattrs.ia_size = length;
        newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
 +      } else
 +              error = notify_change(dentry, &newattrs);
        up(&inode->i_sem);
+       up_write(&inode->i_alloc_sem);
        return error;
- }
-@@ -118,12 +127,13 @@ static inline long do_sys_truncate(const
+@@ -120,12 +129,13 @@ static inline long do_sys_truncate(const
        struct nameidata nd;
        struct inode * inode;
        int error;
        if (error)
                goto out;
        inode = nd.dentry->d_inode;
-@@ -163,11 +173,13 @@ static inline long do_sys_truncate(const
+@@ -165,11 +175,13 @@ static inline long do_sys_truncate(const
        error = locks_verify_truncate(inode, NULL, length);
        if (!error) {
                DQUOT_INIT(inode);
        path_release(&nd);
  out:
        return error;
-@@ -215,7 +227,7 @@ static inline long do_sys_ftruncate(unsi
+@@ -217,7 +229,7 @@ static inline long do_sys_ftruncate(unsi
  
        error = locks_verify_truncate(inode, file, length);
        if (!error)
  out_putf:
        fput(file);
  out:
-@@ -260,11 +272,13 @@ asmlinkage long sys_utime(char * filenam
+@@ -262,11 +274,13 @@ asmlinkage long sys_utime(char * filenam
        struct inode * inode;
        struct iattr newattrs;
  
        error = -EROFS;
        if (IS_RDONLY(inode))
                goto dput_and_out;
-@@ -279,11 +293,25 @@ asmlinkage long sys_utime(char * filenam
+@@ -281,11 +295,25 @@ asmlinkage long sys_utime(char * filenam
                        goto dput_and_out;
  
                newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
        error = notify_change(nd.dentry, &newattrs);
  dput_and_out:
        path_release(&nd);
-@@ -304,12 +332,14 @@ asmlinkage long sys_utimes(char * filena
+@@ -306,12 +334,14 @@ asmlinkage long sys_utimes(char * filena
        struct inode * inode;
        struct iattr newattrs;
  
        error = -EROFS;
        if (IS_RDONLY(inode))
                goto dput_and_out;
-@@ -324,7 +354,20 @@ asmlinkage long sys_utimes(char * filena
+@@ -326,7 +356,20 @@ asmlinkage long sys_utimes(char * filena
                newattrs.ia_atime = times[0].tv_sec;
                newattrs.ia_mtime = times[1].tv_sec;
                newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
                if (current->fsuid != inode->i_uid &&
                    (error = permission(inode,MAY_WRITE)) != 0)
                        goto dput_and_out;
-@@ -347,6 +390,7 @@ asmlinkage long sys_access(const char * 
+@@ -349,6 +392,7 @@ asmlinkage long sys_access(const char * 
        int old_fsuid, old_fsgid;
        kernel_cap_t old_cap;
        int res;
  
        if (mode & ~S_IRWXO)    /* where's F_OK, X_OK, W_OK, R_OK? */
                return -EINVAL;
-@@ -364,13 +408,14 @@ asmlinkage long sys_access(const char * 
+@@ -366,13 +410,14 @@ asmlinkage long sys_access(const char * 
        else
                current->cap_effective = current->cap_permitted;
  
                path_release(&nd);
        }
  
-@@ -385,8 +430,9 @@ asmlinkage long sys_chdir(const char * f
+@@ -387,8 +432,9 @@ asmlinkage long sys_chdir(const char * f
  {
        int error;
        struct nameidata nd;
        if (error)
                goto out;
  
-@@ -397,6 +443,7 @@ asmlinkage long sys_chdir(const char * f
+@@ -399,6 +445,7 @@ asmlinkage long sys_chdir(const char * f
        set_fs_pwd(current->fs, nd.mnt, nd.dentry);
  
  dput_and_out:
        path_release(&nd);
  out:
        return error;
-@@ -436,9 +483,10 @@ asmlinkage long sys_chroot(const char * 
+@@ -438,9 +485,10 @@ asmlinkage long sys_chroot(const char * 
  {
        int error;
        struct nameidata nd;
        if (error)
                goto out;
  
-@@ -454,39 +502,56 @@ asmlinkage long sys_chroot(const char * 
+@@ -456,39 +504,56 @@ asmlinkage long sys_chroot(const char * 
        set_fs_altroot();
        error = 0;
  dput_and_out:
        fput(file);
  out:
        return err;
-@@ -495,30 +560,14 @@ out:
+@@ -497,30 +562,14 @@ out:
  asmlinkage long sys_chmod(const char * filename, mode_t mode)
  {
        struct nameidata nd;
        path_release(&nd);
  out:
        return error;
-@@ -538,6 +587,20 @@ static int chown_common(struct dentry * 
+@@ -540,6 +589,20 @@ static int chown_common(struct dentry * 
        error = -EROFS;
        if (IS_RDONLY(inode))
                goto out;
        error = -EPERM;
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
                goto out;
-@@ -642,6 +705,7 @@ struct file *filp_open(const char * file
+@@ -644,6 +707,7 @@ struct file *filp_open(const char * file
  {
        int namei_flags, error;
        struct nameidata nd;
  
        namei_flags = flags;
        if ((namei_flags+1) & O_ACCMODE)
-@@ -649,14 +713,15 @@ struct file *filp_open(const char * file
+@@ -651,14 +715,15 @@ struct file *filp_open(const char * file
        if (namei_flags & O_TRUNC)
                namei_flags |= 2;
  
  {
        struct file * f;
        struct inode *inode;
-@@ -693,12 +758,15 @@ struct file *dentry_open(struct dentry *
+@@ -695,12 +760,15 @@ struct file *dentry_open(struct dentry *
        }
  
        if (f->f_op && f->f_op->open) {
        return f;
  
  cleanup_all:
-@@ -713,11 +781,17 @@ cleanup_all:
+@@ -715,11 +783,17 @@ cleanup_all:
  cleanup_file:
        put_filp(f);
  cleanup_dentry:
  /*
   * Find an empty file descriptor entry, and mark it busy.
   */
---- linux-2.4.20-vanilla/fs/stat.c~vfs_intent-2.4.20-vanilla   2001-09-14 03:04:43.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/fs/stat.c      2003-09-17 21:05:04.000000000 +0400
-@@ -17,10 +17,14 @@
+Index: linux-2.4.24/fs/stat.c
+===================================================================
+--- linux-2.4.24.orig/fs/stat.c        Mon Aug 25 04:44:43 2003
++++ linux-2.4.24/fs/stat.c     Wed Mar 17 17:36:52 2004
+@@ -17,10 +17,12 @@
   * Revalidate the inode. This is required for proper NFS attribute caching.
   */
  static __inline__ int
  {
        struct inode * inode = dentry->d_inode;
 -      if (inode->i_op && inode->i_op->revalidate)
-+      if (!inode)
-+              return -ENOENT;
 +      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;
  }
-@@ -135,13 +139,15 @@ static int cp_new_stat(struct inode * in
+@@ -137,13 +139,15 @@ static int cp_new_stat(struct inode * in
  asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
  {
        struct nameidata nd;
                path_release(&nd);
        }
        return error;
-@@ -151,13 +157,15 @@ asmlinkage long sys_stat(char * filename
+@@ -153,13 +157,15 @@ asmlinkage long sys_stat(char * filename
  asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
  {
        struct nameidata nd;
                path_release(&nd);
        }
        return error;
-@@ -172,13 +180,15 @@ asmlinkage long sys_newstat(char * filen
+@@ -174,13 +180,15 @@ asmlinkage long sys_newstat(char * filen
  asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
  {
        struct nameidata nd;
                path_release(&nd);
        }
        return error;
-@@ -189,13 +199,15 @@ asmlinkage long sys_lstat(char * filenam
+@@ -191,13 +199,15 @@ asmlinkage long sys_lstat(char * filenam
  asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
  {
        struct nameidata nd;
                path_release(&nd);
        }
        return error;
-@@ -216,7 +228,7 @@ asmlinkage long sys_fstat(unsigned int f
+@@ -218,7 +228,7 @@ asmlinkage long sys_fstat(unsigned int f
        if (f) {
                struct dentry * dentry = f->f_dentry;
  
                if (!err)
                        err = cp_old_stat(dentry->d_inode, statbuf);
                fput(f);
-@@ -235,7 +247,7 @@ asmlinkage long sys_newfstat(unsigned in
+@@ -237,7 +247,7 @@ asmlinkage long sys_newfstat(unsigned in
        if (f) {
                struct dentry * dentry = f->f_dentry;
  
                if (!err)
                        err = cp_new_stat(dentry->d_inode, statbuf);
                fput(f);
-@@ -257,7 +269,7 @@ asmlinkage long sys_readlink(const char 
+@@ -259,7 +269,7 @@ asmlinkage long sys_readlink(const char 
  
                error = -EINVAL;
                if (inode->i_op && inode->i_op->readlink &&
                        UPDATE_ATIME(inode);
                        error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
                }
-@@ -333,12 +345,14 @@ asmlinkage long sys_stat64(char * filena
+@@ -335,12 +345,14 @@ asmlinkage long sys_stat64(char * filena
  {
        struct nameidata nd;
        int error;
                path_release(&nd);
        }
        return error;
-@@ -348,12 +362,14 @@ asmlinkage long sys_lstat64(char * filen
+@@ -350,12 +362,14 @@ asmlinkage long sys_lstat64(char * filen
  {
        struct nameidata nd;
        int error;
                path_release(&nd);
        }
        return error;
-@@ -368,7 +384,7 @@ asmlinkage long sys_fstat64(unsigned lon
+@@ -370,7 +384,7 @@ asmlinkage long sys_fstat64(unsigned lon
        if (f) {
                struct dentry * dentry = f->f_dentry;
  
                if (!err)
                        err = cp_new_stat64(dentry->d_inode, statbuf);
                fput(f);
---- linux-2.4.20-vanilla/include/linux/dcache.h~vfs_intent-2.4.20-vanilla      2003-05-16 05:29:15.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/include/linux/dcache.h 2003-09-17 21:05:42.000000000 +0400
+Index: linux-2.4.24/include/linux/dcache.h
+===================================================================
+--- linux-2.4.24.orig/include/linux/dcache.h   Thu Nov 28 15:53:15 2002
++++ linux-2.4.24/include/linux/dcache.h        Wed Mar 17 17:36:14 2004
 @@ -6,6 +6,51 @@
  #include <asm/atomic.h>
  #include <linux/mount.h>
  
  extern spinlock_t dcache_lock;
  
---- linux-2.4.20-vanilla/include/linux/fs.h~vfs_intent-2.4.20-vanilla  2003-09-17 21:05:03.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/include/linux/fs.h     2003-09-17 21:05:04.000000000 +0400
+Index: linux-2.4.24/include/linux/fs.h
+===================================================================
+--- linux-2.4.24.orig/include/linux/fs.h       Wed Mar 17 17:36:14 2004
++++ linux-2.4.24/include/linux/fs.h    Wed Mar 17 17:36:14 2004
 @@ -73,6 +73,7 @@ extern int leases_enable, dir_notify_ena
  
  #define FMODE_READ 1
  
  #define READ 0
  #define WRITE 1
-@@ -338,6 +339,9 @@ extern void set_bh_page(struct buffer_he
+@@ -340,6 +341,9 @@ extern void set_bh_page(struct buffer_he
  #define ATTR_MTIME_SET        256
  #define ATTR_FORCE    512     /* Not a change, but a change it */
  #define ATTR_ATTR_FLAG        1024
  
  /*
   * This is the Inode Attributes structure, used for notify_change().  It
-@@ -471,6 +475,7 @@ struct inode {
+@@ -478,6 +482,7 @@ struct inode {
        struct pipe_inode_info  *i_pipe;
        struct block_device     *i_bdev;
        struct char_device      *i_cdev;
  
        unsigned long           i_dnotify_mask; /* Directory notify events */
        struct dnotify_struct   *i_dnotify; /* for directory notifications */
-@@ -542,6 +547,7 @@ struct file {
+@@ -582,6 +587,7 @@ struct file {
  
        /* needed for tty driver, and maybe others */
        void                    *private_data;
  
        /* preallocated helper kiobuf to speedup O_DIRECT */
        struct kiobuf           *f_iobuf;
-@@ -661,6 +667,7 @@ struct nameidata {
+@@ -702,6 +708,7 @@ struct nameidata {
        struct qstr last;
        unsigned int flags;
        int last_type;
 +      struct lookup_intent *intent;
  };
  
- #define DQUOT_USR_ENABLED     0x01            /* User diskquotas enabled */
-@@ -794,7 +801,8 @@ extern int vfs_symlink(struct inode *, s
+ /*
+@@ -822,7 +829,8 @@ extern int vfs_symlink(struct inode *, s
  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 *);
  
  /*
   * File types
-@@ -854,21 +862,32 @@ struct file_operations {
+@@ -884,21 +892,32 @@ struct file_operations {
  
  struct inode_operations {
        int (*create) (struct inode *,struct dentry *,int);
        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);
-@@ -1070,10 +1089,14 @@ static inline int get_lease(struct inode
+@@ -1094,10 +1113,14 @@ static inline int get_lease(struct inode
  
  asmlinkage long sys_open(const char *, int, int);
  asmlinkage long sys_close(unsigned int);      /* yes, it's really unsigned */
  extern int filp_close(struct file *, fl_owner_t id);
  extern char * getname(const char *);
  
-@@ -1335,6 +1358,7 @@ typedef int (*read_actor_t)(read_descrip
+@@ -1386,6 +1409,7 @@ typedef int (*read_actor_t)(read_descrip
  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(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 *));
-@@ -1346,6 +1370,8 @@ extern struct dentry * lookup_one_len(co
+@@ -1397,6 +1421,8 @@ extern struct dentry * lookup_one_len(co
  extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
  #define user_path_walk(name,nd)        __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
  #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
 +#define user_path_walk_it(name,nd,it)  __user_walk_it(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd, it)
 +#define user_path_walk_link_it(name,nd,it) __user_walk_it(name, LOOKUP_POSITIVE, nd, it)
  
+ extern void inode_init_once(struct inode *);
  extern void iput(struct inode *);
- extern void force_delete(struct inode *);
-@@ -1455,6 +1481,8 @@ extern struct file_operations generic_ro
+@@ -1500,6 +1526,8 @@ extern struct file_operations generic_ro
  
  extern int vfs_readlink(struct dentry *, char *, int, const char *);
  extern int vfs_follow_link(struct nameidata *, const char *);
  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;
---- linux-2.4.20-vanilla/include/linux/fs_struct.h~vfs_intent-2.4.20-vanilla   2001-07-14 02:10:44.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/include/linux/fs_struct.h      2003-09-17 21:05:04.000000000 +0400
+Index: linux-2.4.24/include/linux/fs_struct.h
+===================================================================
+--- linux-2.4.24.orig/include/linux/fs_struct.h        Fri Jul 13 15:10:44 2001
++++ linux-2.4.24/include/linux/fs_struct.h     Wed Mar 17 17:36:14 2004
 @@ -34,10 +34,12 @@ static inline void set_fs_root(struct fs
        write_lock(&fs->lock);
        old_root = fs->root;
                dput(old_pwd);
                mntput(old_pwdmnt);
        }
---- linux-2.4.20-vanilla/kernel/ksyms.c~vfs_intent-2.4.20-vanilla      2003-09-17 21:05:03.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/kernel/ksyms.c 2003-09-17 21:05:04.000000000 +0400
-@@ -269,6 +269,7 @@ EXPORT_SYMBOL(read_cache_page);
- EXPORT_SYMBOL(set_page_dirty);
+Index: linux-2.4.24/kernel/ksyms.c
+===================================================================
+--- linux-2.4.24.orig/kernel/ksyms.c   Wed Mar 17 17:36:14 2004
++++ linux-2.4.24/kernel/ksyms.c        Wed Mar 17 17:36:14 2004
+@@ -275,6 +275,7 @@ EXPORT_SYMBOL(set_page_dirty);
+ 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);
---- linux-2.4.20-vanilla/kernel/fork.c~vfs_intent-2.4.20-vanilla       2003-05-16 05:29:15.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/kernel/fork.c  2003-09-17 21:05:04.000000000 +0400
-@@ -384,10 +384,13 @@ static inline struct fs_struct *__copy_f
+Index: linux-2.4.24/kernel/fork.c
+===================================================================
+--- linux-2.4.24.orig/kernel/fork.c    Fri Nov 28 10:26:21 2003
++++ linux-2.4.24/kernel/fork.c Wed Mar 17 17:36:14 2004
+@@ -386,10 +386,13 @@ static inline struct fs_struct *__copy_f
                fs->umask = old->umask;
                read_lock(&old->lock);
                fs->rootmnt = mntget(old->rootmnt);
                        fs->altrootmnt = mntget(old->altrootmnt);
                        fs->altroot = dget(old->altroot);
                } else {
---- linux-2.4.20-vanilla/kernel/exit.c~vfs_intent-2.4.20-vanilla       2003-05-16 05:29:15.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/kernel/exit.c  2003-09-17 21:05:04.000000000 +0400
+Index: linux-2.4.24/kernel/exit.c
+===================================================================
+--- linux-2.4.24.orig/kernel/exit.c    Thu Nov 28 15:53:15 2002
++++ linux-2.4.24/kernel/exit.c Wed Mar 17 17:36:14 2004
 @@ -238,11 +238,14 @@ static inline void __put_fs_struct(struc
  {
        /* No need to hold fs->lock if we are killing it */
                        dput(fs->altroot);
                        mntput(fs->altrootmnt);
                }
-
-_
index 7587ad2..09ef2f9 100644 (file)
  kernel/ksyms.c            |    1 
  12 files changed, 558 insertions(+), 128 deletions(-)
 
-Index: linux-2.4.21-chaos/fs/dcache.c
+Index: linux-ia64/fs/dcache.c
 ===================================================================
---- linux-2.4.21-chaos.orig/fs/dcache.c        2003-09-19 03:49:54.000000000 +0400
-+++ linux-2.4.21-chaos/fs/dcache.c     2003-12-12 17:02:47.000000000 +0300
-@@ -186,6 +186,13 @@
+--- linux-ia64.orig/fs/dcache.c        2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/fs/dcache.c     2004-03-17 16:05:28.000000000 -0800
+@@ -186,6 +186,13 @@ int d_invalidate(struct dentry * dentry)
                spin_unlock(&dcache_lock);
                return 0;
        }
@@ -30,7 +30,7 @@ Index: linux-2.4.21-chaos/fs/dcache.c
        /*
         * Check whether to do a partial shrink_dcache
         * to get rid of unused child entries.
-@@ -847,13 +854,19 @@
+@@ -850,13 +857,19 @@ void d_delete(struct dentry * dentry)
   * Adds a dentry to the hash according to its name.
   */
   
@@ -53,11 +53,11 @@ Index: linux-2.4.21-chaos/fs/dcache.c
  }
  
  #define do_switch(x,y) do { \
-Index: linux-2.4.21-chaos/fs/exec.c
+Index: linux-ia64/fs/exec.c
 ===================================================================
---- linux-2.4.21-chaos.orig/fs/exec.c  2003-12-05 07:55:47.000000000 +0300
-+++ linux-2.4.21-chaos/fs/exec.c       2003-12-12 17:02:47.000000000 +0300
-@@ -119,8 +119,10 @@
+--- linux-ia64.orig/fs/exec.c  2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/fs/exec.c       2004-03-17 16:05:28.000000000 -0800
+@@ -119,8 +119,10 @@ asmlinkage long sys_uselib(const char * 
        struct file * file;
        struct nameidata nd;
        int error;
@@ -69,7 +69,7 @@ Index: linux-2.4.21-chaos/fs/exec.c
        if (error)
                goto out;
  
-@@ -132,7 +134,8 @@
+@@ -132,7 +134,8 @@ asmlinkage long sys_uselib(const char * 
        if (error)
                goto exit;
  
@@ -79,7 +79,7 @@ Index: linux-2.4.21-chaos/fs/exec.c
        error = PTR_ERR(file);
        if (IS_ERR(file))
                goto out;
-@@ -400,8 +403,10 @@
+@@ -400,8 +403,10 @@ struct file *open_exec(const char *name)
        struct inode *inode;
        struct file *file;
        int err = 0;
@@ -91,7 +91,7 @@ Index: linux-2.4.21-chaos/fs/exec.c
        file = ERR_PTR(err);
        if (!err) {
                inode = nd.dentry->d_inode;
-@@ -413,7 +418,8 @@
+@@ -413,7 +418,8 @@ struct file *open_exec(const char *name)
                                err = -EACCES;
                        file = ERR_PTR(err);
                        if (!err) {
@@ -101,7 +101,7 @@ Index: linux-2.4.21-chaos/fs/exec.c
                                if (!IS_ERR(file)) {
                                        err = deny_write_access(file);
                                        if (err) {
-@@ -425,6 +431,7 @@
+@@ -425,6 +431,7 @@ out:
                                return file;
                        }
                }
@@ -109,7 +109,7 @@ Index: linux-2.4.21-chaos/fs/exec.c
                path_release(&nd);
        }
        goto out;
-@@ -1348,7 +1355,7 @@
+@@ -1348,7 +1355,7 @@ int do_coredump(long signr, int exit_cod
                goto close_fail;
        if (!file->f_op->write)
                goto close_fail;
@@ -118,10 +118,10 @@ Index: linux-2.4.21-chaos/fs/exec.c
                goto close_fail;
  
        retval = binfmt->core_dump(signr, regs, file);
-Index: linux-2.4.21-chaos/fs/namei.c
+Index: linux-ia64/fs/namei.c
 ===================================================================
---- linux-2.4.21-chaos.orig/fs/namei.c 2003-07-15 04:41:01.000000000 +0400
-+++ linux-2.4.21-chaos/fs/namei.c      2003-12-12 17:03:37.000000000 +0300
+--- linux-ia64.orig/fs/namei.c 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/fs/namei.c      2004-03-17 16:06:13.000000000 -0800
 @@ -94,6 +94,13 @@
   * XEmacs seems to be relying on it...
   */
@@ -136,7 +136,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  /* 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 @@
+@@ -260,10 +267,19 @@ void path_release(struct nameidata *nd)
   * Internal lookup() using the new generic dcache.
   * SMP-safe
   */
@@ -157,7 +157,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
        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 @@
+@@ -281,11 +297,15 @@ static struct dentry * cached_lookup(str
   * make sure that nobody added the entry to the dcache in the meantime..
   * SMP-safe
   */
@@ -174,7 +174,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
        down(&dir->i_sem);
        /*
         * First re-do the cached lookup just in case it was created
-@@ -300,6 +320,9 @@
+@@ -300,6 +320,9 @@ static struct dentry * real_lookup(struc
                result = ERR_PTR(-ENOMEM);
                if (dentry) {
                        lock_kernel();
@@ -184,7 +184,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                        result = dir->i_op->lookup(dir, dentry);
                        unlock_kernel();
                        if (result)
-@@ -321,6 +344,15 @@
+@@ -321,6 +344,15 @@ static struct dentry * real_lookup(struc
                        dput(result);
                        result = ERR_PTR(-ENOENT);
                }
@@ -200,7 +200,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
        }
        return result;
  }
-@@ -332,7 +364,8 @@
+@@ -332,7 +364,8 @@ static struct dentry * real_lookup(struc
   * Without that kind of total limit, nasty chains of consecutive
   * symlinks can cause almost arbitrarily long lookups. 
   */
@@ -210,7 +210,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  {
        int err;
        if (current->link_count >= 8)
-@@ -346,10 +379,12 @@
+@@ -346,10 +379,12 @@ static inline int do_follow_link(struct 
        current->link_count++;
        current->total_link_count++;
        UPDATE_ATIME(dentry->d_inode);
@@ -223,7 +223,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
        path_release(nd);
        return -ELOOP;
  }
-@@ -447,7 +482,8 @@
+@@ -447,7 +482,8 @@ static inline void follow_dotdot(struct 
   *
   * We expect 'base' to be positive and a directory.
   */
@@ -233,7 +233,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  {
        struct dentry *dentry;
        struct inode *inode;
-@@ -524,12 +560,12 @@
+@@ -524,12 +560,12 @@ int link_path_walk(const char * name, st
                                break;
                }
                /* This does the actual lookups.. */
@@ -248,7 +248,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                        err = PTR_ERR(dentry);
                        if (IS_ERR(dentry))
                                break;
-@@ -547,7 +583,7 @@
+@@ -547,7 +583,7 @@ int link_path_walk(const char * name, st
                        goto out_dput;
  
                if (inode->i_op->follow_link) {
@@ -257,7 +257,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                        dput(dentry);
                        if (err)
                                goto return_err;
-@@ -563,7 +599,7 @@
+@@ -563,7 +599,7 @@ int link_path_walk(const char * name, st
                        nd->dentry = dentry;
                }
                err = -ENOTDIR; 
@@ -266,7 +266,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                        break;
                continue;
                /* here ends the main loop */
-@@ -590,12 +626,12 @@
+@@ -590,12 +626,12 @@ last_component:
                        if (err < 0)
                                break;
                }
@@ -281,7 +281,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                        err = PTR_ERR(dentry);
                        if (IS_ERR(dentry))
                                break;
-@@ -605,7 +641,7 @@
+@@ -605,7 +641,7 @@ last_component:
                inode = dentry->d_inode;
                if ((lookup_flags & LOOKUP_FOLLOW)
                    && inode && inode->i_op && inode->i_op->follow_link) {
@@ -290,7 +290,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                        dput(dentry);
                        if (err)
                                goto return_err;
-@@ -619,7 +655,8 @@
+@@ -619,7 +655,8 @@ last_component:
                        goto no_inode;
                if (lookup_flags & LOOKUP_DIRECTORY) {
                        err = -ENOTDIR; 
@@ -300,7 +300,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                                break;
                }
                goto return_base;
-@@ -643,6 +680,25 @@
+@@ -643,6 +680,27 @@ return_reval:
                 * Check the cached dentry for staleness.
                 */
                dentry = nd->dentry;
@@ -316,17 +316,19 @@ Index: linux-2.4.21-chaos/fs/namei.c
 +                                              &dentry->d_name, 0, NULL);
 +                              d_invalidate(dentry);
 +                              dput(dentry);
-+                              if (IS_ERR(new)) { 
++                              if (IS_ERR(new)) {
 +                                      err = PTR_ERR(new);
 +                                      break;
 +                              }
 +                              nd->dentry = new;
 +                      }
++                      if (!nd->dentry->d_inode)
++                              goto no_inode;
 +              } else
                if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
                        err = -ESTALE;
                        if (!dentry->d_op->d_revalidate(dentry, 0)) {
-@@ -656,15 +712,28 @@
+@@ -656,15 +714,28 @@ out_dput:
                dput(dentry);
                break;
        }
@@ -356,7 +358,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  }
  
  /* SMP-safe */
-@@ -749,6 +818,17 @@
+@@ -749,6 +820,17 @@ walk_init_root(const char *name, struct 
  }
  
  /* SMP-safe */
@@ -374,7 +376,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
  {
        int error = 0;
-@@ -763,6 +843,7 @@
+@@ -763,6 +845,7 @@ int path_init(const char *name, unsigned
  {
        nd->last_type = LAST_ROOT; /* if there are only slashes... */
        nd->flags = flags;
@@ -382,7 +384,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
        if (*name=='/')
                return walk_init_root(name,nd);
        read_lock(&current->fs->lock);
-@@ -777,7 +858,8 @@
+@@ -777,7 +860,8 @@ int path_init(const char *name, unsigned
   * needs parent already locked. Doesn't follow mounts.
   * SMP-safe.
   */
@@ -392,7 +394,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  {
        struct dentry * dentry;
        struct inode *inode;
-@@ -800,13 +882,16 @@
+@@ -800,13 +884,16 @@ struct dentry * lookup_hash(struct qstr 
                        goto out;
        }
  
@@ -410,7 +412,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                dentry = inode->i_op->lookup(inode, new);
                unlock_kernel();
                if (!dentry)
-@@ -818,6 +903,12 @@
+@@ -818,6 +905,12 @@ out:
        return dentry;
  }
  
@@ -423,7 +425,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  /* SMP-safe */
  struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
  {
-@@ -839,7 +930,7 @@
+@@ -839,7 +932,7 @@ struct dentry * lookup_one_len(const cha
        }
        this.hash = end_name_hash(hash);
  
@@ -432,7 +434,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  access:
        return ERR_PTR(-EACCES);
  }
-@@ -870,6 +961,23 @@
+@@ -870,6 +963,23 @@ int __user_walk(const char *name, unsign
        return err;
  }
  
@@ -456,7 +458,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  /*
   * It's inline, so penalty for filesystems that don't use sticky bit is
   * minimal.
-@@ -967,7 +1075,8 @@
+@@ -967,7 +1077,8 @@ static inline int lookup_flags(unsigned 
        return retval;
  }
  
@@ -466,7 +468,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  {
        int error;
  
-@@ -980,12 +1089,15 @@
+@@ -980,12 +1091,15 @@ int vfs_create(struct inode *dir, struct
                goto exit_lock;
  
        error = -EACCES;        /* shouldn't it be ENOSYS? */
@@ -484,7 +486,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
        unlock_kernel();
  exit_lock:
        up(&dir->i_zombie);
-@@ -994,6 +1106,11 @@
+@@ -994,6 +1108,11 @@ exit_lock:
        return error;
  }
  
@@ -496,7 +498,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  /*
   *    open_namei()
   *
-@@ -1008,7 +1125,8 @@
+@@ -1008,7 +1127,8 @@ exit_lock:
   * for symlinks (where the permissions are checked later).
   * SMP-safe
   */
@@ -506,7 +508,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  {
        int acc_mode, error = 0;
        struct inode *inode;
-@@ -1018,11 +1136,14 @@
+@@ -1018,11 +1138,14 @@ int open_namei(const char * pathname, in
  
        acc_mode = ACC_MODE(flag);
  
@@ -522,7 +524,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                if (error)
                        return error;
                dentry = nd->dentry;
-@@ -1032,6 +1153,10 @@
+@@ -1032,6 +1155,10 @@ int open_namei(const char * pathname, in
        /*
         * Create - we need to know the parent.
         */
@@ -533,7 +535,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
        error = path_lookup(pathname, LOOKUP_PARENT, nd);
        if (error)
                return error;
-@@ -1047,7 +1172,7 @@
+@@ -1047,7 +1174,7 @@ int open_namei(const char * pathname, in
  
        dir = nd->dentry;
        down(&dir->d_inode->i_sem);
@@ -542,7 +544,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  
  do_last:
        error = PTR_ERR(dentry);
-@@ -1056,11 +1181,12 @@
+@@ -1056,11 +1183,12 @@ do_last:
                goto exit;
        }
  
@@ -556,7 +558,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                up(&dir->d_inode->i_sem);
                dput(nd->dentry);
                nd->dentry = dentry;
-@@ -1164,7 +1290,7 @@
+@@ -1164,7 +1292,7 @@ ok:
                if (!error) {
                        DQUOT_INIT(inode);
                        
@@ -565,7 +567,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                }
                put_write_access(inode);
                if (error)
-@@ -1176,8 +1302,10 @@
+@@ -1176,8 +1304,10 @@ ok:
        return 0;
  
  exit_dput:
@@ -576,7 +578,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
        path_release(nd);
        return error;
  
-@@ -1196,7 +1324,10 @@
+@@ -1196,7 +1326,10 @@ do_link:
         * are done. Procfs-like symlinks just set LAST_BIND.
         */
        UPDATE_ATIME(dentry->d_inode);
@@ -587,7 +589,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
        dput(dentry);
        if (error)
                return error;
-@@ -1218,13 +1349,20 @@
+@@ -1218,13 +1351,20 @@ do_link:
        }
        dir = nd->dentry;
        down(&dir->d_inode->i_sem);
@@ -610,7 +612,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  {
        struct dentry *dentry;
  
-@@ -1232,7 +1370,7 @@
+@@ -1232,7 +1372,7 @@ static struct dentry *lookup_create(stru
        dentry = ERR_PTR(-EEXIST);
        if (nd->last_type != LAST_NORM)
                goto fail;
@@ -619,12 +621,16 @@ Index: linux-2.4.21-chaos/fs/namei.c
        if (IS_ERR(dentry))
                goto fail;
        if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
-@@ -1288,7 +1426,16 @@
+@@ -1288,7 +1428,20 @@ asmlinkage long sys_mknod(const char * f
        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);
@@ -637,7 +643,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
        error = PTR_ERR(dentry);
  
        if (!IS_POSIXACL(nd.dentry->d_inode))
-@@ -1310,6 +1457,7 @@
+@@ -1310,6 +1463,7 @@ asmlinkage long sys_mknod(const char * f
                dput(dentry);
        }
        up(&nd.dentry->d_inode->i_sem);
@@ -645,11 +651,15 @@ Index: linux-2.4.21-chaos/fs/namei.c
        path_release(&nd);
  out:
        putname(tmp);
-@@ -1357,7 +1505,14 @@
+@@ -1357,7 +1511,18 @@ asmlinkage long sys_mkdir(const char * p
                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);
@@ -661,7 +671,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                error = PTR_ERR(dentry);
                if (!IS_ERR(dentry)) {
                        if (!IS_POSIXACL(nd.dentry->d_inode))
-@@ -1366,6 +1521,7 @@
+@@ -1366,6 +1531,7 @@ asmlinkage long sys_mkdir(const char * p
                        dput(dentry);
                }
                up(&nd.dentry->d_inode->i_sem);
@@ -669,7 +679,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                path_release(&nd);
  out:
                putname(tmp);
-@@ -1466,8 +1622,16 @@
+@@ -1466,8 +1632,16 @@ asmlinkage long sys_rmdir(const char * p
                        error = -EBUSY;
                        goto exit1;
        }
@@ -687,7 +697,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
        error = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
                error = vfs_rmdir(nd.dentry->d_inode, dentry);
-@@ -1525,8 +1689,15 @@
+@@ -1525,8 +1699,15 @@ asmlinkage long sys_unlink(const char * 
        error = -EISDIR;
        if (nd.last_type != LAST_NORM)
                goto exit1;
@@ -704,11 +714,15 @@ Index: linux-2.4.21-chaos/fs/namei.c
        error = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
                /* Why not before? Because we want correct error value */
-@@ -1593,15 +1764,23 @@
+@@ -1593,15 +1774,27 @@ asmlinkage long sys_symlink(const char *
                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);
@@ -730,11 +744,15 @@ Index: linux-2.4.21-chaos/fs/namei.c
                putname(to);
        }
        putname(from);
-@@ -1677,7 +1856,14 @@
+@@ -1677,7 +1870,18 @@ asmlinkage long sys_link(const char * ol
                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);
@@ -746,7 +764,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
                error = PTR_ERR(new_dentry);
                if (!IS_ERR(new_dentry)) {
                        error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
-@@ -1721,7 +1907,7 @@
+@@ -1721,7 +1925,7 @@ exit:
   *       locking].
   */
  int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
@@ -755,7 +773,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  {
        int error;
        struct inode *target;
-@@ -1800,7 +1986,7 @@
+@@ -1800,7 +2004,7 @@ out_unlock:
  }
  
  int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
@@ -764,7 +782,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  {
        int error;
  
-@@ -1888,9 +2074,18 @@
+@@ -1888,9 +2092,18 @@ static inline int do_rename(const char *
        if (newnd.last_type != LAST_NORM)
                goto exit2;
  
@@ -784,7 +802,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
        error = PTR_ERR(old_dentry);
        if (IS_ERR(old_dentry))
                goto exit3;
-@@ -1906,16 +2101,16 @@
+@@ -1906,16 +2119,16 @@ static inline int do_rename(const char *
                if (newnd.last.name[newnd.last.len])
                        goto exit4;
        }
@@ -803,7 +821,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
        dput(new_dentry);
  exit4:
        dput(old_dentry);
-@@ -1966,20 +2161,26 @@
+@@ -1966,20 +2179,26 @@ out:
  }
  
  static inline int
@@ -832,7 +850,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  out:
        if (current->link_count || res || nd->last_type!=LAST_NORM)
                return res;
-@@ -2003,7 +2204,13 @@
+@@ -2003,7 +2222,13 @@ fail:
  
  int vfs_follow_link(struct nameidata *nd, const char *link)
  {
@@ -847,7 +865,7 @@ Index: linux-2.4.21-chaos/fs/namei.c
  }
  
  /* get the link contents into pagecache */
-@@ -2045,7 +2252,7 @@
+@@ -2045,7 +2270,7 @@ int page_follow_link(struct dentry *dent
  {
        struct page *page = NULL;
        char *s = page_getlink(dentry, &page);
@@ -856,11 +874,11 @@ Index: linux-2.4.21-chaos/fs/namei.c
        if (page) {
                kunmap(page);
                page_cache_release(page);
-Index: linux-2.4.21-chaos/fs/namespace.c
+Index: linux-ia64/fs/namespace.c
 ===================================================================
---- linux-2.4.21-chaos.orig/fs/namespace.c     2003-07-15 04:41:01.000000000 +0400
-+++ linux-2.4.21-chaos/fs/namespace.c  2003-12-12 17:02:47.000000000 +0300
-@@ -98,6 +98,7 @@
+--- linux-ia64.orig/fs/namespace.c     2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/fs/namespace.c  2004-03-17 16:05:28.000000000 -0800
+@@ -98,6 +98,7 @@ static void detach_mnt(struct vfsmount *
  {
        old_nd->dentry = mnt->mnt_mountpoint;
        old_nd->mnt = mnt->mnt_parent;
@@ -868,7 +886,7 @@ Index: linux-2.4.21-chaos/fs/namespace.c
        mnt->mnt_parent = mnt;
        mnt->mnt_mountpoint = mnt->mnt_root;
        list_del_init(&mnt->mnt_child);
-@@ -109,6 +110,7 @@
+@@ -109,6 +110,7 @@ static void attach_mnt(struct vfsmount *
  {
        mnt->mnt_parent = mntget(nd->mnt);
        mnt->mnt_mountpoint = dget(nd->dentry);
@@ -876,7 +894,7 @@ Index: linux-2.4.21-chaos/fs/namespace.c
        list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry));
        list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts);
        nd->dentry->d_mounted++;
-@@ -488,14 +490,17 @@
+@@ -488,14 +490,17 @@ static int do_loopback(struct nameidata 
  {
        struct nameidata old_nd;
        struct vfsmount *mnt = NULL;
@@ -896,7 +914,7 @@ Index: linux-2.4.21-chaos/fs/namespace.c
  
        down_write(&current->namespace->sem);
        err = -EINVAL;
-@@ -518,6 +523,7 @@
+@@ -518,6 +523,7 @@ static int do_loopback(struct nameidata 
        }
  
        up_write(&current->namespace->sem);
@@ -904,7 +922,7 @@ Index: linux-2.4.21-chaos/fs/namespace.c
        path_release(&old_nd);
        return err;
  }
-@@ -701,6 +707,7 @@
+@@ -701,6 +707,7 @@ long do_mount(char * dev_name, char * di
                  unsigned long flags, void *data_page)
  {
        struct nameidata nd;
@@ -912,7 +930,7 @@ Index: linux-2.4.21-chaos/fs/namespace.c
        int retval = 0;
        int mnt_flags = 0;
  
-@@ -725,10 +732,11 @@
+@@ -725,10 +732,11 @@ long do_mount(char * dev_name, char * di
        flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
  
        /* ... and get the mountpoint */
@@ -927,7 +945,7 @@ Index: linux-2.4.21-chaos/fs/namespace.c
        if (flags & MS_REMOUNT)
                retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
                                    data_page);
-@@ -739,6 +747,8 @@
+@@ -739,6 +747,8 @@ long do_mount(char * dev_name, char * di
        else
                retval = do_add_mount(&nd, type_page, flags, mnt_flags,
                                      dev_name, data_page);
@@ -936,7 +954,7 @@ Index: linux-2.4.21-chaos/fs/namespace.c
        path_release(&nd);
        return retval;
  }
-@@ -904,6 +914,8 @@
+@@ -904,6 +914,8 @@ asmlinkage long sys_pivot_root(const cha
  {
        struct vfsmount *tmp;
        struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
@@ -945,7 +963,7 @@ Index: linux-2.4.21-chaos/fs/namespace.c
        int error;
  
        if (!capable(CAP_SYS_ADMIN))
-@@ -911,14 +923,14 @@
+@@ -911,14 +923,14 @@ asmlinkage long sys_pivot_root(const cha
  
        lock_kernel();
  
@@ -962,7 +980,7 @@ Index: linux-2.4.21-chaos/fs/namespace.c
        if (error)
                goto out1;
  
-@@ -973,8 +985,10 @@
+@@ -973,8 +985,10 @@ out2:
        up(&old_nd.dentry->d_inode->i_zombie);
        up_write(&current->namespace->sem);
        path_release(&user_nd);
@@