[Ocfs2-tools-commits] taoma commits r1315 - trunk/libocfs2

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Wed Mar 7 21:46:21 PST 2007


Author: taoma
Date: 2007-03-07 21:46:18 -0800 (Wed, 07 Mar 2007)
New Revision: 1315

Modified:
   trunk/libocfs2/extents.c
   trunk/libocfs2/truncate.c
Log:
Modify ocfs2_truncate in libocfs2 to truncate a file.

ocfs2_truncate is designed to modify a file to a desirable size, but actually this function
can't work except setting the i_size of ocfs2_dinode.
For more details, please see
http://oss.oracle.com/bugzilla/show_bug.cgi?id=856

Signed-off-by: jlbec

Modified: trunk/libocfs2/extents.c
===================================================================
--- trunk/libocfs2/extents.c	2007-03-02 22:13:04 UTC (rev 1314)
+++ trunk/libocfs2/extents.c	2007-03-08 05:46:18 UTC (rev 1315)
@@ -217,20 +217,6 @@
 			   struct ocfs2_extent_rec *before,
 			   struct ocfs2_extent_rec *current)
 {
-	uint64_t start;
-	uint32_t len;
-
-	if (current->e_clusters == before->e_clusters)
-		return 0;
-
-	start = current->e_blkno +
-		ocfs2_clusters_to_blocks(ctxt->fs, current->e_clusters);
-	len = current->e_clusters - before->e_clusters;
-
-	ctxt->errcode = ocfs2_free_clusters(ctxt->fs, len, start);
-	if (ctxt->errcode)
-		return OCFS2_EXTENT_ERROR;
-
 	return 0;
 }
 
@@ -238,14 +224,6 @@
 			 struct ocfs2_extent_rec *before,
 			 struct ocfs2_extent_rec *current)
 {
-	if (current->e_clusters)
-		return 0;
-
-	ctxt->errcode = ocfs2_delete_extent_block(ctxt->fs,
-						  before->e_blkno); 
-	if (ctxt->errcode)
-		return OCFS2_EXTENT_ERROR;
-
 	return 0;
 }
 

Modified: trunk/libocfs2/truncate.c
===================================================================
--- trunk/libocfs2/truncate.c	2007-03-02 22:13:04 UTC (rev 1314)
+++ trunk/libocfs2/truncate.c	2007-03-08 05:46:18 UTC (rev 1315)
@@ -33,10 +33,7 @@
 #include "ocfs2.h"
 
 /*
- * We let ocfs2_extent_iterate() update the tree for us by
- * altering the records beyond the new size and returning
- * _CHANGED.  It will delete unused extent blocks and file
- * data for us.  This only works with DEPTH_TRAVERSE..
+ * Delete and free clusters if needed.  This only works with DEPTH_TRAVERSE.
  */
 static int truncate_iterate(ocfs2_filesys *fs,
 			    struct ocfs2_extent_rec *rec,
@@ -44,22 +41,50 @@
 			    uint64_t ref_blkno, int ref_recno,
 			    void *priv_data)
 {
-	uint64_t new_i_clusters = *(uint64_t *)priv_data;
+	uint32_t len, new_i_clusters = *(uint32_t *)priv_data;
+	uint64_t start = 0;
+	errcode_t ret;
 
 	if ((rec->e_cpos + rec->e_clusters) <= new_i_clusters)
 		return 0;
 
 	if (rec->e_cpos >= new_i_clusters) {
 		/* the rec is entirely outside the new size, free it */
+		if (!tree_depth) {
+			start = rec->e_blkno;
+			len = rec->e_clusters;
+		} else {
+			/* here we meet with a full empty extent block, delete
+			 * it. The extent list it contains should already be
+			 * iterated and all the clusters have been freed.
+			 */
+			ret = ocfs2_delete_extent_block(fs, rec->e_blkno);
+			if (ret)
+				goto bail;
+		}
+
 		rec->e_blkno = 0;
 		rec->e_clusters = 0;
 		rec->e_cpos = 0;
 	} else {
 		/* we're truncating into the middle of the rec */
+		len = rec->e_cpos + rec->e_clusters;
+		len -= new_i_clusters;
 		rec->e_clusters = new_i_clusters - rec->e_cpos;
+		if (!tree_depth)
+			start = rec->e_blkno +
+				ocfs2_clusters_to_blocks(fs, rec->e_clusters);
 	}
 
+	if (start) {
+		ret = ocfs2_free_clusters(fs, len, start);
+		if (ret)
+			goto bail;
+	}
+
 	return OCFS2_EXTENT_CHANGED;
+bail:
+	return OCFS2_EXTENT_ERROR;
 }
 
 /* XXX care about zeroing new clusters and final partially truncated 
@@ -92,6 +117,13 @@
 					new_i_clusters - di->i_clusters);
 		if (ret)
 			goto out;
+
+		/* the information of dinode has been changed, and we need to
+		 * read it again.
+		 */
+		ret = ocfs2_read_inode(fs, ino, buf);
+		if (ret)
+			goto out;
 	} else {
 		ret = ocfs2_extent_iterate_inode(fs, di,
 						 OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE,
@@ -99,6 +131,14 @@
 						 &new_i_clusters);
 		if (ret)
 			goto out;
+
+		/* now all the clusters and extent blocks are freed.
+		 * only when the file's content is empty, should the tree depth
+		 * change.
+		 */
+		if (new_i_clusters == 0)
+			di->id2.i_list.l_tree_depth = 0;
+
 	}
 
 	di->i_clusters = new_i_clusters;
@@ -110,3 +150,92 @@
 
 	return ret;
 }
+
+#ifdef DEBUG_EXE
+#include <stdlib.h>
+#include <getopt.h>
+#include <inttypes.h>
+
+static uint64_t read_number(const char *num)
+{
+	uint64_t val;
+	char *ptr;
+
+	val = strtoull(num, &ptr, 0);
+	if (!ptr || *ptr)
+		return 0;
+
+	return val;
+}
+
+static void print_usage(void)
+{
+	fprintf(stderr,
+		"Usage: debug_truncate -i <ino_blkno> -s <new_size> device\n");
+}
+
+extern int opterr, optind;
+extern char *optarg;
+
+int main(int argc, char *argv[])
+{
+	errcode_t ret;
+	int c;
+	uint64_t blkno = 0, new_size = 0;
+	ocfs2_filesys *fs;
+	char *device;
+
+	initialize_ocfs_error_table();
+
+	while ((c = getopt(argc, argv, "i:s:")) != EOF) {
+		switch (c) {
+			case 'i':
+				blkno = read_number(optarg);
+				if (blkno <= OCFS2_SUPER_BLOCK_BLKNO) {
+					fprintf(stderr,
+						"Invalid inode block: %s\n",
+						optarg);
+					print_usage();
+					return 1;
+				}
+				break;
+
+			case 's':
+				new_size = read_number(optarg);
+				break;
+
+			default:
+				print_usage();
+				return 1;
+				break;
+		}
+	}
+
+	if (optind >= argc) {
+		fprintf(stderr, "Missing device name\n");
+		print_usage();
+		return 1;
+	}
+	device = argv[optind];
+
+	if (!blkno || !new_size) {
+		print_usage();
+		return 1;
+	}
+
+	ret = ocfs2_open(device, OCFS2_FLAG_RW, 0, 0, &fs);
+	if (ret) {
+		com_err(argv[0], ret,
+			"while opening file \"%s\"", device);
+		return ret;
+	}
+
+	ret = ocfs2_truncate(fs, blkno, new_size);
+	if (ret)
+		com_err(argv[0], ret, "while truncating inode %"PRIu64, blkno);
+
+	ocfs2_close(fs);
+
+	return ret;
+}
+#endif  /* DEBUG_EXE */




More information about the Ocfs2-tools-commits mailing list