diff options
author | Vladimir V. Saveliev <vs@namesys.com> | 2006-12-06 23:39:12 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-07 11:39:42 -0500 |
commit | c55747682e938c57a9a859d3b26f2c4c83cea011 (patch) | |
tree | 5af319c0a61851b68be9cef30172808f6e8e77f0 /fs/reiserfs | |
parent | 301827acbe49d0ba7ec9770803970893ac9ded97 (diff) |
[PATCH] reiserfs: do not add save links for O_DIRECT writes
We add a save link for O_DIRECT writes to protect the i_size against the
crashes before we actually finish the I/O. If we hit an -ENOSPC in
aops->prepare_write(), we would do a truncate() to release the blocks which
might have got initialized. Now the truncate would add another save link
for the same inode causing a reiserfs panic for having multiple save links
for the same inode.
Signed-off-by: Vladimir V. Saveliev <vs@namesys.com>
Signed-off-by: Amit Arora <amitarora@in.ibm.com>
Signed-off-by: Suzuki K P <suzuki@in.ibm.com>
Cc: Jeff Mahoney <jeffm@suse.com>
Cc: Chris Mason <mason@suse.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/reiserfs')
-rw-r--r-- | fs/reiserfs/file.c | 54 |
1 files changed, 4 insertions, 50 deletions
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 970ecd9dbe69..373d862c3f87 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c | |||
@@ -406,6 +406,8 @@ static int reiserfs_allocate_blocks_for_region(struct reiserfs_transaction_handl | |||
406 | we restart it. This will also free the path. */ | 406 | we restart it. This will also free the path. */ |
407 | if (journal_transaction_should_end | 407 | if (journal_transaction_should_end |
408 | (th, th->t_blocks_allocated)) { | 408 | (th, th->t_blocks_allocated)) { |
409 | inode->i_size = cpu_key_k_offset(&key) + | ||
410 | (to_paste << inode->i_blkbits); | ||
409 | res = | 411 | res = |
410 | restart_transaction(th, inode, | 412 | restart_transaction(th, inode, |
411 | &path); | 413 | &path); |
@@ -1310,56 +1312,8 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t | |||
1310 | count = MAX_NON_LFS - (unsigned long)*ppos; | 1312 | count = MAX_NON_LFS - (unsigned long)*ppos; |
1311 | } | 1313 | } |
1312 | 1314 | ||
1313 | if (file->f_flags & O_DIRECT) { // Direct IO needs treatment | 1315 | if (file->f_flags & O_DIRECT) |
1314 | ssize_t result, after_file_end = 0; | 1316 | return do_sync_write(file, buf, count, ppos); |
1315 | if ((*ppos + count >= inode->i_size) | ||
1316 | || (file->f_flags & O_APPEND)) { | ||
1317 | /* If we are appending a file, we need to put this savelink in here. | ||
1318 | If we will crash while doing direct io, finish_unfinished will | ||
1319 | cut the garbage from the file end. */ | ||
1320 | reiserfs_write_lock(inode->i_sb); | ||
1321 | err = | ||
1322 | journal_begin(&th, inode->i_sb, | ||
1323 | JOURNAL_PER_BALANCE_CNT); | ||
1324 | if (err) { | ||
1325 | reiserfs_write_unlock(inode->i_sb); | ||
1326 | return err; | ||
1327 | } | ||
1328 | reiserfs_update_inode_transaction(inode); | ||
1329 | add_save_link(&th, inode, 1 /* Truncate */ ); | ||
1330 | after_file_end = 1; | ||
1331 | err = | ||
1332 | journal_end(&th, inode->i_sb, | ||
1333 | JOURNAL_PER_BALANCE_CNT); | ||
1334 | reiserfs_write_unlock(inode->i_sb); | ||
1335 | if (err) | ||
1336 | return err; | ||
1337 | } | ||
1338 | result = do_sync_write(file, buf, count, ppos); | ||
1339 | |||
1340 | if (after_file_end) { /* Now update i_size and remove the savelink */ | ||
1341 | struct reiserfs_transaction_handle th; | ||
1342 | reiserfs_write_lock(inode->i_sb); | ||
1343 | err = journal_begin(&th, inode->i_sb, 1); | ||
1344 | if (err) { | ||
1345 | reiserfs_write_unlock(inode->i_sb); | ||
1346 | return err; | ||
1347 | } | ||
1348 | reiserfs_update_inode_transaction(inode); | ||
1349 | mark_inode_dirty(inode); | ||
1350 | err = journal_end(&th, inode->i_sb, 1); | ||
1351 | if (err) { | ||
1352 | reiserfs_write_unlock(inode->i_sb); | ||
1353 | return err; | ||
1354 | } | ||
1355 | err = remove_save_link(inode, 1 /* truncate */ ); | ||
1356 | reiserfs_write_unlock(inode->i_sb); | ||
1357 | if (err) | ||
1358 | return err; | ||
1359 | } | ||
1360 | |||
1361 | return result; | ||
1362 | } | ||
1363 | 1317 | ||
1364 | if (unlikely((ssize_t) count < 0)) | 1318 | if (unlikely((ssize_t) count < 0)) |
1365 | return -EINVAL; | 1319 | return -EINVAL; |