--- /dev/null
+Index: linux-2.4.24/fs/ext3/namei.c
+===================================================================
+--- linux-2.4.24.orig/fs/ext3/namei.c 2004-07-19 11:11:29.000000000 +0400
++++ linux-2.4.24/fs/ext3/namei.c 2004-07-19 11:11:29.000000000 +0400
+@@ -1099,6 +1099,23 @@
+ inode = NULL;
+ if (bh) {
+ unsigned long ino = le32_to_cpu(de->inode);
++ unsigned type = de->file_type;
++ __u32 *mds;
++ mds = (__u32 *)((char *) de + EXT3_DIR_REC_LEN(de->name_len));
++ if ((type & 128) && EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb,
++ EXT3_FEATURE_INCOMPAT_MDSNUM) &&
++ mds[0] != EXT3_SB(dir->i_sb)->s_mdsnum) {
++ struct ext3_super_block *es;
++ es = EXT3_SB(dir->i_sb)->s_es;
++ ext3_unlock_htree(dir, lock);
++ brelse (bh);
++ dentry->d_flags |= DCACHE_CROSS_REF;
++ dentry->d_generation = mds[1];
++ dentry->d_mdsnum = mds[0];
++ dentry->d_inum = ino;
++ d_add(dentry, NULL);
++ return NULL;
++ }
+ ext3_unlock_htree(dir, lock);
+ brelse (bh);
+ inode = iget(dir->i_sb, ino);
+@@ -1138,7 +1155,7 @@
+ while (count--) {
+ struct ext3_dir_entry_2 *de =
+ (struct ext3_dir_entry_2 *) (from + map->offs);
+- rec_len = EXT3_DIR_REC_LEN(de->name_len);
++ rec_len = EXT3_DIR_REC_LEN_DE(de);
+ memcpy (to, de, rec_len);
+ ((struct ext3_dir_entry_2 *)to)->rec_len = cpu_to_le16(rec_len);
+ de->inode = 0;
+@@ -1159,7 +1176,7 @@
+ next = (struct ext3_dir_entry_2 *) ((char *) de +
+ le16_to_cpu(de->rec_len));
+ if (de->inode && de->name_len) {
+- rec_len = EXT3_DIR_REC_LEN(de->name_len);
++ rec_len = EXT3_DIR_REC_LEN_DE(de);
+ if (de > to)
+ memmove(to, de, rec_len);
+ to->rec_len = cpu_to_le16(rec_len);
+@@ -1275,6 +1292,7 @@
+ struct buffer_head * bh)
+ {
+ struct inode *dir = dentry->d_parent->d_inode;
++ struct super_block *sb = dir->i_sb;
+ const char *name = dentry->d_name.name;
+ int namelen = dentry->d_name.len;
+ unsigned long offset = 0;
+@@ -1283,6 +1301,10 @@
+ char *top;
+
+ reclen = EXT3_DIR_REC_LEN(namelen);
++ if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_MDSNUM)
++ && (dentry->d_flags & DCACHE_CROSS_REF)
++ && (dentry->d_mdsnum != EXT3_SB(sb)->s_mdsnum))
++ reclen += 8; /* we need space to store mds num */
+ if (!de) {
+ de = (struct ext3_dir_entry_2 *)bh->b_data;
+ top = bh->b_data + dir->i_sb->s_blocksize - reclen;
+@@ -1296,7 +1318,7 @@
+ brelse (bh);
+ return -EEXIST;
+ }
+- nlen = EXT3_DIR_REC_LEN(de->name_len);
++ nlen = EXT3_DIR_REC_LEN_DE(de);
+ rlen = le16_to_cpu(de->rec_len);
+ if ((de->inode? rlen - nlen: rlen) >= reclen)
+ break;
+@@ -1315,7 +1337,7 @@
+ }
+
+ /* By now the buffer is marked for journaling */
+- nlen = EXT3_DIR_REC_LEN(de->name_len);
++ nlen = EXT3_DIR_REC_LEN_DE(de);
+ rlen = le16_to_cpu(de->rec_len);
+ if (de->inode) {
+ struct ext3_dir_entry_2 *de1 =
+@@ -1327,8 +1349,20 @@
+ de->file_type = EXT3_FT_UNKNOWN;
+ if (inode) {
+ de->inode = cpu_to_le32(inode->i_ino);
+- ext3_set_de_type(dir->i_sb, de, inode->i_mode);
+- } else
++ ext3_set_de_type(sb, de, inode->i_mode);
++ } else if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_MDSNUM)
++ && (dentry->d_flags & DCACHE_CROSS_REF)) {
++ if (dentry->d_mdsnum != EXT3_SB(sb)->s_mdsnum) {
++ __u32 *mds;
++ mds = (__u32 *)((char *)de + EXT3_DIR_REC_LEN(namelen));
++ mds[0] = cpu_to_le32(dentry->d_mdsnum);
++ mds[1] = cpu_to_le32(dentry->d_generation);
++ de->inode = cpu_to_le32(dentry->d_inum);
++ de->file_type = 128;
++ } else {
++ de->inode = cpu_to_le32(dentry->d_inum);
++ }
++ } else
+ de->inode = 0;
+ de->name_len = namelen;
+ memcpy (de->name, name, namelen);
+@@ -2662,6 +2696,79 @@
+ }
+
+ /*
++ * caller has to make sure directory is protected
++ */
++int ext3_add_dir_entry(struct dentry *dentry)
++{
++ struct inode *dir = dentry->d_parent->d_inode;
++ handle_t *handle;
++ int err;
++
++ handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
++ EXT3_INDEX_EXTRA_TRANS_BLOCKS);
++ if (IS_ERR(handle)) {
++ return PTR_ERR(handle);
++ }
++
++ if (IS_SYNC(dir))
++ handle->h_sync = 1;
++
++ err = ext3_add_entry(handle, dentry, NULL);
++ ext3_journal_stop(handle, dir);
++ return err;
++}
++
++/*
++ * caller has to make sure directory is protected
++ */
++int ext3_del_dir_entry(struct dentry *dentry)
++{
++ struct inode * inode;
++ struct inode * dir = dentry->d_parent->d_inode;
++ struct buffer_head * bh;
++ struct ext3_dir_entry_2 * de;
++ handle_t *handle;
++ void *lock;
++ int retval;
++
++ handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
++ if (IS_ERR(handle)) {
++ return PTR_ERR(handle);
++ }
++
++ if (IS_SYNC(dir))
++ handle->h_sync = 1;
++
++ retval = -ENOENT;
++ bh = ext3_find_entry (dentry, &de, 1, &lock);
++ if (!bh)
++ goto end_unlink;
++
++ inode = dentry->d_inode;
++ if (inode)
++ DQUOT_INIT(inode);
++
++ 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;
++ ext3_update_dx_flag(dir);
++ if (inode) {
++ inode->i_ctime = dir->i_ctime;
++ ext3_mark_inode_dirty(handle, inode);
++ if (S_ISDIR(inode->i_mode))
++ dir->i_nlink--;
++ }
++ ext3_mark_inode_dirty(handle, dir);
++ retval = 0;
++
++end_unlink:
++ ext3_journal_stop(handle, dir);
++ brelse (bh);
++ return retval;
++}
++/*
+ * directories can handle most operations...
+ */
+ struct inode_operations ext3_dir_inode_operations = {
+Index: linux-2.4.24/fs/ext3/dir.c
+===================================================================
+--- linux-2.4.24.orig/fs/ext3/dir.c 2004-07-19 11:11:16.000000000 +0400
++++ linux-2.4.24/fs/ext3/dir.c 2004-07-30 23:56:03.000000000 +0400
+@@ -42,6 +42,9 @@
+
+ static unsigned char get_dtype(struct super_block *sb, int filetype)
+ {
++ if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_MDSNUM))
++ return DT_UNKNOWN;
++
+ if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_FILETYPE) ||
+ (filetype >= EXT3_FT_MAX))
+ return DT_UNKNOWN;
+@@ -67,8 +70,10 @@
+ else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
+ error_msg = "directory entry across blocks";
+ else if (le32_to_cpu(de->inode) >
+- le32_to_cpu(dir->i_sb->u.ext3_sb.s_es->s_inodes_count))
+- error_msg = "inode out of bounds";
++ le32_to_cpu(dir->i_sb->u.ext3_sb.s_es->s_inodes_count)) {
++ if (de->file_type != 128)
++ error_msg = "inode out of bounds";
++ }
+
+ if (error_msg != NULL)
+ ext3_error (dir->i_sb, function,
+Index: linux-2.4.24/fs/ext3/ext3-exports.c
+===================================================================
+--- linux-2.4.24.orig/fs/ext3/ext3-exports.c 2004-07-19 11:11:16.000000000 +0400
++++ linux-2.4.24/fs/ext3/ext3-exports.c 2004-07-19 11:11:29.000000000 +0400
+@@ -26,3 +26,10 @@
+ EXPORT_SYMBOL(ext3_decode_error);
+ EXPORT_SYMBOL(__ext3_std_error);
+
++int ext3_add_dir_entry (struct dentry *dentry);
++EXPORT_SYMBOL(ext3_add_dir_entry);
++int ext3_del_dir_entry(struct dentry *dentry);
++EXPORT_SYMBOL(ext3_del_dir_entry);
++
++
++
+Index: linux-2.4.24/include/linux/ext3_fs.h
+===================================================================
+--- linux-2.4.24.orig/include/linux/ext3_fs.h 2004-07-19 11:11:29.000000000 +0400
++++ linux-2.4.24/include/linux/ext3_fs.h 2004-07-19 11:13:53.000000000 +0400
+@@ -446,7 +446,8 @@
+ __u8 s_def_hash_version; /* Default hash version to use */
+ __u8 s_reserved_char_pad;
+ __u16 s_reserved_word_pad;
+- __u32 s_reserved[192]; /* Padding to the end of the block */
++ __u32 s_mdsnum;
++ __u32 s_reserved[191]; /* Padding to the end of the block */
+ };
+
+ #ifdef __KERNEL__
+@@ -519,10 +520,12 @@
+ #define EXT3_FEATURE_INCOMPAT_FILETYPE 0x0002
+ #define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
+ #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
++#define EXT3_FEATURE_INCOMPAT_MDSNUM 0x0020 /* direntry has mdsnum */
+
+ #define EXT3_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR
+ #define EXT3_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_FILETYPE| \
+- EXT3_FEATURE_INCOMPAT_RECOVER)
++ EXT3_FEATURE_INCOMPAT_RECOVER| \
++ EXT3_FEATURE_INCOMPAT_MDSNUM)
+ #define EXT3_FEATURE_RO_COMPAT_SUPP (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
+@@ -583,6 +586,9 @@
+ #define EXT3_DIR_ROUND (EXT3_DIR_PAD - 1)
+ #define EXT3_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT3_DIR_ROUND) & \
+ ~EXT3_DIR_ROUND)
++#define EXT3_DIR_REC_LEN_DE(de) (EXT3_DIR_REC_LEN((de)->name_len) + \
++ (((de)->file_type & 128) ? 8 : 0))
++
+ /*
+ * Hash Tree Directory indexing
+ * (c) Daniel Phillips, 2001
+Index: linux-2.4.24/include/linux/ext3_fs_sb.h
+===================================================================
+--- linux-2.4.24.orig/include/linux/ext3_fs_sb.h 2004-07-19 11:11:16.000000000 +0400
++++ linux-2.4.24/include/linux/ext3_fs_sb.h 2004-07-19 11:12:54.000000000 +0400
+@@ -86,6 +86,7 @@
+ wait_queue_head_t s_delete_thread_queue;
+ wait_queue_head_t s_delete_waiter_queue;
+ #endif
++ u32 s_mdsnum;
+ };
+
+ #endif /* _LINUX_EXT3_FS_SB */
+Index: linux-2.4.24/include/linux/dcache.h
+===================================================================
+--- linux-2.4.24.orig/include/linux/dcache.h 2004-07-19 11:11:16.000000000 +0400
++++ linux-2.4.24/include/linux/dcache.h 2004-07-19 11:12:53.000000000 +0400
+@@ -120,6 +120,9 @@
+ atomic_t d_count;
+ unsigned int d_flags;
+ struct inode * d_inode; /* Where the name belongs to - NULL is negative */
++ unsigned d_inum; /* for cross-fs references (Lustre) */
++ unsigned d_mdsnum; /* for cross-fs references (Lustre) */
++ unsigned d_generation; /* for cross-fs references (Lustre) */
+ struct dentry * d_parent; /* parent directory */
+ struct list_head d_hash; /* lookup hash list */
+ struct list_head d_lru; /* d_count = 0 LRU list */
+@@ -193,6 +196,7 @@
+ */
+ #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */
+ #define DCACHE_LUSTRE_INVALID 0x0010 /* Lustre invalidated */
++#define DCACHE_CROSS_REF 0x0020 /* entry points to inode on another MDS */
+
+ extern spinlock_t dcache_lock;
+