mtd_info->size again (lengthy)

Bruce_Leonard at selinc.com Bruce_Leonard at selinc.com
Tue Jun 10 20:09:35 EDT 2008


Jorn,

Well I'm glad I started a lively discussion :).  Most of what you and 
Jamie are talking about are beyond me though so I don't think I'll try and 
contribute.  I'll just keep asking questions to try and understand.

I think I'm starting to glean some things and one of those things is that 
I think I'm in over my head :(.  Are you suggesting that the direction we 
want to move is to change the MTD layer over to function the same way as 
the Block I/O layer?  With all of it's attendant infrastructure?  I've 
read through the 'Block Device Drivers' chapter of 'Understanding the 
Linux Kernal'.  It talks about the I/O scheduler and queues of requests 
consisting of multiple bios which can consist of multiple segments 
(bio_vec?), and a WHOLE lot of 'stuff'.  If that's what we're talking 
about then it's WAY beyond my scope or my abilities.  I'm trying to solve 
a very narrow problem (i.e., I want to access 8GiB of flash as a single 
device using UBI/UBIFS).

So here's what I suggest I can do for you and you can tell me if it'll be 
of any help.  I can continue to ask questions about the code you posted so 
I understand both the plumbing end and the calling end (I'm still a bit 
confused on the struct page part and how to use it), implement basically 
just what you showed me (not anything like I've read about BIO), and try 
to make it work for my UBI/MTD/NAND case.  That would be a start to the 
changes without being beyond my abilities and I can do it in a way that 
should't break any existing code.  Sound resonable or just a waste of 
your's and the list's time?

On to some questions:

> +static int ram_submit_fio(struct mtd_info *mtd, struct fio *fio)
> +{
> +   int i, err = 0;
> +   u32 ofs;
> +   size_t *retlen;
> +   const u_char *buf;
> +   struct fio_vec *vec;
> +
> +   /* This driver cannot deal with device >32bit yet */
> +   if (fio->fi_blockno * mtd->erasesize + fio->block_ofs + fio->fi_len
> +         > 0xffffffff)
> +      return -EIO;
> +
> +   ofs = fio->fi_blockno * mtd->erasesize + fio->block_ofs;
> +
> +   if (fio->fi_command == FI_ERASE) {
> +      memset(mtd->priv + ofs, 0xff, fio->fi_len);
> +      goto out;
> +   }
> +
> +   for (i = 0; i < fio->fi_vcnt; i++) {
> +      vec = fio->fi_io_vec + i;
> +      buf = kmap_atomic(vec->fv_page, KM_USER0);
> +      switch (fio->fi_command) {
> +      case FI_READ:
> +         err = ram_read(mtd, ofs, vec->fv_len, &retlen,
> +               buf + vec->fv_offset);

I don't understand 'struct page' which is probably where my confusion 
comes from.  'ofs' passed to ram_read() is calculated from fi_blockno and 
fi_blockofs.  This makes sense as ram_read() is going to use this as the 
starting location in the "mtd" device to read from.  'buf' is calculated 
from vec->fv_page and vec->fv_offset.  I think this makes sense, as this 
is used by ram_read() is the starting location in fv_page to write to. 
'len' confuses me a bit as it comes from vec->fv_len rather than fi_len. 
Why use the length from the vector rather than the struct fio?  Should 
they be initialized to the same thing?  I would think to use fi_len as the 
calling function should have loaded that at the same time it figured out 
where to start from (i.e., when it loaded fi_blockno and fi_blockofs). I'm 
sure I'm missing something because I've never used struct page before and 
it's probably obvious to someone with more kernel experiance.

Does vec->fv_len represent the remaining length of vec->fv_page?  And 
vec->fv_offset the offset to start accessing vec->fv_page from?  Sorry to 
be asking dumb questions.

Bruce



More information about the linux-mtd mailing list