
From: Oleg Drokin <green@namesys.com>

Hello!

This patch adds support for remounting taking into account all extra options
you may want to pass it.  (by Jeff Mahooney).

Also it reworks the parser to correctly deal with mutually exclusive options.
Now whatever option was specified last will take an effect.

- If you pass more than one jdev= option, the error will be reported and
  mount/remount refused.

- If you pass incorrect alloc= suboptions, the mount/remount will fail. 
  (it did not before).

- nolargeio now actually looks at its argument.  Argument is expected to be
  numeric.  If it is zero, default io size is set to 128k (default setting),
  if it is non-zero, default io size is set to PAGE_SIZE.




 25-akpm/fs/reiserfs/super.c |  117 +++++++++++++++++++++++++++++---------------
 1 files changed, 78 insertions(+), 39 deletions(-)

diff -puN fs/reiserfs/super.c~reiserfs-parser-fix-remount fs/reiserfs/super.c
--- 25/fs/reiserfs/super.c~reiserfs-parser-fix-remount	Thu May 29 14:47:31 2003
+++ 25-akpm/fs/reiserfs/super.c	Thu May 29 14:47:31 2003
@@ -500,8 +500,11 @@ static struct export_operations reiserfs
    mount options that have values rather than being toggles. */
 typedef struct {
     char * value;
-    int bitmask; /* bit which is to be set in mount_options bitmask when this
-                    value is found, 0 is no bits are to be set */
+    int setmask; /* bitmask which is to set on mount_options bitmask when this
+                    value is found, 0 is no bits are to be changed. */
+    int clrmask; /* bitmask which is to clear on mount_options bitmask when  this
+		    value is found, 0 is no bits are to be changed. This is
+		    applied BEFORE setmask */
 } arg_desc_t;
 
 
@@ -511,25 +514,30 @@ typedef struct {
     char * option_name;
     int arg_required; /* 0 if argument is not required, not 0 otherwise */
     const arg_desc_t * values; /* list of values accepted by an option */
-    int bitmask;  /* bit which is to be set in mount_options bitmask when this
-		     option is selected, 0 is not bits are to be set */
+    int setmask; /* bitmask which is to set on mount_options bitmask when this
+                    value is found, 0 is no bits are to be changed. */
+    int clrmask; /* bitmask which is to clear on mount_options bitmask when  this
+		    value is found, 0 is no bits are to be changed. This is
+		    applied BEFORE setmask */
 } opt_desc_t;
 
 /* possible values for "-o block-allocator=" and bits which are to be set in
    s_mount_opt of reiserfs specific part of in-core super block */
 static const arg_desc_t balloc[] = {
-    {"noborder", REISERFS_NO_BORDER},
-    {"no_unhashed_relocation", REISERFS_NO_UNHASHED_RELOCATION},
-    {"hashed_relocation", REISERFS_HASHED_RELOCATION},
-    {"test4", REISERFS_TEST4},
-    {NULL, -1}
+    {"noborder", 1<<REISERFS_NO_BORDER, 0},
+    {"border", 0, 1<<REISERFS_NO_BORDER},
+    {"no_unhashed_relocation", 1<<REISERFS_NO_UNHASHED_RELOCATION, 0},
+    {"hashed_relocation", 1<<REISERFS_HASHED_RELOCATION, 0},
+    {"test4", 1<<REISERFS_TEST4, 0},
+    {"notest4", 0, 1<<REISERFS_TEST4},
+    {NULL, 0, 0}
 };
 
 static const arg_desc_t tails[] = {
-    {"on", REISERFS_LARGETAIL},
-    {"off", -1},
-    {"small", REISERFS_SMALLTAIL},
-    {NULL, 0}
+    {"on", 1<<REISERFS_LARGETAIL, 1<<REISERFS_SMALLTAIL},
+    {"off", 0, (1<<REISERFS_LARGETAIL)|(1<<REISERFS_SMALLTAIL)},
+    {"small", 1<<REISERFS_SMALLTAIL, 1<<REISERFS_LARGETAIL},
+    {NULL, 0, 0}
 };
 
 int reiserfs_default_io_size = 128 * 1024; /* Default recommended I/O size is 128k.
@@ -571,16 +579,21 @@ static int reiserfs_getopt ( struct supe
 	/* Ugly special case, probably we should redo options parser so that
 	   it can understand several arguments for some options, also so that
 	   it can fill several bitfields with option values. */
-	reiserfs_parse_alloc_options( s, p + 6);
-	return 0;
+	if ( reiserfs_parse_alloc_options( s, p + 6) ) {
+	    return -1;
+	} else {
+	    return 0;
+	}
     }
 
  
     /* for every option in the list */
     for (opt = opts; opt->option_name; opt ++) {
 	if (!strncmp (p, opt->option_name, strlen (opt->option_name))) {
-	    if (bit_flags && opt->bitmask != -1)
-		set_bit (opt->bitmask, bit_flags);
+	    if (bit_flags) {
+		*bit_flags &= ~opt->clrmask;
+		*bit_flags |= opt->setmask;
+	    }
 	    break;
 	}
     }
@@ -620,7 +633,7 @@ static int reiserfs_getopt ( struct supe
     }
     
     if (!opt->values) {
-	/* *opt_arg contains pointer to argument */
+	/* *=NULLopt_arg contains pointer to argument */
 	*opt_arg = p;
 	return opt->arg_required;
     }
@@ -628,8 +641,10 @@ static int reiserfs_getopt ( struct supe
     /* values possible for this option are listed in opt->values */
     for (arg = opt->values; arg->value; arg ++) {
 	if (!strcmp (p, arg->value)) {
-	    if (bit_flags && arg->bitmask != -1 )
-		set_bit (arg->bitmask, bit_flags);
+	    if (bit_flags) {
+		*bit_flags &= ~arg->clrmask;
+		*bit_flags |= arg->setmask;
+	    }
 	    return opt->arg_required;
 	}
     }
@@ -638,7 +653,6 @@ static int reiserfs_getopt ( struct supe
     return -1;
 }
 
-
 /* returns 0 if something is wrong in option string, 1 - otherwise */
 static int reiserfs_parse_options (struct super_block * s, char * options, /* string given via mount's -o */
 				   unsigned long * mount_options,
@@ -652,18 +666,18 @@ static int reiserfs_parse_options (struc
     char * arg = NULL;
     char * pos;
     opt_desc_t opts[] = {
-		{"tails", 't', tails, -1},
-		{"notail", 0, 0, -1}, /* Compatibility stuff, so that -o notail
-for old setups still work */
-		{"conv", 0, 0, REISERFS_CONVERT}, 
-		{"attrs", 0, 0, REISERFS_ATTRS}, 
-		{"nolog", 0, 0, -1},
-		{"replayonly", 0, 0, REPLAYONLY},
-		{"block-allocator", 'a', balloc, -1}, 
-		{"resize", 'r', 0, -1},
-		{"jdev", 'j', 0, -1},
-		{"nolargeio", 'w', 0, -1},
-		{NULL, 0, 0, -1}
+	{"tails", 't', tails, 0, 0}, /* Compatibility stuff, so that -o notail for old setups still work */
+	{"notail", 0, 0, 0,  (1<<REISERFS_LARGETAIL)|(1<<REISERFS_SMALLTAIL)},
+	{"conv", 0, 0, 1<<REISERFS_CONVERT, 0},
+	{"attrs", 0, 0, 1<<REISERFS_ATTRS, 0},
+	{"noattrs", 0, 0, 0, 1<<REISERFS_ATTRS},
+	{"nolog", 0, 0, 0, 0}, /* This is unsupported */
+	{"replayonly", 0, 0, 1<<REPLAYONLY, 0},
+	{"block-allocator", 'a', balloc, 0, 0},
+	{"resize", 'r', 0, 0, 0},
+	{"jdev", 'j', 0, 0, 0},
+	{"nolargeio", 'w', 0, 0, 0},
+	{NULL, 0, 0, 0, 0}
     };
 	
     *blocks = 0;
@@ -671,9 +685,6 @@ for old setups still work */
 	/* use default configuration: create tails, journaling on, no
 	   conversion to newest format */
 	return 1;
-    else
-	/* Drop defaults to zeroes */
-	*mount_options = 0;
     
     for (pos = options; pos; ) {
 	c = reiserfs_getopt (s, &pos, opts, &arg, mount_options);
@@ -695,11 +706,25 @@ for old setups still work */
 	}
 
 	if ( c == 'w' ) {
-		reiserfs_default_io_size = PAGE_SIZE;
+		char *p=0;
+		int val = simple_strtoul (arg, &p, 0);
+
+		if ( *p != '\0') {
+		    printk ("reiserfs_parse_options: non-numeric value %s for nolargeio option\n", arg);
+		    return 0;
+		}
+		if ( val ) 
+		    reiserfs_default_io_size = PAGE_SIZE;
+		else
+		    reiserfs_default_io_size = 128 * 1024;
 	}
 
 	if (c == 'j') {
 	    if (arg && *arg && jdev_name) {
+		if ( *jdev_name ) { //Hm, already assigned?
+		    printk("reiserfs_parse_options: journal device was already  specified to be %s\n", *jdev_name);
+		    return 0;
+		}
 		*jdev_name = arg;
 	    }
 	}
@@ -731,14 +756,28 @@ static int reiserfs_remount (struct supe
   struct reiserfs_super_block * rs;
   struct reiserfs_transaction_handle th ;
   unsigned long blocks;
-  unsigned long mount_options;
+  unsigned long mount_options = REISERFS_SB(s)->s_mount_opt;
+  unsigned long safe_mask = 0;
 
   rs = SB_DISK_SUPER_BLOCK (s);
 
   if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL))
     return -EINVAL;
   
-  handle_attrs( s );
+  handle_attrs(s);
+
+  /* Add options that are safe here */
+  safe_mask |= 1 << REISERFS_SMALLTAIL;
+  safe_mask |= 1 << REISERFS_LARGETAIL;
+  safe_mask |= 1 << REISERFS_NO_BORDER;
+  safe_mask |= 1 << REISERFS_NO_UNHASHED_RELOCATION;
+  safe_mask |= 1 << REISERFS_HASHED_RELOCATION;
+  safe_mask |= 1 << REISERFS_TEST4;
+  safe_mask |= 1 << REISERFS_ATTRS;
+
+  /* Update the bitmask, taking care to keep
+   * the bits we're not allowed to change here */
+  REISERFS_SB(s)->s_mount_opt = (REISERFS_SB(s)->s_mount_opt & ~safe_mask) |  (mount_options & safe_mask);
 
   if(blocks) {
     int rc = reiserfs_resize(s, blocks);

_
