aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext3
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2009-07-13 14:26:52 -0400
committerJan Kara <jack@suse.cz>2009-07-15 15:28:07 -0400
commit9eaaa2d5759837402ec5eee13b2a97921808c3eb (patch)
treec1ba576d1175a91e7fb443a7d87a76c2380ce9cf /fs/ext3
parent7447a668a3860b66b3c9db86fdea91e355ba59ac (diff)
ext3: Fix truncation of symlinks after failed write
Contents of long symlinks is written via standard write methods. So when the write fails, we add inode to orphan list. But symlinks don't have .truncate method defined so nobody properly removes them from the orphan list (both on disk and in memory). Fix this by calling ext3_truncate() directly instead of calling vmtruncate() (which is saner anyway since we don't need anything vmtruncate() does except from calling .truncate in these paths). We also add inode to orphan list only if ext3_can_truncate() is true (currently, it can be false for symlinks when there are no blocks allocated) - otherwise orphan list processing will complain and ext3_truncate() will not remove inode from on-disk orphan list. Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/ext3')
-rw-r--r--fs/ext3/inode.c19
1 files changed, 10 insertions, 9 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 5f51fed5c750..4d7da6f6184b 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1193,15 +1193,16 @@ write_begin_failed:
1193 * i_size_read because we hold i_mutex. 1193 * i_size_read because we hold i_mutex.
1194 * 1194 *
1195 * Add inode to orphan list in case we crash before truncate 1195 * Add inode to orphan list in case we crash before truncate
1196 * finishes. 1196 * finishes. Do this only if ext3_can_truncate() agrees so
1197 * that orphan processing code is happy.
1197 */ 1198 */
1198 if (pos + len > inode->i_size) 1199 if (pos + len > inode->i_size && ext3_can_truncate(inode))
1199 ext3_orphan_add(handle, inode); 1200 ext3_orphan_add(handle, inode);
1200 ext3_journal_stop(handle); 1201 ext3_journal_stop(handle);
1201 unlock_page(page); 1202 unlock_page(page);
1202 page_cache_release(page); 1203 page_cache_release(page);
1203 if (pos + len > inode->i_size) 1204 if (pos + len > inode->i_size)
1204 vmtruncate(inode, inode->i_size); 1205 ext3_truncate(inode);
1205 } 1206 }
1206 if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) 1207 if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
1207 goto retry; 1208 goto retry;
@@ -1287,7 +1288,7 @@ static int ext3_ordered_write_end(struct file *file,
1287 * There may be allocated blocks outside of i_size because 1288 * There may be allocated blocks outside of i_size because
1288 * we failed to copy some data. Prepare for truncate. 1289 * we failed to copy some data. Prepare for truncate.
1289 */ 1290 */
1290 if (pos + len > inode->i_size) 1291 if (pos + len > inode->i_size && ext3_can_truncate(inode))
1291 ext3_orphan_add(handle, inode); 1292 ext3_orphan_add(handle, inode);
1292 ret2 = ext3_journal_stop(handle); 1293 ret2 = ext3_journal_stop(handle);
1293 if (!ret) 1294 if (!ret)
@@ -1296,7 +1297,7 @@ static int ext3_ordered_write_end(struct file *file,
1296 page_cache_release(page); 1297 page_cache_release(page);
1297 1298
1298 if (pos + len > inode->i_size) 1299 if (pos + len > inode->i_size)
1299 vmtruncate(inode, inode->i_size); 1300 ext3_truncate(inode);
1300 return ret ? ret : copied; 1301 return ret ? ret : copied;
1301} 1302}
1302 1303
@@ -1315,14 +1316,14 @@ static int ext3_writeback_write_end(struct file *file,
1315 * There may be allocated blocks outside of i_size because 1316 * There may be allocated blocks outside of i_size because
1316 * we failed to copy some data. Prepare for truncate. 1317 * we failed to copy some data. Prepare for truncate.
1317 */ 1318 */
1318 if (pos + len > inode->i_size) 1319 if (pos + len > inode->i_size && ext3_can_truncate(inode))
1319 ext3_orphan_add(handle, inode); 1320 ext3_orphan_add(handle, inode);
1320 ret = ext3_journal_stop(handle); 1321 ret = ext3_journal_stop(handle);
1321 unlock_page(page); 1322 unlock_page(page);
1322 page_cache_release(page); 1323 page_cache_release(page);
1323 1324
1324 if (pos + len > inode->i_size) 1325 if (pos + len > inode->i_size)
1325 vmtruncate(inode, inode->i_size); 1326 ext3_truncate(inode);
1326 return ret ? ret : copied; 1327 return ret ? ret : copied;
1327} 1328}
1328 1329
@@ -1358,7 +1359,7 @@ static int ext3_journalled_write_end(struct file *file,
1358 * There may be allocated blocks outside of i_size because 1359 * There may be allocated blocks outside of i_size because
1359 * we failed to copy some data. Prepare for truncate. 1360 * we failed to copy some data. Prepare for truncate.
1360 */ 1361 */
1361 if (pos + len > inode->i_size) 1362 if (pos + len > inode->i_size && ext3_can_truncate(inode))
1362 ext3_orphan_add(handle, inode); 1363 ext3_orphan_add(handle, inode);
1363 EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; 1364 EXT3_I(inode)->i_state |= EXT3_STATE_JDATA;
1364 if (inode->i_size > EXT3_I(inode)->i_disksize) { 1365 if (inode->i_size > EXT3_I(inode)->i_disksize) {
@@ -1375,7 +1376,7 @@ static int ext3_journalled_write_end(struct file *file,
1375 page_cache_release(page); 1376 page_cache_release(page);
1376 1377
1377 if (pos + len > inode->i_size) 1378 if (pos + len > inode->i_size)
1378 vmtruncate(inode, inode->i_size); 1379 ext3_truncate(inode);
1379 return ret ? ret : copied; 1380 return ret ? ret : copied;
1380} 1381}
1381 1382