Alexander Viro wrote:
> frankly, I see no point in "put buffers on page if it's a block-based fs
> that uses buffer_heads, but don't map them" as a method.
I finally understand where this comment came from. The current
arrangement doesn't handle unmapped buffers on a page very well. As
soon as you mark the unmapped buffer dirty it goes on the dirty list,
then after a while bdflush comes along and feeds an unmapped buffer to
ll_rw_block, which freaks out. I dealt with this by doing an
ext2_get_block right after putting the buffers on the page, just to
avoid leaving an unmapped, dirty buffer hanging on the buffer lists.
There is no good reason why you can't have an unmapped, dirty buffer
on a page, because you there is a readily available method that knows
how to map it: prepare_write. The only problem is the current dirty
list handling. I have a general sort of intuition that it's good to
be able to defer block allocation as long as possible because you
might be able to do a little optimization, or you might find the
problem went away while you procrastinated. The current mechanism
doesn't seem to be written with that in mind, but I think it can be
iterated in that direction, and even be simplified in the process.
I'll just try to forget about this until 2.5 gets underway.
static
Here is the current untailing code. The idea of this code is to get
the tail fragment out of the shared tail block and onto a regular file
page without creating an alias:
u32 iblock = (size >> bbits);
u32 *tp = inode->u.ext2_i.i_data + iblock;
struct buffer_head *newbh;
struct buffer_head *oldbh = bread (sb->s_dev, *tp, sb->s_blocksize);
struct page *page = grab_cache_page(inode->i_mapping,
size>>PAGE_SHIFT);
if (!page->buffers) create_empty_buffers (page, inode, bsize);
newbh = page_buffer (page, (size & (PAGE_SIZE-1)) >> bbits);
memcpy (newbh->b_data, oldbh->b_data + toff, size & bmask);
*tp = 0; /* forget about the shared tail block */
inode->i_blocks -= 1 << (bbits - 9); /* bad old sector count */
ext2_get_block (inode, iblock, newbh, 1);
newbh->b_state &= ~(1UL << BH_New); /* suppress this state */
mark_buffer_uptodate (newbh, 1);
mark_buffer_dirty (newbh);
SetPageDirty(page);
UnlockPage (page);
page_cache_release (page);
brelse (oldbh);
--
Daniel
-
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to [EMAIL PROTECTED]