aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext3/inode.c85
1 files changed, 10 insertions, 75 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 8a824f4ce5c6..a5b150f7e8a2 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1148,102 +1148,37 @@ static int do_journal_get_write_access(handle_t *handle,
1148 return ext3_journal_get_write_access(handle, bh); 1148 return ext3_journal_get_write_access(handle, bh);
1149} 1149}
1150 1150
1151/*
1152 * The idea of this helper function is following:
1153 * if prepare_write has allocated some blocks, but not all of them, the
1154 * transaction must include the content of the newly allocated blocks.
1155 * This content is expected to be set to zeroes by block_prepare_write().
1156 * 2006/10/14 SAW
1157 */
1158static int ext3_prepare_failure(struct file *file, struct page *page,
1159 unsigned from, unsigned to)
1160{
1161 struct address_space *mapping;
1162 struct buffer_head *bh, *head, *next;
1163 unsigned block_start, block_end;
1164 unsigned blocksize;
1165 int ret;
1166 handle_t *handle = ext3_journal_current_handle();
1167
1168 mapping = page->mapping;
1169 if (ext3_should_writeback_data(mapping->host)) {
1170 /* optimization: no constraints about data */
1171skip:
1172 return ext3_journal_stop(handle);
1173 }
1174
1175 head = page_buffers(page);
1176 blocksize = head->b_size;
1177 for ( bh = head, block_start = 0;
1178 bh != head || !block_start;
1179 block_start = block_end, bh = next)
1180 {
1181 next = bh->b_this_page;
1182 block_end = block_start + blocksize;
1183 if (block_end <= from)
1184 continue;
1185 if (block_start >= to) {
1186 block_start = to;
1187 break;
1188 }
1189 if (!buffer_mapped(bh))
1190 /* prepare_write failed on this bh */
1191 break;
1192 if (ext3_should_journal_data(mapping->host)) {
1193 ret = do_journal_get_write_access(handle, bh);
1194 if (ret) {
1195 ext3_journal_stop(handle);
1196 return ret;
1197 }
1198 }
1199 /*
1200 * block_start here becomes the first block where the current iteration
1201 * of prepare_write failed.
1202 */
1203 }
1204 if (block_start <= from)
1205 goto skip;
1206
1207 /* commit allocated and zeroed buffers */
1208 return mapping->a_ops->commit_write(file, page, from, block_start);
1209}
1210
1211static int ext3_prepare_write(struct file *file, struct page *page, 1151static int ext3_prepare_write(struct file *file, struct page *page,
1212 unsigned from, unsigned to) 1152 unsigned from, unsigned to)
1213{ 1153{
1214 struct inode *inode = page->mapping->host; 1154 struct inode *inode = page->mapping->host;
1215 int ret, ret2; 1155 int ret, needed_blocks = ext3_writepage_trans_blocks(inode);
1216 int needed_blocks = ext3_writepage_trans_blocks(inode);
1217 handle_t *handle; 1156 handle_t *handle;
1218 int retries = 0; 1157 int retries = 0;
1219 1158
1220retry: 1159retry:
1221 handle = ext3_journal_start(inode, needed_blocks); 1160 handle = ext3_journal_start(inode, needed_blocks);
1222 if (IS_ERR(handle)) 1161 if (IS_ERR(handle)) {
1223 return PTR_ERR(handle); 1162 ret = PTR_ERR(handle);
1163 goto out;
1164 }
1224 if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) 1165 if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode))
1225 ret = nobh_prepare_write(page, from, to, ext3_get_block); 1166 ret = nobh_prepare_write(page, from, to, ext3_get_block);
1226 else 1167 else
1227 ret = block_prepare_write(page, from, to, ext3_get_block); 1168 ret = block_prepare_write(page, from, to, ext3_get_block);
1228 if (ret) 1169 if (ret)
1229 goto failure; 1170 goto prepare_write_failed;
1230 1171
1231 if (ext3_should_journal_data(inode)) { 1172 if (ext3_should_journal_data(inode)) {
1232 ret = walk_page_buffers(handle, page_buffers(page), 1173 ret = walk_page_buffers(handle, page_buffers(page),
1233 from, to, NULL, do_journal_get_write_access); 1174 from, to, NULL, do_journal_get_write_access);
1234 if (ret)
1235 /* fatal error, just put the handle and return */
1236 journal_stop(handle);
1237 } 1175 }
1238 return ret; 1176prepare_write_failed:
1239 1177 if (ret)
1240failure: 1178 ext3_journal_stop(handle);
1241 ret2 = ext3_prepare_failure(file, page, from, to);
1242 if (ret2 < 0)
1243 return ret2;
1244 if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) 1179 if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
1245 goto retry; 1180 goto retry;
1246 /* retry number exceeded, or other error like -EDQUOT */ 1181out:
1247 return ret; 1182 return ret;
1248} 1183}
1249 1184