public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
From: Rainer Weikusat <rainer.weikusat@sncag.com>
To: linux-kernel@vger.kernel.org
Subject: write support for MTD partitions w/ multiple erase sizes
Date: Wed, 22 Dec 2004 21:38:04 +0100	[thread overview]
Message-ID: <874qiekr0z.fsf@farside.sncag.com> (raw)

The MTD partition setup code in drivers/mtd/mtdpart.c doesn't
copy erase region info from master to slave devices, but instead
(wrongfully) prints a message that MTD partitions spanning multiple
erase regions cannot be written to and forces them to be read-only.
The following patch adds a function that does copy this information,
which enables writing to such MTD partitions as long as they begin
and end on an erase block boundary. The patch is against 2.4.28, but
can be used with 2.6.9, too. It hasn't been tested with anything more
esoteric than a MTD partition starting in one erase region and
ending in the next (is this even possible?)

--- linux-2.4.28/drivers/mtd/mtdpart.c	2004-12-19 16:02:48.000000000 +0100
+++ linux-eli/drivers/mtd/mtdpart.c	2004-12-19 20:47:15.000000000 +0100
@@ -272,6 +272,7 @@
 			__list_del(prev, node->next);
 			if(slave->registered)
 				del_mtd_device(&slave->mtd);
+			kfree(slave->mtd.eraseregions);
 			kfree(slave);
 			node = prev;
 		}
@@ -281,12 +282,98 @@
 }
 
 /*
- * This function, given a master MTD object and a partition table, creates
+ * These functions, given a master MTD object and a partition table, creates
  * and registers slave MTD objects which are bound to the master according to
  * the partition definitions.
  * (Q: should we register the master MTD object as well?)
  */
 
+static void setup_erase_regions(struct mtd_info const *master,
+				struct mtd_info *slave, u_int32_t slave_offset)
+/*
+  Setup erase region info for slave devices.
+*/
+{
+#define region_end(region) (region.offset + region.erasesize * region.numblocks)
+	
+	struct mtd_erase_region_info *master_regions, *slave_regions;
+	unsigned first, last, ofs, n, remain;
+
+	slave->numeraseregions = 0;
+	if (master->numeraseregions == 1) {
+		slave->erasesize = master->erasesize;
+		return;
+	}
+	
+	master_regions = master->eraseregions;
+	slave->erasesize = 0;
+
+	first = 0;
+	while (region_end(master_regions[first]) <= slave_offset) ++first;
+	slave->erasesize = master_regions[first].erasesize;
+
+	last = first;
+	n = slave_offset + slave->size;
+	while (region_end(master_regions[last]) < n) {
+		++last;
+		
+		if (master_regions[last].erasesize > slave->erasesize)
+			slave->erasesize = master_regions[last].erasesize;
+	}
+
+	if (slave_offset % master_regions[first].erasesize) {
+	    printk("partition \"%s\" does not start on an erase"
+		   " block boundary -- forcing read-only\n", slave->name);
+	    goto force_read_only;
+	}
+	
+	slave_regions = kmalloc(sizeof(*slave_regions) * (last - first + 1),
+				GFP_KERNEL);
+	if (!slave_regions) {
+		printk("partition \"%s\": could not allocate memory for erase"
+		       " region information\n", slave->name);
+		printk("forcing read-only\n");
+		goto force_read_only;
+	}
+	
+	ofs = n = 0;
+	slave_regions[n].offset = ofs;
+	slave_regions[n].erasesize = master_regions[first].erasesize;
+	slave_regions[n].numblocks = master_regions[first].numblocks;
+	slave_regions[n].numblocks -=
+		(slave_offset - master_regions[first].offset)
+		/ slave_regions[n].erasesize;
+	ofs += slave_regions[n].numblocks * slave_regions[n].erasesize;
+
+	while (first + ++n < last) {
+		slave_regions[n].offset = ofs;
+		slave_regions[n].erasesize = master_regions[first + n].erasesize;
+		slave_regions[n].numblocks = master_regions[first + n].numblocks;
+		ofs += slave_regions[n].numblocks * slave_regions[n].erasesize;
+	}
+	
+	remain = slave->size - ofs;
+	
+	if (remain % master_regions[last].erasesize) {
+		printk("partition \"%s\" does not end on an erase block boundary\n"
+		       " -- forcing read-only\n", slave->name);
+		kfree(slave_regions);
+		goto force_read_only;
+	}
+		
+	slave_regions[n].offset = ofs;
+	slave_regions[n].erasesize = master_regions[last].erasesize;
+	slave_regions[n].numblocks = remain / master_regions[last].erasesize;
+
+	slave->eraseregions = slave_regions;
+	slave->numeraseregions = last - first + 1;
+	return;
+
+ force_read_only:
+	slave->flags &= ~(MTD_WRITEABLE | MTD_ERASEABLE);
+#undef region_end
+}
+
 int add_mtd_partitions(struct mtd_info *master, 
 		       struct mtd_partition *parts,
 		       int nbparts)
@@ -399,39 +486,8 @@
 			printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n",
 				parts[i].name, master->name, slave->mtd.size);
 		}
-		if (master->numeraseregions>1) {
-			/* Deal with variable erase size stuff */
-			int i;
-			struct mtd_erase_region_info *regions = master->eraseregions;
-			
-			/* Find the first erase regions which is part of this partition. */
-			for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
-				;
-
-			for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) {
-				if (slave->mtd.erasesize < regions[i].erasesize) {
-					slave->mtd.erasesize = regions[i].erasesize;
-				}
-			}
-		} else {
-			/* Single erase size */
-			slave->mtd.erasesize = master->erasesize;
-		}
-
-		if ((slave->mtd.flags & MTD_WRITEABLE) && 
-		    (slave->offset % slave->mtd.erasesize)) {
-			/* Doesn't start on a boundary of major erase size */
-			/* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
-			slave->mtd.flags &= ~MTD_WRITEABLE;
-			printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
-				parts[i].name);
-		}
-		if ((slave->mtd.flags & MTD_WRITEABLE) && 
-		    (slave->mtd.size % slave->mtd.erasesize)) {
-			slave->mtd.flags &= ~MTD_WRITEABLE;
-			printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
-				parts[i].name);
-		}
+		
+		setup_erase_regions(master, &slave->mtd, slave->offset);
 
 		if(parts[i].mtdp)
 		{	/* store the object pointer (caller may or may not register it */

                 reply	other threads:[~2004-12-22 20:58 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=874qiekr0z.fsf@farside.sncag.com \
    --to=rainer.weikusat@sncag.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox