Index: linux-2.4.24/fs/ext3/namei.c =================================================================== --- linux-2.4.24.orig/fs/ext3/namei.c 2004-09-23 13:10:48.181661672 +0400 +++ linux-2.4.24/fs/ext3/namei.c 2004-09-23 13:10:48.274647536 +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-09-23 13:10:45.649046688 +0400 +++ linux-2.4.24/fs/ext3/dir.c 2004-09-23 13:10:48.275647384 +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-09-23 13:10:46.365937704 +0400 +++ linux-2.4.24/fs/ext3/ext3-exports.c 2004-09-23 13:10:48.275647384 +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-09-23 13:10:48.188660608 +0400 +++ linux-2.4.24/include/linux/ext3_fs.h 2004-09-23 13:17:40.703948752 +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,11 +520,13 @@ #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_INCOMPAT_EXTENTS 0x0040 /* extents support */ #define EXT3_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR #define EXT3_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_FILETYPE| \ EXT3_FEATURE_INCOMPAT_RECOVER| \ + EXT3_FEATURE_INCOMPAT_MDSNUM| \ EXT3_FEATURE_INCOMPAT_EXTENTS) #define EXT3_FEATURE_RO_COMPAT_SUPP (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \ EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \ @@ -585,6 +588,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-09-23 13:10:46.069982696 +0400 +++ linux-2.4.24/include/linux/ext3_fs_sb.h 2004-09-23 13:11:21.026668472 +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-09-23 13:10:46.153969928 +0400 +++ linux-2.4.24/include/linux/dcache.h 2004-09-23 13:11:06.451884176 +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;