On Wed, 01 May 2013 16:39:30 +0900 (JST) Ryusuke Konishi
<[email protected]> wrote:
> DESCRIPTION:
> There are use-cases when NILFS2 file system (formatted with block size
> lesser than 4 KB) can be remounted in RO mode because of encountering
> of "broken bmap" issue.
>
> ...
>
> --- a/fs/nilfs2/inode.c
> +++ b/fs/nilfs2/inode.c
> @@ -219,13 +219,25 @@ static int nilfs_writepage(struct page *page, struct
> writeback_control *wbc)
>
> static int nilfs_set_page_dirty(struct page *page)
> {
> - int ret = __set_page_dirty_buffers(page);
> + int ret = __set_page_dirty_nobuffers(page);
>
> - if (ret) {
> + if (page_has_buffers(page)) {
> struct inode *inode = page->mapping->host;
> - unsigned nr_dirty = 1 << (PAGE_SHIFT - inode->i_blkbits);
> + unsigned nr_dirty = 0;
> + struct buffer_head *bh, *head;
>
> - nilfs_set_file_dirty(inode, nr_dirty);
> + bh = head = page_buffers(page);
> + do {
> + /* Do not mark hole blocks dirty */
> + if (!buffer_dirty(bh) || !buffer_mapped(bh))
> + continue;
> +
> + set_buffer_dirty(bh);
This doesn't seem right. The only time we will run set_buffer_dirty()
is if the buffer was dirty and mapped. What's the point in running
set_buffer_dirty() against an already dirty buffer?
I suspect you intended (buffer_dirty || !buffer_mapped)
> + nr_dirty++;
> + } while (bh = bh->b_this_page, bh != head);
> +
> + if (nr_dirty)
> + nilfs_set_file_dirty(inode, nr_dirty);
Rather secondarily: the above code appears to assume that no other
thread can come in and mark a buffer dirty while the loop is executing.
This *should* be OK - the page is locked (or it should be). Can you
confirm that this is the case? There are no other places where a
buffer can be concurrently dirtied against an unlocked page?
> }
> return ret;
> }
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html