diff mbox series

[4/6] fs/ntfs3: Refactoring attr_insert_range to restore after errors

Message ID ab84cf8a-63bc-fc54-9f0c-43b3ef2705ab@paragon-software.com (mailing list archive)
State New, archived
Headers show
Series fs/ntfs3: Refactoring of several functions | expand

Commit Message

Konstantin Komarov July 13, 2022, 4:46 p.m. UTC
Added done and undo labels for restoring after errors

Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
---
  fs/ntfs3/attrib.c | 115 ++++++++++++++++++++++++++++++++++------------
  1 file changed, 86 insertions(+), 29 deletions(-)
diff mbox series

Patch

diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c
index 24d545041787..71f870d497ae 100644
--- a/fs/ntfs3/attrib.c
+++ b/fs/ntfs3/attrib.c
@@ -2275,28 +2275,29 @@  int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
  
  	if (!attr_b->non_res) {
  		err = attr_set_size(ni, ATTR_DATA, NULL, 0, run,
-				    data_size + bytes, NULL, false, &attr);
+				    data_size + bytes, NULL, false, NULL);
+
+		le_b = NULL;
+		attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
+				      &mi_b);
+		if (!attr_b) {
+			err = -EINVAL;
+			goto bad_inode;
+		}
+
  		if (err)
  			goto out;
-		if (!attr->non_res) {
+
+		if (!attr_b->non_res) {
  			/* Still resident. */
-			char *data = Add2Ptr(attr, attr->res.data_off);
+			char *data = Add2Ptr(attr_b, attr_b->res.data_off);
  
  			memmove(data + bytes, data, bytes);
  			memset(data, 0, bytes);
-			err = 0;
-			goto out;
+			goto done;
  		}
+
  		/* Resident files becomes nonresident. */
-		le_b = NULL;
-		attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
-				      &mi_b);
-		if (!attr_b)
-			return -ENOENT;
-		if (!attr_b->non_res) {
-			err = -EINVAL;
-			goto out;
-		}
  		data_size = le64_to_cpu(attr_b->nres.data_size);
  		alloc_size = le64_to_cpu(attr_b->nres.alloc_size);
  	}
@@ -2314,14 +2315,14 @@  int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
  		mi = mi_b;
  	} else if (!le_b) {
  		err = -EINVAL;
-		goto out;
+		goto bad_inode;
  	} else {
  		le = le_b;
  		attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
  				    &mi);
  		if (!attr) {
  			err = -EINVAL;
-			goto out;
+			goto bad_inode;
  		}
  
  		svcn = le64_to_cpu(attr->nres.svcn);
@@ -2344,7 +2345,6 @@  int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
  		goto out;
  
  	next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
-	run_truncate_head(run, next_svcn);
  
  	while ((attr = ni_enum_attr_ex(ni, attr, &le, &mi)) &&
  	       attr->type == ATTR_DATA && !attr->name_len) {
@@ -2357,9 +2357,27 @@  int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
  		mi->dirty = true;
  	}
  
+	if (next_svcn < evcn1 + len) {
+		err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
+					    next_svcn, evcn1 + len - next_svcn,
+					    a_flags, NULL, NULL, NULL);
+
+		le_b = NULL;
+		attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
+				      &mi_b);
+		if (!attr_b) {
+			err = -EINVAL;
+			goto bad_inode;
+		}
+
+		if (err) {
+			/* ni_insert_nonresident failed. Try to undo. */
+			goto undo_insert_range;
+		}
+	}
+
  	/*
-	 * Update primary attribute segment in advance.
-	 * pointer attr_b may become invalid (layout of mft is changed)
+	 * Update primary attribute segment.
  	 */
  	if (vbo <= ni->i_valid)
  		ni->i_valid += bytes;
@@ -2374,14 +2392,7 @@  int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
  		attr_b->nres.valid_size = cpu_to_le64(ni->i_valid);
  	mi_b->dirty = true;
  
-	if (next_svcn < evcn1 + len) {
-		err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
-					    next_svcn, evcn1 + len - next_svcn,
-					    a_flags, NULL, NULL, NULL);
-		if (err)
-			goto out;
-	}
-
+done:
  	ni->vfs_inode.i_size += bytes;
  	ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
  	mark_inode_dirty(&ni->vfs_inode);
@@ -2390,8 +2401,54 @@  int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
  	run_truncate(run, 0); /* clear cached values. */
  
  	up_write(&ni->file.run_lock);
-	if (err)
-		_ntfs_bad_inode(&ni->vfs_inode);
  
  	return err;
+
+bad_inode:
+	_ntfs_bad_inode(&ni->vfs_inode);
+	goto out;
+
+undo_insert_range:
+	svcn = le64_to_cpu(attr_b->nres.svcn);
+	evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
+
+	if (svcn <= vcn && vcn < evcn1) {
+		attr = attr_b;
+		le = le_b;
+		mi = mi_b;
+	} else if (!le_b) {
+		goto bad_inode;
+	} else {
+		le = le_b;
+		attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
+				    &mi);
+		if (!attr) {
+			goto bad_inode;
+		}
+
+		svcn = le64_to_cpu(attr->nres.svcn);
+		evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
+	}
+
+	if (attr_load_runs(attr, ni, run, NULL))
+		goto bad_inode;
+
+	if (!run_collapse_range(run, vcn, len))
+		goto bad_inode;
+
+	if (mi_pack_runs(mi, attr, run, evcn1 + len - svcn))
+		goto bad_inode;
+
+	while ((attr = ni_enum_attr_ex(ni, attr, &le, &mi)) &&
+	       attr->type == ATTR_DATA && !attr->name_len) {
+		le64_sub_cpu(&attr->nres.svcn, len);
+		le64_sub_cpu(&attr->nres.evcn, len);
+		if (le) {
+			le->vcn = attr->nres.svcn;
+			ni->attr_list.dirty = true;
+		}
+		mi->dirty = true;
+	}
+
+	goto out;
  }