Skip to contentSkip to conversation

ext4: Update i_diskzie during writepage for delayed allocation.

RFC PATCH In review Aneesh Kumar K.V 2 participants 6 messages Mar 21, 2008 – Mar 24, 2008 ext4 file system

lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 ext4: Update i_diskzie during writepage for delayed allocation.

We need to update i_disksize after allocating blocks. writepages already does this. Update writepage to also update i_disksize.

---
 fs/ext4/inode.c |   40 +++++++++++++++++++++++++++++++++++++++-
 1 files changed, 39 insertions(+), 1 deletions(-)
fs/ext4/inode.c +39 -1
index 79930df..50d700f 100644
@@ -1488,6 +1488,44 @@ out:
 
 	return ret;
 }
+/* FIXME!! only support data=writeback mode */
+static int ext4_da_writepage(struct page *page,
+				struct writeback_control *wbc)
+{
+	struct inode *inode = page->mapping->host;
+	handle_t *handle = NULL;
+	int ret = 0;
+	int err;
+
+	if (ext4_journal_current_handle())
+		goto out_fail;
+
+	handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode));
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		goto out_fail;
+	}
+
+	if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
+		ret = nobh_writepage(page, ext4_get_block, wbc);
+	else
+		ret = block_write_full_page(page, ext4_get_block, wbc);
+
+	if (!ret && inode->i_size > EXT4_I(inode)->i_disksize) {
+		EXT4_I(inode)->i_disksize = inode->i_size;
+		ext4_mark_inode_dirty(handle, inode);
+	}
+
+	err = ext4_journal_stop(handle);
+	if (!ret)
+		ret = err;
+	return ret;
+
+out_fail:
+	redirty_page_for_writepage(wbc, page);
+	unlock_page(page);
+	return ret;
+}
 
 static int ext4_da_writepages(struct address_space *mapping,
 				struct writeback_control *wbc)
@@ -2015,7 +2053,7 @@ static const struct address_space_operations ext4_journalled_aops = {
 static const struct address_space_operations ext4_da_aops = {
 	.readpage	= ext4_readpage,
 	.readpages	= ext4_readpages,
-	.writepage	= ext4_writeback_writepage,
+	.writepage	= ext4_da_writepage,
 	.writepages	= ext4_da_writepages,
 	.sync_page	= block_sync_page,
 	.write_begin	= ext4_da_write_begin,
Signature · 1 line
1.5.5.rc0.16.g02b00.dirty
#1 lore raw

RFC PATCH 1/1 ext4: Return unwritten buffer head when trying to read from prealloc space.

ext4_ext_get_blocks returns number of blocks allocated with buffer head unmapped for a read from prealloc space. This is needed so that delayed allocation doesn't do block reservation for prealloc space since the blocks are already resevred on disk. Fix ext4_ext_get_blocks to not return greater than max_blocks and also mark the buffer head unwritten. Some code path tries to read the block if buffer_head is not new and no uptodate. Marking the buffer head unwritten avoid this reading.

---
 fs/ext4/extents.c |   14 +++++++++++++-
 1 files changed, 13 insertions(+), 1 deletions(-)
fs/ext4/extents.c +13 -1
index d6ae40a..edd1bf2 100644
@@ -2600,8 +2600,20 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
 			}
 			if (create == EXT4_CREATE_UNINITIALIZED_EXT)
 				goto out;
-			if (!create)
+			if (!create) {
+				/*
+				 * We have blocks reserved already. We
+				 * return allocated blocks so that delalloc
+				 * won't do block reservation for us. But
+				 * the buffer head will be unmapped so that
+				 * a read from the block return 0
+				 */
+				if (allocated > max_blocks)
+					allocated = max_blocks;
+				/* mark the buffer unwritten */
+				__set_bit(BH_Unwritten, &bh_result->b_state);
 				goto out2;
+			}
 
 			ret = ext4_ext_convert_to_initialized(handle, inode,
 								path, iblock,
Signature · 1 line
1.5.5.rc0.16.g02b00.dirty
#2 lore raw

Re: [RFC PATCH] ext4: Return unwritten buffer head when trying to read from prealloc space.

Quoted 8 lines · Aneesh Kumar K.V

ext4_ext_get_blocks returns number of blocks allocated with buffer head unmapped for a read from prealloc space. This is needed so that delayed allocation doesn't do block reservation for prealloc space since the blocks are already resevred on disk. Fix ext4_ext_get_blocks to not return greater than max_blocks and also mark the buffer head unwritten. Some code path tries to read the block if buffer_head is not new and no uptodate. Marking the buffer head unwritten avoid this reading.

Seems this patch fixes two bugs together, it would be nice to split to two as they cause two different problems.

To fix the bh->b_size warning solof founds for delayed allocation, I would say we need to fix it in ext4_get_blocks_handle() (for indirect files) and ext4_ext_get_blocks()(for extent files) both, not allowing returning b_size greater than what the caller asking for. Also, the patch below seems only address the preallocation map case, we need to fix in in general block lookup case.

Quoted 31 lines
---
 fs/ext4/extents.c |   14 +++++++++++++-
 1 files changed, 13 insertions(+), 1 deletions(-)
fs/ext4/extents.c +13 -1
index d6ae40a..edd1bf2 100644
@@ -2600,8 +2600,20 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
 			}
 			if (create == EXT4_CREATE_UNINITIALIZED_EXT)
 				goto out;
-			if (!create)
+			if (!create) {
+				/*
+				 * We have blocks reserved already. We
+				 * return allocated blocks so that delalloc
+				 * won't do block reservation for us. But
+				 * the buffer head will be unmapped so that
+				 * a read from the block return 0
+				 */
+				if (allocated > max_blocks)
+					allocated = max_blocks;
+				/* mark the buffer unwritten */
+				__set_bit(BH_Unwritten, &bh_result->b_state);
 				goto out2;
+			}
 
 			ret = ext4_ext_convert_to_initialized(handle, inode,
 								path, iblock,
#3 lore raw

Re: [RFC PATCH] ext4: Return unwritten buffer head when trying to read from prealloc space.

Quoted 10 lines · Mingming Cao
Quoted 8 lines · Aneesh Kumar K.V

ext4_ext_get_blocks returns number of blocks allocated with buffer head unmapped for a read from prealloc space. This is needed so that delayed allocation doesn't do block reservation for prealloc space since the blocks are already resevred on disk. Fix ext4_ext_get_blocks to not return greater than max_blocks and also mark the buffer head unwritten. Some code path tries to read the block if buffer_head is not new and no uptodate. Marking the buffer head unwritten avoid this reading.

Quoted 2 lines

Seems this patch fixes two bugs together, it would be nice to split to two as they cause two different problems.

Split patches here.

http://www.radian.org/~kvaneesh/ext4/patches-to-patchqueue/

Quoted 8 lines

To fix the bh->b_size warning solof founds for delayed allocation, I would say we need to fix it in ext4_get_blocks_handle() (for indirect files) and ext4_ext_get_blocks()(for extent files) both, not allowing returning b_size greater than what the caller asking for. Also, the patch below seems only address the preallocation map case, we need to fix in in general block lookup case.

ext4_ext_get_blocks already make sure we doesn't return > max_blocks. for normal allocation.

2694 out:
2695 if (allocated > max_blocks)
2696 allocated = max_blocks;

-aneesh

#4 lore raw

Re: [RFC PATCH] ext4: Return unwritten buffer head when trying to read from prealloc space.

Quoted 11 lines · Aneesh Kumar K.V
Quoted 10 lines · Mingming Cao
Quoted 8 lines · Aneesh Kumar K.V

ext4_ext_get_blocks returns number of blocks allocated with buffer head unmapped for a read from prealloc space. This is needed so that delayed allocation doesn't do block reservation for prealloc space since the blocks are already resevred on disk. Fix ext4_ext_get_blocks to not return greater than max_blocks and also mark the buffer head unwritten. Some code path tries to read the block if buffer_head is not new and no uptodate. Marking the buffer head unwritten avoid this reading.

Quoted 7 lines
Quoted 2 lines

Seems this patch fixes two bugs together, it would be nice to split to two as they cause two different problems.

Split patches here.

http://www.radian.org/~kvaneesh/ext4/patches-to-patchqueue/

I will pick them up in patch queue.

Quoted 9 lines
Quoted 8 lines

To fix the bh->b_size warning solof founds for delayed allocation, I would say we need to fix it in ext4_get_blocks_handle() (for indirect files) and ext4_ext_get_blocks()(for extent files) both, not allowing returning b_size greater than what the caller asking for. Also, the patch below seems only address the preallocation map case, we need to fix in in general block lookup case.

Quoted 7 lines

ext4_ext_get_blocks already make sure we doesn't return > max_blocks. for normal allocation.

2694 out:
2695 if (allocated > max_blocks)
2696 allocated = max_blocks;

Oh I see, I missed that.

Regards,
Mingming

Quoted 2 lines

-aneesh

#5 lore raw
In reply to Aneesh Kumar K.V
Quoted 3 lines · Aneesh Kumar K.V

We need to update i_disksize after allocating blocks. writepages already does this. Update writepage to also update i_disksize.

I agree that we should update the i_disk size after the allocation, to avoid possible exposing stale data in case of fs crash happened after the metadata hit to disk but before data being written out.

Quoted 63 lines
---
 fs/ext4/inode.c |   40 +++++++++++++++++++++++++++++++++++++++-
 1 files changed, 39 insertions(+), 1 deletions(-)
fs/ext4/inode.c +39 -1
index 79930df..50d700f 100644
@@ -1488,6 +1488,44 @@ out:
 
 	return ret;
 }
+/* FIXME!! only support data=writeback mode */
+static int ext4_da_writepage(struct page *page,
+				struct writeback_control *wbc)
+{
+	struct inode *inode = page->mapping->host;
+	handle_t *handle = NULL;
+	int ret = 0;
+	int err;
+
+	if (ext4_journal_current_handle())
+		goto out_fail;
+
+	handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode));
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		goto out_fail;
+	}
+
+	if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
+		ret = nobh_writepage(page, ext4_get_block, wbc);
+	else
+		ret = block_write_full_page(page, ext4_get_block, wbc);
+
+	if (!ret && inode->i_size > EXT4_I(inode)->i_disksize) {
+		EXT4_I(inode)->i_disksize = inode->i_size;
+		ext4_mark_inode_dirty(handle, inode);
+	}
+
+	err = ext4_journal_stop(handle);
+	if (!ret)
+		ret = err;
+	return ret;
+
+out_fail:
+	redirty_page_for_writepage(wbc, page);
+	unlock_page(page);
+	return ret;
+}
 
 static int ext4_da_writepages(struct address_space *mapping,
 				struct writeback_control *wbc)
@@ -2015,7 +2053,7 @@ static const struct address_space_operations ext4_journalled_aops = {
 static const struct address_space_operations ext4_da_aops = {
 	.readpage	= ext4_readpage,
 	.readpages	= ext4_readpages,
-	.writepage	= ext4_writeback_writepage,
+	.writepage	= ext4_da_writepage,
 	.writepages	= ext4_da_writepages,
 	.sync_page	= block_sync_page,
 	.write_begin	= ext4_da_write_begin,