On Sat, 2007-06-16 at 12:14 +0400, Dmitriy Monakhov wrote: > On 16:16 Птн 15 Июн , Mingming Cao wrote: > > I hit almost the same issue today also, but with different error #, and > > one more kernel oops, when run fsstress on x86_64. > > > > EXT4-fs: writeback error = -2 > > EXT4-fs: writeback error = -2 > This error never happens in writeback in my case, only ENOSPC. I see why, error -2 is ENOENT, your kernel already patched with your previus patch to fix the return error from ext4_reserve_global() from ENOENT to ENOSPC. > > > > I've digged this a litle bit with folowig results: > > > > > > > > int block_read_full_page(struct page *page, get_block_t *get_block) > > > > { > > > > ... > > > > 1914: if (!page_has_buffers(page)) <<< page_has_buffers(page) == true > > > > create_empty_buffers(page, blocksize, 0); > > > > head = page_buffers(page); <<<< page_buffers(page) == NULL > > > > <<<i've add debug info here: > > > > <<< page->flags == 100000000000821 > > > > <<< PagePrivate(page) == 1, (page)->private == NULL > > > > <<< So we have private page without buffers, it is WRONG. > > > > Right, I think the problem is the PagePrivate() is being set without a valid page->private pointer. The PagePrivate flag is being set by delayed allocation in the ext4_wb_commit_write(). Looking at ext4-delayed-allocation.patch +int ext4_wb_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + struct inode *inode = page->mapping->host; + int err = 0; + + wb_debug("commit page %lu (%u-%u) for inode %lu\n", + page->index, from, to, inode->i_ino); + + /* mark page private so that we get + * called to invalidate/release page */ + SetPagePrivate(page); + + if (!PageBooked(page) && !PageMappedToDisk(page)) { + /* ->prepare_write() observed that block for this + * page hasn't been allocated yet. there fore it + * asked to reserve block for later allocation */ + BUG_ON(page->private == 0); + page->private = 0; + err = ext4_wb_reserve_space_page(page, 1); + if (err) + return err; + } It sets the PagePrivate flag at the commit_write() time. And the page- >private is cleared to 0. page->private is being set to 1 at ext4_wb_prepare_write(): +int ext4_wb_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + struct inode *inode = page->mapping->host; + struct buffer_head bh, *bhw = &bh; + int err = 0; + + wb_debug("prepare page %lu (%u-%u) for inode %lu\n", + page->index, from, to, page->mapping->host->i_ino); + + /* if page is uptodate this means that ->prepare_write() has + * been called on page before and page is mapped to disk or + * we did reservation. page is protected and nobody can + * access it. hence, it safe to use page->private to pass + * flag that ->commit_write() has to reserve blocks. because + * an error may occur after ->prepare_write() we should not + * reserve block here. it's better to do in ->commit_write() + * when we're sure page is to be written */ + page->private = 0; + if (!PageUptodate(page)) { + /* first write to this page */ + bh.b_state = 0; + err = ext4_get_block(inode, page->index, bhw, 0); + if (err) + return err; + if (!buffer_mapped(bhw)) { + /* this block isn't allocated yet, reserve space */ + wb_debug("reserve space for new block\n"); + page->private = 1; + ext4_wb_clear_page(page, from, to); + ClearPageMappedToDisk(page); >From the comments it says the page->private is set to 1 to letting commit_write know that it needs block reservation, but I don't see the page->private value being checked in ext4_wb_commit_write(). Instead, the PageMappedToDisk(page) flag is being checked. Alex, can you clarify the use of page->private and PagePrivate flag here? Do we still need the page->private for delayed allocation, with PageBooked flag and PageMappedToDisk page flag? Thanks, Mingming - To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html