diff options
Diffstat (limited to 'fs/ext3/inode.c')
-rw-r--r-- | fs/ext3/inode.c | 139 |
1 files changed, 74 insertions, 65 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 4a09ff169870..d3ef6566b019 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -1149,12 +1149,15 @@ static int ext3_write_begin(struct file *file, struct address_space *mapping, | |||
1149 | struct page **pagep, void **fsdata) | 1149 | struct page **pagep, void **fsdata) |
1150 | { | 1150 | { |
1151 | struct inode *inode = mapping->host; | 1151 | struct inode *inode = mapping->host; |
1152 | int ret, needed_blocks = ext3_writepage_trans_blocks(inode); | 1152 | int ret; |
1153 | handle_t *handle; | 1153 | handle_t *handle; |
1154 | int retries = 0; | 1154 | int retries = 0; |
1155 | struct page *page; | 1155 | struct page *page; |
1156 | pgoff_t index; | 1156 | pgoff_t index; |
1157 | unsigned from, to; | 1157 | unsigned from, to; |
1158 | /* Reserve one block more for addition to orphan list in case | ||
1159 | * we allocate blocks but write fails for some reason */ | ||
1160 | int needed_blocks = ext3_writepage_trans_blocks(inode) + 1; | ||
1158 | 1161 | ||
1159 | index = pos >> PAGE_CACHE_SHIFT; | 1162 | index = pos >> PAGE_CACHE_SHIFT; |
1160 | from = pos & (PAGE_CACHE_SIZE - 1); | 1163 | from = pos & (PAGE_CACHE_SIZE - 1); |
@@ -1184,15 +1187,20 @@ retry: | |||
1184 | } | 1187 | } |
1185 | write_begin_failed: | 1188 | write_begin_failed: |
1186 | if (ret) { | 1189 | if (ret) { |
1187 | ext3_journal_stop(handle); | ||
1188 | unlock_page(page); | ||
1189 | page_cache_release(page); | ||
1190 | /* | 1190 | /* |
1191 | * block_write_begin may have instantiated a few blocks | 1191 | * block_write_begin may have instantiated a few blocks |
1192 | * outside i_size. Trim these off again. Don't need | 1192 | * outside i_size. Trim these off again. Don't need |
1193 | * i_size_read because we hold i_mutex. | 1193 | * i_size_read because we hold i_mutex. |
1194 | * | ||
1195 | * Add inode to orphan list in case we crash before truncate | ||
1196 | * finishes. | ||
1194 | */ | 1197 | */ |
1195 | if (pos + len > inode->i_size) | 1198 | if (pos + len > inode->i_size) |
1199 | ext3_orphan_add(handle, inode); | ||
1200 | ext3_journal_stop(handle); | ||
1201 | unlock_page(page); | ||
1202 | page_cache_release(page); | ||
1203 | if (pos + len > inode->i_size) | ||
1196 | vmtruncate(inode, inode->i_size); | 1204 | vmtruncate(inode, inode->i_size); |
1197 | } | 1205 | } |
1198 | if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) | 1206 | if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) |
@@ -1211,6 +1219,18 @@ int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh) | |||
1211 | return err; | 1219 | return err; |
1212 | } | 1220 | } |
1213 | 1221 | ||
1222 | /* For ordered writepage and write_end functions */ | ||
1223 | static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) | ||
1224 | { | ||
1225 | /* | ||
1226 | * Write could have mapped the buffer but it didn't copy the data in | ||
1227 | * yet. So avoid filing such buffer into a transaction. | ||
1228 | */ | ||
1229 | if (buffer_mapped(bh) && buffer_uptodate(bh)) | ||
1230 | return ext3_journal_dirty_data(handle, bh); | ||
1231 | return 0; | ||
1232 | } | ||
1233 | |||
1214 | /* For write_end() in data=journal mode */ | 1234 | /* For write_end() in data=journal mode */ |
1215 | static int write_end_fn(handle_t *handle, struct buffer_head *bh) | 1235 | static int write_end_fn(handle_t *handle, struct buffer_head *bh) |
1216 | { | 1236 | { |
@@ -1221,26 +1241,20 @@ static int write_end_fn(handle_t *handle, struct buffer_head *bh) | |||
1221 | } | 1241 | } |
1222 | 1242 | ||
1223 | /* | 1243 | /* |
1224 | * Generic write_end handler for ordered and writeback ext3 journal modes. | 1244 | * This is nasty and subtle: ext3_write_begin() could have allocated blocks |
1225 | * We can't use generic_write_end, because that unlocks the page and we need to | 1245 | * for the whole page but later we failed to copy the data in. Update inode |
1226 | * unlock the page after ext3_journal_stop, but ext3_journal_stop must run | 1246 | * size according to what we managed to copy. The rest is going to be |
1227 | * after block_write_end. | 1247 | * truncated in write_end function. |
1228 | */ | 1248 | */ |
1229 | static int ext3_generic_write_end(struct file *file, | 1249 | static void update_file_sizes(struct inode *inode, loff_t pos, unsigned copied) |
1230 | struct address_space *mapping, | ||
1231 | loff_t pos, unsigned len, unsigned copied, | ||
1232 | struct page *page, void *fsdata) | ||
1233 | { | 1250 | { |
1234 | struct inode *inode = file->f_mapping->host; | 1251 | /* What matters to us is i_disksize. We don't write i_size anywhere */ |
1235 | 1252 | if (pos + copied > inode->i_size) | |
1236 | copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); | 1253 | i_size_write(inode, pos + copied); |
1237 | 1254 | if (pos + copied > EXT3_I(inode)->i_disksize) { | |
1238 | if (pos+copied > inode->i_size) { | 1255 | EXT3_I(inode)->i_disksize = pos + copied; |
1239 | i_size_write(inode, pos+copied); | ||
1240 | mark_inode_dirty(inode); | 1256 | mark_inode_dirty(inode); |
1241 | } | 1257 | } |
1242 | |||
1243 | return copied; | ||
1244 | } | 1258 | } |
1245 | 1259 | ||
1246 | /* | 1260 | /* |
@@ -1260,35 +1274,29 @@ static int ext3_ordered_write_end(struct file *file, | |||
1260 | unsigned from, to; | 1274 | unsigned from, to; |
1261 | int ret = 0, ret2; | 1275 | int ret = 0, ret2; |
1262 | 1276 | ||
1263 | from = pos & (PAGE_CACHE_SIZE - 1); | 1277 | copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); |
1264 | to = from + len; | ||
1265 | 1278 | ||
1279 | from = pos & (PAGE_CACHE_SIZE - 1); | ||
1280 | to = from + copied; | ||
1266 | ret = walk_page_buffers(handle, page_buffers(page), | 1281 | ret = walk_page_buffers(handle, page_buffers(page), |
1267 | from, to, NULL, ext3_journal_dirty_data); | 1282 | from, to, NULL, journal_dirty_data_fn); |
1268 | 1283 | ||
1269 | if (ret == 0) { | 1284 | if (ret == 0) |
1270 | /* | 1285 | update_file_sizes(inode, pos, copied); |
1271 | * generic_write_end() will run mark_inode_dirty() if i_size | 1286 | /* |
1272 | * changes. So let's piggyback the i_disksize mark_inode_dirty | 1287 | * There may be allocated blocks outside of i_size because |
1273 | * into that. | 1288 | * we failed to copy some data. Prepare for truncate. |
1274 | */ | 1289 | */ |
1275 | loff_t new_i_size; | 1290 | if (pos + len > inode->i_size) |
1276 | 1291 | ext3_orphan_add(handle, inode); | |
1277 | new_i_size = pos + copied; | ||
1278 | if (new_i_size > EXT3_I(inode)->i_disksize) | ||
1279 | EXT3_I(inode)->i_disksize = new_i_size; | ||
1280 | ret2 = ext3_generic_write_end(file, mapping, pos, len, copied, | ||
1281 | page, fsdata); | ||
1282 | copied = ret2; | ||
1283 | if (ret2 < 0) | ||
1284 | ret = ret2; | ||
1285 | } | ||
1286 | ret2 = ext3_journal_stop(handle); | 1292 | ret2 = ext3_journal_stop(handle); |
1287 | if (!ret) | 1293 | if (!ret) |
1288 | ret = ret2; | 1294 | ret = ret2; |
1289 | unlock_page(page); | 1295 | unlock_page(page); |
1290 | page_cache_release(page); | 1296 | page_cache_release(page); |
1291 | 1297 | ||
1298 | if (pos + len > inode->i_size) | ||
1299 | vmtruncate(inode, inode->i_size); | ||
1292 | return ret ? ret : copied; | 1300 | return ret ? ret : copied; |
1293 | } | 1301 | } |
1294 | 1302 | ||
@@ -1299,25 +1307,22 @@ static int ext3_writeback_write_end(struct file *file, | |||
1299 | { | 1307 | { |
1300 | handle_t *handle = ext3_journal_current_handle(); | 1308 | handle_t *handle = ext3_journal_current_handle(); |
1301 | struct inode *inode = file->f_mapping->host; | 1309 | struct inode *inode = file->f_mapping->host; |
1302 | int ret = 0, ret2; | 1310 | int ret; |
1303 | loff_t new_i_size; | ||
1304 | |||
1305 | new_i_size = pos + copied; | ||
1306 | if (new_i_size > EXT3_I(inode)->i_disksize) | ||
1307 | EXT3_I(inode)->i_disksize = new_i_size; | ||
1308 | |||
1309 | ret2 = ext3_generic_write_end(file, mapping, pos, len, copied, | ||
1310 | page, fsdata); | ||
1311 | copied = ret2; | ||
1312 | if (ret2 < 0) | ||
1313 | ret = ret2; | ||
1314 | 1311 | ||
1315 | ret2 = ext3_journal_stop(handle); | 1312 | copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); |
1316 | if (!ret) | 1313 | update_file_sizes(inode, pos, copied); |
1317 | ret = ret2; | 1314 | /* |
1315 | * There may be allocated blocks outside of i_size because | ||
1316 | * we failed to copy some data. Prepare for truncate. | ||
1317 | */ | ||
1318 | if (pos + len > inode->i_size) | ||
1319 | ext3_orphan_add(handle, inode); | ||
1320 | ret = ext3_journal_stop(handle); | ||
1318 | unlock_page(page); | 1321 | unlock_page(page); |
1319 | page_cache_release(page); | 1322 | page_cache_release(page); |
1320 | 1323 | ||
1324 | if (pos + len > inode->i_size) | ||
1325 | vmtruncate(inode, inode->i_size); | ||
1321 | return ret ? ret : copied; | 1326 | return ret ? ret : copied; |
1322 | } | 1327 | } |
1323 | 1328 | ||
@@ -1338,15 +1343,23 @@ static int ext3_journalled_write_end(struct file *file, | |||
1338 | if (copied < len) { | 1343 | if (copied < len) { |
1339 | if (!PageUptodate(page)) | 1344 | if (!PageUptodate(page)) |
1340 | copied = 0; | 1345 | copied = 0; |
1341 | page_zero_new_buffers(page, from+copied, to); | 1346 | page_zero_new_buffers(page, from + copied, to); |
1347 | to = from + copied; | ||
1342 | } | 1348 | } |
1343 | 1349 | ||
1344 | ret = walk_page_buffers(handle, page_buffers(page), from, | 1350 | ret = walk_page_buffers(handle, page_buffers(page), from, |
1345 | to, &partial, write_end_fn); | 1351 | to, &partial, write_end_fn); |
1346 | if (!partial) | 1352 | if (!partial) |
1347 | SetPageUptodate(page); | 1353 | SetPageUptodate(page); |
1348 | if (pos+copied > inode->i_size) | 1354 | |
1349 | i_size_write(inode, pos+copied); | 1355 | if (pos + copied > inode->i_size) |
1356 | i_size_write(inode, pos + copied); | ||
1357 | /* | ||
1358 | * There may be allocated blocks outside of i_size because | ||
1359 | * we failed to copy some data. Prepare for truncate. | ||
1360 | */ | ||
1361 | if (pos + len > inode->i_size) | ||
1362 | ext3_orphan_add(handle, inode); | ||
1350 | EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; | 1363 | EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; |
1351 | if (inode->i_size > EXT3_I(inode)->i_disksize) { | 1364 | if (inode->i_size > EXT3_I(inode)->i_disksize) { |
1352 | EXT3_I(inode)->i_disksize = inode->i_size; | 1365 | EXT3_I(inode)->i_disksize = inode->i_size; |
@@ -1361,6 +1374,8 @@ static int ext3_journalled_write_end(struct file *file, | |||
1361 | unlock_page(page); | 1374 | unlock_page(page); |
1362 | page_cache_release(page); | 1375 | page_cache_release(page); |
1363 | 1376 | ||
1377 | if (pos + len > inode->i_size) | ||
1378 | vmtruncate(inode, inode->i_size); | ||
1364 | return ret ? ret : copied; | 1379 | return ret ? ret : copied; |
1365 | } | 1380 | } |
1366 | 1381 | ||
@@ -1428,17 +1443,11 @@ static int bput_one(handle_t *handle, struct buffer_head *bh) | |||
1428 | return 0; | 1443 | return 0; |
1429 | } | 1444 | } |
1430 | 1445 | ||
1431 | static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) | ||
1432 | { | ||
1433 | if (buffer_mapped(bh)) | ||
1434 | return ext3_journal_dirty_data(handle, bh); | ||
1435 | return 0; | ||
1436 | } | ||
1437 | |||
1438 | static int buffer_unmapped(handle_t *handle, struct buffer_head *bh) | 1446 | static int buffer_unmapped(handle_t *handle, struct buffer_head *bh) |
1439 | { | 1447 | { |
1440 | return !buffer_mapped(bh); | 1448 | return !buffer_mapped(bh); |
1441 | } | 1449 | } |
1450 | |||
1442 | /* | 1451 | /* |
1443 | * Note that we always start a transaction even if we're not journalling | 1452 | * Note that we always start a transaction even if we're not journalling |
1444 | * data. This is to preserve ordering: any hole instantiation within | 1453 | * data. This is to preserve ordering: any hole instantiation within |