diff options
author | Mark Fasheh <mark.fasheh@oracle.com> | 2006-07-11 17:38:54 -0400 |
---|---|---|
committer | Mark Fasheh <mark.fasheh@oracle.com> | 2006-09-20 18:53:05 -0400 |
commit | e0b4096d34fbd6b30838c417100c9d0ef73c71f2 (patch) | |
tree | cabe34d3ae64b906f186ddea53bf3b4f84099ab7 /fs/ocfs2 | |
parent | 0f62de2c9ca60a35f63122e7ea992cee8aae4bef (diff) |
ocfs2: properly update i_mtime on buffered write
We weren't always updating i_mtime on writes, so fix ocfs2_commit_write() to
handle this.
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
Acked-by: Zach Brown <zach.brown@oracle.com>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r-- | fs/ocfs2/aops.c | 83 |
1 files changed, 34 insertions, 49 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index f1d1c342ce01..3d7c082a8f58 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -391,31 +391,28 @@ out: | |||
391 | static int ocfs2_commit_write(struct file *file, struct page *page, | 391 | static int ocfs2_commit_write(struct file *file, struct page *page, |
392 | unsigned from, unsigned to) | 392 | unsigned from, unsigned to) |
393 | { | 393 | { |
394 | int ret, extending = 0, locklevel = 0; | 394 | int ret; |
395 | loff_t new_i_size; | ||
396 | struct buffer_head *di_bh = NULL; | 395 | struct buffer_head *di_bh = NULL; |
397 | struct inode *inode = page->mapping->host; | 396 | struct inode *inode = page->mapping->host; |
398 | struct ocfs2_journal_handle *handle = NULL; | 397 | struct ocfs2_journal_handle *handle = NULL; |
398 | struct ocfs2_dinode *di; | ||
399 | 399 | ||
400 | mlog_entry("(0x%p, 0x%p, %u, %u)\n", file, page, from, to); | 400 | mlog_entry("(0x%p, 0x%p, %u, %u)\n", file, page, from, to); |
401 | 401 | ||
402 | /* NOTE: ocfs2_file_aio_write has ensured that it's safe for | 402 | /* NOTE: ocfs2_file_aio_write has ensured that it's safe for |
403 | * us to sample inode->i_size here without the metadata lock: | 403 | * us to continue here without rechecking the I/O against |
404 | * changed inode values. | ||
404 | * | 405 | * |
405 | * 1) We're currently holding the inode alloc lock, so no | 406 | * 1) We're currently holding the inode alloc lock, so no |
406 | * nodes can change it underneath us. | 407 | * nodes can change it underneath us. |
407 | * | 408 | * |
408 | * 2) We've had to take the metadata lock at least once | 409 | * 2) We've had to take the metadata lock at least once |
409 | * already to check for extending writes, hence insuring | 410 | * already to check for extending writes, suid removal, etc. |
410 | * that our current copy is also up to date. | 411 | * The meta data update code then ensures that we don't get a |
412 | * stale inode allocation image (i_size, i_clusters, etc). | ||
411 | */ | 413 | */ |
412 | new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | ||
413 | if (new_i_size > i_size_read(inode)) { | ||
414 | extending = 1; | ||
415 | locklevel = 1; | ||
416 | } | ||
417 | 414 | ||
418 | ret = ocfs2_meta_lock_with_page(inode, NULL, &di_bh, locklevel, page); | 415 | ret = ocfs2_meta_lock_with_page(inode, NULL, &di_bh, 1, page); |
419 | if (ret != 0) { | 416 | if (ret != 0) { |
420 | mlog_errno(ret); | 417 | mlog_errno(ret); |
421 | goto out; | 418 | goto out; |
@@ -427,23 +424,20 @@ static int ocfs2_commit_write(struct file *file, struct page *page, | |||
427 | goto out_unlock_meta; | 424 | goto out_unlock_meta; |
428 | } | 425 | } |
429 | 426 | ||
430 | if (extending) { | 427 | handle = ocfs2_start_walk_page_trans(inode, page, from, to); |
431 | handle = ocfs2_start_walk_page_trans(inode, page, from, to); | 428 | if (IS_ERR(handle)) { |
432 | if (IS_ERR(handle)) { | 429 | ret = PTR_ERR(handle); |
433 | ret = PTR_ERR(handle); | 430 | goto out_unlock_data; |
434 | handle = NULL; | 431 | } |
435 | goto out_unlock_data; | ||
436 | } | ||
437 | 432 | ||
438 | /* Mark our buffer early. We'd rather catch this error up here | 433 | /* Mark our buffer early. We'd rather catch this error up here |
439 | * as opposed to after a successful commit_write which would | 434 | * as opposed to after a successful commit_write which would |
440 | * require us to set back inode->i_size. */ | 435 | * require us to set back inode->i_size. */ |
441 | ret = ocfs2_journal_access(handle, inode, di_bh, | 436 | ret = ocfs2_journal_access(handle, inode, di_bh, |
442 | OCFS2_JOURNAL_ACCESS_WRITE); | 437 | OCFS2_JOURNAL_ACCESS_WRITE); |
443 | if (ret < 0) { | 438 | if (ret < 0) { |
444 | mlog_errno(ret); | 439 | mlog_errno(ret); |
445 | goto out_commit; | 440 | goto out_commit; |
446 | } | ||
447 | } | 441 | } |
448 | 442 | ||
449 | /* might update i_size */ | 443 | /* might update i_size */ |
@@ -453,37 +447,28 @@ static int ocfs2_commit_write(struct file *file, struct page *page, | |||
453 | goto out_commit; | 447 | goto out_commit; |
454 | } | 448 | } |
455 | 449 | ||
456 | if (extending) { | 450 | di = (struct ocfs2_dinode *)di_bh->b_data; |
457 | loff_t size = (u64) i_size_read(inode); | ||
458 | struct ocfs2_dinode *di = | ||
459 | (struct ocfs2_dinode *)di_bh->b_data; | ||
460 | 451 | ||
461 | /* ocfs2_mark_inode_dirty is too heavy to use here. */ | 452 | /* ocfs2_mark_inode_dirty() is too heavy to use here. */ |
462 | inode->i_blocks = ocfs2_align_bytes_to_sectors(size); | 453 | inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
463 | inode->i_ctime = inode->i_mtime = CURRENT_TIME; | 454 | di->i_mtime = di->i_ctime = cpu_to_le64(inode->i_mtime.tv_sec); |
455 | di->i_mtime_nsec = di->i_ctime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec); | ||
464 | 456 | ||
465 | di->i_size = cpu_to_le64(size); | 457 | inode->i_blocks = ocfs2_align_bytes_to_sectors((u64)(i_size_read(inode))); |
466 | di->i_ctime = di->i_mtime = | 458 | di->i_size = cpu_to_le64((u64)i_size_read(inode)); |
467 | cpu_to_le64(inode->i_mtime.tv_sec); | ||
468 | di->i_ctime_nsec = di->i_mtime_nsec = | ||
469 | cpu_to_le32(inode->i_mtime.tv_nsec); | ||
470 | 459 | ||
471 | ret = ocfs2_journal_dirty(handle, di_bh); | 460 | ret = ocfs2_journal_dirty(handle, di_bh); |
472 | if (ret < 0) { | 461 | if (ret < 0) { |
473 | mlog_errno(ret); | 462 | mlog_errno(ret); |
474 | goto out_commit; | 463 | goto out_commit; |
475 | } | ||
476 | } | 464 | } |
477 | 465 | ||
478 | BUG_ON(extending && (i_size_read(inode) != new_i_size)); | ||
479 | |||
480 | out_commit: | 466 | out_commit: |
481 | if (handle) | 467 | ocfs2_commit_trans(handle); |
482 | ocfs2_commit_trans(handle); | ||
483 | out_unlock_data: | 468 | out_unlock_data: |
484 | ocfs2_data_unlock(inode, 1); | 469 | ocfs2_data_unlock(inode, 1); |
485 | out_unlock_meta: | 470 | out_unlock_meta: |
486 | ocfs2_meta_unlock(inode, locklevel); | 471 | ocfs2_meta_unlock(inode, 1); |
487 | out: | 472 | out: |
488 | if (di_bh) | 473 | if (di_bh) |
489 | brelse(di_bh); | 474 | brelse(di_bh); |