Blame SOURCES/0028-fs-ntfs3-Rework-file-operations.patch

Kmods SIG d83023
From 78ab59fee07f22464f32eafebab2bd97ba94ff2d Mon Sep 17 00:00:00 2001
Kmods SIG d83023
From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Kmods SIG d83023
Date: Tue, 31 Aug 2021 18:52:39 +0300
Kmods SIG d83023
Subject: [Backport 78ab59fee07f] src: Rework file operations
Kmods SIG d83023
Kmods SIG d83023
Rename now works "Add new name and remove old name".
Kmods SIG d83023
"Remove old name and add new name" may result in bad inode
Kmods SIG d83023
if we can't add new name and then can't restore (add) old name.
Kmods SIG d83023
Kmods SIG d83023
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Kmods SIG d83023
---
Kmods SIG d83023
 src/attrib.c   |  17 +--
Kmods SIG d83023
 src/attrlist.c |  26 ++--
Kmods SIG d83023
 src/frecord.c  | 342 ++++++++++++++++++++++++++++++++++++--------
Kmods SIG d83023
 src/fsntfs.c   |  87 +++++------
Kmods SIG d83023
 src/index.c    |  45 +++---
Kmods SIG d83023
 src/inode.c    | 275 ++++++++++++-----------------------
Kmods SIG d83023
 src/namei.c    | 236 ++++++++----------------------
Kmods SIG d83023
 src/ntfs_fs.h  |  31 +++-
Kmods SIG d83023
 src/record.c   |   8 +-
Kmods SIG d83023
 src/xattr.c    |  25 ++--
Kmods SIG d83023
 10 files changed, 563 insertions(+), 529 deletions(-)
Kmods SIG d83023
Kmods SIG d83023
diff --git a/src/attrib.c b/src/attrib.c
Kmods SIG d83023
index 4b285f704e621ef5cbba11f1a006622e6387ea09..ffc323bacc9fe63683395d9535ec65849137551a 100644
Kmods SIG d83023
--- a/src/attrib.c
Kmods SIG d83023
+++ b/src/attrib.c
Kmods SIG d83023
@@ -218,9 +218,11 @@ int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
 out:
Kmods SIG d83023
-	/* Undo. */
Kmods SIG d83023
-	run_deallocate_ex(sbi, run, vcn0, vcn - vcn0, NULL, false);
Kmods SIG d83023
-	run_truncate(run, vcn0);
Kmods SIG d83023
+	/* Undo 'ntfs_look_for_free_space' */
Kmods SIG d83023
+	if (vcn - vcn0) {
Kmods SIG d83023
+		run_deallocate_ex(sbi, run, vcn0, vcn - vcn0, NULL, false);
Kmods SIG d83023
+		run_truncate(run, vcn0);
Kmods SIG d83023
+	}
Kmods SIG d83023
 
Kmods SIG d83023
 	return err;
Kmods SIG d83023
 }
Kmods SIG d83023
@@ -701,7 +703,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG d83023
 			 * (list entry for std attribute always first).
Kmods SIG d83023
 			 * So it is safe to step back.
Kmods SIG d83023
 			 */
Kmods SIG d83023
-			mi_remove_attr(mi, attr);
Kmods SIG d83023
+			mi_remove_attr(NULL, mi, attr);
Kmods SIG d83023
 
Kmods SIG d83023
 			if (!al_remove_le(ni, le)) {
Kmods SIG d83023
 				err = -EINVAL;
Kmods SIG d83023
@@ -1004,7 +1006,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
Kmods SIG d83023
 			end = next_svcn;
Kmods SIG d83023
 		while (end > evcn) {
Kmods SIG d83023
 			/* Remove segment [svcn : evcn). */
Kmods SIG d83023
-			mi_remove_attr(mi, attr);
Kmods SIG d83023
+			mi_remove_attr(NULL, mi, attr);
Kmods SIG d83023
 
Kmods SIG d83023
 			if (!al_remove_le(ni, le)) {
Kmods SIG d83023
 				err = -EINVAL;
Kmods SIG d83023
@@ -1600,7 +1602,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
Kmods SIG d83023
 			end = next_svcn;
Kmods SIG d83023
 		while (end > evcn) {
Kmods SIG d83023
 			/* Remove segment [svcn : evcn). */
Kmods SIG d83023
-			mi_remove_attr(mi, attr);
Kmods SIG d83023
+			mi_remove_attr(NULL, mi, attr);
Kmods SIG d83023
 
Kmods SIG d83023
 			if (!al_remove_le(ni, le)) {
Kmods SIG d83023
 				err = -EINVAL;
Kmods SIG d83023
@@ -1836,13 +1838,12 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
Kmods SIG d83023
 			u16 le_sz;
Kmods SIG d83023
 			u16 roff = le16_to_cpu(attr->nres.run_off);
Kmods SIG d83023
 
Kmods SIG d83023
-			/* run==1 means unpack and deallocate. */
Kmods SIG d83023
 			run_unpack_ex(RUN_DEALLOCATE, sbi, ni->mi.rno, svcn,
Kmods SIG d83023
 				      evcn1 - 1, svcn, Add2Ptr(attr, roff),
Kmods SIG d83023
 				      le32_to_cpu(attr->size) - roff);
Kmods SIG d83023
 
Kmods SIG d83023
 			/* Delete this attribute segment. */
Kmods SIG d83023
-			mi_remove_attr(mi, attr);
Kmods SIG d83023
+			mi_remove_attr(NULL, mi, attr);
Kmods SIG d83023
 			if (!le)
Kmods SIG d83023
 				break;
Kmods SIG d83023
 
Kmods SIG d83023
diff --git a/src/attrlist.c b/src/attrlist.c
Kmods SIG d83023
index 32ca990af64b53b4e9572d5dd0d6ae5f057760c4..fa32399eb5171ce25f037fbd1bd8e483a37b839c 100644
Kmods SIG d83023
--- a/src/attrlist.c
Kmods SIG d83023
+++ b/src/attrlist.c
Kmods SIG d83023
@@ -279,7 +279,7 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
Kmods SIG d83023
 	struct ATTR_LIST_ENTRY *le;
Kmods SIG d83023
 	size_t off;
Kmods SIG d83023
 	u16 sz;
Kmods SIG d83023
-	size_t asize, new_asize;
Kmods SIG d83023
+	size_t asize, new_asize, old_size;
Kmods SIG d83023
 	u64 new_size;
Kmods SIG d83023
 	typeof(ni->attr_list) *al = &ni->attr_list;
Kmods SIG d83023
 
Kmods SIG d83023
@@ -287,8 +287,9 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
Kmods SIG d83023
 	 * Compute the size of the new 'le'
Kmods SIG d83023
 	 */
Kmods SIG d83023
 	sz = le_size(name_len);
Kmods SIG d83023
-	new_size = al->size + sz;
Kmods SIG d83023
-	asize = al_aligned(al->size);
Kmods SIG d83023
+	old_size = al->size;
Kmods SIG d83023
+	new_size = old_size + sz;
Kmods SIG d83023
+	asize = al_aligned(old_size);
Kmods SIG d83023
 	new_asize = al_aligned(new_size);
Kmods SIG d83023
 
Kmods SIG d83023
 	/* Scan forward to the point at which the new 'le' should be inserted. */
Kmods SIG d83023
@@ -302,13 +303,14 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
Kmods SIG d83023
 			return -ENOMEM;
Kmods SIG d83023
 
Kmods SIG d83023
 		memcpy(ptr, al->le, off);
Kmods SIG d83023
-		memcpy(Add2Ptr(ptr, off + sz), le, al->size - off);
Kmods SIG d83023
+		memcpy(Add2Ptr(ptr, off + sz), le, old_size - off);
Kmods SIG d83023
 		le = Add2Ptr(ptr, off);
Kmods SIG d83023
 		kfree(al->le);
Kmods SIG d83023
 		al->le = ptr;
Kmods SIG d83023
 	} else {
Kmods SIG d83023
-		memmove(Add2Ptr(le, sz), le, al->size - off);
Kmods SIG d83023
+		memmove(Add2Ptr(le, sz), le, old_size - off);
Kmods SIG d83023
 	}
Kmods SIG d83023
+	*new_le = le;
Kmods SIG d83023
 
Kmods SIG d83023
 	al->size = new_size;
Kmods SIG d83023
 
Kmods SIG d83023
@@ -321,23 +323,25 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
Kmods SIG d83023
 	le->id = id;
Kmods SIG d83023
 	memcpy(le->name, name, sizeof(short) * name_len);
Kmods SIG d83023
 
Kmods SIG d83023
-	al->dirty = true;
Kmods SIG d83023
-
Kmods SIG d83023
 	err = attr_set_size(ni, ATTR_LIST, NULL, 0, &al->run, new_size,
Kmods SIG d83023
 			    &new_size, true, &attr);
Kmods SIG d83023
-	if (err)
Kmods SIG d83023
+	if (err) {
Kmods SIG d83023
+		/* Undo memmove above. */
Kmods SIG d83023
+		memmove(le, Add2Ptr(le, sz), old_size - off);
Kmods SIG d83023
+		al->size = old_size;
Kmods SIG d83023
 		return err;
Kmods SIG d83023
+	}
Kmods SIG d83023
+
Kmods SIG d83023
+	al->dirty = true;
Kmods SIG d83023
 
Kmods SIG d83023
 	if (attr && attr->non_res) {
Kmods SIG d83023
 		err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le,
Kmods SIG d83023
 					al->size);
Kmods SIG d83023
 		if (err)
Kmods SIG d83023
 			return err;
Kmods SIG d83023
+		al->dirty = false;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
-	al->dirty = false;
Kmods SIG d83023
-	*new_le = le;
Kmods SIG d83023
-
Kmods SIG d83023
 	return 0;
Kmods SIG d83023
 }
Kmods SIG d83023
 
Kmods SIG d83023
diff --git a/src/frecord.c b/src/frecord.c
Kmods SIG d83023
index 9d374827750b2b39261f5985ec2fbb554ac8f6df..3f48b612ec962c6720fb3d3b3e0d63312f389c81 100644
Kmods SIG d83023
--- a/src/frecord.c
Kmods SIG d83023
+++ b/src/frecord.c
Kmods SIG d83023
@@ -163,7 +163,7 @@ int ni_load_mi_ex(struct ntfs_inode *ni, CLST rno, struct mft_inode **mi)
Kmods SIG d83023
 /*
Kmods SIG d83023
  * ni_load_mi - Load mft_inode corresponded list_entry.
Kmods SIG d83023
  */
Kmods SIG d83023
-int ni_load_mi(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
Kmods SIG d83023
+int ni_load_mi(struct ntfs_inode *ni, const struct ATTR_LIST_ENTRY *le,
Kmods SIG d83023
 	       struct mft_inode **mi)
Kmods SIG d83023
 {
Kmods SIG d83023
 	CLST rno;
Kmods SIG d83023
@@ -402,7 +402,7 @@ int ni_remove_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG d83023
 		if (!attr)
Kmods SIG d83023
 			return -ENOENT;
Kmods SIG d83023
 
Kmods SIG d83023
-		mi_remove_attr(&ni->mi, attr);
Kmods SIG d83023
+		mi_remove_attr(ni, &ni->mi, attr);
Kmods SIG d83023
 		return 0;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
@@ -441,7 +441,7 @@ int ni_remove_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG d83023
 		if (!attr)
Kmods SIG d83023
 			return -ENOENT;
Kmods SIG d83023
 
Kmods SIG d83023
-		mi_remove_attr(mi, attr);
Kmods SIG d83023
+		mi_remove_attr(ni, mi, attr);
Kmods SIG d83023
 
Kmods SIG d83023
 		if (PtrOffset(ni->attr_list.le, le) >= ni->attr_list.size)
Kmods SIG d83023
 			return 0;
Kmods SIG d83023
@@ -454,12 +454,11 @@ int ni_remove_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG d83023
  *
Kmods SIG d83023
  * Return: Not full constructed attribute or NULL if not possible to create.
Kmods SIG d83023
  */
Kmods SIG d83023
-static struct ATTRIB *ni_ins_new_attr(struct ntfs_inode *ni,
Kmods SIG d83023
-				      struct mft_inode *mi,
Kmods SIG d83023
-				      struct ATTR_LIST_ENTRY *le,
Kmods SIG d83023
-				      enum ATTR_TYPE type, const __le16 *name,
Kmods SIG d83023
-				      u8 name_len, u32 asize, u16 name_off,
Kmods SIG d83023
-				      CLST svcn)
Kmods SIG d83023
+static struct ATTRIB *
Kmods SIG d83023
+ni_ins_new_attr(struct ntfs_inode *ni, struct mft_inode *mi,
Kmods SIG d83023
+		struct ATTR_LIST_ENTRY *le, enum ATTR_TYPE type,
Kmods SIG d83023
+		const __le16 *name, u8 name_len, u32 asize, u16 name_off,
Kmods SIG d83023
+		CLST svcn, struct ATTR_LIST_ENTRY **ins_le)
Kmods SIG d83023
 {
Kmods SIG d83023
 	int err;
Kmods SIG d83023
 	struct ATTRIB *attr;
Kmods SIG d83023
@@ -507,6 +506,8 @@ static struct ATTRIB *ni_ins_new_attr(struct ntfs_inode *ni,
Kmods SIG d83023
 	le->ref = ref;
Kmods SIG d83023
 
Kmods SIG d83023
 out:
Kmods SIG d83023
+	if (ins_le)
Kmods SIG d83023
+		*ins_le = le;
Kmods SIG d83023
 	return attr;
Kmods SIG d83023
 }
Kmods SIG d83023
 
Kmods SIG d83023
@@ -599,7 +600,7 @@ static int ni_repack(struct ntfs_inode *ni)
Kmods SIG d83023
 		if (next_svcn >= evcn + 1) {
Kmods SIG d83023
 			/* We can remove this attribute segment. */
Kmods SIG d83023
 			al_remove_le(ni, le);
Kmods SIG d83023
-			mi_remove_attr(mi, attr);
Kmods SIG d83023
+			mi_remove_attr(NULL, mi, attr);
Kmods SIG d83023
 			le = le_p;
Kmods SIG d83023
 			continue;
Kmods SIG d83023
 		}
Kmods SIG d83023
@@ -695,8 +696,8 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
Kmods SIG d83023
 		free -= asize;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
-	/* Is seems that attribute list can be removed from primary record. */
Kmods SIG d83023
-	mi_remove_attr(&ni->mi, attr_list);
Kmods SIG d83023
+	/* It seems that attribute list can be removed from primary record. */
Kmods SIG d83023
+	mi_remove_attr(NULL, &ni->mi, attr_list);
Kmods SIG d83023
 
Kmods SIG d83023
 	/*
Kmods SIG d83023
 	 * Repeat the cycle above and move all attributes to primary record.
Kmods SIG d83023
@@ -724,7 +725,7 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
Kmods SIG d83023
 		attr_ins->id = id;
Kmods SIG d83023
 
Kmods SIG d83023
 		/* Remove from original record. */
Kmods SIG d83023
-		mi_remove_attr(mi, attr);
Kmods SIG d83023
+		mi_remove_attr(NULL, mi, attr);
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
 	run_deallocate(sbi, &ni->attr_list.run, true);
Kmods SIG d83023
@@ -842,7 +843,8 @@ int ni_create_attr_list(struct ntfs_inode *ni)
Kmods SIG d83023
 		memcpy(attr, b, asize);
Kmods SIG d83023
 		attr->id = le_b[nb]->id;
Kmods SIG d83023
 
Kmods SIG d83023
-		WARN_ON(!mi_remove_attr(&ni->mi, b));
Kmods SIG d83023
+		/* Remove from primary record. */
Kmods SIG d83023
+		WARN_ON(!mi_remove_attr(NULL, &ni->mi, b));
Kmods SIG d83023
 
Kmods SIG d83023
 		if (to_free <= asize)
Kmods SIG d83023
 			break;
Kmods SIG d83023
@@ -883,7 +885,8 @@ int ni_create_attr_list(struct ntfs_inode *ni)
Kmods SIG d83023
 static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
Kmods SIG d83023
 			   enum ATTR_TYPE type, const __le16 *name, u8 name_len,
Kmods SIG d83023
 			   u32 asize, CLST svcn, u16 name_off, bool force_ext,
Kmods SIG d83023
-			   struct ATTRIB **ins_attr, struct mft_inode **ins_mi)
Kmods SIG d83023
+			   struct ATTRIB **ins_attr, struct mft_inode **ins_mi,
Kmods SIG d83023
+			   struct ATTR_LIST_ENTRY **ins_le)
Kmods SIG d83023
 {
Kmods SIG d83023
 	struct ATTRIB *attr;
Kmods SIG d83023
 	struct mft_inode *mi;
Kmods SIG d83023
@@ -956,12 +959,14 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
Kmods SIG d83023
 
Kmods SIG d83023
 		/* Try to insert attribute into this subrecord. */
Kmods SIG d83023
 		attr = ni_ins_new_attr(ni, mi, le, type, name, name_len, asize,
Kmods SIG d83023
-				       name_off, svcn);
Kmods SIG d83023
+				       name_off, svcn, ins_le);
Kmods SIG d83023
 		if (!attr)
Kmods SIG d83023
 			continue;
Kmods SIG d83023
 
Kmods SIG d83023
 		if (ins_attr)
Kmods SIG d83023
 			*ins_attr = attr;
Kmods SIG d83023
+		if (ins_mi)
Kmods SIG d83023
+			*ins_mi = mi;
Kmods SIG d83023
 		return 0;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
@@ -977,7 +982,7 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
 	attr = ni_ins_new_attr(ni, mi, le, type, name, name_len, asize,
Kmods SIG d83023
-			       name_off, svcn);
Kmods SIG d83023
+			       name_off, svcn, ins_le);
Kmods SIG d83023
 	if (!attr)
Kmods SIG d83023
 		goto out2;
Kmods SIG d83023
 
Kmods SIG d83023
@@ -1016,7 +1021,8 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
Kmods SIG d83023
 static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG d83023
 			  const __le16 *name, u8 name_len, u32 asize,
Kmods SIG d83023
 			  u16 name_off, CLST svcn, struct ATTRIB **ins_attr,
Kmods SIG d83023
-			  struct mft_inode **ins_mi)
Kmods SIG d83023
+			  struct mft_inode **ins_mi,
Kmods SIG d83023
+			  struct ATTR_LIST_ENTRY **ins_le)
Kmods SIG d83023
 {
Kmods SIG d83023
 	struct ntfs_sb_info *sbi = ni->mi.sbi;
Kmods SIG d83023
 	int err;
Kmods SIG d83023
@@ -1045,7 +1051,7 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG d83023
 
Kmods SIG d83023
 	if (asize <= free) {
Kmods SIG d83023
 		attr = ni_ins_new_attr(ni, &ni->mi, NULL, type, name, name_len,
Kmods SIG d83023
-				       asize, name_off, svcn);
Kmods SIG d83023
+				       asize, name_off, svcn, ins_le);
Kmods SIG d83023
 		if (attr) {
Kmods SIG d83023
 			if (ins_attr)
Kmods SIG d83023
 				*ins_attr = attr;
Kmods SIG d83023
@@ -1059,7 +1065,8 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG d83023
 	if (!is_mft || type != ATTR_DATA || svcn) {
Kmods SIG d83023
 		/* This ATTRIB will be external. */
Kmods SIG d83023
 		err = ni_ins_attr_ext(ni, NULL, type, name, name_len, asize,
Kmods SIG d83023
-				      svcn, name_off, false, ins_attr, ins_mi);
Kmods SIG d83023
+				      svcn, name_off, false, ins_attr, ins_mi,
Kmods SIG d83023
+				      ins_le);
Kmods SIG d83023
 		goto out;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
@@ -1117,7 +1124,7 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG d83023
 		t16 = le16_to_cpu(attr->name_off);
Kmods SIG d83023
 		err = ni_ins_attr_ext(ni, le, attr->type, Add2Ptr(attr, t16),
Kmods SIG d83023
 				      attr->name_len, t32, attr_svcn(attr), t16,
Kmods SIG d83023
-				      false, &eattr, NULL);
Kmods SIG d83023
+				      false, &eattr, NULL, NULL);
Kmods SIG d83023
 		if (err)
Kmods SIG d83023
 			return err;
Kmods SIG d83023
 
Kmods SIG d83023
@@ -1125,8 +1132,8 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG d83023
 		memcpy(eattr, attr, t32);
Kmods SIG d83023
 		eattr->id = id;
Kmods SIG d83023
 
Kmods SIG d83023
-		/* Remove attrib from primary record. */
Kmods SIG d83023
-		mi_remove_attr(&ni->mi, attr);
Kmods SIG d83023
+		/* Remove from primary record. */
Kmods SIG d83023
+		mi_remove_attr(NULL, &ni->mi, attr);
Kmods SIG d83023
 
Kmods SIG d83023
 		/* attr now points to next attribute. */
Kmods SIG d83023
 		if (attr->type == ATTR_END)
Kmods SIG d83023
@@ -1136,7 +1143,7 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG d83023
 		;
Kmods SIG d83023
 
Kmods SIG d83023
 	attr = ni_ins_new_attr(ni, &ni->mi, NULL, type, name, name_len, asize,
Kmods SIG d83023
-			       name_off, svcn);
Kmods SIG d83023
+			       name_off, svcn, ins_le);
Kmods SIG d83023
 	if (!attr) {
Kmods SIG d83023
 		err = -EINVAL;
Kmods SIG d83023
 		goto out;
Kmods SIG d83023
@@ -1251,7 +1258,7 @@ static int ni_expand_mft_list(struct ntfs_inode *ni)
Kmods SIG d83023
 	 */
Kmods SIG d83023
 	attr = ni_ins_new_attr(ni, mi_min, NULL, ATTR_DATA, NULL, 0,
Kmods SIG d83023
 			       SIZEOF_NONRESIDENT + run_size,
Kmods SIG d83023
-			       SIZEOF_NONRESIDENT, svcn);
Kmods SIG d83023
+			       SIZEOF_NONRESIDENT, svcn, NULL);
Kmods SIG d83023
 	if (!attr) {
Kmods SIG d83023
 		err = -EINVAL;
Kmods SIG d83023
 		goto out;
Kmods SIG d83023
@@ -1315,14 +1322,15 @@ int ni_expand_list(struct ntfs_inode *ni)
Kmods SIG d83023
 		err = ni_ins_attr_ext(ni, le, attr->type, attr_name(attr),
Kmods SIG d83023
 				      attr->name_len, asize, attr_svcn(attr),
Kmods SIG d83023
 				      le16_to_cpu(attr->name_off), true,
Kmods SIG d83023
-				      &ins_attr, NULL);
Kmods SIG d83023
+				      &ins_attr, NULL, NULL);
Kmods SIG d83023
 
Kmods SIG d83023
 		if (err)
Kmods SIG d83023
 			goto out;
Kmods SIG d83023
 
Kmods SIG d83023
 		memcpy(ins_attr, attr, asize);
Kmods SIG d83023
 		ins_attr->id = le->id;
Kmods SIG d83023
-		mi_remove_attr(&ni->mi, attr);
Kmods SIG d83023
+		/* Remove from primary record. */
Kmods SIG d83023
+		mi_remove_attr(NULL, &ni->mi, attr);
Kmods SIG d83023
 
Kmods SIG d83023
 		done += asize;
Kmods SIG d83023
 		goto out;
Kmods SIG d83023
@@ -1382,7 +1390,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
 	err = ni_insert_attr(ni, type, name, name_len, asize, name_off, svcn,
Kmods SIG d83023
-			     &attr, mi);
Kmods SIG d83023
+			     &attr, mi, NULL);
Kmods SIG d83023
 
Kmods SIG d83023
 	if (err)
Kmods SIG d83023
 		goto out;
Kmods SIG d83023
@@ -1422,7 +1430,8 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG d83023
  */
Kmods SIG d83023
 int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
Kmods SIG d83023
 		       enum ATTR_TYPE type, const __le16 *name, u8 name_len,
Kmods SIG d83023
-		       struct ATTRIB **new_attr, struct mft_inode **mi)
Kmods SIG d83023
+		       struct ATTRIB **new_attr, struct mft_inode **mi,
Kmods SIG d83023
+		       struct ATTR_LIST_ENTRY **le)
Kmods SIG d83023
 {
Kmods SIG d83023
 	int err;
Kmods SIG d83023
 	u32 name_size = ALIGN(name_len * sizeof(short), 8);
Kmods SIG d83023
@@ -1430,7 +1439,7 @@ int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
Kmods SIG d83023
 	struct ATTRIB *attr;
Kmods SIG d83023
 
Kmods SIG d83023
 	err = ni_insert_attr(ni, type, name, name_len, asize, SIZEOF_RESIDENT,
Kmods SIG d83023
-			     0, &attr, mi);
Kmods SIG d83023
+			     0, &attr, mi, le);
Kmods SIG d83023
 	if (err)
Kmods SIG d83023
 		return err;
Kmods SIG d83023
 
Kmods SIG d83023
@@ -1439,8 +1448,13 @@ int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
Kmods SIG d83023
 
Kmods SIG d83023
 	attr->res.data_size = cpu_to_le32(data_size);
Kmods SIG d83023
 	attr->res.data_off = cpu_to_le16(SIZEOF_RESIDENT + name_size);
Kmods SIG d83023
-	if (type == ATTR_NAME)
Kmods SIG d83023
+	if (type == ATTR_NAME) {
Kmods SIG d83023
 		attr->res.flags = RESIDENT_FLAG_INDEXED;
Kmods SIG d83023
+
Kmods SIG d83023
+		/* is_attr_indexed(attr)) == true */
Kmods SIG d83023
+		le16_add_cpu(&ni->mi.mrec->hard_links, +1);
Kmods SIG d83023
+		ni->mi.dirty = true;
Kmods SIG d83023
+	}
Kmods SIG d83023
 	attr->res.res = 0;
Kmods SIG d83023
 
Kmods SIG d83023
 	if (new_attr)
Kmods SIG d83023
@@ -1452,22 +1466,13 @@ int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
Kmods SIG d83023
 /*
Kmods SIG d83023
  * ni_remove_attr_le - Remove attribute from record.
Kmods SIG d83023
  */
Kmods SIG d83023
-int ni_remove_attr_le(struct ntfs_inode *ni, struct ATTRIB *attr,
Kmods SIG d83023
-		      struct ATTR_LIST_ENTRY *le)
Kmods SIG d83023
+void ni_remove_attr_le(struct ntfs_inode *ni, struct ATTRIB *attr,
Kmods SIG d83023
+		       struct mft_inode *mi, struct ATTR_LIST_ENTRY *le)
Kmods SIG d83023
 {
Kmods SIG d83023
-	int err;
Kmods SIG d83023
-	struct mft_inode *mi;
Kmods SIG d83023
-
Kmods SIG d83023
-	err = ni_load_mi(ni, le, &mi);
Kmods SIG d83023
-	if (err)
Kmods SIG d83023
-		return err;
Kmods SIG d83023
-
Kmods SIG d83023
-	mi_remove_attr(mi, attr);
Kmods SIG d83023
+	mi_remove_attr(ni, mi, attr);
Kmods SIG d83023
 
Kmods SIG d83023
 	if (le)
Kmods SIG d83023
 		al_remove_le(ni, le);
Kmods SIG d83023
-
Kmods SIG d83023
-	return 0;
Kmods SIG d83023
 }
Kmods SIG d83023
 
Kmods SIG d83023
 /*
Kmods SIG d83023
@@ -1549,10 +1554,12 @@ int ni_delete_all(struct ntfs_inode *ni)
Kmods SIG d83023
 
Kmods SIG d83023
 /* ni_fname_name
Kmods SIG d83023
  *
Kmods SIG d83023
- *Return: File name attribute by its value. */
Kmods SIG d83023
+ * Return: File name attribute by its value.
Kmods SIG d83023
+ */
Kmods SIG d83023
 struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
Kmods SIG d83023
 				     const struct cpu_str *uni,
Kmods SIG d83023
 				     const struct MFT_REF *home_dir,
Kmods SIG d83023
+				     struct mft_inode **mi,
Kmods SIG d83023
 				     struct ATTR_LIST_ENTRY **le)
Kmods SIG d83023
 {
Kmods SIG d83023
 	struct ATTRIB *attr = NULL;
Kmods SIG d83023
@@ -1562,7 +1569,7 @@ struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
Kmods SIG d83023
 
Kmods SIG d83023
 	/* Enumerate all names. */
Kmods SIG d83023
 next:
Kmods SIG d83023
-	attr = ni_find_attr(ni, attr, le, ATTR_NAME, NULL, 0, NULL, NULL);
Kmods SIG d83023
+	attr = ni_find_attr(ni, attr, le, ATTR_NAME, NULL, 0, NULL, mi);
Kmods SIG d83023
 	if (!attr)
Kmods SIG d83023
 		return NULL;
Kmods SIG d83023
 
Kmods SIG d83023
@@ -1592,6 +1599,7 @@ struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
Kmods SIG d83023
  * Return: File name attribute with given type.
Kmods SIG d83023
  */
Kmods SIG d83023
 struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type,
Kmods SIG d83023
+				     struct mft_inode **mi,
Kmods SIG d83023
 				     struct ATTR_LIST_ENTRY **le)
Kmods SIG d83023
 {
Kmods SIG d83023
 	struct ATTRIB *attr = NULL;
Kmods SIG d83023
@@ -1599,10 +1607,12 @@ struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type,
Kmods SIG d83023
 
Kmods SIG d83023
 	*le = NULL;
Kmods SIG d83023
 
Kmods SIG d83023
+	if (FILE_NAME_POSIX == name_type)
Kmods SIG d83023
+		return NULL;
Kmods SIG d83023
+
Kmods SIG d83023
 	/* Enumerate all names. */
Kmods SIG d83023
 	for (;;) {
Kmods SIG d83023
-		attr = ni_find_attr(ni, attr, le, ATTR_NAME, NULL, 0, NULL,
Kmods SIG d83023
-				    NULL);
Kmods SIG d83023
+		attr = ni_find_attr(ni, attr, le, ATTR_NAME, NULL, 0, NULL, mi);
Kmods SIG d83023
 		if (!attr)
Kmods SIG d83023
 			return NULL;
Kmods SIG d83023
 
Kmods SIG d83023
@@ -2788,6 +2798,222 @@ int ni_write_frame(struct ntfs_inode *ni, struct page **pages,
Kmods SIG d83023
 	return err;
Kmods SIG d83023
 }
Kmods SIG d83023
 
Kmods SIG d83023
+/*
Kmods SIG d83023
+ * ni_remove_name - Removes name 'de' from MFT and from directory.
Kmods SIG d83023
+ * 'de2' and 'undo_step' are used to restore MFT/dir, if error occurs.
Kmods SIG d83023
+ */
Kmods SIG d83023
+int ni_remove_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
Kmods SIG d83023
+		   struct NTFS_DE *de, struct NTFS_DE **de2, int *undo_step)
Kmods SIG d83023
+{
Kmods SIG d83023
+	int err;
Kmods SIG d83023
+	struct ntfs_sb_info *sbi = ni->mi.sbi;
Kmods SIG d83023
+	struct ATTR_FILE_NAME *de_name = (struct ATTR_FILE_NAME *)(de + 1);
Kmods SIG d83023
+	struct ATTR_FILE_NAME *fname;
Kmods SIG d83023
+	struct ATTR_LIST_ENTRY *le;
Kmods SIG d83023
+	struct mft_inode *mi;
Kmods SIG d83023
+	u16 de_key_size = le16_to_cpu(de->key_size);
Kmods SIG d83023
+	u8 name_type;
Kmods SIG d83023
+
Kmods SIG d83023
+	*undo_step = 0;
Kmods SIG d83023
+
Kmods SIG d83023
+	/* Find name in record. */
Kmods SIG d83023
+	mi_get_ref(&dir_ni->mi, &de_name->home);
Kmods SIG d83023
+
Kmods SIG d83023
+	fname = ni_fname_name(ni, (struct cpu_str *)&de_name->name_len,
Kmods SIG d83023
+			      &de_name->home, &mi, &le);
Kmods SIG d83023
+	if (!fname)
Kmods SIG d83023
+		return -ENOENT;
Kmods SIG d83023
+
Kmods SIG d83023
+	memcpy(&de_name->dup, &fname->dup, sizeof(struct NTFS_DUP_INFO));
Kmods SIG d83023
+	name_type = paired_name(fname->type);
Kmods SIG d83023
+
Kmods SIG d83023
+	/* Mark ntfs as dirty. It will be cleared at umount. */
Kmods SIG d83023
+	ntfs_set_state(sbi, NTFS_DIRTY_DIRTY);
Kmods SIG d83023
+
Kmods SIG d83023
+	/* Step 1: Remove name from directory. */
Kmods SIG d83023
+	err = indx_delete_entry(&dir_ni->dir, dir_ni, fname, de_key_size, sbi);
Kmods SIG d83023
+	if (err)
Kmods SIG d83023
+		return err;
Kmods SIG d83023
+
Kmods SIG d83023
+	/* Step 2: Remove name from MFT. */
Kmods SIG d83023
+	ni_remove_attr_le(ni, attr_from_name(fname), mi, le);
Kmods SIG d83023
+
Kmods SIG d83023
+	*undo_step = 2;
Kmods SIG d83023
+
Kmods SIG d83023
+	/* Get paired name. */
Kmods SIG d83023
+	fname = ni_fname_type(ni, name_type, &mi, &le);
Kmods SIG d83023
+	if (fname) {
Kmods SIG d83023
+		u16 de2_key_size = fname_full_size(fname);
Kmods SIG d83023
+
Kmods SIG d83023
+		*de2 = Add2Ptr(de, 1024);
Kmods SIG d83023
+		(*de2)->key_size = cpu_to_le16(de2_key_size);
Kmods SIG d83023
+
Kmods SIG d83023
+		memcpy(*de2 + 1, fname, de2_key_size);
Kmods SIG d83023
+
Kmods SIG d83023
+		/* Step 3: Remove paired name from directory. */
Kmods SIG d83023
+		err = indx_delete_entry(&dir_ni->dir, dir_ni, fname,
Kmods SIG d83023
+					de2_key_size, sbi);
Kmods SIG d83023
+		if (err)
Kmods SIG d83023
+			return err;
Kmods SIG d83023
+
Kmods SIG d83023
+		/* Step 4: Remove paired name from MFT. */
Kmods SIG d83023
+		ni_remove_attr_le(ni, attr_from_name(fname), mi, le);
Kmods SIG d83023
+
Kmods SIG d83023
+		*undo_step = 4;
Kmods SIG d83023
+	}
Kmods SIG d83023
+	return 0;
Kmods SIG d83023
+}
Kmods SIG d83023
+
Kmods SIG d83023
+/*
Kmods SIG d83023
+ * ni_remove_name_undo - Paired function for ni_remove_name.
Kmods SIG d83023
+ *
Kmods SIG d83023
+ * Return: True if ok
Kmods SIG d83023
+ */
Kmods SIG d83023
+bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
Kmods SIG d83023
+			 struct NTFS_DE *de, struct NTFS_DE *de2, int undo_step)
Kmods SIG d83023
+{
Kmods SIG d83023
+	struct ntfs_sb_info *sbi = ni->mi.sbi;
Kmods SIG d83023
+	struct ATTRIB *attr;
Kmods SIG d83023
+	u16 de_key_size = de2 ? le16_to_cpu(de2->key_size) : 0;
Kmods SIG d83023
+
Kmods SIG d83023
+	switch (undo_step) {
Kmods SIG d83023
+	case 4:
Kmods SIG d83023
+		if (ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0,
Kmods SIG d83023
+				       &attr, NULL, NULL)) {
Kmods SIG d83023
+			return false;
Kmods SIG d83023
+		}
Kmods SIG d83023
+		memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de2 + 1, de_key_size);
Kmods SIG d83023
+
Kmods SIG d83023
+		mi_get_ref(&ni->mi, &de2->ref);
Kmods SIG d83023
+		de2->size = cpu_to_le16(ALIGN(de_key_size, 8) +
Kmods SIG d83023
+					sizeof(struct NTFS_DE));
Kmods SIG d83023
+		de2->flags = 0;
Kmods SIG d83023
+		de2->res = 0;
Kmods SIG d83023
+
Kmods SIG d83023
+		if (indx_insert_entry(&dir_ni->dir, dir_ni, de2, sbi, NULL,
Kmods SIG d83023
+				      1)) {
Kmods SIG d83023
+			return false;
Kmods SIG d83023
+		}
Kmods SIG d83023
+		fallthrough;
Kmods SIG d83023
+
Kmods SIG d83023
+	case 2:
Kmods SIG d83023
+		de_key_size = le16_to_cpu(de->key_size);
Kmods SIG d83023
+
Kmods SIG d83023
+		if (ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0,
Kmods SIG d83023
+				       &attr, NULL, NULL)) {
Kmods SIG d83023
+			return false;
Kmods SIG d83023
+		}
Kmods SIG d83023
+
Kmods SIG d83023
+		memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de + 1, de_key_size);
Kmods SIG d83023
+		mi_get_ref(&ni->mi, &de->ref);
Kmods SIG d83023
+
Kmods SIG d83023
+		if (indx_insert_entry(&dir_ni->dir, dir_ni, de, sbi, NULL, 1)) {
Kmods SIG d83023
+			return false;
Kmods SIG d83023
+		}
Kmods SIG d83023
+	}
Kmods SIG d83023
+
Kmods SIG d83023
+	return true;
Kmods SIG d83023
+}
Kmods SIG d83023
+
Kmods SIG d83023
+/*
Kmods SIG d83023
+ * ni_add_name - Add new name in MFT and in directory.
Kmods SIG d83023
+ */
Kmods SIG d83023
+int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
Kmods SIG d83023
+		struct NTFS_DE *de)
Kmods SIG d83023
+{
Kmods SIG d83023
+	int err;
Kmods SIG d83023
+	struct ATTRIB *attr;
Kmods SIG d83023
+	struct ATTR_LIST_ENTRY *le;
Kmods SIG d83023
+	struct mft_inode *mi;
Kmods SIG d83023
+	struct ATTR_FILE_NAME *de_name = (struct ATTR_FILE_NAME *)(de + 1);
Kmods SIG d83023
+	u16 de_key_size = le16_to_cpu(de->key_size);
Kmods SIG d83023
+
Kmods SIG d83023
+	mi_get_ref(&ni->mi, &de->ref);
Kmods SIG d83023
+	mi_get_ref(&dir_ni->mi, &de_name->home);
Kmods SIG d83023
+
Kmods SIG d83023
+	/* Insert new name in MFT. */
Kmods SIG d83023
+	err = ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0, &attr,
Kmods SIG d83023
+				 &mi, &le);
Kmods SIG d83023
+	if (err)
Kmods SIG d83023
+		return err;
Kmods SIG d83023
+
Kmods SIG d83023
+	memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de_name, de_key_size);
Kmods SIG d83023
+
Kmods SIG d83023
+	/* Insert new name in directory. */
Kmods SIG d83023
+	err = indx_insert_entry(&dir_ni->dir, dir_ni, de, ni->mi.sbi, NULL, 0);
Kmods SIG d83023
+	if (err)
Kmods SIG d83023
+		ni_remove_attr_le(ni, attr, mi, le);
Kmods SIG d83023
+
Kmods SIG d83023
+	return err;
Kmods SIG d83023
+}
Kmods SIG d83023
+
Kmods SIG d83023
+/*
Kmods SIG d83023
+ * ni_rename - Remove one name and insert new name.
Kmods SIG d83023
+ */
Kmods SIG d83023
+int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
Kmods SIG d83023
+	      struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de,
Kmods SIG d83023
+	      bool *is_bad)
Kmods SIG d83023
+{
Kmods SIG d83023
+	int err;
Kmods SIG d83023
+	struct NTFS_DE *de2 = NULL;
Kmods SIG d83023
+	int undo = 0;
Kmods SIG d83023
+
Kmods SIG d83023
+	/*
Kmods SIG d83023
+	 * There are two possible ways to rename:
Kmods SIG d83023
+	 * 1) Add new name and remove old name.
Kmods SIG d83023
+	 * 2) Remove old name and add new name.
Kmods SIG d83023
+	 *
Kmods SIG d83023
+	 * In most cases (not all!) adding new name in MFT and in directory can
Kmods SIG d83023
+	 * allocate additional cluster(s).
Kmods SIG d83023
+	 * Second way may result to bad inode if we can't add new name
Kmods SIG d83023
+	 * and then can't restore (add) old name.
Kmods SIG d83023
+	 */
Kmods SIG d83023
+
Kmods SIG d83023
+	/*
Kmods SIG d83023
+	 * Way 1 - Add new + remove old.
Kmods SIG d83023
+	 */
Kmods SIG d83023
+	err = ni_add_name(new_dir_ni, ni, new_de);
Kmods SIG d83023
+	if (!err) {
Kmods SIG d83023
+		err = ni_remove_name(dir_ni, ni, de, &de2, &undo);
Kmods SIG d83023
+		if (err && ni_remove_name(new_dir_ni, ni, new_de, &de2, &undo))
Kmods SIG d83023
+			*is_bad = true;
Kmods SIG d83023
+	}
Kmods SIG d83023
+
Kmods SIG d83023
+	/*
Kmods SIG d83023
+	 * Way 2 - Remove old + add new.
Kmods SIG d83023
+	 */
Kmods SIG d83023
+	/*
Kmods SIG d83023
+	 *	err = ni_remove_name(dir_ni, ni, de, &de2, &undo);
Kmods SIG d83023
+	 *	if (!err) {
Kmods SIG d83023
+	 *		err = ni_add_name(new_dir_ni, ni, new_de);
Kmods SIG d83023
+	 *		if (err && !ni_remove_name_undo(dir_ni, ni, de, de2, undo))
Kmods SIG d83023
+	 *			*is_bad = true;
Kmods SIG d83023
+	 *	}
Kmods SIG d83023
+	 */
Kmods SIG d83023
+
Kmods SIG d83023
+	return err;
Kmods SIG d83023
+}
Kmods SIG d83023
+
Kmods SIG d83023
+/*
Kmods SIG d83023
+ * ni_is_dirty - Return: True if 'ni' requires ni_write_inode.
Kmods SIG d83023
+ */
Kmods SIG d83023
+bool ni_is_dirty(struct inode *inode)
Kmods SIG d83023
+{
Kmods SIG d83023
+	struct ntfs_inode *ni = ntfs_i(inode);
Kmods SIG d83023
+	struct rb_node *node;
Kmods SIG d83023
+
Kmods SIG d83023
+	if (ni->mi.dirty || ni->attr_list.dirty ||
Kmods SIG d83023
+	    (ni->ni_flags & NI_FLAG_UPDATE_PARENT))
Kmods SIG d83023
+		return true;
Kmods SIG d83023
+
Kmods SIG d83023
+	for (node = rb_first(&ni->mi_tree); node; node = rb_next(node)) {
Kmods SIG d83023
+		if (rb_entry(node, struct mft_inode, node)->dirty)
Kmods SIG d83023
+			return true;
Kmods SIG d83023
+	}
Kmods SIG d83023
+
Kmods SIG d83023
+	return false;
Kmods SIG d83023
+}
Kmods SIG d83023
+
Kmods SIG d83023
 /*
Kmods SIG d83023
  * ni_update_parent
Kmods SIG d83023
  *
Kmods SIG d83023
@@ -2802,8 +3028,6 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
Kmods SIG d83023
 	struct ntfs_sb_info *sbi = ni->mi.sbi;
Kmods SIG d83023
 	struct super_block *sb = sbi->sb;
Kmods SIG d83023
 	bool re_dirty = false;
Kmods SIG d83023
-	bool active = sb->s_flags & SB_ACTIVE;
Kmods SIG d83023
-	bool upd_parent = ni->ni_flags & NI_FLAG_UPDATE_PARENT;
Kmods SIG d83023
 
Kmods SIG d83023
 	if (ni->mi.mrec->flags & RECORD_FLAG_DIR) {
Kmods SIG d83023
 		dup->fa |= FILE_ATTRIBUTE_DIRECTORY;
Kmods SIG d83023
@@ -2867,19 +3091,9 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
Kmods SIG d83023
 		struct ATTR_FILE_NAME *fname;
Kmods SIG d83023
 
Kmods SIG d83023
 		fname = resident_data_ex(attr, SIZEOF_ATTRIBUTE_FILENAME);
Kmods SIG d83023
-		if (!fname)
Kmods SIG d83023
+		if (!fname || !memcmp(&fname->dup, dup, sizeof(fname->dup)))
Kmods SIG d83023
 			continue;
Kmods SIG d83023
 
Kmods SIG d83023
-		if (memcmp(&fname->dup, dup, sizeof(fname->dup))) {
Kmods SIG d83023
-			memcpy(&fname->dup, dup, sizeof(fname->dup));
Kmods SIG d83023
-			mi->dirty = true;
Kmods SIG d83023
-		} else if (!upd_parent) {
Kmods SIG d83023
-			continue;
Kmods SIG d83023
-		}
Kmods SIG d83023
-
Kmods SIG d83023
-		if (!active)
Kmods SIG d83023
-			continue; /* Avoid __wait_on_freeing_inode(inode); */
Kmods SIG d83023
-
Kmods SIG d83023
 		/* ntfs_iget5 may sleep. */
Kmods SIG d83023
 		dir = ntfs_iget5(sb, &fname->home, NULL);
Kmods SIG d83023
 		if (IS_ERR(dir)) {
Kmods SIG d83023
@@ -2898,6 +3112,8 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
Kmods SIG d83023
 			} else {
Kmods SIG d83023
 				indx_update_dup(dir_ni, sbi, fname, dup, sync);
Kmods SIG d83023
 				ni_unlock(dir_ni);
Kmods SIG d83023
+				memcpy(&fname->dup, dup, sizeof(fname->dup));
Kmods SIG d83023
+				mi->dirty = true;
Kmods SIG d83023
 			}
Kmods SIG d83023
 		}
Kmods SIG d83023
 		iput(dir);
Kmods SIG d83023
@@ -2969,7 +3185,9 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
Kmods SIG d83023
 			ni->mi.dirty = true;
Kmods SIG d83023
 
Kmods SIG d83023
 		if (!ntfs_is_meta_file(sbi, inode->i_ino) &&
Kmods SIG d83023
-		    (modified || (ni->ni_flags & NI_FLAG_UPDATE_PARENT))) {
Kmods SIG d83023
+		    (modified || (ni->ni_flags & NI_FLAG_UPDATE_PARENT))
Kmods SIG d83023
+		    /* Avoid __wait_on_freeing_inode(inode). */
Kmods SIG d83023
+		    && (sb->s_flags & SB_ACTIVE)) {
Kmods SIG d83023
 			dup.cr_time = std->cr_time;
Kmods SIG d83023
 			/* Not critical if this function fail. */
Kmods SIG d83023
 			re_dirty = ni_update_parent(ni, &dup, sync);
Kmods SIG d83023
@@ -3033,7 +3251,7 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
Kmods SIG d83023
 		return err;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
-	if (re_dirty && (sb->s_flags & SB_ACTIVE))
Kmods SIG d83023
+	if (re_dirty)
Kmods SIG d83023
 		mark_inode_dirty_sync(inode);
Kmods SIG d83023
 
Kmods SIG d83023
 	return 0;
Kmods SIG d83023
diff --git a/src/fsntfs.c b/src/fsntfs.c
Kmods SIG d83023
index 0edb95ed9717f442f97b3ba3e85b4b6a361e0e27..66924943921771d3cf46f6a762b1ea81ae1e9ca2 100644
Kmods SIG d83023
--- a/src/fsntfs.c
Kmods SIG d83023
+++ b/src/fsntfs.c
Kmods SIG d83023
@@ -358,29 +358,25 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
Kmods SIG d83023
 			     enum ALLOCATE_OPT opt)
Kmods SIG d83023
 {
Kmods SIG d83023
 	int err;
Kmods SIG d83023
+	CLST alen = 0;
Kmods SIG d83023
 	struct super_block *sb = sbi->sb;
Kmods SIG d83023
-	size_t a_lcn, zlen, zeroes, zlcn, zlen2, ztrim, new_zlen;
Kmods SIG d83023
+	size_t alcn, zlen, zeroes, zlcn, zlen2, ztrim, new_zlen;
Kmods SIG d83023
 	struct wnd_bitmap *wnd = &sbi->used.bitmap;
Kmods SIG d83023
 
Kmods SIG d83023
 	down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
Kmods SIG d83023
 	if (opt & ALLOCATE_MFT) {
Kmods SIG d83023
-		CLST alen;
Kmods SIG d83023
-
Kmods SIG d83023
 		zlen = wnd_zone_len(wnd);
Kmods SIG d83023
 
Kmods SIG d83023
 		if (!zlen) {
Kmods SIG d83023
 			err = ntfs_refresh_zone(sbi);
Kmods SIG d83023
 			if (err)
Kmods SIG d83023
 				goto out;
Kmods SIG d83023
-
Kmods SIG d83023
 			zlen = wnd_zone_len(wnd);
Kmods SIG d83023
+		}
Kmods SIG d83023
 
Kmods SIG d83023
-			if (!zlen) {
Kmods SIG d83023
-				ntfs_err(sbi->sb,
Kmods SIG d83023
-					 "no free space to extend mft");
Kmods SIG d83023
-				err = -ENOSPC;
Kmods SIG d83023
-				goto out;
Kmods SIG d83023
-			}
Kmods SIG d83023
+		if (!zlen) {
Kmods SIG d83023
+			ntfs_err(sbi->sb, "no free space to extend mft");
Kmods SIG d83023
+			goto out;
Kmods SIG d83023
 		}
Kmods SIG d83023
 
Kmods SIG d83023
 		lcn = wnd_zone_bit(wnd);
Kmods SIG d83023
@@ -389,14 +385,13 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
Kmods SIG d83023
 		wnd_zone_set(wnd, lcn + alen, zlen - alen);
Kmods SIG d83023
 
Kmods SIG d83023
 		err = wnd_set_used(wnd, lcn, alen);
Kmods SIG d83023
-		if (err)
Kmods SIG d83023
-			goto out;
Kmods SIG d83023
-
Kmods SIG d83023
-		*new_lcn = lcn;
Kmods SIG d83023
-		*new_len = alen;
Kmods SIG d83023
-		goto ok;
Kmods SIG d83023
+		if (err) {
Kmods SIG d83023
+			up_write(&wnd->rw_lock);
Kmods SIG d83023
+			return err;
Kmods SIG d83023
+		}
Kmods SIG d83023
+		alcn = lcn;
Kmods SIG d83023
+		goto out;
Kmods SIG d83023
 	}
Kmods SIG d83023
-
Kmods SIG d83023
 	/*
Kmods SIG d83023
 	 * 'Cause cluster 0 is always used this value means that we should use
Kmods SIG d83023
 	 * cached value of 'next_free_lcn' to improve performance.
Kmods SIG d83023
@@ -407,22 +402,17 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
Kmods SIG d83023
 	if (lcn >= wnd->nbits)
Kmods SIG d83023
 		lcn = 0;
Kmods SIG d83023
 
Kmods SIG d83023
-	*new_len = wnd_find(wnd, len, lcn, BITMAP_FIND_MARK_AS_USED, &a_lcn);
Kmods SIG d83023
-	if (*new_len) {
Kmods SIG d83023
-		*new_lcn = a_lcn;
Kmods SIG d83023
-		goto ok;
Kmods SIG d83023
-	}
Kmods SIG d83023
+	alen = wnd_find(wnd, len, lcn, BITMAP_FIND_MARK_AS_USED, &alcn);
Kmods SIG d83023
+	if (alen)
Kmods SIG d83023
+		goto out;
Kmods SIG d83023
 
Kmods SIG d83023
 	/* Try to use clusters from MftZone. */
Kmods SIG d83023
 	zlen = wnd_zone_len(wnd);
Kmods SIG d83023
 	zeroes = wnd_zeroes(wnd);
Kmods SIG d83023
 
Kmods SIG d83023
-	/* Check too big request. */
Kmods SIG d83023
-	if (len > zeroes + zlen)
Kmods SIG d83023
-		goto no_space;
Kmods SIG d83023
-
Kmods SIG d83023
-	if (zlen <= NTFS_MIN_MFT_ZONE)
Kmods SIG d83023
-		goto no_space;
Kmods SIG d83023
+	/* Check too big request */
Kmods SIG d83023
+	if (len > zeroes + zlen || zlen <= NTFS_MIN_MFT_ZONE)
Kmods SIG d83023
+		goto out;
Kmods SIG d83023
 
Kmods SIG d83023
 	/* How many clusters to cat from zone. */
Kmods SIG d83023
 	zlcn = wnd_zone_bit(wnd);
Kmods SIG d83023
@@ -439,31 +429,24 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
Kmods SIG d83023
 	wnd_zone_set(wnd, zlcn, new_zlen);
Kmods SIG d83023
 
Kmods SIG d83023
 	/* Allocate continues clusters. */
Kmods SIG d83023
-	*new_len =
Kmods SIG d83023
-		wnd_find(wnd, len, 0,
Kmods SIG d83023
-			 BITMAP_FIND_MARK_AS_USED | BITMAP_FIND_FULL, &a_lcn);
Kmods SIG d83023
-	if (*new_len) {
Kmods SIG d83023
-		*new_lcn = a_lcn;
Kmods SIG d83023
-		goto ok;
Kmods SIG d83023
-	}
Kmods SIG d83023
-
Kmods SIG d83023
-no_space:
Kmods SIG d83023
-	up_write(&wnd->rw_lock);
Kmods SIG d83023
-
Kmods SIG d83023
-	return -ENOSPC;
Kmods SIG d83023
-
Kmods SIG d83023
-ok:
Kmods SIG d83023
-	err = 0;
Kmods SIG d83023
+	alen = wnd_find(wnd, len, 0,
Kmods SIG d83023
+			BITMAP_FIND_MARK_AS_USED | BITMAP_FIND_FULL, &alcn);
Kmods SIG d83023
 
Kmods SIG d83023
-	ntfs_unmap_meta(sb, *new_lcn, *new_len);
Kmods SIG d83023
+out:
Kmods SIG d83023
+	if (alen) {
Kmods SIG d83023
+		err = 0;
Kmods SIG d83023
+		*new_len = alen;
Kmods SIG d83023
+		*new_lcn = alcn;
Kmods SIG d83023
 
Kmods SIG d83023
-	if (opt & ALLOCATE_MFT)
Kmods SIG d83023
-		goto out;
Kmods SIG d83023
+		ntfs_unmap_meta(sb, alcn, alen);
Kmods SIG d83023
 
Kmods SIG d83023
-	/* Set hint for next requests. */
Kmods SIG d83023
-	sbi->used.next_free_lcn = *new_lcn + *new_len;
Kmods SIG d83023
+		/* Set hint for next requests. */
Kmods SIG d83023
+		if (!(opt & ALLOCATE_MFT))
Kmods SIG d83023
+			sbi->used.next_free_lcn = alcn + alen;
Kmods SIG d83023
+	} else {
Kmods SIG d83023
+		err = -ENOSPC;
Kmods SIG d83023
+	}
Kmods SIG d83023
 
Kmods SIG d83023
-out:
Kmods SIG d83023
 	up_write(&wnd->rw_lock);
Kmods SIG d83023
 	return err;
Kmods SIG d83023
 }
Kmods SIG d83023
@@ -2226,7 +2209,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
Kmods SIG d83023
 	sii_e.sec_id = d_security->key.sec_id;
Kmods SIG d83023
 	memcpy(&sii_e.sec_hdr, d_security, SIZEOF_SECURITY_HDR);
Kmods SIG d83023
 
Kmods SIG d83023
-	err = indx_insert_entry(indx_sii, ni, &sii_e.de, NULL, NULL);
Kmods SIG d83023
+	err = indx_insert_entry(indx_sii, ni, &sii_e.de, NULL, NULL, 0);
Kmods SIG d83023
 	if (err)
Kmods SIG d83023
 		goto out;
Kmods SIG d83023
 
Kmods SIG d83023
@@ -2247,7 +2230,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
Kmods SIG d83023
 
Kmods SIG d83023
 	fnd_clear(fnd_sdh);
Kmods SIG d83023
 	err = indx_insert_entry(indx_sdh, ni, &sdh_e.de, (void *)(size_t)1,
Kmods SIG d83023
-				fnd_sdh);
Kmods SIG d83023
+				fnd_sdh, 0);
Kmods SIG d83023
 	if (err)
Kmods SIG d83023
 		goto out;
Kmods SIG d83023
 
Kmods SIG d83023
@@ -2385,7 +2368,7 @@ int ntfs_insert_reparse(struct ntfs_sb_info *sbi, __le32 rtag,
Kmods SIG d83023
 
Kmods SIG d83023
 	mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_REPARSE);
Kmods SIG d83023
 
Kmods SIG d83023
-	err = indx_insert_entry(indx, ni, &re.de, NULL, NULL);
Kmods SIG d83023
+	err = indx_insert_entry(indx, ni, &re.de, NULL, NULL, 0);
Kmods SIG d83023
 
Kmods SIG d83023
 	mark_inode_dirty(&ni->vfs_inode);
Kmods SIG d83023
 	ni_unlock(ni);
Kmods SIG d83023
diff --git a/src/index.c b/src/index.c
Kmods SIG d83023
index 70ef59455b72c927b40bbb76c5420b8dfc72e24a..1224b8e42b3e3d07938310739843f0ab7195f326 100644
Kmods SIG d83023
--- a/src/index.c
Kmods SIG d83023
+++ b/src/index.c
Kmods SIG d83023
@@ -1427,7 +1427,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 	alloc->nres.valid_size = alloc->nres.data_size = cpu_to_le64(data_size);
Kmods SIG d83023
 
Kmods SIG d83023
 	err = ni_insert_resident(ni, bitmap_size(1), ATTR_BITMAP, in->name,
Kmods SIG d83023
-				 in->name_len, &bitmap, NULL);
Kmods SIG d83023
+				 in->name_len, &bitmap, NULL, NULL);
Kmods SIG d83023
 	if (err)
Kmods SIG d83023
 		goto out2;
Kmods SIG d83023
 
Kmods SIG d83023
@@ -1443,7 +1443,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 	return 0;
Kmods SIG d83023
 
Kmods SIG d83023
 out2:
Kmods SIG d83023
-	mi_remove_attr(&ni->mi, alloc);
Kmods SIG d83023
+	mi_remove_attr(NULL, &ni->mi, alloc);
Kmods SIG d83023
 
Kmods SIG d83023
 out1:
Kmods SIG d83023
 	run_deallocate(sbi, &run, false);
Kmods SIG d83023
@@ -1529,24 +1529,24 @@ static int indx_add_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 /*
Kmods SIG d83023
  * indx_insert_into_root - Attempt to insert an entry into the index root.
Kmods SIG d83023
  *
Kmods SIG d83023
+ * @undo - True if we undoing previous remove.
Kmods SIG d83023
  * If necessary, it will twiddle the index b-tree.
Kmods SIG d83023
  */
Kmods SIG d83023
 static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 				 const struct NTFS_DE *new_de,
Kmods SIG d83023
 				 struct NTFS_DE *root_de, const void *ctx,
Kmods SIG d83023
-				 struct ntfs_fnd *fnd)
Kmods SIG d83023
+				 struct ntfs_fnd *fnd, bool undo)
Kmods SIG d83023
 {
Kmods SIG d83023
 	int err = 0;
Kmods SIG d83023
 	struct NTFS_DE *e, *e0, *re;
Kmods SIG d83023
 	struct mft_inode *mi;
Kmods SIG d83023
 	struct ATTRIB *attr;
Kmods SIG d83023
-	struct MFT_REC *rec;
Kmods SIG d83023
 	struct INDEX_HDR *hdr;
Kmods SIG d83023
 	struct indx_node *n;
Kmods SIG d83023
 	CLST new_vbn;
Kmods SIG d83023
 	__le64 *sub_vbn, t_vbn;
Kmods SIG d83023
 	u16 new_de_size;
Kmods SIG d83023
-	u32 hdr_used, hdr_total, asize, used, to_move;
Kmods SIG d83023
+	u32 hdr_used, hdr_total, asize, to_move;
Kmods SIG d83023
 	u32 root_size, new_root_size;
Kmods SIG d83023
 	struct ntfs_sb_info *sbi;
Kmods SIG d83023
 	int ds_root;
Kmods SIG d83023
@@ -1559,12 +1559,11 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 
Kmods SIG d83023
 	/*
Kmods SIG d83023
 	 * Try easy case:
Kmods SIG d83023
-	 * hdr_insert_de will succeed if there's room the root for the new entry.
Kmods SIG d83023
+	 * hdr_insert_de will succeed if there's
Kmods SIG d83023
+	 * room the root for the new entry.
Kmods SIG d83023
 	 */
Kmods SIG d83023
 	hdr = &root->ihdr;
Kmods SIG d83023
 	sbi = ni->mi.sbi;
Kmods SIG d83023
-	rec = mi->mrec;
Kmods SIG d83023
-	used = le32_to_cpu(rec->used);
Kmods SIG d83023
 	new_de_size = le16_to_cpu(new_de->size);
Kmods SIG d83023
 	hdr_used = le32_to_cpu(hdr->used);
Kmods SIG d83023
 	hdr_total = le32_to_cpu(hdr->total);
Kmods SIG d83023
@@ -1573,9 +1572,9 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 
Kmods SIG d83023
 	ds_root = new_de_size + hdr_used - hdr_total;
Kmods SIG d83023
 
Kmods SIG d83023
-	if (used + ds_root < sbi->max_bytes_per_attr) {
Kmods SIG d83023
-		/* Make a room for new elements. */
Kmods SIG d83023
-		mi_resize_attr(mi, attr, ds_root);
Kmods SIG d83023
+	/* If 'undo' is set then reduce requirements. */
Kmods SIG d83023
+	if ((undo || asize + ds_root < sbi->max_bytes_per_attr) &&
Kmods SIG d83023
+	    mi_resize_attr(mi, attr, ds_root)) {
Kmods SIG d83023
 		hdr->total = cpu_to_le32(hdr_total + ds_root);
Kmods SIG d83023
 		e = hdr_insert_de(indx, hdr, new_de, root_de, ctx);
Kmods SIG d83023
 		WARN_ON(!e);
Kmods SIG d83023
@@ -1629,7 +1628,7 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 			sizeof(u64);
Kmods SIG d83023
 	ds_root = new_root_size - root_size;
Kmods SIG d83023
 
Kmods SIG d83023
-	if (ds_root > 0 && used + ds_root > sbi->max_bytes_per_attr) {
Kmods SIG d83023
+	if (ds_root > 0 && asize + ds_root > sbi->max_bytes_per_attr) {
Kmods SIG d83023
 		/* Make root external. */
Kmods SIG d83023
 		err = -EOPNOTSUPP;
Kmods SIG d83023
 		goto out_free_re;
Kmods SIG d83023
@@ -1710,7 +1709,7 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 
Kmods SIG d83023
 		put_indx_node(n);
Kmods SIG d83023
 		fnd_clear(fnd);
Kmods SIG d83023
-		err = indx_insert_entry(indx, ni, new_de, ctx, fnd);
Kmods SIG d83023
+		err = indx_insert_entry(indx, ni, new_de, ctx, fnd, undo);
Kmods SIG d83023
 		goto out_free_root;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
@@ -1854,7 +1853,7 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 	 */
Kmods SIG d83023
 	if (!level) {
Kmods SIG d83023
 		/* Insert in root. */
Kmods SIG d83023
-		err = indx_insert_into_root(indx, ni, up_e, NULL, ctx, fnd);
Kmods SIG d83023
+		err = indx_insert_into_root(indx, ni, up_e, NULL, ctx, fnd, 0);
Kmods SIG d83023
 		if (err)
Kmods SIG d83023
 			goto out;
Kmods SIG d83023
 	} else {
Kmods SIG d83023
@@ -1876,10 +1875,12 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 
Kmods SIG d83023
 /*
Kmods SIG d83023
  * indx_insert_entry - Insert new entry into index.
Kmods SIG d83023
+ *
Kmods SIG d83023
+ * @undo - True if we undoing previous remove.
Kmods SIG d83023
  */
Kmods SIG d83023
 int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 		      const struct NTFS_DE *new_de, const void *ctx,
Kmods SIG d83023
-		      struct ntfs_fnd *fnd)
Kmods SIG d83023
+		      struct ntfs_fnd *fnd, bool undo)
Kmods SIG d83023
 {
Kmods SIG d83023
 	int err;
Kmods SIG d83023
 	int diff;
Kmods SIG d83023
@@ -1925,7 +1926,7 @@ int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 		 * new entry into it.
Kmods SIG d83023
 		 */
Kmods SIG d83023
 		err = indx_insert_into_root(indx, ni, new_de, fnd->root_de, ctx,
Kmods SIG d83023
-					    fnd);
Kmods SIG d83023
+					    fnd, undo);
Kmods SIG d83023
 		if (err)
Kmods SIG d83023
 			goto out;
Kmods SIG d83023
 	} else {
Kmods SIG d83023
@@ -2302,7 +2303,7 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 							      fnd->level - 1,
Kmods SIG d83023
 							      fnd)
Kmods SIG d83023
 				    : indx_insert_into_root(indx, ni, re, e,
Kmods SIG d83023
-							    ctx, fnd);
Kmods SIG d83023
+							    ctx, fnd, 0);
Kmods SIG d83023
 			kfree(re);
Kmods SIG d83023
 
Kmods SIG d83023
 			if (err)
Kmods SIG d83023
@@ -2507,7 +2508,7 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 		 * Re-insert the entry into the tree.
Kmods SIG d83023
 		 * Find the spot the tree where we want to insert the new entry.
Kmods SIG d83023
 		 */
Kmods SIG d83023
-		err = indx_insert_entry(indx, ni, me, ctx, fnd);
Kmods SIG d83023
+		err = indx_insert_entry(indx, ni, me, ctx, fnd, 0);
Kmods SIG d83023
 		kfree(me);
Kmods SIG d83023
 		if (err)
Kmods SIG d83023
 			goto out;
Kmods SIG d83023
@@ -2595,10 +2596,8 @@ int indx_update_dup(struct ntfs_inode *ni, struct ntfs_sb_info *sbi,
Kmods SIG d83023
 	struct ntfs_index *indx = &ni->dir;
Kmods SIG d83023
 
Kmods SIG d83023
 	fnd = fnd_get();
Kmods SIG d83023
-	if (!fnd) {
Kmods SIG d83023
-		err = -ENOMEM;
Kmods SIG d83023
-		goto out1;
Kmods SIG d83023
-	}
Kmods SIG d83023
+	if (!fnd)
Kmods SIG d83023
+		return -ENOMEM;
Kmods SIG d83023
 
Kmods SIG d83023
 	root = indx_get_root(indx, ni, NULL, &mi);
Kmods SIG d83023
 	if (!root) {
Kmods SIG d83023
@@ -2645,7 +2644,5 @@ int indx_update_dup(struct ntfs_inode *ni, struct ntfs_sb_info *sbi,
Kmods SIG d83023
 
Kmods SIG d83023
 out:
Kmods SIG d83023
 	fnd_put(fnd);
Kmods SIG d83023
-
Kmods SIG d83023
-out1:
Kmods SIG d83023
 	return err;
Kmods SIG d83023
 }
Kmods SIG d83023
diff --git a/src/inode.c b/src/inode.c
Kmods SIG d83023
index b86ec7dd731cea9fd0b41abb40fe4d81ca965c13..8f72066b3229a3f87b7b0b0e770bce20a4b06edd 100644
Kmods SIG d83023
--- a/src/inode.c
Kmods SIG d83023
+++ b/src/inode.c
Kmods SIG d83023
@@ -399,6 +399,12 @@ static struct inode *ntfs_read_mft(struct inode *inode,
Kmods SIG d83023
 		goto out;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
+	if (names != le16_to_cpu(rec->hard_links)) {
Kmods SIG d83023
+		/* Correct minor error on the fly. Do not mark inode as dirty. */
Kmods SIG d83023
+		rec->hard_links = cpu_to_le16(names);
Kmods SIG d83023
+		ni->mi.dirty = true;
Kmods SIG d83023
+	}
Kmods SIG d83023
+
Kmods SIG d83023
 	set_nlink(inode, names);
Kmods SIG d83023
 
Kmods SIG d83023
 	if (S_ISDIR(mode)) {
Kmods SIG d83023
@@ -1279,6 +1285,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG d83023
 	}
Kmods SIG d83023
 	inode = &ni->vfs_inode;
Kmods SIG d83023
 	inode_init_owner(mnt_userns, inode, dir, mode);
Kmods SIG d83023
+	mode = inode->i_mode;
Kmods SIG d83023
 
Kmods SIG d83023
 	inode->i_atime = inode->i_mtime = inode->i_ctime = ni->i_crtime =
Kmods SIG d83023
 		current_time(inode);
Kmods SIG d83023
@@ -1371,6 +1378,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG d83023
 		attr = Add2Ptr(attr, asize);
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
+	attr->id = cpu_to_le16(aid++);
Kmods SIG d83023
 	if (fa & FILE_ATTRIBUTE_DIRECTORY) {
Kmods SIG d83023
 		/*
Kmods SIG d83023
 		 * Regular directory or symlink to directory.
Kmods SIG d83023
@@ -1381,7 +1389,6 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG d83023
 
Kmods SIG d83023
 		attr->type = ATTR_ROOT;
Kmods SIG d83023
 		attr->size = cpu_to_le32(asize);
Kmods SIG d83023
-		attr->id = cpu_to_le16(aid++);
Kmods SIG d83023
 
Kmods SIG d83023
 		attr->name_len = ARRAY_SIZE(I30_NAME);
Kmods SIG d83023
 		attr->name_off = SIZEOF_RESIDENT_LE;
Kmods SIG d83023
@@ -1412,52 +1419,46 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG d83023
 		/* Insert empty ATTR_DATA */
Kmods SIG d83023
 		attr->type = ATTR_DATA;
Kmods SIG d83023
 		attr->size = cpu_to_le32(SIZEOF_RESIDENT);
Kmods SIG d83023
-		attr->id = cpu_to_le16(aid++);
Kmods SIG d83023
 		attr->name_off = SIZEOF_RESIDENT_LE;
Kmods SIG d83023
 		attr->res.data_off = SIZEOF_RESIDENT_LE;
Kmods SIG d83023
-	} else {
Kmods SIG d83023
+	} else if (S_ISREG(mode)) {
Kmods SIG d83023
 		/*
Kmods SIG d83023
-		 * Regular file or node.
Kmods SIG d83023
+		 * Regular file. Create empty non resident data attribute.
Kmods SIG d83023
 		 */
Kmods SIG d83023
 		attr->type = ATTR_DATA;
Kmods SIG d83023
-		attr->id = cpu_to_le16(aid++);
Kmods SIG d83023
-
Kmods SIG d83023
-		if (S_ISREG(mode)) {
Kmods SIG d83023
-			/* Create empty non resident data attribute. */
Kmods SIG d83023
-			attr->non_res = 1;
Kmods SIG d83023
-			attr->nres.evcn = cpu_to_le64(-1ll);
Kmods SIG d83023
-			if (fa & FILE_ATTRIBUTE_SPARSE_FILE) {
Kmods SIG d83023
-				attr->size =
Kmods SIG d83023
-					cpu_to_le32(SIZEOF_NONRESIDENT_EX + 8);
Kmods SIG d83023
-				attr->name_off = SIZEOF_NONRESIDENT_EX_LE;
Kmods SIG d83023
-				attr->flags = ATTR_FLAG_SPARSED;
Kmods SIG d83023
-				asize = SIZEOF_NONRESIDENT_EX + 8;
Kmods SIG d83023
-			} else if (fa & FILE_ATTRIBUTE_COMPRESSED) {
Kmods SIG d83023
-				attr->size =
Kmods SIG d83023
-					cpu_to_le32(SIZEOF_NONRESIDENT_EX + 8);
Kmods SIG d83023
-				attr->name_off = SIZEOF_NONRESIDENT_EX_LE;
Kmods SIG d83023
-				attr->flags = ATTR_FLAG_COMPRESSED;
Kmods SIG d83023
-				attr->nres.c_unit = COMPRESSION_UNIT;
Kmods SIG d83023
-				asize = SIZEOF_NONRESIDENT_EX + 8;
Kmods SIG d83023
-			} else {
Kmods SIG d83023
-				attr->size =
Kmods SIG d83023
-					cpu_to_le32(SIZEOF_NONRESIDENT + 8);
Kmods SIG d83023
-				attr->name_off = SIZEOF_NONRESIDENT_LE;
Kmods SIG d83023
-				asize = SIZEOF_NONRESIDENT + 8;
Kmods SIG d83023
-			}
Kmods SIG d83023
-			attr->nres.run_off = attr->name_off;
Kmods SIG d83023
+		attr->non_res = 1;
Kmods SIG d83023
+		attr->nres.evcn = cpu_to_le64(-1ll);
Kmods SIG d83023
+		if (fa & FILE_ATTRIBUTE_SPARSE_FILE) {
Kmods SIG d83023
+			attr->size = cpu_to_le32(SIZEOF_NONRESIDENT_EX + 8);
Kmods SIG d83023
+			attr->name_off = SIZEOF_NONRESIDENT_EX_LE;
Kmods SIG d83023
+			attr->flags = ATTR_FLAG_SPARSED;
Kmods SIG d83023
+			asize = SIZEOF_NONRESIDENT_EX + 8;
Kmods SIG d83023
+		} else if (fa & FILE_ATTRIBUTE_COMPRESSED) {
Kmods SIG d83023
+			attr->size = cpu_to_le32(SIZEOF_NONRESIDENT_EX + 8);
Kmods SIG d83023
+			attr->name_off = SIZEOF_NONRESIDENT_EX_LE;
Kmods SIG d83023
+			attr->flags = ATTR_FLAG_COMPRESSED;
Kmods SIG d83023
+			attr->nres.c_unit = COMPRESSION_UNIT;
Kmods SIG d83023
+			asize = SIZEOF_NONRESIDENT_EX + 8;
Kmods SIG d83023
 		} else {
Kmods SIG d83023
-			/* Create empty resident data attribute. */
Kmods SIG d83023
-			attr->size = cpu_to_le32(SIZEOF_RESIDENT);
Kmods SIG d83023
-			attr->name_off = SIZEOF_RESIDENT_LE;
Kmods SIG d83023
-			if (fa & FILE_ATTRIBUTE_SPARSE_FILE)
Kmods SIG d83023
-				attr->flags = ATTR_FLAG_SPARSED;
Kmods SIG d83023
-			else if (fa & FILE_ATTRIBUTE_COMPRESSED)
Kmods SIG d83023
-				attr->flags = ATTR_FLAG_COMPRESSED;
Kmods SIG d83023
-			attr->res.data_off = SIZEOF_RESIDENT_LE;
Kmods SIG d83023
-			asize = SIZEOF_RESIDENT;
Kmods SIG d83023
-			ni->ni_flags |= NI_FLAG_RESIDENT;
Kmods SIG d83023
+			attr->size = cpu_to_le32(SIZEOF_NONRESIDENT + 8);
Kmods SIG d83023
+			attr->name_off = SIZEOF_NONRESIDENT_LE;
Kmods SIG d83023
+			asize = SIZEOF_NONRESIDENT + 8;
Kmods SIG d83023
 		}
Kmods SIG d83023
+		attr->nres.run_off = attr->name_off;
Kmods SIG d83023
+	} else {
Kmods SIG d83023
+		/*
Kmods SIG d83023
+		 * Node. Create empty resident data attribute.
Kmods SIG d83023
+		 */
Kmods SIG d83023
+		attr->type = ATTR_DATA;
Kmods SIG d83023
+		attr->size = cpu_to_le32(SIZEOF_RESIDENT);
Kmods SIG d83023
+		attr->name_off = SIZEOF_RESIDENT_LE;
Kmods SIG d83023
+		if (fa & FILE_ATTRIBUTE_SPARSE_FILE)
Kmods SIG d83023
+			attr->flags = ATTR_FLAG_SPARSED;
Kmods SIG d83023
+		else if (fa & FILE_ATTRIBUTE_COMPRESSED)
Kmods SIG d83023
+			attr->flags = ATTR_FLAG_COMPRESSED;
Kmods SIG d83023
+		attr->res.data_off = SIZEOF_RESIDENT_LE;
Kmods SIG d83023
+		asize = SIZEOF_RESIDENT;
Kmods SIG d83023
+		ni->ni_flags |= NI_FLAG_RESIDENT;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
 	if (S_ISDIR(mode)) {
Kmods SIG d83023
@@ -1485,7 +1486,8 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG d83023
 		asize = ALIGN(SIZEOF_RESIDENT + nsize, 8);
Kmods SIG d83023
 		t16 = PtrOffset(rec, attr);
Kmods SIG d83023
 
Kmods SIG d83023
-		if (asize + t16 + 8 > sbi->record_size) {
Kmods SIG d83023
+		/* 0x78 - the size of EA + EAINFO to store WSL */
Kmods SIG d83023
+		if (asize + t16 + 0x78 + 8 > sbi->record_size) {
Kmods SIG d83023
 			CLST alen;
Kmods SIG d83023
 			CLST clst = bytes_to_cluster(sbi, nsize);
Kmods SIG d83023
 
Kmods SIG d83023
@@ -1545,20 +1547,15 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG d83023
 	rec->next_attr_id = cpu_to_le16(aid);
Kmods SIG d83023
 
Kmods SIG d83023
 	/* Step 2: Add new name in index. */
Kmods SIG d83023
-	err = indx_insert_entry(&dir_ni->dir, dir_ni, new_de, sbi, fnd);
Kmods SIG d83023
+	err = indx_insert_entry(&dir_ni->dir, dir_ni, new_de, sbi, fnd, 0);
Kmods SIG d83023
 	if (err)
Kmods SIG d83023
 		goto out6;
Kmods SIG d83023
 
Kmods SIG d83023
-	/* Update current directory record. */
Kmods SIG d83023
-	mark_inode_dirty(dir);
Kmods SIG d83023
-
Kmods SIG d83023
 	inode->i_generation = le16_to_cpu(rec->seq);
Kmods SIG d83023
 
Kmods SIG d83023
 	dir->i_mtime = dir->i_ctime = inode->i_atime;
Kmods SIG d83023
 
Kmods SIG d83023
 	if (S_ISDIR(mode)) {
Kmods SIG d83023
-		if (dir->i_mode & S_ISGID)
Kmods SIG d83023
-			mode |= S_ISGID;
Kmods SIG d83023
 		inode->i_op = &ntfs_dir_inode_operations;
Kmods SIG d83023
 		inode->i_fop = &ntfs_dir_operations;
Kmods SIG d83023
 	} else if (S_ISLNK(mode)) {
Kmods SIG d83023
@@ -1601,8 +1598,8 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG d83023
 	d_instantiate(dentry, inode);
Kmods SIG d83023
 
Kmods SIG d83023
 	ntfs_save_wsl_perm(inode);
Kmods SIG d83023
-	mark_inode_dirty(inode);
Kmods SIG d83023
 	mark_inode_dirty(dir);
Kmods SIG d83023
+	mark_inode_dirty(inode);
Kmods SIG d83023
 
Kmods SIG d83023
 	/* Normal exit. */
Kmods SIG d83023
 	goto out2;
Kmods SIG d83023
@@ -1646,61 +1643,36 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
Kmods SIG d83023
 int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
Kmods SIG d83023
 {
Kmods SIG d83023
 	int err;
Kmods SIG d83023
-	struct inode *dir = d_inode(dentry->d_parent);
Kmods SIG d83023
-	struct ntfs_inode *dir_ni = ntfs_i(dir);
Kmods SIG d83023
 	struct ntfs_inode *ni = ntfs_i(inode);
Kmods SIG d83023
-	struct super_block *sb = inode->i_sb;
Kmods SIG d83023
-	struct ntfs_sb_info *sbi = sb->s_fs_info;
Kmods SIG d83023
-	const struct qstr *name = &dentry->d_name;
Kmods SIG d83023
-	struct NTFS_DE *new_de = NULL;
Kmods SIG d83023
-	struct ATTR_FILE_NAME *fname;
Kmods SIG d83023
-	struct ATTRIB *attr;
Kmods SIG d83023
-	u16 key_size;
Kmods SIG d83023
-	struct INDEX_ROOT *dir_root;
Kmods SIG d83023
-
Kmods SIG d83023
-	dir_root = indx_get_root(&dir_ni->dir, dir_ni, NULL, NULL);
Kmods SIG d83023
-	if (!dir_root)
Kmods SIG d83023
-		return -EINVAL;
Kmods SIG d83023
+	struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
Kmods SIG d83023
+	struct NTFS_DE *de;
Kmods SIG d83023
+	struct ATTR_FILE_NAME *de_name;
Kmods SIG d83023
 
Kmods SIG d83023
 	/* Allocate PATH_MAX bytes. */
Kmods SIG d83023
-	new_de = __getname();
Kmods SIG d83023
-	if (!new_de)
Kmods SIG d83023
+	de = __getname();
Kmods SIG d83023
+	if (!de)
Kmods SIG d83023
 		return -ENOMEM;
Kmods SIG d83023
 
Kmods SIG d83023
-	/* Mark rw ntfs as dirty.  It will be cleared at umount. */
Kmods SIG d83023
-	ntfs_set_state(ni->mi.sbi, NTFS_DIRTY_DIRTY);
Kmods SIG d83023
-
Kmods SIG d83023
-	/* Insert file name. */
Kmods SIG d83023
-	err = fill_name_de(sbi, new_de, name, NULL);
Kmods SIG d83023
-	if (err)
Kmods SIG d83023
-		goto out;
Kmods SIG d83023
-
Kmods SIG d83023
-	key_size = le16_to_cpu(new_de->key_size);
Kmods SIG d83023
-	err = ni_insert_resident(ni, key_size, ATTR_NAME, NULL, 0, &attr, NULL);
Kmods SIG d83023
-	if (err)
Kmods SIG d83023
-		goto out;
Kmods SIG d83023
-
Kmods SIG d83023
-	mi_get_ref(&ni->mi, &new_de->ref);
Kmods SIG d83023
-
Kmods SIG d83023
-	fname = (struct ATTR_FILE_NAME *)(new_de + 1);
Kmods SIG d83023
-	mi_get_ref(&dir_ni->mi, &fname->home);
Kmods SIG d83023
-	fname->dup.cr_time = fname->dup.m_time = fname->dup.c_time =
Kmods SIG d83023
-		fname->dup.a_time = kernel2nt(&inode->i_ctime);
Kmods SIG d83023
-	fname->dup.alloc_size = fname->dup.data_size = 0;
Kmods SIG d83023
-	fname->dup.fa = ni->std_fa;
Kmods SIG d83023
-	fname->dup.ea_size = fname->dup.reparse = 0;
Kmods SIG d83023
-
Kmods SIG d83023
-	memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), fname, key_size);
Kmods SIG d83023
+	/* Mark rw ntfs as dirty. It will be cleared at umount. */
Kmods SIG d83023
+	ntfs_set_state(sbi, NTFS_DIRTY_DIRTY);
Kmods SIG d83023
 
Kmods SIG d83023
-	err = indx_insert_entry(&dir_ni->dir, dir_ni, new_de, sbi, NULL);
Kmods SIG d83023
+	/* Construct 'de'. */
Kmods SIG d83023
+	err = fill_name_de(sbi, de, &dentry->d_name, NULL);
Kmods SIG d83023
 	if (err)
Kmods SIG d83023
 		goto out;
Kmods SIG d83023
 
Kmods SIG d83023
-	le16_add_cpu(&ni->mi.mrec->hard_links, 1);
Kmods SIG d83023
-	ni->mi.dirty = true;
Kmods SIG d83023
+	de_name = (struct ATTR_FILE_NAME *)(de + 1);
Kmods SIG d83023
+	/* Fill duplicate info. */
Kmods SIG d83023
+	de_name->dup.cr_time = de_name->dup.m_time = de_name->dup.c_time =
Kmods SIG d83023
+		de_name->dup.a_time = kernel2nt(&inode->i_ctime);
Kmods SIG d83023
+	de_name->dup.alloc_size = de_name->dup.data_size =
Kmods SIG d83023
+		cpu_to_le64(inode->i_size);
Kmods SIG d83023
+	de_name->dup.fa = ni->std_fa;
Kmods SIG d83023
+	de_name->dup.ea_size = de_name->dup.reparse = 0;
Kmods SIG d83023
 
Kmods SIG d83023
+	err = ni_add_name(ntfs_i(d_inode(dentry->d_parent)), ni, de);
Kmods SIG d83023
 out:
Kmods SIG d83023
-	__putname(new_de);
Kmods SIG d83023
+	__putname(de);
Kmods SIG d83023
 	return err;
Kmods SIG d83023
 }
Kmods SIG d83023
 
Kmods SIG d83023
@@ -1713,113 +1685,56 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
Kmods SIG d83023
 int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry)
Kmods SIG d83023
 {
Kmods SIG d83023
 	int err;
Kmods SIG d83023
-	struct super_block *sb = dir->i_sb;
Kmods SIG d83023
-	struct ntfs_sb_info *sbi = sb->s_fs_info;
Kmods SIG d83023
+	struct ntfs_sb_info *sbi = dir->i_sb->s_fs_info;
Kmods SIG d83023
 	struct inode *inode = d_inode(dentry);
Kmods SIG d83023
 	struct ntfs_inode *ni = ntfs_i(inode);
Kmods SIG d83023
-	const struct qstr *name = &dentry->d_name;
Kmods SIG d83023
 	struct ntfs_inode *dir_ni = ntfs_i(dir);
Kmods SIG d83023
-	struct ntfs_index *indx = &dir_ni->dir;
Kmods SIG d83023
-	struct cpu_str *uni = NULL;
Kmods SIG d83023
-	struct ATTR_FILE_NAME *fname;
Kmods SIG d83023
-	u8 name_type;
Kmods SIG d83023
-	struct ATTR_LIST_ENTRY *le;
Kmods SIG d83023
-	struct MFT_REF ref;
Kmods SIG d83023
-	bool is_dir = S_ISDIR(inode->i_mode);
Kmods SIG d83023
-	struct INDEX_ROOT *dir_root;
Kmods SIG d83023
+	struct NTFS_DE *de, *de2 = NULL;
Kmods SIG d83023
+	int undo_remove;
Kmods SIG d83023
 
Kmods SIG d83023
-	dir_root = indx_get_root(indx, dir_ni, NULL, NULL);
Kmods SIG d83023
-	if (!dir_root)
Kmods SIG d83023
+	if (ntfs_is_meta_file(sbi, ni->mi.rno))
Kmods SIG d83023
 		return -EINVAL;
Kmods SIG d83023
 
Kmods SIG d83023
+	/* Allocate PATH_MAX bytes. */
Kmods SIG d83023
+	de = __getname();
Kmods SIG d83023
+	if (!de)
Kmods SIG d83023
+		return -ENOMEM;
Kmods SIG d83023
+
Kmods SIG d83023
 	ni_lock(ni);
Kmods SIG d83023
 
Kmods SIG d83023
-	if (is_dir && !dir_is_empty(inode)) {
Kmods SIG d83023
+	if (S_ISDIR(inode->i_mode) && !dir_is_empty(inode)) {
Kmods SIG d83023
 		err = -ENOTEMPTY;
Kmods SIG d83023
-		goto out1;
Kmods SIG d83023
-	}
Kmods SIG d83023
-
Kmods SIG d83023
-	if (ntfs_is_meta_file(sbi, inode->i_ino)) {
Kmods SIG d83023
-		err = -EINVAL;
Kmods SIG d83023
-		goto out1;
Kmods SIG d83023
-	}
Kmods SIG d83023
-
Kmods SIG d83023
-	/* Allocate PATH_MAX bytes. */
Kmods SIG d83023
-	uni = __getname();
Kmods SIG d83023
-	if (!uni) {
Kmods SIG d83023
-		err = -ENOMEM;
Kmods SIG d83023
-		goto out1;
Kmods SIG d83023
+		goto out;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
-	/* Convert input string to unicode. */
Kmods SIG d83023
-	err = ntfs_nls_to_utf16(sbi, name->name, name->len, uni, NTFS_NAME_LEN,
Kmods SIG d83023
-				UTF16_HOST_ENDIAN);
Kmods SIG d83023
+	err = fill_name_de(sbi, de, &dentry->d_name, NULL);
Kmods SIG d83023
 	if (err < 0)
Kmods SIG d83023
-		goto out2;
Kmods SIG d83023
-
Kmods SIG d83023
-	/* Mark rw ntfs as dirty.  It will be cleared at umount. */
Kmods SIG d83023
-	ntfs_set_state(sbi, NTFS_DIRTY_DIRTY);
Kmods SIG d83023
-
Kmods SIG d83023
-	/* Find name in record. */
Kmods SIG d83023
-	mi_get_ref(&dir_ni->mi, &ref;;
Kmods SIG d83023
-
Kmods SIG d83023
-	le = NULL;
Kmods SIG d83023
-	fname = ni_fname_name(ni, uni, &ref, &le);
Kmods SIG d83023
-	if (!fname) {
Kmods SIG d83023
-		err = -ENOENT;
Kmods SIG d83023
-		goto out3;
Kmods SIG d83023
-	}
Kmods SIG d83023
-
Kmods SIG d83023
-	name_type = paired_name(fname->type);
Kmods SIG d83023
-
Kmods SIG d83023
-	err = indx_delete_entry(indx, dir_ni, fname, fname_full_size(fname),
Kmods SIG d83023
-				sbi);
Kmods SIG d83023
-	if (err)
Kmods SIG d83023
-		goto out3;
Kmods SIG d83023
-
Kmods SIG d83023
-	/* Then remove name from MFT. */
Kmods SIG d83023
-	ni_remove_attr_le(ni, attr_from_name(fname), le);
Kmods SIG d83023
-
Kmods SIG d83023
-	le16_add_cpu(&ni->mi.mrec->hard_links, -1);
Kmods SIG d83023
-	ni->mi.dirty = true;
Kmods SIG d83023
-
Kmods SIG d83023
-	if (name_type != FILE_NAME_POSIX) {
Kmods SIG d83023
-		/* Now we should delete name by type. */
Kmods SIG d83023
-		fname = ni_fname_type(ni, name_type, &le);
Kmods SIG d83023
-		if (fname) {
Kmods SIG d83023
-			err = indx_delete_entry(indx, dir_ni, fname,
Kmods SIG d83023
-						fname_full_size(fname), sbi);
Kmods SIG d83023
-			if (err)
Kmods SIG d83023
-				goto out3;
Kmods SIG d83023
+		goto out;
Kmods SIG d83023
 
Kmods SIG d83023
-			ni_remove_attr_le(ni, attr_from_name(fname), le);
Kmods SIG d83023
+	undo_remove = 0;
Kmods SIG d83023
+	err = ni_remove_name(dir_ni, ni, de, &de2, &undo_remove);
Kmods SIG d83023
 
Kmods SIG d83023
-			le16_add_cpu(&ni->mi.mrec->hard_links, -1);
Kmods SIG d83023
-		}
Kmods SIG d83023
-	}
Kmods SIG d83023
-out3:
Kmods SIG d83023
-	switch (err) {
Kmods SIG d83023
-	case 0:
Kmods SIG d83023
+	if (!err) {
Kmods SIG d83023
 		drop_nlink(inode);
Kmods SIG d83023
-		break;
Kmods SIG d83023
-	case -ENOTEMPTY:
Kmods SIG d83023
-	case -ENOSPC:
Kmods SIG d83023
-	case -EROFS:
Kmods SIG d83023
-		break;
Kmods SIG d83023
-	default:
Kmods SIG d83023
+		dir->i_mtime = dir->i_ctime = current_time(dir);
Kmods SIG d83023
+		mark_inode_dirty(dir);
Kmods SIG d83023
+		inode->i_ctime = dir->i_ctime;
Kmods SIG d83023
+		if (inode->i_nlink)
Kmods SIG d83023
+			mark_inode_dirty(inode);
Kmods SIG d83023
+	} else if (!ni_remove_name_undo(dir_ni, ni, de, de2, undo_remove)) {
Kmods SIG d83023
 		make_bad_inode(inode);
Kmods SIG d83023
+		ntfs_inode_err(inode, "failed to undo unlink");
Kmods SIG d83023
+		ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
Kmods SIG d83023
+	} else {
Kmods SIG d83023
+		if (ni_is_dirty(dir))
Kmods SIG d83023
+			mark_inode_dirty(dir);
Kmods SIG d83023
+		if (ni_is_dirty(inode))
Kmods SIG d83023
+			mark_inode_dirty(inode);
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
-	dir->i_mtime = dir->i_ctime = current_time(dir);
Kmods SIG d83023
-	mark_inode_dirty(dir);
Kmods SIG d83023
-	inode->i_ctime = dir->i_ctime;
Kmods SIG d83023
-	if (inode->i_nlink)
Kmods SIG d83023
-		mark_inode_dirty(inode);
Kmods SIG d83023
-
Kmods SIG d83023
-out2:
Kmods SIG d83023
-	__putname(uni);
Kmods SIG d83023
-out1:
Kmods SIG d83023
+out:
Kmods SIG d83023
 	ni_unlock(ni);
Kmods SIG d83023
+	__putname(de);
Kmods SIG d83023
 	return err;
Kmods SIG d83023
 }
Kmods SIG d83023
 
Kmods SIG d83023
diff --git a/src/namei.c b/src/namei.c
Kmods SIG d83023
index f79a399bd015056f320714c91b935afac16eb488..e58415d0713280297df1b7bac30eb17642431fa0 100644
Kmods SIG d83023
--- a/src/namei.c
Kmods SIG d83023
+++ b/src/namei.c
Kmods SIG d83023
@@ -152,12 +152,14 @@ static int ntfs_link(struct dentry *ode, struct inode *dir, struct dentry *de)
Kmods SIG d83023
 	if (inode != dir)
Kmods SIG d83023
 		ni_lock(ni);
Kmods SIG d83023
 
Kmods SIG d83023
-	dir->i_ctime = dir->i_mtime = inode->i_ctime = current_time(inode);
Kmods SIG d83023
 	inc_nlink(inode);
Kmods SIG d83023
 	ihold(inode);
Kmods SIG d83023
 
Kmods SIG d83023
 	err = ntfs_link_inode(inode, de);
Kmods SIG d83023
+
Kmods SIG d83023
 	if (!err) {
Kmods SIG d83023
+		dir->i_ctime = dir->i_mtime = inode->i_ctime =
Kmods SIG d83023
+			current_time(dir);
Kmods SIG d83023
 		mark_inode_dirty(inode);
Kmods SIG d83023
 		mark_inode_dirty(dir);
Kmods SIG d83023
 		d_instantiate(de, inode);
Kmods SIG d83023
@@ -249,25 +251,26 @@ static int ntfs_rmdir(struct inode *dir, struct dentry *dentry)
Kmods SIG d83023
 /*
Kmods SIG d83023
  * ntfs_rename - inode_operations::rename
Kmods SIG d83023
  */
Kmods SIG d83023
-static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
Kmods SIG d83023
-		       struct dentry *old_dentry, struct inode *new_dir,
Kmods SIG d83023
+static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *dir,
Kmods SIG d83023
+		       struct dentry *dentry, struct inode *new_dir,
Kmods SIG d83023
 		       struct dentry *new_dentry, u32 flags)
Kmods SIG d83023
 {
Kmods SIG d83023
 	int err;
Kmods SIG d83023
-	struct super_block *sb = old_dir->i_sb;
Kmods SIG d83023
+	struct super_block *sb = dir->i_sb;
Kmods SIG d83023
 	struct ntfs_sb_info *sbi = sb->s_fs_info;
Kmods SIG d83023
-	struct ntfs_inode *old_dir_ni = ntfs_i(old_dir);
Kmods SIG d83023
+	struct ntfs_inode *dir_ni = ntfs_i(dir);
Kmods SIG d83023
 	struct ntfs_inode *new_dir_ni = ntfs_i(new_dir);
Kmods SIG d83023
-	struct ntfs_inode *old_ni;
Kmods SIG d83023
-	struct ATTR_FILE_NAME *old_name, *new_name, *fname;
Kmods SIG d83023
-	u8 name_type;
Kmods SIG d83023
-	bool is_same;
Kmods SIG d83023
-	struct inode *old_inode, *new_inode;
Kmods SIG d83023
-	struct NTFS_DE *old_de, *new_de;
Kmods SIG d83023
-	struct ATTRIB *attr;
Kmods SIG d83023
-	struct ATTR_LIST_ENTRY *le;
Kmods SIG d83023
-	u16 new_de_key_size;
Kmods SIG d83023
-
Kmods SIG d83023
+	struct inode *inode = d_inode(dentry);
Kmods SIG d83023
+	struct ntfs_inode *ni = ntfs_i(inode);
Kmods SIG d83023
+	struct inode *new_inode = d_inode(new_dentry);
Kmods SIG d83023
+	struct NTFS_DE *de, *new_de;
Kmods SIG d83023
+	bool is_same, is_bad;
Kmods SIG d83023
+	/*
Kmods SIG d83023
+	 * de		- memory of PATH_MAX bytes:
Kmods SIG d83023
+	 * [0-1024)	- original name (dentry->d_name)
Kmods SIG d83023
+	 * [1024-2048)	- paired to original name, usually DOS variant of dentry->d_name
Kmods SIG d83023
+	 * [2048-3072)	- new name (new_dentry->d_name)
Kmods SIG d83023
+	 */
Kmods SIG d83023
 	static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + SIZEOF_RESIDENT < 1024);
Kmods SIG d83023
 	static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + sizeof(struct NTFS_DE) <
Kmods SIG d83023
 		      1024);
Kmods SIG d83023
@@ -276,24 +279,18 @@ static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
Kmods SIG d83023
 	if (flags & ~RENAME_NOREPLACE)
Kmods SIG d83023
 		return -EINVAL;
Kmods SIG d83023
 
Kmods SIG d83023
-	old_inode = d_inode(old_dentry);
Kmods SIG d83023
-	new_inode = d_inode(new_dentry);
Kmods SIG d83023
-
Kmods SIG d83023
-	old_ni = ntfs_i(old_inode);
Kmods SIG d83023
+	is_same = dentry->d_name.len == new_dentry->d_name.len &&
Kmods SIG d83023
+		  !memcmp(dentry->d_name.name, new_dentry->d_name.name,
Kmods SIG d83023
+			  dentry->d_name.len);
Kmods SIG d83023
 
Kmods SIG d83023
-	is_same = old_dentry->d_name.len == new_dentry->d_name.len &&
Kmods SIG d83023
-		  !memcmp(old_dentry->d_name.name, new_dentry->d_name.name,
Kmods SIG d83023
-			  old_dentry->d_name.len);
Kmods SIG d83023
-
Kmods SIG d83023
-	if (is_same && old_dir == new_dir) {
Kmods SIG d83023
+	if (is_same && dir == new_dir) {
Kmods SIG d83023
 		/* Nothing to do. */
Kmods SIG d83023
-		err = 0;
Kmods SIG d83023
-		goto out;
Kmods SIG d83023
+		return 0;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
-	if (ntfs_is_meta_file(sbi, old_inode->i_ino)) {
Kmods SIG d83023
-		err = -EINVAL;
Kmods SIG d83023
-		goto out;
Kmods SIG d83023
+	if (ntfs_is_meta_file(sbi, inode->i_ino)) {
Kmods SIG d83023
+		/* Should we print an error? */
Kmods SIG d83023
+		return -EINVAL;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
 	if (new_inode) {
Kmods SIG d83023
@@ -304,168 +301,61 @@ static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
Kmods SIG d83023
 		ni_unlock(new_dir_ni);
Kmods SIG d83023
 		dput(new_dentry);
Kmods SIG d83023
 		if (err)
Kmods SIG d83023
-			goto out;
Kmods SIG d83023
+			return err;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
 	/* Allocate PATH_MAX bytes. */
Kmods SIG d83023
-	old_de = __getname();
Kmods SIG d83023
-	if (!old_de) {
Kmods SIG d83023
-		err = -ENOMEM;
Kmods SIG d83023
-		goto out;
Kmods SIG d83023
-	}
Kmods SIG d83023
+	de = __getname();
Kmods SIG d83023
+	if (!de)
Kmods SIG d83023
+		return -ENOMEM;
Kmods SIG d83023
 
Kmods SIG d83023
-	err = fill_name_de(sbi, old_de, &old_dentry->d_name, NULL);
Kmods SIG d83023
+	/* Translate dentry->d_name into unicode form. */
Kmods SIG d83023
+	err = fill_name_de(sbi, de, &dentry->d_name, NULL);
Kmods SIG d83023
 	if (err < 0)
Kmods SIG d83023
-		goto out1;
Kmods SIG d83023
-
Kmods SIG d83023
-	old_name = (struct ATTR_FILE_NAME *)(old_de + 1);
Kmods SIG d83023
+		goto out;
Kmods SIG d83023
 
Kmods SIG d83023
 	if (is_same) {
Kmods SIG d83023
-		new_de = old_de;
Kmods SIG d83023
+		/* Reuse 'de'. */
Kmods SIG d83023
+		new_de = de;
Kmods SIG d83023
 	} else {
Kmods SIG d83023
-		new_de = Add2Ptr(old_de, 1024);
Kmods SIG d83023
+		/* Translate new_dentry->d_name into unicode form. */
Kmods SIG d83023
+		new_de = Add2Ptr(de, 2048);
Kmods SIG d83023
 		err = fill_name_de(sbi, new_de, &new_dentry->d_name, NULL);
Kmods SIG d83023
 		if (err < 0)
Kmods SIG d83023
-			goto out1;
Kmods SIG d83023
-	}
Kmods SIG d83023
-
Kmods SIG d83023
-	ni_lock_dir(old_dir_ni);
Kmods SIG d83023
-	ni_lock(old_ni);
Kmods SIG d83023
-
Kmods SIG d83023
-	mi_get_ref(&old_dir_ni->mi, &old_name->home);
Kmods SIG d83023
-
Kmods SIG d83023
-	/* Get pointer to file_name in MFT. */
Kmods SIG d83023
-	fname = ni_fname_name(old_ni, (struct cpu_str *)&old_name->name_len,
Kmods SIG d83023
-			      &old_name->home, &le);
Kmods SIG d83023
-	if (!fname) {
Kmods SIG d83023
-		err = -EINVAL;
Kmods SIG d83023
-		goto out2;
Kmods SIG d83023
+			goto out;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
-	/* Copy fname info from record into new fname. */
Kmods SIG d83023
-	new_name = (struct ATTR_FILE_NAME *)(new_de + 1);
Kmods SIG d83023
-	memcpy(&new_name->dup, &fname->dup, sizeof(fname->dup));
Kmods SIG d83023
-
Kmods SIG d83023
-	name_type = paired_name(fname->type);
Kmods SIG d83023
-
Kmods SIG d83023
-	/* Remove first name from directory. */
Kmods SIG d83023
-	err = indx_delete_entry(&old_dir_ni->dir, old_dir_ni, old_de + 1,
Kmods SIG d83023
-				le16_to_cpu(old_de->key_size), sbi);
Kmods SIG d83023
-	if (err)
Kmods SIG d83023
-		goto out3;
Kmods SIG d83023
-
Kmods SIG d83023
-	/* Remove first name from MFT. */
Kmods SIG d83023
-	err = ni_remove_attr_le(old_ni, attr_from_name(fname), le);
Kmods SIG d83023
-	if (err)
Kmods SIG d83023
-		goto out4;
Kmods SIG d83023
-
Kmods SIG d83023
-	le16_add_cpu(&old_ni->mi.mrec->hard_links, -1);
Kmods SIG d83023
-	old_ni->mi.dirty = true;
Kmods SIG d83023
-
Kmods SIG d83023
-	if (name_type != FILE_NAME_POSIX) {
Kmods SIG d83023
-		/* Get paired name. */
Kmods SIG d83023
-		fname = ni_fname_type(old_ni, name_type, &le);
Kmods SIG d83023
-		if (fname) {
Kmods SIG d83023
-			/* Remove second name from directory. */
Kmods SIG d83023
-			err = indx_delete_entry(&old_dir_ni->dir, old_dir_ni,
Kmods SIG d83023
-						fname, fname_full_size(fname),
Kmods SIG d83023
-						sbi);
Kmods SIG d83023
-			if (err)
Kmods SIG d83023
-				goto out5;
Kmods SIG d83023
-
Kmods SIG d83023
-			/* Remove second name from MFT. */
Kmods SIG d83023
-			err = ni_remove_attr_le(old_ni, attr_from_name(fname),
Kmods SIG d83023
-						le);
Kmods SIG d83023
-			if (err)
Kmods SIG d83023
-				goto out6;
Kmods SIG d83023
-
Kmods SIG d83023
-			le16_add_cpu(&old_ni->mi.mrec->hard_links, -1);
Kmods SIG d83023
-			old_ni->mi.dirty = true;
Kmods SIG d83023
+	ni_lock_dir(dir_ni);
Kmods SIG d83023
+	ni_lock(ni);
Kmods SIG d83023
+
Kmods SIG d83023
+	is_bad = false;
Kmods SIG d83023
+	err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de, &is_bad);
Kmods SIG d83023
+	if (is_bad) {
Kmods SIG d83023
+		/* Restore after failed rename failed too. */
Kmods SIG d83023
+		make_bad_inode(inode);
Kmods SIG d83023
+		ntfs_inode_err(inode, "failed to undo rename");
Kmods SIG d83023
+		ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
Kmods SIG d83023
+	} else if (!err) {
Kmods SIG d83023
+		inode->i_ctime = dir->i_ctime = dir->i_mtime =
Kmods SIG d83023
+			current_time(dir);
Kmods SIG d83023
+		mark_inode_dirty(inode);
Kmods SIG d83023
+		mark_inode_dirty(dir);
Kmods SIG d83023
+		if (dir != new_dir) {
Kmods SIG d83023
+			new_dir->i_mtime = new_dir->i_ctime = dir->i_ctime;
Kmods SIG d83023
+			mark_inode_dirty(new_dir);
Kmods SIG d83023
 		}
Kmods SIG d83023
-	}
Kmods SIG d83023
-
Kmods SIG d83023
-	/* Add new name. */
Kmods SIG d83023
-	mi_get_ref(&old_ni->mi, &new_de->ref);
Kmods SIG d83023
-	mi_get_ref(&ntfs_i(new_dir)->mi, &new_name->home);
Kmods SIG d83023
-
Kmods SIG d83023
-	new_de_key_size = le16_to_cpu(new_de->key_size);
Kmods SIG d83023
-
Kmods SIG d83023
-	/* Insert new name in MFT. */
Kmods SIG d83023
-	err = ni_insert_resident(old_ni, new_de_key_size, ATTR_NAME, NULL, 0,
Kmods SIG d83023
-				 &attr, NULL);
Kmods SIG d83023
-	if (err)
Kmods SIG d83023
-		goto out7;
Kmods SIG d83023
-
Kmods SIG d83023
-	attr->res.flags = RESIDENT_FLAG_INDEXED;
Kmods SIG d83023
-
Kmods SIG d83023
-	memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), new_name, new_de_key_size);
Kmods SIG d83023
-
Kmods SIG d83023
-	le16_add_cpu(&old_ni->mi.mrec->hard_links, 1);
Kmods SIG d83023
-	old_ni->mi.dirty = true;
Kmods SIG d83023
-
Kmods SIG d83023
-	/* Insert new name in directory. */
Kmods SIG d83023
-	err = indx_insert_entry(&new_dir_ni->dir, new_dir_ni, new_de, sbi,
Kmods SIG d83023
-				NULL);
Kmods SIG d83023
-	if (err)
Kmods SIG d83023
-		goto out8;
Kmods SIG d83023
 
Kmods SIG d83023
-	if (IS_DIRSYNC(new_dir))
Kmods SIG d83023
-		err = ntfs_sync_inode(old_inode);
Kmods SIG d83023
-	else
Kmods SIG d83023
-		mark_inode_dirty(old_inode);
Kmods SIG d83023
+		if (IS_DIRSYNC(dir))
Kmods SIG d83023
+			ntfs_sync_inode(dir);
Kmods SIG d83023
 
Kmods SIG d83023
-	old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
Kmods SIG d83023
-	if (IS_DIRSYNC(old_dir))
Kmods SIG d83023
-		(void)ntfs_sync_inode(old_dir);
Kmods SIG d83023
-	else
Kmods SIG d83023
-		mark_inode_dirty(old_dir);
Kmods SIG d83023
-
Kmods SIG d83023
-	if (old_dir != new_dir) {
Kmods SIG d83023
-		new_dir->i_mtime = new_dir->i_ctime = old_dir->i_ctime;
Kmods SIG d83023
-		mark_inode_dirty(new_dir);
Kmods SIG d83023
-	}
Kmods SIG d83023
-
Kmods SIG d83023
-	if (old_inode) {
Kmods SIG d83023
-		old_inode->i_ctime = old_dir->i_ctime;
Kmods SIG d83023
-		mark_inode_dirty(old_inode);
Kmods SIG d83023
+		if (IS_DIRSYNC(new_dir))
Kmods SIG d83023
+			ntfs_sync_inode(inode);
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
-	err = 0;
Kmods SIG d83023
-	/* Normal way* */
Kmods SIG d83023
-	goto out2;
Kmods SIG d83023
-
Kmods SIG d83023
-out8:
Kmods SIG d83023
-	/* undo
Kmods SIG d83023
-	 * ni_insert_resident(old_ni, new_de_key_size, ATTR_NAME, NULL, 0,
Kmods SIG d83023
-	 *			 &attr, NULL);
Kmods SIG d83023
-	 */
Kmods SIG d83023
-	mi_remove_attr(&old_ni->mi, attr);
Kmods SIG d83023
-out7:
Kmods SIG d83023
-	/* undo
Kmods SIG d83023
-	 * ni_remove_attr_le(old_ni, attr_from_name(fname), le);
Kmods SIG d83023
-	 */
Kmods SIG d83023
-out6:
Kmods SIG d83023
-	/* undo
Kmods SIG d83023
-	 * indx_delete_entry(&old_dir_ni->dir, old_dir_ni,
Kmods SIG d83023
-	 *					fname, fname_full_size(fname),
Kmods SIG d83023
-	 *					sbi);
Kmods SIG d83023
-	 */
Kmods SIG d83023
-out5:
Kmods SIG d83023
-	/* undo
Kmods SIG d83023
-	 * ni_remove_attr_le(old_ni, attr_from_name(fname), le);
Kmods SIG d83023
-	 */
Kmods SIG d83023
-out4:
Kmods SIG d83023
-	/* undo:
Kmods SIG d83023
-	 * indx_delete_entry(&old_dir_ni->dir, old_dir_ni, old_de + 1,
Kmods SIG d83023
-	 *			old_de->key_size, NULL);
Kmods SIG d83023
-	 */
Kmods SIG d83023
-out3:
Kmods SIG d83023
-out2:
Kmods SIG d83023
-	ni_unlock(old_ni);
Kmods SIG d83023
-	ni_unlock(old_dir_ni);
Kmods SIG d83023
-out1:
Kmods SIG d83023
-	__putname(old_de);
Kmods SIG d83023
+	ni_unlock(ni);
Kmods SIG d83023
+	ni_unlock(dir_ni);
Kmods SIG d83023
 out:
Kmods SIG d83023
+	__putname(de);
Kmods SIG d83023
 	return err;
Kmods SIG d83023
 }
Kmods SIG d83023
 
Kmods SIG d83023
diff --git a/src/ntfs_fs.h b/src/ntfs_fs.h
Kmods SIG d83023
index 64ef92e16363c4973be6438efdeea0663ce10e84..f9436cbbc347b617b458bb21d6c7229b467ca289 100644
Kmods SIG d83023
--- a/src/ntfs_fs.h
Kmods SIG d83023
+++ b/src/ntfs_fs.h
Kmods SIG d83023
@@ -478,7 +478,7 @@ struct ATTR_STD_INFO *ni_std(struct ntfs_inode *ni);
Kmods SIG d83023
 struct ATTR_STD_INFO5 *ni_std5(struct ntfs_inode *ni);
Kmods SIG d83023
 void ni_clear(struct ntfs_inode *ni);
Kmods SIG d83023
 int ni_load_mi_ex(struct ntfs_inode *ni, CLST rno, struct mft_inode **mi);
Kmods SIG d83023
-int ni_load_mi(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
Kmods SIG d83023
+int ni_load_mi(struct ntfs_inode *ni, const struct ATTR_LIST_ENTRY *le,
Kmods SIG d83023
 	       struct mft_inode **mi);
Kmods SIG d83023
 struct ATTRIB *ni_find_attr(struct ntfs_inode *ni, struct ATTRIB *attr,
Kmods SIG d83023
 			    struct ATTR_LIST_ENTRY **entry_o,
Kmods SIG d83023
@@ -505,15 +505,18 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
Kmods SIG d83023
 			  struct mft_inode **mi);
Kmods SIG d83023
 int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
Kmods SIG d83023
 		       enum ATTR_TYPE type, const __le16 *name, u8 name_len,
Kmods SIG d83023
-		       struct ATTRIB **new_attr, struct mft_inode **mi);
Kmods SIG d83023
-int ni_remove_attr_le(struct ntfs_inode *ni, struct ATTRIB *attr,
Kmods SIG d83023
-		      struct ATTR_LIST_ENTRY *le);
Kmods SIG d83023
+		       struct ATTRIB **new_attr, struct mft_inode **mi,
Kmods SIG d83023
+		       struct ATTR_LIST_ENTRY **le);
Kmods SIG d83023
+void ni_remove_attr_le(struct ntfs_inode *ni, struct ATTRIB *attr,
Kmods SIG d83023
+		       struct mft_inode *mi, struct ATTR_LIST_ENTRY *le);
Kmods SIG d83023
 int ni_delete_all(struct ntfs_inode *ni);
Kmods SIG d83023
 struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
Kmods SIG d83023
 				     const struct cpu_str *uni,
Kmods SIG d83023
 				     const struct MFT_REF *home,
Kmods SIG d83023
+				     struct mft_inode **mi,
Kmods SIG d83023
 				     struct ATTR_LIST_ENTRY **entry);
Kmods SIG d83023
 struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type,
Kmods SIG d83023
+				     struct mft_inode **mi,
Kmods SIG d83023
 				     struct ATTR_LIST_ENTRY **entry);
Kmods SIG d83023
 int ni_new_attr_flags(struct ntfs_inode *ni, enum FILE_ATTRIBUTE new_fa);
Kmods SIG d83023
 enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
Kmods SIG d83023
@@ -528,6 +531,21 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
Kmods SIG d83023
 		  u32 pages_per_frame);
Kmods SIG d83023
 int ni_write_frame(struct ntfs_inode *ni, struct page **pages,
Kmods SIG d83023
 		   u32 pages_per_frame);
Kmods SIG d83023
+int ni_remove_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
Kmods SIG d83023
+		   struct NTFS_DE *de, struct NTFS_DE **de2, int *undo_step);
Kmods SIG d83023
+
Kmods SIG d83023
+bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
Kmods SIG d83023
+			 struct NTFS_DE *de, struct NTFS_DE *de2,
Kmods SIG d83023
+			 int undo_step);
Kmods SIG d83023
+
Kmods SIG d83023
+int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
Kmods SIG d83023
+		struct NTFS_DE *de);
Kmods SIG d83023
+
Kmods SIG d83023
+int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
Kmods SIG d83023
+	      struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de,
Kmods SIG d83023
+	      bool *is_bad);
Kmods SIG d83023
+
Kmods SIG d83023
+bool ni_is_dirty(struct inode *inode);
Kmods SIG d83023
 
Kmods SIG d83023
 /* Globals from fslog.c */
Kmods SIG d83023
 int log_replay(struct ntfs_inode *ni, bool *initialized);
Kmods SIG d83023
@@ -631,7 +649,7 @@ int indx_find_raw(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 		  size_t *off, struct ntfs_fnd *fnd);
Kmods SIG d83023
 int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 		      const struct NTFS_DE *new_de, const void *param,
Kmods SIG d83023
-		      struct ntfs_fnd *fnd);
Kmods SIG d83023
+		      struct ntfs_fnd *fnd, bool undo);
Kmods SIG d83023
 int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
Kmods SIG d83023
 		      const void *key, u32 key_len, const void *param);
Kmods SIG d83023
 int indx_update_dup(struct ntfs_inode *ni, struct ntfs_sb_info *sbi,
Kmods SIG d83023
@@ -694,7 +712,8 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
Kmods SIG d83023
 			      const __le16 *name, u8 name_len, u32 asize,
Kmods SIG d83023
 			      u16 name_off);
Kmods SIG d83023
 
Kmods SIG d83023
-bool mi_remove_attr(struct mft_inode *mi, struct ATTRIB *attr);
Kmods SIG d83023
+bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi,
Kmods SIG d83023
+		    struct ATTRIB *attr);
Kmods SIG d83023
 bool mi_resize_attr(struct mft_inode *mi, struct ATTRIB *attr, int bytes);
Kmods SIG d83023
 int mi_pack_runs(struct mft_inode *mi, struct ATTRIB *attr,
Kmods SIG d83023
 		 struct runs_tree *run, CLST len);
Kmods SIG d83023
diff --git a/src/record.c b/src/record.c
Kmods SIG d83023
index d48a5e6c5045c5f154f3c1aba4108f458e9676b0..61e3f2fb619f698ffdf5d81ca6f488008002de52 100644
Kmods SIG d83023
--- a/src/record.c
Kmods SIG d83023
+++ b/src/record.c
Kmods SIG d83023
@@ -489,7 +489,8 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
Kmods SIG d83023
  *
Kmods SIG d83023
  * NOTE: The source attr will point to next attribute.
Kmods SIG d83023
  */
Kmods SIG d83023
-bool mi_remove_attr(struct mft_inode *mi, struct ATTRIB *attr)
Kmods SIG d83023
+bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi,
Kmods SIG d83023
+		    struct ATTRIB *attr)
Kmods SIG d83023
 {
Kmods SIG d83023
 	struct MFT_REC *rec = mi->mrec;
Kmods SIG d83023
 	u32 aoff = PtrOffset(rec, attr);
Kmods SIG d83023
@@ -499,6 +500,11 @@ bool mi_remove_attr(struct mft_inode *mi, struct ATTRIB *attr)
Kmods SIG d83023
 	if (aoff + asize > used)
Kmods SIG d83023
 		return false;
Kmods SIG d83023
 
Kmods SIG d83023
+	if (ni && is_attr_indexed(attr)) {
Kmods SIG d83023
+		le16_add_cpu(&ni->mi.mrec->hard_links, -1);
Kmods SIG d83023
+		ni->mi.dirty = true;
Kmods SIG d83023
+	}
Kmods SIG d83023
+
Kmods SIG d83023
 	used -= asize;
Kmods SIG d83023
 	memmove(attr, Add2Ptr(attr, asize), used - aoff);
Kmods SIG d83023
 	rec->used = cpu_to_le32(used);
Kmods SIG d83023
diff --git a/src/xattr.c b/src/xattr.c
Kmods SIG d83023
index b4c921e4bc1a1b4bbb1c51ef7cef6677967b8e13..22fd5eb32c5be7f53b3fd8076599f7dbaf84e2cf 100644
Kmods SIG d83023
--- a/src/xattr.c
Kmods SIG d83023
+++ b/src/xattr.c
Kmods SIG d83023
@@ -395,11 +395,13 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
Kmods SIG d83023
 		}
Kmods SIG d83023
 
Kmods SIG d83023
 		err = ni_insert_resident(ni, sizeof(struct EA_INFO),
Kmods SIG d83023
-					 ATTR_EA_INFO, NULL, 0, NULL, NULL);
Kmods SIG d83023
+					 ATTR_EA_INFO, NULL, 0, NULL, NULL,
Kmods SIG d83023
+					 NULL);
Kmods SIG d83023
 		if (err)
Kmods SIG d83023
 			goto out;
Kmods SIG d83023
 
Kmods SIG d83023
-		err = ni_insert_resident(ni, 0, ATTR_EA, NULL, 0, NULL, NULL);
Kmods SIG d83023
+		err = ni_insert_resident(ni, 0, ATTR_EA, NULL, 0, NULL, NULL,
Kmods SIG d83023
+					 NULL);
Kmods SIG d83023
 		if (err)
Kmods SIG d83023
 			goto out;
Kmods SIG d83023
 	}
Kmods SIG d83023
@@ -419,9 +421,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
Kmods SIG d83023
 
Kmods SIG d83023
 	if (!size) {
Kmods SIG d83023
 		/* Delete xattr, ATTR_EA_INFO */
Kmods SIG d83023
-		err = ni_remove_attr_le(ni, attr, le);
Kmods SIG d83023
-		if (err)
Kmods SIG d83023
-			goto out;
Kmods SIG d83023
+		ni_remove_attr_le(ni, attr, mi, le);
Kmods SIG d83023
 	} else {
Kmods SIG d83023
 		p = resident_data_ex(attr, sizeof(struct EA_INFO));
Kmods SIG d83023
 		if (!p) {
Kmods SIG d83023
@@ -441,9 +441,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
Kmods SIG d83023
 
Kmods SIG d83023
 	if (!size) {
Kmods SIG d83023
 		/* Delete xattr, ATTR_EA */
Kmods SIG d83023
-		err = ni_remove_attr_le(ni, attr, le);
Kmods SIG d83023
-		if (err)
Kmods SIG d83023
-			goto out;
Kmods SIG d83023
+		ni_remove_attr_le(ni, attr, mi, le);
Kmods SIG d83023
 	} else if (attr->non_res) {
Kmods SIG d83023
 		err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size);
Kmods SIG d83023
 		if (err)
Kmods SIG d83023
@@ -605,8 +603,7 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
Kmods SIG d83023
 			goto out;
Kmods SIG d83023
 	}
Kmods SIG d83023
 
Kmods SIG d83023
-	err = ntfs_set_ea(inode, name, name_len, value, size,
Kmods SIG d83023
-			  acl ? 0 : XATTR_REPLACE, locked);
Kmods SIG d83023
+	err = ntfs_set_ea(inode, name, name_len, value, size, 0, locked);
Kmods SIG d83023
 	if (!err)
Kmods SIG d83023
 		set_cached_acl(inode, type, acl);
Kmods SIG d83023
 
Kmods SIG d83023
@@ -632,8 +629,10 @@ static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns,
Kmods SIG d83023
 	struct posix_acl *acl;
Kmods SIG d83023
 	int err;
Kmods SIG d83023
 
Kmods SIG d83023
-	if (!(inode->i_sb->s_flags & SB_POSIXACL))
Kmods SIG d83023
+	if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
Kmods SIG d83023
+		ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
Kmods SIG d83023
 		return -EOPNOTSUPP;
Kmods SIG d83023
+	}
Kmods SIG d83023
 
Kmods SIG d83023
 	acl = ntfs_get_acl(inode, type);
Kmods SIG d83023
 	if (IS_ERR(acl))
Kmods SIG d83023
@@ -655,8 +654,10 @@ static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns,
Kmods SIG d83023
 	struct posix_acl *acl;
Kmods SIG d83023
 	int err;
Kmods SIG d83023
 
Kmods SIG d83023
-	if (!(inode->i_sb->s_flags & SB_POSIXACL))
Kmods SIG d83023
+	if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
Kmods SIG d83023
+		ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
Kmods SIG d83023
 		return -EOPNOTSUPP;
Kmods SIG d83023
+	}
Kmods SIG d83023
 
Kmods SIG d83023
 	if (!inode_owner_or_capable(mnt_userns, inode))
Kmods SIG d83023
 		return -EPERM;
Kmods SIG d83023
-- 
Kmods SIG d83023
2.31.1
Kmods SIG d83023