Whamcloud - gitweb
b=17670
authorpravins <pravins>
Sun, 4 Oct 2009 18:13:14 +0000 (18:13 +0000)
committerpravins <pravins>
Sun, 4 Oct 2009 18:13:14 +0000 (18:13 +0000)
i=adilger
i=girish

        add "FID in dirent" support in ext4

ldiskfs/kernel_patches/patches/ext4-kill-dx_root.patch [new file with mode: 0644]
ldiskfs/kernel_patches/patches/ext4_data_in_dirent.patch [new file with mode: 0644]
ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel5-ext4.series

diff --git a/ldiskfs/kernel_patches/patches/ext4-kill-dx_root.patch b/ldiskfs/kernel_patches/patches/ext4-kill-dx_root.patch
new file mode 100644 (file)
index 0000000..908a6de
--- /dev/null
@@ -0,0 +1,237 @@
+removes static definition of dx_root struct. so that "." and ".." dirent can
+have extra data. This patch does not change any functionality but is required for
+ext4_data_in_dirent patch.
+Index: b/fs/ext4/namei.c
+===================================================================
+--- a/fs/ext4/namei.c
++++ b/fs/ext4/namei.c
+@@ -121,22 +121,13 @@ struct dx_entry
+  * hash version mod 4 should never be 0.  Sincerely, the paranoia department.
+  */
+-struct dx_root
++struct dx_root_info
+ {
+-      struct fake_dirent dot;
+-      char dot_name[4];
+-      struct fake_dirent dotdot;
+-      char dotdot_name[4];
+-      struct dx_root_info
+-      {
+-              __le32 reserved_zero;
+-              u8 hash_version;
+-              u8 info_length; /* 8 */
+-              u8 indirect_levels;
+-              u8 unused_flags;
+-      }
+-      info;
+-      struct dx_entry entries[0];
++      __le32 reserved_zero;
++      u8 hash_version;
++      u8 info_length; /* 8 */
++      u8 indirect_levels;
++      u8 unused_flags;
+ };
+ struct dx_node
+@@ -225,6 +216,16 @@ ext4_next_entry(struct ext4_dir_entry_2 
+  * Future: use high four bits of block for coalesce-on-delete flags
+  * Mask them off for now.
+  */
++struct dx_root_info * dx_get_dx_info(struct ext4_dir_entry_2 *de)
++{
++       /* get dotdot first */
++       de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(1));
++
++       /* dx root info is after dotdot entry */
++       de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(2));
++
++       return (struct dx_root_info *) de;
++}
+ static inline ext4_lblk_t dx_get_block(struct dx_entry *entry)
+ {
+@@ -378,7 +379,7 @@ dx_probe(struct dentry *dentry, struct i
+ {
+       unsigned count, indirect;
+       struct dx_entry *at, *entries, *p, *q, *m;
+-      struct dx_root *root;
++      struct dx_root_info * info;
+       struct buffer_head *bh;
+       struct dx_frame *frame = frame_in;
+       u32 hash;
+@@ -388,46 +389,46 @@ dx_probe(struct dentry *dentry, struct i
+               dir = dentry->d_parent->d_inode;
+       if (!(bh = ext4_bread (NULL,dir, 0, 0, err)))
+               goto fail;
+-      root = (struct dx_root *) bh->b_data;
+-      if (root->info.hash_version != DX_HASH_TEA &&
+-          root->info.hash_version != DX_HASH_HALF_MD4 &&
+-          root->info.hash_version != DX_HASH_LEGACY) {
++
++      info = dx_get_dx_info((struct ext4_dir_entry_2*)bh->b_data);
++      if (info->hash_version != DX_HASH_TEA &&
++          info->hash_version != DX_HASH_HALF_MD4 &&
++          info->hash_version != DX_HASH_LEGACY) {
+               ext4_warning(dir->i_sb, __func__,
+                            "Unrecognised inode hash code %d for directory "
+-                           "#%lu", root->info.hash_version, dir->i_ino);
++                           "#%lu", info->hash_version, dir->i_ino);
+               brelse(bh);
+               *err = ERR_BAD_DX_DIR;
+               goto fail;
+       }
+-      hinfo->hash_version = root->info.hash_version;
++      hinfo->hash_version = info->hash_version;
+       hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed;
+       if (dentry)
+               ext4fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);
+       hash = hinfo->hash;
+-      if (root->info.unused_flags & 1) {
++      if (info->unused_flags & 1) {
+               ext4_warning(dir->i_sb, __func__,
+                            "Unimplemented inode hash flags: %#06x",
+-                           root->info.unused_flags);
++                           info->unused_flags);
+               brelse(bh);
+               *err = ERR_BAD_DX_DIR;
+               goto fail;
+       }
+-      if ((indirect = root->info.indirect_levels) > 1) {
++      if ((indirect = info->indirect_levels) > 1) {
+               ext4_warning(dir->i_sb, __func__,
+                            "Unimplemented inode hash depth: %#06x",
+-                           root->info.indirect_levels);
++                           info->indirect_levels);
+               brelse(bh);
+               *err = ERR_BAD_DX_DIR;
+               goto fail;
+       }
+-      entries = (struct dx_entry *) (((char *)&root->info) +
+-                                     root->info.info_length);
++      entries = (struct dx_entry *) (((char *)info) + info->info_length);
+       if (dx_get_limit(entries) != dx_root_limit(dir,
+-                                                 root->info.info_length)) {
++                                                 info->info_length)) {
+               ext4_warning(dir->i_sb, __func__,
+                            "dx entry: limit != root limit");
+               brelse(bh);
+@@ -509,10 +510,12 @@ fail:
+ static void dx_release (struct dx_frame *frames)
+ {
++      struct dx_root_info *info;
+       if (frames[0].bh == NULL)
+               return;
+-      if (((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels)
++      info = dx_get_dx_info((struct ext4_dir_entry_2*)frames[0].bh->b_data);
++      if (info->indirect_levels)
+               brelse(frames[1].bh);
+       brelse(frames[0].bh);
+ }
+@@ -1430,17 +1433,16 @@ static int make_indexed_dir(handle_t *ha
+       const char      *name = dentry->d_name.name;
+       int             namelen = dentry->d_name.len;
+       struct buffer_head *bh2;
+-      struct dx_root  *root;
+       struct dx_frame frames[2], *frame;
+       struct dx_entry *entries;
+-      struct ext4_dir_entry_2 *de, *de2;
++      struct ext4_dir_entry_2 *de, *de2, *dot_de, *dotdot_de;
+       char            *data1, *top;
+       unsigned        len;
+       int             retval;
+       unsigned        blocksize;
+       struct dx_hash_info hinfo;
+       ext4_lblk_t  block;
+-      struct fake_dirent *fde;
++      struct dx_root_info *dx_info;
+       blocksize =  dir->i_sb->s_blocksize;
+       dxtrace(printk("Creating index\n"));
+@@ -1450,7 +1452,6 @@ static int make_indexed_dir(handle_t *ha
+               brelse(bh);
+               return retval;
+       }
+-      root = (struct dx_root *) bh->b_data;
+       bh2 = ext4_append (handle, dir, &block, &retval);
+       if (!(bh2)) {
+@@ -1460,11 +1461,13 @@ static int make_indexed_dir(handle_t *ha
+       EXT4_I(dir)->i_flags |= EXT4_INDEX_FL;
+       data1 = bh2->b_data;
++      dot_de = (struct ext4_dir_entry_2 *) bh->b_data;
++      dotdot_de = ext4_next_entry(dot_de);
++
+       /* The 0th block becomes the root, move the dirents out */
+-      fde = &root->dotdot;
+-      de = (struct ext4_dir_entry_2 *)((char *)fde +
+-              ext4_rec_len_from_disk(fde->rec_len));
+-      len = ((char *) root) + blocksize - (char *) de;
++      de = (struct ext4_dir_entry_2 *)((char *)dotdot_de +
++              ext4_rec_len_from_disk(dotdot_de->rec_len));
++      len = ((char *) dot_de) + blocksize - (char *) de;
+       memcpy (data1, de, len);
+       de = (struct ext4_dir_entry_2 *) data1;
+       top = data1 + len;
+@@ -1472,18 +1475,24 @@ static int make_indexed_dir(handle_t *ha
+               de = de2;
+       de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de);
+       /* Initialize the root; the dot dirents already exist */
+-      de = (struct ext4_dir_entry_2 *) (&root->dotdot);
+-      de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2));
+-      memset (&root->info, 0, sizeof(root->info));
+-      root->info.info_length = sizeof(root->info);
+-      root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
+-      entries = root->entries;
+-      dx_set_block (entries, 1);
+-      dx_set_count (entries, 1);
+-      dx_set_limit (entries, dx_root_limit(dir, sizeof(root->info)));
++      dotdot_de->rec_len = ext4_rec_len_to_disk(blocksize -
++                      le16_to_cpu(dot_de->rec_len));
++
++      /* initialize hashing info */
++      dx_info = dx_get_dx_info(dot_de);
++      memset (dx_info, 0, sizeof(*dx_info));
++      dx_info->info_length = sizeof(*dx_info);
++      dx_info->hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
++
++      entries = (void *)dx_info + sizeof(*dx_info);
++
++      dx_set_block(entries, 1);
++      dx_set_count(entries, 1);
++      dx_set_limit(entries, dx_root_limit(dir, sizeof(*dx_info)));
+       /* Initialize as for dx_probe */
+-      hinfo.hash_version = root->info.hash_version;
++      hinfo.hash_version = dx_info->hash_version;
++
+       hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
+       ext4fs_dirhash(name, namelen, &hinfo);
+       frame = frames;
+@@ -1724,6 +1733,7 @@ static int ext4_dx_add_entry(handle_t *h
+                               goto journal_error;
+                       brelse (bh2);
+               } else {
++                      struct dx_root_info * info;
+                       dxtrace(printk("Creating second level index...\n"));
+                       memcpy((char *) entries2, (char *) entries,
+                              icount * sizeof(struct dx_entry));
+@@ -1732,7 +1742,9 @@ static int ext4_dx_add_entry(handle_t *h
+                       /* Set up root */
+                       dx_set_count(entries, 1);
+                       dx_set_block(entries + 0, newblock);
+-                      ((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1;
++                      info = dx_get_dx_info((struct ext4_dir_entry_2*)
++                                      frames[0].bh->b_data);
++                      info->indirect_levels = 1;
+                       /* Add new access path frame */
+                       frame = frames + 1;
diff --git a/ldiskfs/kernel_patches/patches/ext4_data_in_dirent.patch b/ldiskfs/kernel_patches/patches/ext4_data_in_dirent.patch
new file mode 100644 (file)
index 0000000..bf348ff
--- /dev/null
@@ -0,0 +1,504 @@
+this patch implements feature which allows ext4 fs users (e.g. Lustre)
+to store data in ext4 dirent.
+data is stored in ext4 dirent after file-name, this space is accounted
+in de->rec_len. flag EXT4_DIRENT_LUFID added to d_type if extra data
+is present.
+
+make use of dentry->d_fsdata to pass fid to ext4. so no
+changes in ext4_add_entry() interface required.
+
+Index: b/fs/ext4/dir.c
+===================================================================
+--- a/fs/ext4/dir.c
++++ b/fs/ext4/dir.c
+@@ -53,11 +53,18 @@ const struct file_operations ext4_dir_op
+ static unsigned char get_dtype(struct super_block *sb, int filetype)
+ {
++      int fl_index = filetype & EXT4_FT_MASK;
++
+       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) ||
+-          (filetype >= EXT4_FT_MAX))
++          (fl_index >= EXT4_FT_MAX))
+               return DT_UNKNOWN;
+-      return (ext4_filetype_table[filetype]);
++      if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_DIRDATA))
++              return (ext4_filetype_table[fl_index]);
++
++      return (ext4_filetype_table[fl_index]) |
++              (filetype & EXT4_DIRENT_LUFID);
++
+ }
+@@ -69,11 +76,11 @@ int ext4_check_dir_entry (const char * f
+       const char * error_msg = NULL;
+       const int rlen = ext4_rec_len_from_disk(de->rec_len);
+-      if (rlen < EXT4_DIR_REC_LEN(1))
++      if (rlen < __EXT4_DIR_REC_LEN(1))
+               error_msg = "rec_len is smaller than minimal";
+       else if (rlen % 4 != 0)
+               error_msg = "rec_len % 4 != 0";
+-      else if (rlen < EXT4_DIR_REC_LEN(de->name_len))
++      else if (rlen < EXT4_DIR_REC_LEN(de))
+               error_msg = "rec_len is too small for name_len";
+       else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
+               error_msg = "directory entry across blocks";
+@@ -175,7 +182,7 @@ revalidate:
+                                * failure will be detected in the
+                                * dirent test below. */
+                               if (ext4_rec_len_from_disk(de->rec_len)
+-                                              < EXT4_DIR_REC_LEN(1))
++                                              < __EXT4_DIR_REC_LEN(1))
+                                       break;
+                               i += ext4_rec_len_from_disk(de->rec_len);
+                       }
+@@ -335,12 +342,17 @@ int ext4_htree_store_dirent(struct file 
+       struct fname * fname, *new_fn;
+       struct dir_private_info *info;
+       int len;
++      int extra_data = 1;
+       info = (struct dir_private_info *) dir_file->private_data;
+       p = &info->root.rb_node;
+       /* Create and allocate the fname structure */
+-      len = sizeof(struct fname) + dirent->name_len + 1;
++      if (dirent->file_type & EXT4_DIRENT_LUFID)
++              extra_data = ext4_get_dirent_data_len(dirent);
++
++      len = sizeof(struct fname) + dirent->name_len + extra_data;
++
+       new_fn = kzalloc(len, GFP_KERNEL);
+       if (!new_fn)
+               return -ENOMEM;
+@@ -349,7 +361,7 @@ int ext4_htree_store_dirent(struct file 
+       new_fn->inode = le32_to_cpu(dirent->inode);
+       new_fn->name_len = dirent->name_len;
+       new_fn->file_type = dirent->file_type;
+-      memcpy(new_fn->name, dirent->name, dirent->name_len);
++      memcpy(new_fn->name, dirent->name, dirent->name_len + extra_data);
+       new_fn->name[dirent->name_len] = 0;
+       while (*p) {
+Index: b/fs/ext4/ext4.h
+===================================================================
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -771,6 +771,7 @@ static inline int ext4_valid_inum(struct
+ #define EXT4_FEATURE_INCOMPAT_64BIT           0x0080
+ #define EXT4_FEATURE_INCOMPAT_MMP               0x0100
+ #define EXT4_FEATURE_INCOMPAT_FLEX_BG         0x0200
++#define EXT4_FEATURE_INCOMPAT_DIRDATA         0x1000
+ #define EXT4_FEATURE_COMPAT_SUPP      EXT2_FEATURE_COMPAT_EXT_ATTR
+ #define EXT4_FEATURE_INCOMPAT_SUPP    (EXT4_FEATURE_INCOMPAT_FILETYPE| \
+@@ -779,7 +780,9 @@ static inline int ext4_valid_inum(struct
+                                        EXT4_FEATURE_INCOMPAT_EXTENTS| \
+                                        EXT4_FEATURE_INCOMPAT_64BIT| \
+                                        EXT4_FEATURE_INCOMPAT_FLEX_BG| \
+-                                       EXT4_FEATURE_INCOMPAT_MMP)
++                                       EXT4_FEATURE_INCOMPAT_MMP| \
++                                       EXT4_FEATURE_INCOMPAT_DIRDATA)
++
+ #define EXT4_FEATURE_RO_COMPAT_SUPP   (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+                                        EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
+                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
+@@ -847,6 +850,43 @@ struct ext4_dir_entry_2 {
+ #define EXT4_FT_SYMLINK               7
+ #define EXT4_FT_MAX           8
++#define EXT4_FT_MASK          0xf
++
++#if EXT4_FT_MAX > EXT4_FT_MASK
++#error "conflicting EXT4_FT_MAX and EXT4_FT_MASK"
++#endif
++
++/*
++ * d_type has 4 unused bits, so it can hold four types data. these different
++ * type of data (e.g. lustre data, high 32 bits of 64-bit inode number) can be
++ * stored, in flag order, after file-name in ext4 dirent.
++*/
++/*
++ * this flag is added to d_type if ext4 dirent has extra data after
++ * filename. this data length is variable and length is stored in first byte
++ * of data. data start after filename NUL byte.
++ * This is used by Lustre FS.
++  */
++#define EXT4_DIRENT_LUFID             0x10
++
++#define EXT4_LUFID_MAGIC    0xAD200907UL
++struct ext4_dentry_param {
++      __u32  edp_magic;       /* EXT4_LUFID_MAGIC */
++      char   edp_len;         /* size of edp_data in bytes */
++      char   edp_data[0];     /* packed array of data */
++} __attribute__((packed));
++
++static inline unsigned char *ext4_dentry_get_data(struct super_block *sb,
++              struct ext4_dentry_param* p)
++
++{
++      if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_DIRDATA))
++              return NULL;
++      if (p && p->edp_magic == EXT4_LUFID_MAGIC)
++              return &p->edp_len;
++      else
++              return NULL;
++}
+ /*
+  * EXT4_DIR_PAD defines the directory entries boundaries
+@@ -855,8 +895,11 @@ struct ext4_dir_entry_2 {
+  */
+ #define EXT4_DIR_PAD                  4
+ #define EXT4_DIR_ROUND                        (EXT4_DIR_PAD - 1)
+-#define EXT4_DIR_REC_LEN(name_len)    (((name_len) + 8 + EXT4_DIR_ROUND) & \
++#define __EXT4_DIR_REC_LEN(name_len)  (((name_len) + 8 + EXT4_DIR_ROUND) & \
+                                        ~EXT4_DIR_ROUND)
++#define EXT4_DIR_REC_LEN(de)          (__EXT4_DIR_REC_LEN(de->name_len +\
++                                      ext4_get_dirent_data_len(de)))
++
+ #define EXT4_MAX_REC_LEN              ((1<<16)-1)
+ static inline unsigned ext4_rec_len_from_disk(__le16 dlen)
+@@ -1155,7 +1198,7 @@ extern struct buffer_head * ext4_find_en
+                                           struct ext4_dir_entry_2
+                                           ** res_dir);
+ extern int ext4_add_dot_dotdot(handle_t *handle, struct inode *dir,
+-                             struct inode *inode);
++                        struct inode *inode, const void *, const void *);
+ extern int ext4_orphan_add(handle_t *, struct inode *);
+ extern int ext4_orphan_del(handle_t *, struct inode *);
+ extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
+@@ -1343,7 +1386,28 @@ static inline int ext4_is_group_locked(s
+       return spin_is_locked(ext4_group_lock_ptr(sb, group));
+ }
+-
++/*
++ * Compute the total directory entry data length.
++ * This includes the filename and an implicit NUL terminator (always present),
++ * and optional extensions.  Each extension has a bit set in the high 4 bits of
++ * de->file_type, and the extension length is the first byte in each entry.
++ */
++
++static inline int ext4_get_dirent_data_len(struct ext4_dir_entry_2 *de)
++{
++      char *len = de->name + de->name_len + 1 /* NUL terminator */;
++      int dlen = 0;
++      __u8 extra_data_flags = (de->file_type & ~EXT4_FT_MASK) >> 4;
++
++      while (extra_data_flags) {
++              if (extra_data_flags & 1) {
++                      dlen += *len + (dlen == 0);
++                      len += *len;
++              }
++              extra_data_flags >>= 1;
++      }
++      return dlen;
++}
+ #endif        /* __KERNEL__ */
+Index: b/fs/ext4/namei.c
+===================================================================
+--- a/fs/ext4/namei.c
++++ b/fs/ext4/namei.c
+@@ -177,7 +177,8 @@ static unsigned dx_get_count (struct dx_
+ static unsigned dx_get_limit (struct dx_entry *entries);
+ static void dx_set_count (struct dx_entry *entries, unsigned value);
+ static void dx_set_limit (struct dx_entry *entries, unsigned value);
+-static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
++static inline unsigned dx_root_limit(__u32 blocksize,
++              struct ext4_dir_entry_2 *dot_de, unsigned infosize);
+ static unsigned dx_node_limit (struct inode *dir);
+ static struct dx_frame *dx_probe(struct dentry *dentry,
+                                struct inode *dir,
+@@ -218,11 +219,12 @@ ext4_next_entry(struct ext4_dir_entry_2 
+  */
+ struct dx_root_info * dx_get_dx_info(struct ext4_dir_entry_2 *de)
+ {
+-       /* get dotdot first */
+-       de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(1));
++      BUG_ON(de->name_len != 1);
++      /* get dotdot first */
++      de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(de));
+-       /* dx root info is after dotdot entry */
+-       de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(2));
++      /* dx root info is after dotdot entry */
++      de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(de));
+        return (struct dx_root_info *) de;
+ }
+@@ -267,16 +269,23 @@ static inline void dx_set_limit (struct 
+       ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value);
+ }
+-static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize)
++static inline unsigned dx_root_limit(__u32 blocksize,
++              struct ext4_dir_entry_2 *dot_de, unsigned infosize)
+ {
+-      unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) -
+-              EXT4_DIR_REC_LEN(2) - infosize;
++      struct ext4_dir_entry_2 *dotdot_de;
++      unsigned entry_space;
++
++      BUG_ON(dot_de->name_len != 1);
++      dotdot_de = ext4_next_entry(dot_de);
++      entry_space = blocksize - EXT4_DIR_REC_LEN(dot_de) -
++                       EXT4_DIR_REC_LEN(dotdot_de) - infosize;
++
+       return entry_space / sizeof(struct dx_entry);
+ }
+ static inline unsigned dx_node_limit (struct inode *dir)
+ {
+-      unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0);
++      unsigned entry_space = dir->i_sb->s_blocksize - __EXT4_DIR_REC_LEN(0);
+       return entry_space / sizeof(struct dx_entry);
+ }
+@@ -323,7 +332,7 @@ static struct stats dx_show_leaf(struct 
+                               printk(":%x.%u ", h.hash,
+                                      ((char *) de - base));
+                       }
+-                      space += EXT4_DIR_REC_LEN(de->name_len);
++                      space += EXT4_DIR_REC_LEN(de);
+                       names++;
+               }
+               de = ext4_next_entry(de);
+@@ -427,7 +436,8 @@ dx_probe(struct dentry *dentry, struct i
+       entries = (struct dx_entry *) (((char *)info) + info->info_length);
+-      if (dx_get_limit(entries) != dx_root_limit(dir,
++      if (dx_get_limit(entries) != dx_root_limit(dir->i_sb->s_blocksize,
++                                                 (struct ext4_dir_entry_2*)bh->b_data,
+                                                  info->info_length)) {
+               ext4_warning(dir->i_sb, __func__,
+                            "dx entry: limit != root limit");
+@@ -617,7 +627,7 @@ static int htree_dirblock_to_tree(struct
+       de = (struct ext4_dir_entry_2 *) bh->b_data;
+       top = (struct ext4_dir_entry_2 *) ((char *) de +
+                                          dir->i_sb->s_blocksize -
+-                                         EXT4_DIR_REC_LEN(0));
++                                         __EXT4_DIR_REC_LEN(0));
+       for (; de < top; de = ext4_next_entry(de)) {
+               if (!ext4_check_dir_entry("htree_dirblock_to_tree", dir, de, bh,
+                                       (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb))
+@@ -1026,7 +1036,7 @@ static struct buffer_head * ext4_dx_find
+                       goto errout;
+               de = (struct ext4_dir_entry_2 *) bh->b_data;
+               top = (struct ext4_dir_entry_2 *) ((char *) de + sb->s_blocksize -
+-                                     EXT4_DIR_REC_LEN(0));
++                                      __EXT4_DIR_REC_LEN(0));
+               for (; de < top; de = ext4_next_entry(de)) {
+                       int off = (block << EXT4_BLOCK_SIZE_BITS(sb))
+                                 + ((char *) de - bh->b_data);
+@@ -1193,7 +1203,7 @@ dx_move_dirents(char *from, char *to, st
+       while (count--) {
+               struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *) (from + map->offs);
+-              rec_len = EXT4_DIR_REC_LEN(de->name_len);
++              rec_len = EXT4_DIR_REC_LEN(de);
+               memcpy (to, de, rec_len);
+               ((struct ext4_dir_entry_2 *) to)->rec_len =
+                               ext4_rec_len_to_disk(rec_len);
+@@ -1217,7 +1227,7 @@ static struct ext4_dir_entry_2* dx_pack_
+       while ((char*)de < base + size) {
+               next = ext4_next_entry(de);
+               if (de->inode && de->name_len) {
+-                      rec_len = EXT4_DIR_REC_LEN(de->name_len);
++                      rec_len = EXT4_DIR_REC_LEN(de);
+                       if (de > to)
+                               memmove(to, de, rec_len);
+                       to->rec_len = ext4_rec_len_to_disk(rec_len);
+@@ -1347,10 +1357,16 @@ static int add_dirent_to_buf(handle_t *h
+       int             namelen = dentry->d_name.len;
+       unsigned long   offset = 0;
+       unsigned short  reclen;
+-      int             nlen, rlen, err;
++      int             nlen, rlen, err, dlen = 0;
++      unsigned char   *data;
+       char            *top;
+-      reclen = EXT4_DIR_REC_LEN(namelen);
++      data = ext4_dentry_get_data(inode->i_sb, (struct ext4_dentry_param *)
++                                              dentry->d_fsdata);
++      if (data)
++              dlen = (*data) + 1;
++
++      reclen = __EXT4_DIR_REC_LEN(namelen + dlen);
+       if (!de) {
+               de = (struct ext4_dir_entry_2 *)bh->b_data;
+               top = bh->b_data + dir->i_sb->s_blocksize - reclen;
+@@ -1364,7 +1380,7 @@ static int add_dirent_to_buf(handle_t *h
+                               brelse (bh);
+                               return -EEXIST;
+                       }
+-                      nlen = EXT4_DIR_REC_LEN(de->name_len);
++                      nlen = EXT4_DIR_REC_LEN(de);
+                       rlen = ext4_rec_len_from_disk(de->rec_len);
+                       if ((de->inode? rlen - nlen: rlen) >= reclen)
+                               break;
+@@ -1383,7 +1399,7 @@ static int add_dirent_to_buf(handle_t *h
+       }
+       /* By now the buffer is marked for journaling */
+-      nlen = EXT4_DIR_REC_LEN(de->name_len);
++      nlen = EXT4_DIR_REC_LEN(de);
+       rlen = ext4_rec_len_from_disk(de->rec_len);
+       if (de->inode) {
+               struct ext4_dir_entry_2 *de1 = (struct ext4_dir_entry_2 *)((char *)de + nlen);
+@@ -1399,6 +1415,12 @@ static int add_dirent_to_buf(handle_t *h
+               de->inode = 0;
+       de->name_len = namelen;
+       memcpy (de->name, name, namelen);
++      if (data) {
++              de->name[namelen] = 0;
++              memcpy(&de->name[namelen + 1], data, *(char *) data);
++              de->file_type |= EXT4_DIRENT_LUFID;
++      }
++
+       /*
+        * XXX shouldn't update any times until successful
+        * completion of syscall, but too many callers depend
+@@ -1488,7 +1510,8 @@ static int make_indexed_dir(handle_t *ha
+       dx_set_block(entries, 1);
+       dx_set_count(entries, 1);
+-      dx_set_limit(entries, dx_root_limit(dir, sizeof(*dx_info)));
++      dx_set_limit(entries, dx_root_limit(dir->i_sb->s_blocksize,
++                                       dot_de, sizeof(*dx_info)));
+       /* Initialize as for dx_probe */
+       hinfo.hash_version = dx_info->hash_version;
+@@ -1516,6 +1539,8 @@ static int ext4_update_dotdot(handle_t *
+       struct buffer_head * dir_block;
+       struct ext4_dir_entry_2 * de;
+       int len, journal = 0, err = 0;
++      int dlen = 0;
++      char *data;
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+@@ -1531,19 +1556,24 @@ static int ext4_update_dotdot(handle_t *
+       /* the first item must be "." */
+       assert(de->name_len == 1 && de->name[0] == '.');
+       len = le16_to_cpu(de->rec_len);
+-      assert(len >= EXT4_DIR_REC_LEN(1));
+-      if (len > EXT4_DIR_REC_LEN(1)) {
++      assert(len >= __EXT4_DIR_REC_LEN(1));
++      if (len > __EXT4_DIR_REC_LEN(1)) {
+               BUFFER_TRACE(dir_block, "get_write_access");
+               err = ext4_journal_get_write_access(handle, dir_block);
+               if (err)
+                       goto out_journal;
+               journal = 1;
+-              de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(1));
++              de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(de));
+       }
+-      len -= EXT4_DIR_REC_LEN(1);
+-      assert(len == 0 || len >= EXT4_DIR_REC_LEN(2));
++      len -= EXT4_DIR_REC_LEN(de);
++      data = ext4_dentry_get_data(dir->i_sb,
++                      (struct ext4_dentry_param *) dentry->d_fsdata);
++      if (data)
++              dlen = *data + 1;
++      assert(len == 0 || len >= __EXT4_DIR_REC_LEN(2 + dlen));
++
+       de = (struct ext4_dir_entry_2 *)
+                       ((char *) de + le16_to_cpu(de->rec_len));
+       if (!journal) {
+@@ -1557,10 +1587,15 @@ static int ext4_update_dotdot(handle_t *
+       if (len > 0)
+               de->rec_len = cpu_to_le16(len);
+       else
+-              assert(le16_to_cpu(de->rec_len) >= EXT4_DIR_REC_LEN(2));
++              assert(le16_to_cpu(de->rec_len) >= __EXT4_DIR_REC_LEN(2));
+       de->name_len = 2;
+       strcpy (de->name, "..");
+       ext4_set_de_type(dir->i_sb, de, S_IFDIR);
++      if (data) {
++              de->name[2] = 0;
++              memcpy(&de->name[2 + 1], data, dlen);
++              de->file_type |= EXT4_DIRENT_LUFID;
++      }
+ out_journal:
+       if (journal) {
+@@ -1972,11 +2007,12 @@ retry:
+ /* Initialize @inode as a subdirectory of @dir, and add the
+  * "." and ".." entries into the first directory block. */
+ int ext4_add_dot_dotdot(handle_t *handle, struct inode * dir,
+-                       struct inode *inode)
++                       struct inode *inode,
++                       const void *data1, const void *data2)
+  {
+       struct buffer_head * dir_block;
+       struct ext4_dir_entry_2 * de;
+-      int err = 0;
++      int err = 0, dot_reclen;
+       inode->i_op = &ext4_dir_inode_operations;
+       inode->i_fop = &ext4_dir_operations;
+@@ -1993,16 +2029,34 @@ int ext4_add_dot_dotdot(handle_t *handle
+       de = (struct ext4_dir_entry_2 *) dir_block->b_data;
+       de->inode = cpu_to_le32(inode->i_ino);
+       de->name_len = 1;
+-      de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len));
+       strcpy (de->name, ".");
+       ext4_set_de_type(dir->i_sb, de, S_IFDIR);
++      /* get packed fid data*/
++      data1 = ext4_dentry_get_data(dir->i_sb,
++                              (struct ext4_dentry_param *) data1);
++      if (data1) {
++              de->name[1] = 0;
++              memcpy(&de->name[2], data1, *(char *) data1);
++              de->file_type |= EXT4_DIRENT_LUFID;
++      }
++      de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(de));
++      dot_reclen = cpu_to_le16(de->rec_len);
++
+       de = ext4_next_entry(de);
+       de->inode = cpu_to_le32(dir->i_ino);
+       de->rec_len = ext4_rec_len_to_disk(inode->i_sb->s_blocksize -
+-                                            EXT4_DIR_REC_LEN(1));
++                                              dot_reclen);
+       de->name_len = 2;
+       strcpy (de->name, "..");
+       ext4_set_de_type(dir->i_sb, de, S_IFDIR);
++      data2 = ext4_dentry_get_data(dir->i_sb,
++                      (struct ext4_dentry_param *) data2);
++      if (data2) {
++              de->name[2] = 0;
++              memcpy(&de->name[3], data2, *(char *) data2);
++              de->file_type |= EXT4_DIRENT_LUFID;
++      }
++
+       inode->i_nlink = 2;
+       BUFFER_TRACE(dir_block, "call ext4_journal_dirty_metadata");
+       ext4_journal_dirty_metadata(handle, dir_block);
+@@ -2037,7 +2091,7 @@ retry:
+       if (IS_ERR(inode))
+               goto out_stop;
+-      err = ext4_add_dot_dotdot(handle, dir, inode);
++      err = ext4_add_dot_dotdot(handle, dir, inode, NULL, NULL);
+       if (err)
+               goto out_stop;
+@@ -2071,7 +2125,7 @@ static int empty_dir (struct inode * ino
+       int err = 0;
+       sb = inode->i_sb;
+-      if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) ||
++      if (inode->i_size < __EXT4_DIR_REC_LEN(1) + __EXT4_DIR_REC_LEN(2) ||
+           !(bh = ext4_bread (NULL, inode, 0, 0, &err))) {
+               if (err)
+                       ext4_error(inode->i_sb, __func__,
index 4e89ef8..06b5e3e 100644 (file)
@@ -29,3 +29,5 @@ ext4-osd-iam-exports.patch
 ext4-dynlocks-common.patch
 ext4-dynlocks-2.6-rhel5.patch
 ext4-hash-indexed-dir-dotdot-update.patch
+ext4-kill-dx_root.patch
+ext4_data_in_dirent.patch