2005-10-07 06:01:45

by Block Device

[permalink] [raw]
Subject: Block I/O Mystery

Hi,
I am trying to write to inode blocks without using the VFS layer
(filp_open, f_op->write)
etc.
I could use __bread to read the inode blocks correctly. But when I'm
trying to write a block after changing it I face a strange problem.
My changes do not show up when I cat the file but if I use dd command on
the block device it shows my writes.

Steps I performed :

a) Created a file of 8K ( 2blocks ) and filled it with 'a'.
b) Read the blocks using __bread and print(k)ed the contents.
This worked correctly.
c) Called __getblk for a file block, locked the buffer, made
changes to it (memcpy),
marked buffer dirty, unlocked it and called sync_dirty_buffer.
d) If I try to see contents of the file ( cat or vi ) they are
shown unchanged, but if I
use dd on the raw device or use step b) to read a block the
changes made @ c)
are seen.

Also, if I unmount the filesystem and mount it again the changes are
visible through cat, vi etc.

Can someone explain what exactly is going wrong ?

I'm using the 2.6.13 kernel.

Thanks & Regards
-BD


2005-10-07 10:46:59

by Nikita Danilov

[permalink] [raw]
Subject: Re: Block I/O Mystery

Block Device writes:
> Hi,
> I am trying to write to inode blocks without using the VFS layer
> (filp_open, f_op->write)
> etc.
> I could use __bread to read the inode blocks correctly. But when I'm
> trying to write a block after changing it I face a strange problem.
> My changes do not show up when I cat the file but if I use dd command on
> the block device it shows my writes.
>
> Steps I performed :
>

Blocks read by bread() and friends are cached in block device (not you
:-) struct address_space. File data are cached in the per-inode struct
address_space.

> a) Created a file of 8K ( 2blocks ) and filled it with 'a'.

Now 2 pages are cached in memory in address_space associated with inode.

> b) Read the blocks using __bread and print(k)ed the contents.
> This worked correctly.

This reads blocks directly from the disk (igrnoing cached copy), and
caches them in block device address_space.

> c) Called __getblk for a file block, locked the buffer, made
> changes to it (memcpy),
> marked buffer dirty, unlocked it and called sync_dirty_buffer.

This makes changes to the block cached in block device address_space.

> d) If I try to see contents of the file ( cat or vi ) they are
> shown unchanged, but if I

vi uses read(1), and, hence, will fetch data from inode address_space,
where original pages still live.

> use dd on the raw device or use step b) to read a block the
> changes made @ c)
> are seen.

And this will read from block device cache.

>
> Also, if I unmount the filesystem and mount it again the changes are
> visible through cat, vi etc.
>
> Can someone explain what exactly is going wrong ?

You are bypassing normal file sysetm caching and results can be
unpredictable.

>
> I'm using the 2.6.13 kernel.
>
> Thanks & Regards
> -BD

Nikita.

2005-10-07 11:36:39

by Block Device

[permalink] [raw]
Subject: Re: Block I/O Mystery

Hi,

After some more toying around, I have seen that it works correctly
on ext2 fs but not
on etx3. :) ...

My questions inline ..

On 10/7/05, Nikita Danilov <[email protected]> wrote:

> Blocks read by bread() and friends are cached in block device (not you
> :-) struct address_space. File data are cached in the per-inode struct
> address_space.

But even if I'm reading blocks from a device directly, they are
finally blocks from the same inode. Why then are they stored
separately ?

> You are bypassing normal file sysetm caching and results can be
> unpredictable.

Is there then a safe way to do it w/o going through the filesystem caching ?

If not, I guess the following steps will be required :
a) Find out the page in the mapping corresponding to the blocks I need
to write.
b) Lock the page. Make changes. Mark it dirty and sync write it ?

Is there something in the kernel which does this already ?

Thanks for the help :) !

-Regards
BD

2005-10-07 11:56:38

by Nikita Danilov

[permalink] [raw]
Subject: Re: Block I/O Mystery

Block Device writes:
> Hi,
>
> After some more toying around, I have seen that it works correctly
> on ext2 fs but not
> on etx3. :) ...
>
> My questions inline ..
>
> On 10/7/05, Nikita Danilov <[email protected]> wrote:
>
> > Blocks read by bread() and friends are cached in block device (not you
> > :-) struct address_space. File data are cached in the per-inode struct
> > address_space.
>
> But even if I'm reading blocks from a device directly, they are
> finally blocks from the same inode. Why then are they stored
> separately ?

bread() has no idea about "inode". It just reads block number N from
device D. And this is how it is stored in the cache (and can later be
found there): "device D, block N".

read(), on the other hand, reads logical block i from file F, and this
is how that block (page actually) is cached: "file F, page with logical
number i within file".

These two caching mechanisms are disjoint and almost no form of
coherency is maintained between them.

All this, of course, is up to file system to implement, and different
file systems do this slightly differently.

Nikita.