linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [Patch 9/13] Adds two extended options and config file counterparts.
@ 2007-07-24 11:05 Girish Shilamkar
  2007-07-24 16:32 ` Theodore Tso
  0 siblings, 1 reply; 2+ messages in thread
From: Girish Shilamkar @ 2007-07-24 11:05 UTC (permalink / raw)
  To: Ext4 Mailing List; +Cc: Andreas Dilger, Theodore Tso

This patch adds two extended options and config file counterparts.
On the command line:

  -E clone=dup|zero

     Select the block cloning method.  "dup" is old behavior which remains
     the default.  "zero" is a new method that substitutes zero-filled
     blocks for the shared blocks in all the files that claim them.

  -E shared=preserve|lost+found|delete

     Select the disposition of files containing shared blocks.  "preserve"
     is the old behavior which remains the default.  "lost+found" causes
     files to be unlinked after cloning so they will be reconnected to
     /lost+found in pass 3.   "delete" skips cloning entirely and simply
     deletes the files.

In the config file:
   [options]
       clone=dup|zero
       shared=preserve|lost+found|delete

Signed-off-by: Jim Garlick  <garlick@llnl.gov>

Index: e2fsprogs-1.40.1/e2fsck/e2fsck.h
===================================================================
--- e2fsprogs-1.40.1.orig/e2fsck/e2fsck.h
+++ e2fsprogs-1.40.1/e2fsck/e2fsck.h
@@ -183,6 +183,17 @@ struct resource_track {
 #define E2F_PASS_5	5
 #define E2F_PASS_1B	6
 
+typedef	enum { 
+	E2F_SHARED_PRESERVE = 0, 
+	E2F_SHARED_DELETE,
+	E2F_SHARED_LPF
+} shared_opt_t;
+
+typedef enum {
+	E2F_CLONE_DUP = 0,
+	E2F_CLONE_ZERO
+} clone_opt_t;
+
 /*
  * Define the extended attribute refcount structure
  */
@@ -332,6 +343,8 @@ struct e2fsck_struct {
 	time_t now;
 
 	int ext_attr_ver;
+	shared_opt_t shared;
+	clone_opt_t clone;
 
 	profile_t	profile;
 
Index: e2fsprogs-1.40.1/e2fsck/unix.c
===================================================================
--- e2fsprogs-1.40.1.orig/e2fsck/unix.c
+++ e2fsprogs-1.40.1/e2fsck/unix.c
@@ -510,6 +510,49 @@ static void signal_cancel(int sig EXT2FS
 }
 #endif
 
+static void initialize_profile_options(e2fsck_t ctx)
+{
+	char *tmp;
+
+	/* [options] shared=preserve|lost+found|delete */
+	tmp = NULL;
+	ctx->shared = E2F_SHARED_PRESERVE; 
+	profile_get_string(ctx->profile, "options", "shared", 0,
+		           "preserve", &tmp);
+	if (tmp) {
+		if (strcmp(tmp, "preserve") == 0)
+			ctx->shared = E2F_SHARED_PRESERVE; 
+		else if (strcmp(tmp, "delete") == 0)
+			ctx->shared = E2F_SHARED_DELETE; 
+		else if (strcmp(tmp, "lost+found") == 0)
+			ctx->shared = E2F_SHARED_LPF; 
+		else {
+			com_err(ctx->program_name, 0, 
+				_("configuration error: 'shared=%s'"), tmp);
+			fatal_error(ctx, 0);
+		}
+		free(tmp);
+	}
+
+	/* [options] clone=dup|zero */
+	tmp = NULL;
+	ctx->clone = E2F_CLONE_DUP;
+	profile_get_string(ctx->profile, "options", "clone", 0,
+			   "dup", &tmp);
+	if (tmp) {
+		if (strcmp(tmp, "dup") == 0)
+			ctx->clone = E2F_CLONE_DUP;
+		else if (strcmp(tmp, "zero") == 0)
+			ctx->clone = E2F_CLONE_ZERO;
+		else {
+			com_err(ctx->program_name, 0, 
+				_("configuration error: 'clone=%s'"), tmp);
+			fatal_error(ctx, 0);
+		}
+		free(tmp);
+	}
+}
+
 static void parse_extended_opts(e2fsck_t ctx, const char *opts)
 {
 	char	*buf, *token, *next, *p, *arg;
@@ -543,6 +586,36 @@ static void parse_extended_opts(e2fsck_t
 				continue;
 			}
 			ctx->ext_attr_ver = ea_ver;
+		/* -E shared=preserve|lost+found|delete */
+		} else if (strcmp(token, "shared") == 0) {
+			if (!arg) {
+				extended_usage++;
+				continue;
+			}
+			if (strcmp(arg, "preserve") == 0) {
+				ctx->shared = E2F_SHARED_PRESERVE;
+			} else if (strcmp(arg, "lost+found") == 0) {
+				ctx->shared = E2F_SHARED_LPF;
+			} else if (strcmp(arg, "delete") == 0) {
+				ctx->shared = E2F_SHARED_DELETE;
+			} else {
+				extended_usage++;
+				continue;
+			}
+		/* -E clone=dup|zero */
+		} else if (strcmp(token, "clone") == 0) {
+			if (!arg) {
+				extended_usage++;
+				continue;
+			}
+			if (strcmp(arg, "dup") == 0) {
+				ctx->clone = E2F_CLONE_DUP;
+			} else if (strcmp(arg, "zero") == 0) {
+				ctx->clone = E2F_CLONE_ZERO;
+			} else {
+				extended_usage++;
+				continue;
+			}
 		} else {
 			fprintf(stderr, _("Unknown extended option: %s\n"),
 				token);
@@ -556,6 +629,8 @@ static void parse_extended_opts(e2fsck_t
 		       "and may take an argument which\n"
 		       "is set off by an equals ('=') sign.  "
 			"Valid extended options are:\n"
+		       "\tshared=<preserve|lost+found|delete>\n"
+		       "\tclone=<dup|zero>\n"
 		       "\tea_ver=<ea_version (1 or 2)>\n\n"), stderr);
 		exit(1);
 	}
@@ -614,6 +689,7 @@ static errcode_t PRS(int argc, char *arg
 		config_fn[0] = cp;
 	profile_set_syntax_err_cb(syntax_err_report);
 	profile_init(config_fn, &ctx->profile);
+	initialize_profile_options(ctx);
 
 	while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF)
 		switch (c) {
Index: e2fsprogs-1.40.1/e2fsck/pass1b.c
===================================================================
--- e2fsprogs-1.40.1.orig/e2fsck/pass1b.c
+++ e2fsprogs-1.40.1/e2fsck/pass1b.c
@@ -456,6 +456,9 @@ static void pass1d(e2fsck_t ctx, char *b
 			q = (struct dup_block *) dnode_get(m);
 			if (q->num_bad > 1)
 				file_ok = 0;
+			if (q->num_bad == 1 && (ctx->clone == E2F_CLONE_ZERO ||
+			    ctx->shared != E2F_SHARED_PRESERVE))
+				file_ok = 0;
 			if (check_if_fs_block(ctx, s->block)) {
 				file_ok = 0;
 				meta_data = 1;
@@ -511,13 +514,26 @@ static void pass1d(e2fsck_t ctx, char *b
 			fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
 			continue;
 		}
-		if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
+		if (ctx->shared != E2F_SHARED_DELETE &&
+		    fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
 			pctx.errcode = clone_file(ctx, ino, p, block_buf);
-			if (pctx.errcode)
+			if (pctx.errcode) {
 				fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
-			else
-				continue;
+				goto delete;
+			}
+			if (ctx->shared == E2F_SHARED_LPF &&
+			    fix_problem(ctx, PR_1D_DISCONNECT_QUESTION, &pctx)) {
+				pctx.errcode = ext2fs_unlink(fs, p->dir, 
+							     NULL, ino, 0);
+				if (pctx.errcode) {
+					fix_problem(ctx, PR_1D_DISCONNECT_ERROR,
+						    &pctx);
+					goto delete;
+				}
+			}
+			continue;
 		}
+delete:
 		if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
 			delete_file(ctx, ino, p, block_buf);
 		else
@@ -534,7 +550,8 @@ static void decrement_badcount(e2fsck_t 
 {
 	p->num_bad--;
 	if (p->num_bad <= 0 ||
-	    (p->num_bad == 1 && !check_if_fs_block(ctx, block)))
+	    (p->num_bad == 1 && !check_if_fs_block(ctx, block) && 
+	    ctx->clone == E2F_CLONE_DUP))
 		ext2fs_unmark_block_bitmap(ctx->block_dup_map, block);
 }
 
@@ -572,7 +589,7 @@ static int delete_file_block(ext2_filsys
 		
 	return 0;
 }
-		
+
 static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
 			struct dup_inode *dp, char* block_buf)
 {
@@ -680,11 +697,15 @@ static int clone_file_block(ext2_filsys 
 			printf("Cloning block %u to %u\n", *block_nr,
 			       new_block);
 #endif
-			retval = io_channel_read_blk(fs->io, *block_nr, 1,
-						     cs->buf);
-			if (retval) {
-				cs->errcode = retval;
-				return BLOCK_ABORT;
+			if (ctx->clone == E2F_CLONE_ZERO) {
+				memset(cs->buf, 0, fs->blocksize);
+			} else {
+				retval = io_channel_read_blk(fs->io, *block_nr,
+							1, cs->buf);
+				if (retval) {
+					cs->errcode = retval;
+					return BLOCK_ABORT;
+				}
 			}
 			retval = io_channel_write_blk(fs->io, new_block, 1,
 						      cs->buf);
@@ -693,6 +714,11 @@ static int clone_file_block(ext2_filsys 
 				return BLOCK_ABORT;
 			}
 			decrement_badcount(ctx, *block_nr, p);
+			if (ctx->clone == E2F_CLONE_ZERO && p->num_bad == 0) {
+				ext2fs_unmark_block_bitmap(ctx->block_found_map,
+							   *block_nr);
+				ext2fs_block_alloc_stats(fs, *block_nr, -1);
+			}
 			*block_nr = new_block;
 			ext2fs_mark_block_bitmap(ctx->block_found_map,
 						 new_block);
Index: e2fsprogs-1.40.1/e2fsck/problem.h
===================================================================
--- e2fsprogs-1.40.1.orig/e2fsck/problem.h
+++ e2fsprogs-1.40.1/e2fsck/problem.h
@@ -542,7 +542,13 @@ struct problem_context {
 
 /* Couldn't clone file (error) */
 #define PR_1D_CLONE_ERROR	0x013008
-		
+
+/* File with shared blocks found */
+#define PR_1D_DISCONNECT_QUESTION 0x013009
+
+/* Couldn't unlink file (error) */
+#define PR_1D_DISCONNECT_ERROR	0x01300A
+
 /*
  * Pass 2 errors
  */
Index: e2fsprogs-1.40.1/e2fsck/problem.c
===================================================================
--- e2fsprogs-1.40.1.orig/e2fsck/problem.c
+++ e2fsprogs-1.40.1/e2fsck/problem.c
@@ -917,6 +917,14 @@ static struct e2fsck_problem problem_tab
 	{ PR_1D_CLONE_ERROR,
 	  N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 },
 
+	/* File with shared blocks found */
+	{ PR_1D_DISCONNECT_QUESTION,
+	  N_("File with shared blocks found\n"), PROMPT_CONNECT, 0 },
+
+	/* Couldn't unlink file (error) */
+	{ PR_1D_DISCONNECT_ERROR,
+	  N_("Couldn't unlink file: %m\n"), PROMPT_NONE, 0 },
+
 	/* Pass 2 errors */
 
 	/* Pass 2: Checking directory structure */
Index: e2fsprogs-1.40.1/e2fsck/e2fsck.8.in
===================================================================
--- e2fsprogs-1.40.1.orig/e2fsck/e2fsck.8.in
+++ e2fsprogs-1.40.1/e2fsck/e2fsck.8.in
@@ -165,6 +165,19 @@ following options are supported:
 Assume the format of the extended attribute blocks in the filesystem is
 the specified version number.  The version number may be 1 or 2.  The
 default extended attribute version format is 2.
+.TP
+.BI clone= dup|zero
+Resolve files with shared blocks in pass 1D by giving each file a private
+copy of the blocks (dup);
+or replacing the shared blocks with private, zero-filled blocks (zero).  
+The default is dup.
+.TP
+.BI shared= preserve|lost+found|delete
+Files with shared blocks discovered in pass 1D are cloned and then left 
+in place (preserve); 
+cloned and then disconnected from their parent directory,
+then reconnected to /lost+found in pass 3 (lost+found); 
+or simply deleted (delete).  The default is preserve.
 .RE
 .TP
 .B \-f
Index: e2fsprogs-1.40.1/e2fsck/e2fsck.conf.5.in
===================================================================
--- e2fsprogs-1.40.1.orig/e2fsck/e2fsck.conf.5.in
+++ e2fsprogs-1.40.1/e2fsck/e2fsck.conf.5.in
@@ -92,6 +92,20 @@ This boolean relation controls whether o
 filesystem checks (either based on time or number of mounts) should 
 be doubled if the system is running on battery.  It defaults to 
 true.
+.TP
+.I clone
+This string relation controls the default handling of shared blocks in pass 1D.
+It can be set to dup or zero.  See the
+.I "-E clone" 
+option description in e2fsck(8).
+.TP
+.I shared
+This string relation controls the default disposition of files discovered to 
+have shared blocks in pass 1D.  It can be set to preserve, lost+found, 
+or delete.  See the
+.I "-E shared" 
+option description in e2fsck(8).
+
 .SH THE [problems] STANZA
 Each tag in the
 .I [problems] 

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [Patch 9/13] Adds two extended options and config file counterparts.
  2007-07-24 11:05 [Patch 9/13] Adds two extended options and config file counterparts Girish Shilamkar
@ 2007-07-24 16:32 ` Theodore Tso
  0 siblings, 0 replies; 2+ messages in thread
From: Theodore Tso @ 2007-07-24 16:32 UTC (permalink / raw)
  To: Girish Shilamkar; +Cc: Ext4 Mailing List, Andreas Dilger

On Tue, Jul 24, 2007 at 04:35:04PM +0530, Girish Shilamkar wrote:
> This patch adds two extended options and config file counterparts.
> On the command line:
> 
>   -E shared=preserve|lost+found|delete
> 
>      Select the disposition of files containing shared blocks.  "preserve"
>      is the old behavior which remains the default.  "lost+found" causes
>      files to be unlinked after cloning so they will be reconnected to
>      /lost+found in pass 3.   "delete" skips cloning entirely and simply
>      deletes the files.

Jim Garlick and I discussed this back in April, and I pointed out a
flaw in his patch.  It doesn't correctly handle the case where the
system administrator wishes to move an inode that contains blocks
claimed by other inodes to lost+found, since it only unlinks the first
filename of the inode.  The result is that the inode loses one of its
directory entries, but it doesn't get oved to lost+found.

Jim reworked the patch to solve this issue, by keeping a linked list
of all of the directory entries where a particular inode could be
found.  This increases the memory used and increases the time to do
pass 1C, though.  The patch you have in your patch queue is the
original version of the patch, not his updated one.

I'm still not happy with this approach, though, since it adds extra
complexity and special case handling into e2fsprogs.  I had made a
counter-proposal as a better long-term approach, which Jim seemed to
agree would meet his needs:

>One of my long-term plans was to extend the fix_problem() function to
>log a detailed set of problems fixed into a file (either binary or
>XML) that could parsed by other programs as part of some kind of
>recovery process.  What would get written out is the problem ID plus
>the entire problem_context structure, which has actually quite a lot
>of information.  This would be enough for a lot of post-processing,
>including making it easier for people to implement policies such as
>deleted or archiving for review by the Site Security Officer any files
>which had some of their blocks cloned.

						- Ted

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2007-07-24 16:32 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-07-24 11:05 [Patch 9/13] Adds two extended options and config file counterparts Girish Shilamkar
2007-07-24 16:32 ` Theodore Tso

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).