[PATCH] libext2fs: Make ext2fs_extent_set_bmap() more robust against ENOSPC

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



In the case where we ext2fs_extent_set_bmap() is replacing the block
mapping at the beginning of an already-existing extent, insert a new
extent if necessary before shrinking an existing extent, to avoid data
loss if the disk is full.

This mostly addresses the problem described in Red Hat Bugzilla's
statistics are still wrong, but at least the files on the filesystem
are not corrupted.  If there is a failure during the
inode_scan_and_fix pass, the simplest thing to do may be to tell the
user to run e2fsck -fy.

Addresses-Red-Hat-Bug: #510379

Signed-off-by: "Theodore Ts'o" <tytso@xxxxxxx>
---
 lib/ext2fs/extent.c |   44 ++++++++++++++++++++++++++++++++------------
 1 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c
index 4a4fd2c..2f280ea 100644
--- a/lib/ext2fs/extent.c
+++ b/lib/ext2fs/extent.c
@@ -1270,24 +1270,44 @@ again:
 #ifdef DEBUG
 		printf("(re/un)mapping first block in extent\n");
 #endif
+		if (physical) {
+			retval = ext2fs_extent_get(handle, 
+						   EXT2_EXTENT_PREV_LEAF,
+						   &extent);
+			if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
+				extent_uninit = 1;
+			if (retval == EXT2_ET_EXTENT_NO_PREV) {
+				retval = ext2fs_extent_insert(handle,
+							      0, &newextent);
+			} else if (retval)
+				goto done;
+			else if ((logical == extent.e_lblk + extent.e_len) &&
+				 (physical == extent.e_pblk + extent.e_len) &&
+				 (new_uninit == extent_uninit) &&
+				 ((int) extent.e_len < max_len-1)) {
+				extent.e_len++;
+				retval = ext2fs_extent_replace(handle, 0,
+							       &extent);
+			} else {
+				retval = ext2fs_extent_insert(handle,
+				      EXT2_EXTENT_INSERT_AFTER, &newextent);
+			}
+			if (retval)
+				goto done;
+		}
+		retval = ext2fs_extent_fix_parents(handle);
+		if (retval)
+			goto done;
+		retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF,
+					   &extent);
+		if (retval)
+			goto done;
 		extent.e_pblk++;
 		extent.e_lblk++;
 		extent.e_len--;
 		retval = ext2fs_extent_replace(handle, 0, &extent);
 		if (retval)
 			goto done;
-		if (physical) {
-			/*
-			 * We've removed the old block, now rely on
-			 * the optimized hueristics for adding a new
-			 * mapping with appropriate merging if necessary.
-			 */
-			goto again;
-		} else {
-			retval = ext2fs_extent_fix_parents(handle);
-			if (retval)
-				goto done;
-		}
 	} else {
 		__u32	orig_length;
 
-- 
1.6.3.2.1.gb9f7d.dirty

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Reiser Filesystem Development]     [Ceph FS]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite National Park]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Media]

  Powered by Linux