Index: kexec-tools-2.0.0/kexec/arch/ppc64/fs2dt.c
===================================================================
--- kexec-tools-2.0.0.orig/kexec/arch/ppc64/fs2dt.c	2011-05-31 01:29:40.000000000 -0500
+++ kexec-tools-2.0.0/kexec/arch/ppc64/fs2dt.c	2011-05-31 01:32:55.447240900 -0500
@@ -35,13 +35,14 @@
 
 #define MAXPATH 1024		/* max path name length */
 #define NAMESPACE 16384		/* max bytes for property names */
-#define TREEWORDS 131070	/* max 32 bit words for property values */
+#define INIT_TREE_WORDS 65536	/* Initial num words for prop values */
 #define MEMRESERVE 256		/* max number of reserved memory blocks */
-#define MAX_MEMORY_RANGES 1024
+#define MEM_RANGE_CHUNK_SZ 2048 /* Initial num dwords for mem ranges */
 
 static char pathname[MAXPATH], *pathstart;
 static char propnames[NAMESPACE] = { 0 };
-static unsigned dtstruct[TREEWORDS] __attribute__ ((aligned (8))), *dt;
+static unsigned *dt_base, *dt;
+static unsigned int dt_cur_size;
 static unsigned long long mem_rsrv[2*MEMRESERVE] = { 0, 0 };
 
 static int crash_param = 0;
@@ -51,6 +52,28 @@
 extern mem_rgns_t usablemem_rgns;
 static struct bootblock bb[1];
 
+/* Before we add something to the dt, reserve N words using this.
+ * If there isn't enough room, it's realloced -- and you don't overflow and
+ * splat bits of your heap.
+ */
+void dt_reserve(unsigned **dt_ptr, unsigned words)
+{
+	if (((*dt_ptr - dt_base) + words) >= dt_cur_size) {
+		int offset;
+		unsigned int new_size = dt_cur_size + INIT_TREE_WORDS;
+		unsigned *new_dt = realloc(dt_base, new_size*4);
+
+		if (!new_dt)
+			die("unrecoverable error: Can't realloc %d bytes for "
+			    "device tree\n", new_size*4);
+		offset = *dt_ptr - dt_base;
+		dt_base = new_dt;
+		dt_cur_size = new_size;
+		*dt_ptr = dt_base + offset;
+		memset(*dt_ptr, 0, (new_size - offset)*4);
+	}
+}
+
 void reserve(unsigned long long where, unsigned long long length)
 {
 	size_t offset;
@@ -126,7 +149,8 @@
 {
 	char fname[MAXPATH], *bname;
 	uint64_t buf[32];
-	uint64_t ranges[2*MAX_MEMORY_RANGES];
+	uint64_t *ranges;
+	int ranges_size = MEM_RANGE_CHUNK_SZ;
 	uint64_t base, end, loc_base, loc_end;
 	int range, rlen = 0, i;
 	int rngs_cnt, tmp_indx;
@@ -142,6 +166,11 @@
 		die("unrecoverable error: error seeking in \"%s\": %s\n",
 			pathname, strerror(errno));
 
+	ranges = malloc(ranges_size*8);
+	if (!ranges)
+		die("unrecoverable error: can't alloc %d bytes for ranges.\n",
+		    ranges_size*8);
+
 	rlen = 0;
 	for (i = 0; i < num_of_lmbs; i++) {
 		if (read(fd, buf, 24) < 0)
@@ -157,36 +186,71 @@
 
 		rngs_cnt = 0;
 		for (range = 0; range < usablemem_rgns.size; range++) {
+			int add = 0;
 			loc_base = usablemem_rgns.ranges[range].start;
 			loc_end = usablemem_rgns.ranges[range].end;
 			if (loc_base >= base && loc_end <= end) {
-				ranges[rlen++] = loc_base;
-				ranges[rlen++] = loc_end - loc_base;
-				rngs_cnt++;
+				add = 1;
 			} else if (base < loc_end && end > loc_base) {
 				if (loc_base < base)
 					loc_base = base;
 				if (loc_end > end)
 					loc_end = end;
+				add = 1;
+			}
+
+			if (add) {
+				if (rlen >= (ranges_size-2)) {
+					ranges_size += MEM_RANGE_CHUNK_SZ;
+					ranges = realloc(ranges, ranges_size*8);
+					if (!ranges)
+						die("unrecoverable error: can't"
+						    " realloc %d bytes for"
+						    " ranges.\n",
+						    ranges_size*8);
+				}
 				ranges[rlen++] = loc_base;
 				ranges[rlen++] = loc_end - loc_base;
 				rngs_cnt++;
 			}
 		}
-		/* Store the count of (base, size) duple */
-		ranges[tmp_indx] = rngs_cnt;
+		if (rngs_cnt == 0) {
+			/* We still need to add a counter for every LMB because
+			 * the kernel parsing code is dumb.  We just have
+			 * a zero in this case, with no following base/len.
+			 */
+			ranges[tmp_indx] = 0;
+			/* rlen is already just tmp_indx+1 as we didn't write
+			 * anything.  Check array size here, as we'll probably
+			 * go on for a while writing zeros now.
+			 */
+			if (rlen >= (ranges_size-1)) {
+				ranges_size += MEM_RANGE_CHUNK_SZ;
+				ranges = realloc(ranges, ranges_size*8);
+				if (!ranges)
+					die("unrecoverable error: can't"
+					    " realloc %d bytes for"
+					    " ranges.\n",
+					    ranges_size*8);
+			}
+		} else {
+			/* Store the count of (base, size) duple */
+			ranges[tmp_indx] = rngs_cnt;
+		}
 	}
 		
 	rlen = rlen * sizeof(uint64_t);
 	/*
 	 * Add linux,drconf-usable-memory property.
 	 */
+	dt_reserve(&dt, 4+((rlen + 3)/4));
 	*dt++ = 3;
 	*dt++ = rlen;
 	*dt++ = propnum("linux,drconf-usable-memory");
 	if ((rlen >= 8) && ((unsigned long)dt & 0x4))
 		dt++;
-	memcpy(dt, &ranges, rlen);
+	memcpy(dt, ranges, rlen);
+	free(ranges);
 	dt += (rlen + 3)/4;
 }
 
@@ -194,7 +258,8 @@
 {
 	char fname[MAXPATH], *bname;
 	uint64_t buf[2];
-	uint64_t ranges[2*MAX_MEMORY_RANGES];
+	uint64_t *ranges;
+	int ranges_size = MEM_RANGE_CHUNK_SZ;
 	uint64_t base, end, loc_base, loc_end;
 	int range, rlen = 0;
 
@@ -221,17 +286,33 @@
 	base = buf[0];
 	end = base + buf[1];
 
+	ranges = malloc(ranges_size*8);
+	if (!ranges)
+		die("unrecoverable error: can't alloc %d bytes for ranges.\n",
+		    ranges_size*8);
+
 	for (range = 0; range < usablemem_rgns.size; range++) {
+		int add = 0;
 		loc_base = usablemem_rgns.ranges[range].start;
 		loc_end = usablemem_rgns.ranges[range].end;
 		if (loc_base >= base && loc_end <= end) {
-			ranges[rlen++] = loc_base;
-			ranges[rlen++] = loc_end - loc_base;
+			add = 1;
 		} else if (base < loc_end && end > loc_base) {
 			if (loc_base < base)
 				loc_base = base;
 			if (loc_end > end)
 				loc_end = end;
+			add = 1;
+		}
+		if (add) {
+			if (rlen >= (ranges_size-2)) {
+				ranges_size += MEM_RANGE_CHUNK_SZ;
+				ranges = realloc(ranges, ranges_size*8);
+				if (!ranges)
+					die("unrecoverable error: can't realloc"
+					    "%d bytes for ranges.\n",
+					    ranges_size*8);
+			}
 			ranges[rlen++] = loc_base;
 			ranges[rlen++] = loc_end - loc_base;
 		}
@@ -251,12 +332,14 @@
 	/*
 	 * No add linux,usable-memory property.
 	 */
+	dt_reserve(&dt, 4+((rlen + 3)/4));
 	*dt++ = 3;
 	*dt++ = rlen;
 	*dt++ = propnum("linux,usable-memory");
 	if ((rlen >= 8) && ((unsigned long)dt & 0x4))
 		dt++;
-	memcpy(dt,&ranges,rlen);
+	memcpy(dt, ranges, rlen);
+	free(ranges);
 	dt += (rlen + 3)/4;
 }
 
@@ -313,6 +396,7 @@
 
 		len = statbuf.st_size;
 
+		dt_reserve(&dt, 4+((len + 3)/4));
 		*dt++ = 3;
 		dt_len = dt;
 		*dt++ = len;
@@ -380,13 +464,17 @@
 	struct dirent **namelist;
 	int numlist, i;
 	struct stat statbuf;
+	int plen;
 
+	plen = *pathstart ? strlen(pathstart) : 1;
+	/* Reserve space for string packed to words; e.g. string length 10
+	 * occupies 3 words, length 12 occupies 4 (for terminating \0s).
+	 * So round up & include the \0:
+	 */
+	dt_reserve(&dt, 1+((plen + 4)/4));
 	*dt++ = 1;
 	strcpy((void *)dt, *pathstart ? pathstart : "/");
-	while(*dt)
-		dt++;
-	if (dt[-1] & 0xff)
-		dt++;
+	dt += ((plen + 4)/4);
 
 	numlist = scandir(pathname, &namelist, 0, comparefunc);
 	if (numlist < 0)
@@ -407,6 +495,8 @@
 	if (initrd_base && !strcmp(basename,"/chosen/")) {
 		int len = 8;
 		unsigned long long initrd_end;
+
+		dt_reserve(&dt, 12); /* both props, of 6 words ea. */
 		*dt++ = 3;
 		*dt++ = len;
 		*dt++ = propnum("linux,initrd-start");
@@ -477,6 +567,7 @@
 		cmd_len = cmd_len + 1;
 
 		/* add new bootargs */
+		dt_reserve(&dt, 4+((cmd_len+3)/4));
 		*dt++ = 3;
 		*dt++ = cmd_len;
 		*dt++ = propnum("bootargs");
@@ -504,6 +595,7 @@
 			putnode();
 	}
 
+	dt_reserve(&dt, 1);
 	*dt++ = 2;
 	dn[-1] = '\0';
 	free(namelist);
@@ -522,12 +614,21 @@
 	strcpy(pathname, "/proc/device-tree/");
 
 	pathstart = pathname + strlen(pathname);
-	dt = dtstruct;
+
+	dt_cur_size = INIT_TREE_WORDS;
+	dt_base = malloc(dt_cur_size*4);
+	if (!dt_base) {
+		die("Can't malloc %d bytes for dt struct!\n", dt_cur_size*4);
+	}
+	memset(dt_base, 0, dt_cur_size*4);
+
+	dt = dt_base;
 
 	if (cmdline)
 		strcpy(local_cmdline, cmdline);
 
 	putnode();
+	dt_reserve(&dt, 1);
 	*dt++ = 9;
 
 	len = sizeof(bb[0]);
@@ -542,7 +643,7 @@
 
 	bb->off_dt_struct = bb->off_mem_rsvmap + len;
 
-	len = dt - dtstruct;
+	len = dt - dt_base;
 	len *= sizeof(unsigned);
 	bb->off_dt_strings = bb->off_dt_struct + len;
 
@@ -562,10 +663,11 @@
 	tlen = bb->off_mem_rsvmap;
 	memcpy(buf+tlen, mem_rsrv, bb->off_dt_struct - bb->off_mem_rsvmap);
 	tlen = tlen + (bb->off_dt_struct - bb->off_mem_rsvmap);
-	memcpy(buf+tlen, dtstruct,  bb->off_dt_strings - bb->off_dt_struct);
+	memcpy(buf+tlen, dt_base,  bb->off_dt_strings - bb->off_dt_struct);
 	tlen = tlen +  (bb->off_dt_strings - bb->off_dt_struct);
 	memcpy(buf+tlen, propnames,  bb->totalsize - bb->off_dt_strings);
 	tlen = tlen + bb->totalsize - bb->off_dt_strings;
 	*sizep = tlen;
+	free(dt_base);
 	return 0;
 }
