
From: Hans Reiser <reiser@namesys.com>

reiser4_parse_option used to define big array as local variable.  This
patch makes that array kmalloc-ed.

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/reiser4/vfs_ops.c |  274 +++++++++++++++++++++++--------------------
 1 files changed, 152 insertions(+), 122 deletions(-)

diff -puN fs/reiser4/vfs_ops.c~reiser4-parse-options-reduce-stack-usage fs/reiser4/vfs_ops.c
--- 25/fs/reiser4/vfs_ops.c~reiser4-parse-options-reduce-stack-usage	2004-09-20 11:05:47.461499288 -0700
+++ 25-akpm/fs/reiser4/vfs_ops.c	2004-09-20 11:05:47.469498072 -0700
@@ -881,6 +881,9 @@ parse_options(char *opt_string /* starti
 		}						\
 	}
 
+
+#define MAX_NR_OPTIONS (30)
+
 /* parse options during mount */
 reiser4_internal int
 reiser4_parse_options(struct super_block *s, char *opt_string)
@@ -888,143 +891,170 @@ reiser4_parse_options(struct super_block
 	int result;
 	reiser4_super_info_data *sbinfo = get_super_private(s);
 	char *log_file_name;
+	opt_desc_t *opts, *p;
 
-	opt_desc_t opts[] = {
-		/* trace_flags=N
+	opts = kmalloc(sizeof(opt_desc_t) * MAX_NR_OPTIONS, GFP_KERNEL);
+	if (opts == NULL)
+		return RETERR(-ENOMEM);
 
-		   set trace flags to be N for this mount. N can be C numeric
-		   literal recognized by %i scanf specifier.  It is treated as
-		   bitfield filled by values of debug.h:reiser4_trace_flags
-		   enum
-		*/
-		SB_FIELD_OPT(trace_flags, "%i"),
-		/* log_flags=N
+	p = opts;
 
-		   set log flags to be N for this mount. N can be C numeric
-		   literal recognized by %i scanf specifier.  It is treated as
-		   bitfield filled by values of debug.h:reiser4_log_flags
-		   enum
-		*/
-		SB_FIELD_OPT(log_flags, "%i"),
-		/* debug_flags=N
+#if REISER4_DEBUG
+#  define OPT_ARRAY_CHECK if ((p) > (opts) + MAX_NR_OPTIONS) {		\
+		warning ("zam-1046", "opt array is overloaded"); break;	\
+	}
+#else
+#   define OPT_ARRAY_CHECK noop
+#endif
 
-		   set debug flags to be N for this mount. N can be C numeric
-		   literal recognized by %i scanf specifier.  It is treated as
-		   bitfield filled by values of debug.h:reiser4_debug_flags
-		   enum
-		*/
-		SB_FIELD_OPT(debug_flags, "%i"),
-		/* tmgr.atom_max_size=N
+#define PUSH_OPT(...)				\
+do {						\
+	 opt_desc_t o = __VA_ARGS__;		\
+	 OPT_ARRAY_CHECK;			\
+	 *p ++ = o;				\
+} while (0)
+
+#define PUSH_SB_FIELD_OPT(field, format) PUSH_OPT(SB_FIELD_OPT(field, format))
+#define PUSH_BIT_OPT(name, bit) PUSH_OPT(BIT_OPT(name, bit))
+
+	/* trace_flags=N
+
+	set trace flags to be N for this mount. N can be C numeric
+	literal recognized by %i scanf specifier.  It is treated as
+	bitfield filled by values of debug.h:reiser4_trace_flags
+	enum
+	*/
+	PUSH_SB_FIELD_OPT(trace_flags, "%i");
+	/* log_flags=N
 
-		   Atoms containing more than N blocks will be forced to
-		   commit. N is decimal.
-		*/
-		SB_FIELD_OPT(tmgr.atom_max_size, "%u"),
-		/* tmgr.atom_max_age=N
+	set log flags to be N for this mount. N can be C numeric
+	literal recognized by %i scanf specifier.  It is treated as
+	bitfield filled by values of debug.h:reiser4_log_flags
+	enum
+	*/
+	PUSH_SB_FIELD_OPT(log_flags, "%i");
+	/* debug_flags=N
 
-		   Atoms older than N seconds will be forced to commit. N is
-		   decimal.
-		*/
-		SB_FIELD_OPT(tmgr.atom_max_age, "%u"),
-		/* tmgr.atom_max_flushers=N
+	set debug flags to be N for this mount. N can be C numeric
+	literal recognized by %i scanf specifier.  It is treated as
+	bitfield filled by values of debug.h:reiser4_debug_flags
+	enum
+	*/
+	PUSH_SB_FIELD_OPT(debug_flags, "%i");
+	/* tmgr.atom_max_size=N
 
-		   limit of concurrent flushers for one atom. 0 means no limit.
-		 */
-		SB_FIELD_OPT(tmgr.atom_max_flushers, "%u"),
-		/* tree.cbk_cache_slots=N
+	Atoms containing more than N blocks will be forced to
+	commit. N is decimal.
+	*/
+	PUSH_SB_FIELD_OPT(tmgr.atom_max_size, "%u");
+	/* tmgr.atom_max_age=N
 
-		   Number of slots in the cbk cache.
-		*/
-		SB_FIELD_OPT(tree.cbk_cache.nr_slots, "%u"),
+	Atoms older than N seconds will be forced to commit. N is
+	decimal.
+	*/
+	PUSH_SB_FIELD_OPT(tmgr.atom_max_age, "%u");
+	/* tmgr.atom_max_flushers=N
+
+	limit of concurrent flushers for one atom. 0 means no limit.
+	*/
+	PUSH_SB_FIELD_OPT(tmgr.atom_max_flushers, "%u");
+	/* tree.cbk_cache_slots=N
+
+	Number of slots in the cbk cache.
+	*/
+	PUSH_SB_FIELD_OPT(tree.cbk_cache.nr_slots, "%u");
 
-		/* If flush finds more than FLUSH_RELOCATE_THRESHOLD adjacent
-		   dirty leaf-level blocks it will force them to be
-		   relocated. */
-		SB_FIELD_OPT(flush.relocate_threshold, "%u"),
-		/* If flush finds can find a block allocation closer than at
-		   most FLUSH_RELOCATE_DISTANCE from the preceder it will
-		   relocate to that position. */
-		SB_FIELD_OPT(flush.relocate_distance, "%u"),
-		/* If we have written this much or more blocks before
-		   encountering busy jnode in flush list - abort flushing
-		   hoping that next time we get called this jnode will be
-		   clean already, and we will save some seeks. */
-		SB_FIELD_OPT(flush.written_threshold, "%u"),
-		/* The maximum number of nodes to scan left on a level during
-		   flush. */
-		SB_FIELD_OPT(flush.scan_maxnodes, "%u"),
-
-		/* preferred IO size */
-		SB_FIELD_OPT(optimal_io_size, "%u"),
-
-		/* carry flags used for insertion of new nodes */
-		SB_FIELD_OPT(tree.carry.new_node_flags, "%u"),
-		/* carry flags used for insertion of new extents */
-		SB_FIELD_OPT(tree.carry.new_extent_flags, "%u"),
-		/* carry flags used for paste operations */
-		SB_FIELD_OPT(tree.carry.paste_flags, "%u"),
-		/* carry flags used for insert operations */
-		SB_FIELD_OPT(tree.carry.insert_flags, "%u"),
+	/* If flush finds more than FLUSH_RELOCATE_THRESHOLD adjacent
+	   dirty leaf-level blocks it will force them to be
+	   relocated. */
+	PUSH_SB_FIELD_OPT(flush.relocate_threshold, "%u");
+	/* If flush finds can find a block allocation closer than at
+	   most FLUSH_RELOCATE_DISTANCE from the preceder it will
+	   relocate to that position. */
+	PUSH_SB_FIELD_OPT(flush.relocate_distance, "%u");
+	/* If we have written this much or more blocks before
+	   encountering busy jnode in flush list - abort flushing
+	   hoping that next time we get called this jnode will be
+	   clean already, and we will save some seeks. */
+	PUSH_SB_FIELD_OPT(flush.written_threshold, "%u");
+	/* The maximum number of nodes to scan left on a level during
+	   flush. */
+	PUSH_SB_FIELD_OPT(flush.scan_maxnodes, "%u");
+
+	/* preferred IO size */
+	PUSH_SB_FIELD_OPT(optimal_io_size, "%u");
+
+	/* carry flags used for insertion of new nodes */
+	PUSH_SB_FIELD_OPT(tree.carry.new_node_flags, "%u");
+	/* carry flags used for insertion of new extents */
+	PUSH_SB_FIELD_OPT(tree.carry.new_extent_flags, "%u");
+	/* carry flags used for paste operations */
+	PUSH_SB_FIELD_OPT(tree.carry.paste_flags, "%u");
+	/* carry flags used for insert operations */
+	PUSH_SB_FIELD_OPT(tree.carry.insert_flags, "%u");
 
 #ifdef CONFIG_REISER4_BADBLOCKS
-		/* Alternative master superblock location in case if it's original
-		   location is not writeable/accessable. This is offset in BYTES. */
-		SB_FIELD_OPT(altsuper, "%lu"),
+	/* Alternative master superblock location in case if it's original
+	   location is not writeable/accessable. This is offset in BYTES. */
+	PUSH_SB_FIELD_OPT(altsuper, "%lu");
 #endif
 
-		/* turn on BSD-style gid assignment */
-		BIT_OPT("bsdgroups", REISER4_BSD_GID),
-		/* turn on 32 bit times */
-		BIT_OPT("32bittimes", REISER4_32_BIT_TIMES),
-		/* turn off concurrent flushing */
-		BIT_OPT("mtflush", REISER4_MTFLUSH),
-		/* disable pseudo files support */
-		BIT_OPT("nopseudo", REISER4_NO_PSEUDO),
-		/* Don't load all bitmap blocks at mount time, it is useful
-		   for machines with tiny RAM and large disks. */
-		BIT_OPT("dont_load_bitmap", REISER4_DONT_LOAD_BITMAP),
-
-		{
-			/* tree traversal readahead parameters:
-			   -o readahead:MAXNUM:FLAGS
-			   MAXNUM - max number fo nodes to request readahead for: -1UL will set it to max_sane_readahead()
-			   FLAGS - combination of bits: RA_ADJCENT_ONLY, RA_ALL_LEVELS, CONTINUE_ON_PRESENT
-			*/
-			.name = "readahead",
-			.type = OPT_FORMAT,
-			.u = {
-				.f = {
-					.format  = "%u:%u",
-					.nr_args = 2,
-					.arg1 = &sbinfo->ra_params.max,
-					.arg2 = &sbinfo->ra_params.flags,
-					.arg3 = NULL,
-					.arg4 = NULL
-				}
-			}
-		},
-		/* What to do in case of fs error */
-		{
-                        .name = "onerror",
-                        .type = OPT_ONEOF,
-                        .u = {
-                                .oneof = {
-                                        .result = &sbinfo->onerror,
-                                        .list = {"panic", "remount-ro", "reboot", NULL},
-                                }
-                        }
-                },
+	/* turn on BSD-style gid assignment */
+	PUSH_BIT_OPT("bsdgroups", REISER4_BSD_GID);
+	/* turn on 32 bit times */
+	PUSH_BIT_OPT("32bittimes", REISER4_32_BIT_TIMES);
+	/* turn off concurrent flushing */
+	PUSH_BIT_OPT("mtflush", REISER4_MTFLUSH);
+	/* disable pseudo files support */
+	PUSH_BIT_OPT("nopseudo", REISER4_NO_PSEUDO);
+	/* Don't load all bitmap blocks at mount time, it is useful
+	   for machines with tiny RAM and large disks. */
+	PUSH_BIT_OPT("dont_load_bitmap", REISER4_DONT_LOAD_BITMAP);
+
+	PUSH_OPT ({
+		/* tree traversal readahead parameters:
+		   -o readahead:MAXNUM:FLAGS
+		   MAXNUM - max number fo nodes to request readahead for: -1UL will set it to max_sane_readahead()
+		   FLAGS - combination of bits: RA_ADJCENT_ONLY, RA_ALL_LEVELS, CONTINUE_ON_PRESENT
+		*/
+		.name = "readahead",
+			 .type = OPT_FORMAT,
+			 .u = {
+				 .f = {
+					 .format  = "%u:%u",
+					 .nr_args = 2,
+					 .arg1 = &sbinfo->ra_params.max,
+					 .arg2 = &sbinfo->ra_params.flags,
+					 .arg3 = NULL,
+					 .arg4 = NULL
+				 }
+			 }
+
+ 	});
+
+	/* What to do in case of fs error */
+	PUSH_OPT ({
+		.name = "onerror",
+			 .type = OPT_ONEOF,
+			 .u = {
+				 .oneof = {
+					 .result = &sbinfo->onerror,
+					 .list = {"panic", "remount-ro", "reboot", NULL},
+				 }
+			 }
+	});
 
 #if REISER4_LOG
-		{
-			.name = "log_file",
-			.type = OPT_STRING,
-			.u = {
-				.string = &log_file_name
-			}
-		},
+	PUSH_OPT({
+		.name = "log_file",
+			 .type = OPT_STRING,
+			 .u = {
+				 .string = &log_file_name
+			 }
+	});
 #endif
-	};
+
+	kfree(opts);
 
 	sbinfo->tmgr.atom_max_size = txnmgr_get_max_atom_size(s);
 	sbinfo->tmgr.atom_max_age = REISER4_ATOM_MAX_AGE / HZ;
@@ -1052,7 +1082,7 @@ reiser4_parse_options(struct super_block
 	sbinfo->ra_params.max = num_physpages / 4;
 	sbinfo->ra_params.flags = 0;
 
-	result = parse_options(opt_string, opts, sizeof_array(opts));
+	result = parse_options(opt_string, opts, p - opts);
 	if (result != 0)
 		return result;
 
_
