男人小便刺痛吃什么药| 操刀是什么意思| 帕金森吃什么药效果好| 食管在什么位置图片| 观音坐莲是什么姿势| 明矾是什么东西| 焕字五行属什么| 吃什么止血| 吃什么有助于睡眠效果好| 37是什么意思| 恐龙为什么叫恐龙| 查肝肾功能挂什么科| 1977年是什么命| 头晕目眩是什么病的征兆| 肾虚吃什么药最有效| 头皮癣用什么药膏最好| skp是什么品牌| 梦见茄子是什么意思| 为什么额头反复长痘痘| 陈皮为什么越陈越好| 珍珠是用什么做的| 乳清蛋白是什么| 吃什么能增强性功能| 经常出鼻血是什么原因| 维生素c什么牌子好| 肚子胀痛什么原因| 温饱是什么意思| 听阴天说什么| 雁过拔毛是什么意思| 写字楼是干什么的| 医院洗牙挂什么科| 被蚂蚁咬了怎么止痒消肿要擦什么药| 血压低会导致什么后果| 什么叫欲擒故纵| 洁身自爱是什么生肖| 女人吃火龙果有什么好处| 后话是什么意思| 滋阴是什么意思| 宁静是什么意思| 食物发霉是什么菌| 张五行属什么| 女人平胸是什么原因| 没谁了是什么意思| 为什么不建议打水光针| 美国今天是什么节日| 天气热吃什么解暑| 割包皮挂什么科| 挂帅是什么意思| 拉垮什么意思| 叶酸什么时间吃最好| 尿路感染不能吃什么东西| 手术后能吃什么水果| 手心经常出汗是什么原因| 老汉推车是什么意思| 90年是什么命| 万里长城是什么生肖| 麦冬长什么样子图片| pr医学上什么意思| 水洗棉是什么面料| 尿酸高可以吃什么| 曹操的脸谱是什么颜色| 想起我叫什么了吗| 青光眼什么症状| 血脂高有什么表现| rap是什么意思| 耘是什么意思| 在眼皮老跳是什么征兆| 委屈什么意思| 湖南有什么好玩的| 猪肝色是什么颜色| 眼睛做激光手术有什么后遗症| 蓝色加红色是什么颜色| 心什么胆什么| 水瓶女喜欢什么样的男生| 爱的真正含义是什么| vodka是什么酒| 苹果浓缩汁是什么| 宫颈锥切术是什么意思| 七月十六是什么日子| 肾病吃什么水果好| 奇花异草的异什么意思| 出大汗是什么原因| 冰岛茶属于什么茶| 冰晶是什么| 艾滋病窗口期是什么意思| 月经前是什么期| 上颚疼痛吃什么药| 子宫复旧是什么意思| 中国海警是什么编制| 香菇配什么菜好吃| 恶寒什么意思| ipada1474是什么型号| 手汗症是什么原因| 降钙素原检测是查什么的| 黑色皮肤适合什么颜色的衣服| 肺大泡有什么症状| 怀孕前期有什么征兆| 什么叫点映| 大人睡觉流口水是什么原因引起的| 泌乳素偏高是什么原因| 打喷嚏流清鼻涕吃什么药| 痰带血丝是什么原因| 槟榔长什么样| 一什么床| 为什么小腿肌肉酸痛| 崩漏下血是什么意思| rinnai是什么品牌| 蛋白高是什么病| 体毛多是什么原因| 什么是生物钟| 血管炎吃什么药最有效| 吃什么补性功能最快| 舌苔发白是什么原因引起的| 打哈哈是什么意思| 牛骨头炖什么好吃| 营养土是什么土| 哆啦a梦大结局是什么| 睾丸瘙痒是什么原因| 唇色深的人适合什么颜色的口红| 心肌酶能查出什么病| 狮子是什么科| 吃什么可以散结节| 竹外桃花三两枝的下一句是什么| 上海话小赤佬是什么意思| 买李世民是什么生肖| sv是什么意思| 鹤立鸡群代表什么生肖| 呆呆的笑是什么笑| 双鱼座女和什么星座最配| 庹是什么意思| 花生死苗烂根用什么药| 为什么会有颈纹| 洋芋是什么东西| 高血压突然变成低血压是什么原因| pvt是什么意思| 传播什么| 打灰是什么意思| 发烧为什么不能吃鸡蛋| 03年属什么的| 貘是什么动物| 合欢是什么意思| 五年是什么婚| 亦什么意思| 个性是什么意思| 血管造影是什么检查| 嘴巴里苦是什么原因| 阴沉木是什么木头| 太乙是什么意思| 89年是什么年| 大姨妈期间可以吃什么水果| 头发湿着睡觉有什么害处| 稷是什么农作物| 上环要做什么检查| bolon是什么牌子眼镜| 夜尿频多吃什么药效果好| 珍珠鸟吃什么食物| 除体内湿热最好的中成药是什么| 小腹痛男性什么原因| 梦到孩子死了是什么征兆| 头发掉得厉害是什么原因| 户口迁移需要什么手续| 甲鱼和什么一起炖最好| 木志读什么| 2005年什么年| 梦见鳄鱼是什么意思| elite是什么意思| 扁平疣用什么治疗| 军士长是什么军衔| ra是什么病的缩写| 痰有腥臭味是什么原因| 地级市市委书记是什么级别| 输血前四项检查是什么| 言谈举止是什么意思| 舍友什么意思| 糖尿病是什么原因造成的| 3680是什么罩杯| 貉是什么动物| 不敢苟同是什么意思| 潋滟什么意思| 喝鲜牛奶有什么好处和坏处| 物美价廉是什么意思| 梗米是什么| 心肌缺血是什么原因引起的| 屎为什么是臭的| 生姜能治什么病| 发烧吃什么水果| 女人脚抽筋是什么原因| 腹泻是什么原因引起的| 澳大利亚的国宝是什么| 威士忌属于什么酒| 鼓的偏旁部首是什么| 生死劫是什么意思| 新癀片主要治什么病| 不规则抗体筛查是什么意思| 小孩吃什么补脑更聪明| 包皮看什么科| 蟑螂怕什么| 绿色的大便是什么原因| 形态各异的异是什么意思| 食指上有痣代表什么| 甲状腺结节是什么原因引起的| 榅桲是什么水果| 痰多吃什么药| 姓杨的女孩子取什么名字| 党内的最高处分是什么| 维生素b族适合什么人吃| 头皮特别痒是什么原因| 酉读什么| 卖腐是什么意思| 胃有幽门螺旋杆菌是什么症状| 郑州有什么好吃的| ky是什么意思| 身宫是什么意思| 拉肚子为什么憋不住| 炖肉什么时候放盐| experiment是什么意思| 小棉袄是什么意思| hpv亚型是什么意思| 橘色五行属什么| 麻风病是什么病| 满日是什么意思| 鼠的三合生肖是什么| zro是什么牌子| 排卵期有什么感觉| 什么是菱形| 奎字五行属什么| 献血前需要注意什么| 吃什么补肾壮阳| 什么叫闰年| 凝血常规是查什么的| 香砂六君丸治什么病| 电瓶车什么牌子好| 女生吃什么可以丰胸| 气短咳嗽是什么原因引起的| 荆芥不能和什么一起吃| 一个黑一个今念什么| 腹泻拉水是什么原因| 爱放屁吃什么药| 赤诚相见是什么意思| 手脚脱皮是什么原因导致的| 北海特产有什么值得带| 四叶草寓意是什么| 梦见穿破鞋是什么意思| 例假来的是黑色的是什么原因| 正确的三观是什么| 云裳是什么意思| 止痛片吃多了有什么副作用| iron什么意思| 喝什么茶叶减肥效果最好| 喝什么酒对身体好| 晚上八点到九点是什么时辰| biubiubiu是什么意思| na是什么| 肠息肉吃什么药| 胃癌手术后吃什么补品| 截瘫是什么意思| 什么一现| 手和脚发麻是什么原因| 黑茶金花是什么菌| 做胃镜之前需要做什么准备| 什么病不能喝酒| 飞的最高的鸟是什么鸟| 鳏寡孤独是什么意思| 琛字五行属什么| 百度
diff mbox series

梦见掉了一颗牙齿是什么征兆

Message ID 20180202094136.13032-3-artem.blagodarenko@gmail.com
State Superseded, archived
Headers show
Series 64 bit inode counter support | expand

Commit Message

Artem Blagodarenko Feb. 2, 2018, 9:41 a.m. UTC
From: Andreas Dilger <andreas.dilger@intel.com>

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.

Signed-off-by: Andreas Dilger <andreas.dilger@intel.com>
Signed-off-by: Artem Blagodarenko <artem.blagodarenko@gmail.com>
---
 fs/ext4/dir.c    |  16 +++++---
 fs/ext4/ext4.h   | 102 ++++++++++++++++++++++++++++++++++++++++++++---
 fs/ext4/inline.c |  18 ++++-----
 fs/ext4/namei.c  | 119 ++++++++++++++++++++++++++++++++++++++++++-------------
 fs/ext4/super.c  |   3 +-
 5 files changed, 210 insertions(+), 48 deletions(-)
diff mbox series

Patch

diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index b04e882179c6..02d6fd0d643e 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -67,11 +67,11 @@  int __ext4_check_dir_entry(const char *function, unsigned int line,
 	const int rlen = ext4_rec_len_from_disk(de->rec_len,
 						dir->i_sb->s_blocksize);
 
-	if (unlikely(rlen < EXT4_DIR_REC_LEN(1)))
+	if (unlikely(rlen < EXT4_DIR_NAME_LEN(1)))
 		error_msg = "rec_len is smaller than minimal";
 	else if (unlikely(rlen % 4 != 0))
 		error_msg = "rec_len % 4 != 0";
-	else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len)))
+	else if (unlikely(rlen < EXT4_DIR_REC_LEN(de)))
 		error_msg = "rec_len is too small for name_len";
 	else if (unlikely(((char *) de - buf) + rlen > size))
 		error_msg = "directory entry across range";
@@ -218,7 +218,8 @@  static int ext4_readdir(struct file *file, struct dir_context *ctx)
 				 * 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_NAME_LEN(1))
 					break;
 				i += ext4_rec_len_from_disk(de->rec_len,
 							    sb->s_blocksize);
@@ -441,12 +442,17 @@  int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
 	struct fname *fname, *new_fn;
 	struct dir_private_info *info;
 	int len;
+	int extra_data = 0;
 
 	info = dir_file->private_data;
 	p = &info->root.rb_node;
 
 	/* Create and allocate the fname structure */
-	len = sizeof(struct fname) + ent_name->len + 1;
+	if (dirent->file_type & ~EXT4_FT_MASK)
+		extra_data = ext4_get_dirent_data_len(dirent);
+
+	len = sizeof(struct fname) + dirent->name_len + extra_data + 1;
+
 	new_fn = kzalloc(len, GFP_KERNEL);
 	if (!new_fn)
 		return -ENOMEM;
@@ -455,7 +461,7 @@  int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
 	new_fn->inode = le32_to_cpu(dirent->inode);
 	new_fn->name_len = ent_name->len;
 	new_fn->file_type = dirent->file_type;
-	memcpy(new_fn->name, ent_name->name, ent_name->len);
+	memcpy(new_fn->name, ent_name->name, ent_name->len + extra_data);
 	new_fn->name[ent_name->len] = 0;
 
 	while (*p) {
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index e2abe01c8c6b..aa02bd8cba0f 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1111,6 +1111,7 @@  struct ext4_inode_info {
  * Mount flags set via mount options or defaults
  */
 #define EXT4_MOUNT_NO_MBCACHE		0x00001 /* Do not use mbcache */
+#define EXT4_MOUNT_DIRDATA		0x00002 /* Data in directory entries*/
 #define EXT4_MOUNT_GRPID		0x00004	/* Create files with directory's group */
 #define EXT4_MOUNT_DEBUG		0x00008	/* Some debugging messages */
 #define EXT4_MOUNT_ERRORS_CONT		0x00010	/* Continue on errors */
@@ -1804,7 +1805,8 @@  EXT4_FEATURE_INCOMPAT_FUNCS(encrypt,		ENCRYPT)
 					 EXT4_FEATURE_INCOMPAT_INLINE_DATA | \
 					 EXT4_FEATURE_INCOMPAT_ENCRYPT | \
 					 EXT4_FEATURE_INCOMPAT_CSUM_SEED | \
-					 EXT4_FEATURE_INCOMPAT_LARGEDIR)
+					 EXT4_FEATURE_INCOMPAT_LARGEDIR | \
+					 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| \
@@ -1965,6 +1967,55 @@  struct ext4_dir_entry_tail {
 
 #define EXT4_FT_DIR_CSUM	0xDE
 
+#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_DIRENT_INODE		0x20
+
+#define EXT4_LUFID_MAGIC    0xAD200907UL
+
+struct ext4_dirent_data_header {
+	/* length of this header + the whole data blob */
+	__u8	ddh_length;
+} __packed;
+
+struct ext4_dirent_lufid {
+	struct ext4_dirent_data_header	dl_header; /* 1 + 16n */
+	__u8				dl_data[0];
+} __packed;
+
+struct ext4_dentry_param {
+	__u32				edp_magic; /* EXT4_LUFID_MAGIC */
+	struct ext4_dirent_lufid	edp_lufid;
+} __packed;
+
+static inline
+struct ext4_dirent_data_header *ext4_dentry_get_data(struct super_block *sb,
+					struct ext4_dentry_param *p)
+{
+	if (!ext4_has_feature_dirdata(sb))
+		return NULL;
+	if (p && p->edp_magic == EXT4_LUFID_MAGIC)
+		return &p->edp_lufid.dl_header;
+	else
+		return NULL;
+}
+
 /*
  * EXT4_DIR_PAD defines the directory entries boundaries
  *
@@ -1972,8 +2023,14 @@  struct ext4_dir_entry_tail {
  */
 #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) & \
+
+/* the name + inode data without any extra dirdata */
+#define EXT4_DIR_NAME_LEN(name_len)	(((name_len) + 8 + EXT4_DIR_ROUND) & \
 					 ~EXT4_DIR_ROUND)
+/* the total size of the dirent including any extra dirdata */
+#define EXT4_DIR_REC_LEN(de)		(EXT4_DIR_NAME_LEN(de->name_len +\
+					ext4_get_dirent_data_len(de)))
+
 #define EXT4_MAX_REC_LEN		((1<<16)-1)
 
 /*
@@ -2376,7 +2433,10 @@  extern int ext4_find_dest_de(struct inode *dir, struct inode *inode,
 			     struct buffer_head *bh,
 			     void *buf, int buf_size,
 			     struct ext4_filename *fname,
-			     struct ext4_dir_entry_2 **dest_de);
+			     struct ext4_dir_entry_2 **dest_de,
+			     bool is_dotdot,
+			     bool *write_short_dotdot,
+			     unsigned short dotdot_reclen);
 void ext4_insert_dentry(struct inode *inode,
 			struct ext4_dir_entry_2 *de,
 			int buf_size,
@@ -2392,10 +2452,16 @@  static const unsigned char ext4_filetype_table[] = {
 
 static inline  unsigned char get_dtype(struct super_block *sb, int filetype)
 {
-	if (!ext4_has_feature_filetype(sb) || filetype >= EXT4_FT_MAX)
+	int fl_index = filetype & EXT4_FT_MASK;
+
+	if (!ext4_has_feature_filetype(sb) || fl_index >= EXT4_FT_MAX)
 		return DT_UNKNOWN;
 
-	return ext4_filetype_table[filetype];
+	if (!test_opt(sb, DIRDATA))
+		return (ext4_filetype_table[fl_index]);
+
+	return (ext4_filetype_table[fl_index]) |
+		(filetype & ~EXT4_FT_MASK);
 }
 extern int ext4_check_all_de(struct inode *dir, struct buffer_head *bh,
 			     void *buf, int buf_size);
@@ -3271,6 +3337,32 @@  static inline void ext4_clear_io_unwritten_flag(ext4_io_end_t *io_end)
 
 extern const struct iomap_ops ext4_iomap_ops;
 
+#define ext4_dirdata_next(ddh) \
+	(struct ext4_dirent_data_header *)((char *)ddh + ddh->ddh_length)
+
+/*
+ * 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)
+{
+	struct ext4_dirent_data_header *ddh =
+		(void *)(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 += ddh->ddh_length + (dlen == 0);
+			ddh = ext4_dirdata_next(ddh);
+		}
+		extra_data_flags >>= 1;
+	}
+	return dlen;
+}
+
 #endif	/* __KERNEL__ */
 
 #define EFSBADCRC	EBADMSG		/* Bad CRC detected */
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 28c5c3abddb3..666891dc03cd 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1026,7 +1026,7 @@  static int ext4_add_dirent_to_inline(handle_t *handle,
 	struct ext4_dir_entry_2 *de;
 
 	err = ext4_find_dest_de(dir, inode, iloc->bh, inline_start,
-				inline_size, fname, &de);
+				inline_size, fname, &de, 0, NULL, 0);
 	if (err)
 		return err;
 
@@ -1103,7 +1103,7 @@  static int ext4_update_inline_dir(handle_t *handle, struct inode *dir,
 	int old_size = EXT4_I(dir)->i_inline_size - EXT4_MIN_INLINE_DATA_SIZE;
 	int new_size = get_max_inline_xattr_value_size(dir, iloc);
 
-	if (new_size - old_size <= EXT4_DIR_REC_LEN(1))
+	if (new_size - old_size <= EXT4_DIR_NAME_LEN(1))
 		return -ENOSPC;
 
 	ret = ext4_update_inline_data(handle, dir,
@@ -1384,8 +1384,8 @@  int htree_inlinedir_to_tree(struct file *dir_file,
 			fake.name_len = 1;
 			strcpy(fake.name, ".");
 			fake.rec_len = ext4_rec_len_to_disk(
-						EXT4_DIR_REC_LEN(fake.name_len),
-						inline_size);
+					EXT4_DIR_NAME_LEN(fake.name_len),
+					inline_size);
 			ext4_set_de_type(inode->i_sb, &fake, S_IFDIR);
 			de = &fake;
 			pos = EXT4_INLINE_DOTDOT_OFFSET;
@@ -1394,8 +1394,8 @@  int htree_inlinedir_to_tree(struct file *dir_file,
 			fake.name_len = 2;
 			strcpy(fake.name, "..");
 			fake.rec_len = ext4_rec_len_to_disk(
-						EXT4_DIR_REC_LEN(fake.name_len),
-						inline_size);
+					EXT4_DIR_NAME_LEN(fake.name_len),
+					inline_size);
 			ext4_set_de_type(inode->i_sb, &fake, S_IFDIR);
 			de = &fake;
 			pos = EXT4_INLINE_DOTDOT_SIZE;
@@ -1492,8 +1492,8 @@  int ext4_read_inline_dir(struct file *file,
 	 * So we will use extra_offset and extra_size to indicate them
 	 * during the inline dir iteration.
 	 */
-	dotdot_offset = EXT4_DIR_REC_LEN(1);
-	dotdot_size = dotdot_offset + EXT4_DIR_REC_LEN(2);
+	dotdot_offset = EXT4_DIR_NAME_LEN(1);
+	dotdot_size = dotdot_offset + EXT4_DIR_NAME_LEN(2);
 	extra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE;
 	extra_size = extra_offset + inline_size;
 
@@ -1528,7 +1528,7 @@  int ext4_read_inline_dir(struct file *file,
 			 * failure will be detected in the
 			 * dirent test below. */
 			if (ext4_rec_len_from_disk(de->rec_len, extra_size)
-				< EXT4_DIR_REC_LEN(1))
+				< EXT4_DIR_NAME_LEN(1))
 				break;
 			i += ext4_rec_len_from_disk(de->rec_len,
 						    extra_size);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 0cb6a061aff6..b6681aebe5cf 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -239,7 +239,8 @@  static unsigned dx_get_count(struct dx_entry *entries);
 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 int dx_root_limit(struct inode *dir,
+		struct ext4_dir_entry_2 *dot_de, unsigned int infosize);
 static unsigned dx_node_limit(struct inode *dir);
 static struct dx_frame *dx_probe(struct ext4_filename *fname,
 				 struct inode *dir,
@@ -552,10 +553,15 @@  static inline void dx_set_limit(struct dx_entry *entries, unsigned value)
 	((struct dx_countlimit *) entries)->limit = cpu_to_le16(value);
 }
 
-static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize)
+static inline unsigned int dx_root_limit(struct inode *dir,
+		struct ext4_dir_entry_2 *dot_de, unsigned int 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 int entry_space;
+
+	dotdot_de = ext4_next_entry(dot_de, dir->i_sb->s_blocksize);
+	entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(dot_de) -
+			 EXT4_DIR_REC_LEN(dotdot_de) - infosize;
 
 	if (ext4_has_metadata_csum(dir->i_sb))
 		entry_space -= sizeof(struct dx_tail);
@@ -564,7 +570,8 @@  static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize)
 
 static inline unsigned dx_node_limit(struct inode *dir)
 {
-	unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0);
+	unsigned int entry_space = dir->i_sb->s_blocksize -
+					EXT4_DIR_NAME_LEN(0);
 
 	if (ext4_has_metadata_csum(dir->i_sb))
 		entry_space -= sizeof(struct dx_tail);
@@ -676,7 +683,7 @@  static struct stats dx_show_leaf(struct inode *dir,
 				       (unsigned) ((char *) de - base));
 #endif
 			}
-			space += EXT4_DIR_REC_LEN(de->name_len);
+			space += EXT4_DIR_REC_LEN(de);
 			names++;
 		}
 		de = ext4_next_entry(de, size);
@@ -983,7 +990,7 @@  static int htree_dirblock_to_tree(struct file *dir_file,
 	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_NAME_LEN(0));
 #ifdef CONFIG_EXT4_FS_ENCRYPTION
 	/* Check if the directory is encrypted */
 	if (ext4_encrypted_inode(dir)) {
@@ -1566,6 +1573,7 @@  static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
 	inode = NULL;
 	if (bh) {
 		__u32 ino = le32_to_cpu(de->inode);
+
 		brelse(bh);
 		if (!ext4_valid_inum(dir->i_sb, ino)) {
 			EXT4_ERROR_INODE(dir, "bad inode number: %u", ino);
@@ -1634,7 +1642,7 @@  dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count,
 	while (count--) {
 		struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *)
 						(from + (map->offs<<2));
-		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, blocksize);
@@ -1658,7 +1666,7 @@  static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize)
 	while ((char*)de < base + blocksize) {
 		next = ext4_next_entry(de, blocksize);
 		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, blocksize);
@@ -1789,10 +1797,13 @@  int ext4_find_dest_de(struct inode *dir, struct inode *inode,
 		      struct buffer_head *bh,
 		      void *buf, int buf_size,
 		      struct ext4_filename *fname,
-		      struct ext4_dir_entry_2 **dest_de)
+		      struct ext4_dir_entry_2 **dest_de,
+		      bool is_dotdot,
+		      bool *write_short_dotdot,
+		      unsigned short dotdot_reclen)
 {
 	struct ext4_dir_entry_2 *de;
-	unsigned short reclen = EXT4_DIR_REC_LEN(fname_len(fname));
+	unsigned short reclen = EXT4_DIR_NAME_LEN(fname_len(fname));
 	int nlen, rlen;
 	unsigned int offset = 0;
 	char *top;
@@ -1805,10 +1816,28 @@  int ext4_find_dest_de(struct inode *dir, struct inode *inode,
 			return -EFSCORRUPTED;
 		if (ext4_match(fname, de))
 			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, buf_size);
+		/* Check first for enough space for the full entry */
 		if ((de->inode ? rlen - nlen : rlen) >= reclen)
 			break;
+		/* Then for dotdot entries, check for the smaller space
+		 * required for just the entry, no FID
+		 */
+		if (is_dotdot) {
+			if ((de->inode ? rlen - nlen : rlen) >=
+			    dotdot_reclen) {
+				*write_short_dotdot = true;
+				break;
+			}
+			/* The new ".." entry mut be written over the
+			 * previous ".." entry, which is the first
+			 * entry traversed by this scan.  If it doesn't
+			 * fit, something is badly wrong, so -EIO.
+			 */
+			return -EIO;
+		}
+
 		de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
 		offset += rlen;
 	}
@@ -1827,7 +1856,8 @@  void ext4_insert_dentry(struct inode *inode,
 
 	int nlen, rlen;
 
-	nlen = EXT4_DIR_REC_LEN(de->name_len);
+	nlen = EXT4_DIR_REC_LEN(de);
+
 	rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
 	if (de->inode) {
 		struct ext4_dir_entry_2 *de1 =
@@ -1851,21 +1881,46 @@  void ext4_insert_dentry(struct inode *inode,
  * space.  It will return -ENOSPC if no space is available, and -EIO
  * and -EEXIST if directory entry already exists.
  */
-static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,
+static int add_dirent_to_buf(handle_t *handle,
+			     struct dentry *dentry,
+			     struct ext4_filename *fname,
 			     struct inode *dir,
 			     struct inode *inode, struct ext4_dir_entry_2 *de,
 			     struct buffer_head *bh)
 {
 	unsigned int	blocksize = dir->i_sb->s_blocksize;
 	int		csum_size = 0;
-	int		err;
+	unsigned short	reclen, dotdot_reclen = 0;
+	int		 err, dlen = 0, data_offset = 0;
+	bool		is_dotdot = false, write_short_dotdot = false;
+	struct ext4_dirent_data_header *ddh;
+	int namelen = dentry->d_name.len;
 
 	if (ext4_has_metadata_csum(inode->i_sb))
 		csum_size = sizeof(struct ext4_dir_entry_tail);
 
+	ddh = ext4_dentry_get_data(inode->i_sb, (struct ext4_dentry_param *)
+						dentry->d_fsdata);
+	if (ddh)
+		dlen = ddh->ddh_length + 1 /* NUL separator */;
+
+	is_dotdot = (namelen == 2 &&
+		     memcmp(dentry->d_name.name, "..", 2) == 0);
+
+	/* dotdot entries must be in the second place in a directory block,
+	 * so calculate an alternate length without the dirdata so they can
+	 * always be made to fit in the existing slot
+	 */
+	if (is_dotdot)
+		dotdot_reclen = EXT4_DIR_NAME_LEN(namelen);
+
+	reclen = EXT4_DIR_NAME_LEN(namelen + dlen + 3);
+
 	if (!de) {
 		err = ext4_find_dest_de(dir, inode, bh, bh->b_data,
-					blocksize - csum_size, fname, &de);
+					blocksize - csum_size, fname, &de,
+					is_dotdot,
+					&write_short_dotdot, dotdot_reclen);
 		if (err)
 			return err;
 	}
@@ -1879,6 +1934,14 @@  static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,
 	/* By now the buffer is marked for journaling */
 	ext4_insert_dentry(inode, de, blocksize, fname);
 
+	/* If we're writing short form of "dotdot", don't add data section */
+	if (ddh && !write_short_dotdot) {
+		de->name[namelen] = 0;
+		memcpy(&de->name[namelen + 1], ddh, ddh->ddh_length);
+		de->file_type |= EXT4_DIRENT_LUFID;
+		data_offset = ddh->ddh_length;
+	}
+
 	/*
 	 * XXX shouldn't update any times until successful
 	 * completion of syscall, but too many callers depend
@@ -1986,9 +2049,9 @@  static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname,
 
 	dx_set_block(entries, 1);
 	dx_set_count(entries, 1);
-	dx_set_limit(entries, dx_root_limit(dir, (struct ext4_dir_entry_2 *)
-					    frame->bh->b_data,
-					    sizeof(*dx_info)));
+	dx_set_limit(entries, dx_root_limit(dir,
+				(struct ext4_dir_entry_2 *)frame->bh->b_data,
+				sizeof(*dx_info)));
 
 	/* Initialize as for dx_probe */
 	fname->hinfo.hash_version = dx_info->hash_version;
@@ -2016,7 +2079,7 @@  static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname,
 		goto out_frames;
 	}
 
-	retval = add_dirent_to_buf(handle, fname, dir, inode, de, bh2);
+	retval = add_dirent_to_buf(handle, NULL, fname, dir, inode, de, bh2);
 out_frames:
 	/*
 	 * Even if the block split failed, we have to properly write
@@ -2093,7 +2156,7 @@  static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
 			bh = NULL;
 			goto out;
 		}
-		retval = add_dirent_to_buf(handle, &fname, dir, inode,
+		retval = add_dirent_to_buf(handle, dentry, &fname, dir, inode,
 					   NULL, bh);
 		if (retval != -ENOSPC)
 			goto out;
@@ -2122,7 +2185,7 @@  static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
 		initialize_dirent_tail(t, blocksize);
 	}
 
-	retval = add_dirent_to_buf(handle, &fname, dir, inode, de, bh);
+	retval = add_dirent_to_buf(handle, dentry, &fname, dir, inode, de, bh);
 out:
 	ext4_fname_free_filename(&fname);
 	brelse(bh);
@@ -2164,7 +2227,7 @@  static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname,
 	if (err)
 		goto journal_error;
 
-	err = add_dirent_to_buf(handle, fname, dir, inode, NULL, bh);
+	err = add_dirent_to_buf(handle, NULL, fname, dir, inode, NULL, bh);
 	if (err != -ENOSPC)
 		goto cleanup;
 
@@ -2290,7 +2353,7 @@  static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname,
 		err = PTR_ERR(de);
 		goto cleanup;
 	}
-	err = add_dirent_to_buf(handle, fname, dir, inode, de, bh);
+	err = add_dirent_to_buf(handle, NULL, fname, dir, inode, de, bh);
 	goto cleanup;
 
 journal_error:
@@ -2556,7 +2619,7 @@  struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
 {
 	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),
+	de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de),
 					   blocksize);
 	strcpy(de->name, ".");
 	ext4_set_de_type(inode->i_sb, de, S_IFDIR);
@@ -2566,11 +2629,11 @@  struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
 	de->name_len = 2;
 	if (!dotdot_real_len)
 		de->rec_len = ext4_rec_len_to_disk(blocksize -
-					(csum_size + EXT4_DIR_REC_LEN(1)),
+					(csum_size + EXT4_DIR_NAME_LEN(1)),
 					blocksize);
 	else
 		de->rec_len = ext4_rec_len_to_disk(
-				EXT4_DIR_REC_LEN(de->name_len), blocksize);
+				EXT4_DIR_REC_LEN(de), blocksize);
 	strcpy(de->name, "..");
 	ext4_set_de_type(inode->i_sb, de, S_IFDIR);
 
@@ -2699,7 +2762,7 @@  bool ext4_empty_dir(struct inode *inode)
 	}
 
 	sb = inode->i_sb;
-	if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2)) {
+	if (inode->i_size < EXT4_DIR_NAME_LEN(1) + EXT4_DIR_NAME_LEN(2)) {
 		EXT4_ERROR_INODE(inode, "invalid size");
 		return true;
 	}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index b0915b734a38..ead9406d9cff 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1339,7 +1339,7 @@  enum {
 	Opt_data_err_abort, Opt_data_err_ignore, Opt_test_dummy_encryption,
 	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
 	Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
-	Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
+	Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err, Opt_dirdata,
 	Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_i_version, Opt_dax,
 	Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,
 	Opt_lazytime, Opt_nolazytime, Opt_debug_want_extra_isize,
@@ -1400,6 +1400,7 @@  static const match_table_t tokens = {
 	{Opt_noquota, "noquota"},
 	{Opt_quota, "quota"},
 	{Opt_usrquota, "usrquota"},
+	{Opt_dirdata, "dirdata"},
 	{Opt_prjquota, "prjquota"},
 	{Opt_barrier, "barrier=%u"},
 	{Opt_barrier, "barrier"},

总是拉肚子是什么原因 支气管炎有什么症状 伟哥是什么药 心脏支架是什么病 白带变绿用什么药
洁癖是什么意思 一个火一个旦读什么字 副乳挂什么科 肛瘘是什么症状表现 陪产假什么时候开始休
肌酸激酶什么意思 马来酸曲美布汀片什么时候吃 恶病质是什么意思 卡帝乐鳄鱼什么档次 麦粒肿不能吃什么食物
军校出来是什么军衔 大便陶土色是什么颜色 月经期后是什么期 糖化是什么意思 举足轻重是什么意思
心季是什么原因hcv7jop6ns9r.cn 清心寡欲什么意思bysq.com 8月8日什么星座hcv9jop2ns0r.cn 成什么结什么mmeoe.com 小龙女叫什么名字xinmaowt.com
政治面貌填什么hcv7jop5ns5r.cn 天秤座男生喜欢什么样的女生zhiyanzhang.com 油头粉面是什么意思hcv8jop1ns5r.cn 心肌缺血用什么药hcv7jop4ns7r.cn 减肥吃什么坚果hcv8jop6ns2r.cn
泛醇是什么dayuxmw.com 白白的云朵像什么hcv8jop6ns6r.cn 月亮星座是什么意思0297y7.com 梦游是什么意思hcv9jop1ns3r.cn 肚子有腹水是什么症状hcv9jop4ns8r.cn
世界屋脊指的是什么hcv9jop4ns0r.cn 红花泡脚有什么好处chuanglingweilai.com 亚麻跌是什么意思hcv8jop2ns1r.cn 例假期间吃什么食物好hcv8jop2ns6r.cn dk是什么牌子wuhaiwuya.com
百度