Chris Mason wrote:
> Daniel Phillips wrote:
> >
> > Simply stated, the new cache design divides filesystem blocks into two
> > classes: those that can be memory-mapped and those that can't. There
> > is no defined way to move a given block from one class to the other.
> >
> This is the sequence of events for a tail unmerge:
>
> - Fix up various inode fields
> - bread the tail block
> - Allocate new block from ext2, map it into a buffer with getblk
> - Copy the tail fragment to the buffer of the newly allocated block
> - Mark the buffer dirty and go away
>
> It isn't as bad as you think ;-) They key is to only unmerge into the page
> cache. If you can't unmerge only into the page cache, you need to do a
> getblk in your get_block call, and deal with the aliases.
>
> If you unmerge inside ext2_get_block, you get passed bh_result. Just
> change bh_result->b_blocknr to your new block, set b_dev, and set it
> mapped, and copy the tail into bh_result. Then block_write_full_page or
> block_commit_write are the ones that dirty bh_result for you, no alias
> created.
The fly in the ointment is that the file size may have changed by this
time. I rely on the file size to tell me which block is the tail
block and when the file size changes I unmerge the tail - nice simple
idea, right? I could keep my own "blocks" field to tell me where the
tail is, but that road descends to hell.
After thinking about it last night I saw the correct approach. I need
a new page cache primitive:
struct page *getpage (struct address_space *mapping, unsigned long
index)
This is getblk, except for pages. It finds or sets up a page in a
mapping. It puts buffers on the page if necessary but doesn't cause
any I/O action.
I also need another function, and I'll write it right now:
struct buffer_head *page_buffer (struct page *page, int i)
{
struct buffer_head *bh = page->buffers;
while (i--)
bh = bh->b_this_page;
return bh;
}
Getpage isn't as easy as this, but it's not that hard either. A
gutted version of do_generic_read_page serves the purpose; the result
is fairly pleasing to the eye (but is for my eyes only until I've
tested it).
Now I can unmerge this way:
- Fix up various inode fields
- getpage the tail page from the mapping
- bread the shared tail block
- get the appropriate page buffer using page_buffer
- copy the tail fragment to that buffer and dirty it
I can do this at a high level - the place where the unmerge conditions
are most easily and accurately detected - as opposed to deep in the
guts of the page I/O. The page is left in a state that already makes
sense to read_page, write_page and friends.
The only question is: should I do it the correct way or should I do a
messy hack "just for now" using the existing page primitives. Fix the
symptom or go after the deep problem? Considering that for about one
nanosecond I decide to do the right thing, and lo! I find myself in a
new cave.
--
Daniel
-
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to [EMAIL PROTECTED]