Skip to contentSkip to conversation

add user data field in ext4 dirent

PATCH New pravin shelar 1 participant 1 message Jul 17, 2009 ext4 file system

lore
Share & tools
lore
#0 lore raw

PATCH 2/2 add user data field in ext4 dirent

Hi
attached patch adds data field in ext4 dirent. so that user can have data
ext4 dirent.

Thanks,
Pravin.

this patch implements feature which allows ext4 fs uses (e.g. Lustre) 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.

fs/ext4/dir.c +18 -8
Index: b/fs/ext4/dir.c
===================================================================
@@ -53,6 +53,8 @@ const struct file_operations ext4_dir_op
 
 static unsigned char get_dtype(struct super_block *sb, int filetype)
 {
+	filetype &= EXT4_FT_MASK;
+
 	if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) ||
 	    (filetype >= EXT4_FT_MAX))
 		return DT_UNKNOWN;
@@ -70,11 +72,11 @@ int ext4_check_dir_entry(const char *fun
 	const int rlen = ext4_rec_len_from_disk(de->rec_len,
 						dir->i_sb->s_blocksize);
 
-	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";
@@ -179,7 +181,7 @@ revalidate:
 				 * failure will be detected in the
 				 * dirent test below. */
 				if (ext4_rec_len_from_disk(de->rec_len,
-					sb->s_blocksize) < EXT4_DIR_REC_LEN(1))
+					sb->s_blocksize) < __EXT4_DIR_REC_LEN(1))
 					break;
 				i += ext4_rec_len_from_disk(de->rec_len,
 							    sb->s_blocksize);
@@ -215,12 +217,13 @@ revalidate:
 				 * during the copy operation.
 				 */
 				u64 version = filp->f_version;
-
 				error = filldir(dirent, de->name,
 						de->name_len,
 						filp->f_pos,
 						le32_to_cpu(de->inode),
-						get_dtype(sb, de->file_type));
+						get_dtype(sb, de->file_type)|
+						(de->file_type &
+                                                 EXT4_DIRENT_LUFID));
 				if (error)
 					break;
 				if (version != filp->f_version)
@@ -342,12 +345,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;
@@ -356,7 +364,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) {
@@ -417,7 +425,9 @@ static int call_filldir(struct file *fil
 		error = filldir(dirent, fname->name,
 				fname->name_len, curr_pos,
 				fname->inode,
-				get_dtype(sb, fname->file_type));
+				get_dtype(sb, fname->file_type)|
+				(fname->file_type &
+				 EXT4_DIRENT_LUFID));
 		if (error) {
 			filp->f_pos = curr_pos;
 			info->extra_fname = fname;
fs/ext4/ext4.h +37 -2
Index: b/fs/ext4/ext4.h
===================================================================
@@ -1061,6 +1061,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| \
@@ -1068,7 +1069,8 @@ static inline int ext4_valid_inum(struct
 					 EXT4_FEATURE_INCOMPAT_META_BG| \
 					 EXT4_FEATURE_INCOMPAT_EXTENTS| \
 					 EXT4_FEATURE_INCOMPAT_64BIT| \
-					 EXT4_FEATURE_INCOMPAT_FLEX_BG)
+					 EXT4_FEATURE_INCOMPAT_FLEX_BG| \
+					 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| \
@@ -1150,6 +1152,25 @@ 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
 
 /*
  * EXT4_DIR_PAD defines the directory entries boundaries
@@ -1158,8 +1179,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)
 
 /*
@@ -1678,6 +1702,17 @@ static inline void set_bitmap_uptodate(s
 	set_bit(BH_BITMAP_UPTODATE, &(bh)->b_state);
 }
 
+static inline int ext4_get_dirent_data_len(struct ext4_dir_entry_2 *de)
+{
+	int dlen = 0;
+	char *data;
+	if (de->file_type & EXT4_DIRENT_LUFID) {
+		data = de->name + de->name_len + 1;
+		dlen = *data + 1;
+	}
+	return dlen;
+}
+
 #endif	/* __KERNEL__ */
 
 #endif	/* _EXT4_H */
fs/ext4/namei.c +42 -24

182 lines not on this page · raw message