diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-18 11:17:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-18 11:17:20 -0400 |
commit | 06a60deca87dba8e2c186ea7f12ea87d6785188e (patch) | |
tree | 2a6c8de6a7b110d13a1c1e3fc07cdc9065dfd749 /fs/f2fs/file.c | |
parent | d6a24d0640d609138a4e40a4ce9fd9fe7859e24c (diff) | |
parent | 10027551ccf5459cc771c31ac8bc8e5cc8db45f8 (diff) |
Merge tag 'for-f2fs-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs
Pull f2fs updates from Jaegeuk Kim:
"New features:
- in-memory extent_cache
- fs_shutdown to test power-off-recovery
- use inline_data to store symlink path
- show f2fs as a non-misc filesystem
Major fixes:
- avoid CPU stalls on sync_dirty_dir_inodes
- fix some power-off-recovery procedure
- fix handling of broken symlink correctly
- fix missing dot and dotdot made by sudden power cuts
- handle wrong data index during roll-forward recovery
- preallocate data blocks for direct_io
... and a bunch of minor bug fixes and cleanups"
* tag 'for-f2fs-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (71 commits)
f2fs: pass checkpoint reason on roll-forward recovery
f2fs: avoid abnormal behavior on broken symlink
f2fs: flush symlink path to avoid broken symlink after POR
f2fs: change 0 to false for bool type
f2fs: do not recover wrong data index
f2fs: do not increase link count during recovery
f2fs: assign parent's i_mode for empty dir
f2fs: add F2FS_INLINE_DOTS to recover missing dot dentries
f2fs: fix mismatching lock and unlock pages for roll-forward recovery
f2fs: fix sparse warnings
f2fs: limit b_size of mapped bh in f2fs_map_bh
f2fs: persist system.advise into on-disk inode
f2fs: avoid NULL pointer dereference in f2fs_xattr_advise_get
f2fs: preallocate fallocated blocks for direct IO
f2fs: enable inline data by default
f2fs: preserve extent info for extent cache
f2fs: initialize extent tree with on-disk extent info of inode
f2fs: introduce __{find,grab}_extent_tree
f2fs: split set_data_blkaddr from f2fs_update_extent_cache
f2fs: enable fast symlink by utilizing inline data
...
Diffstat (limited to 'fs/f2fs/file.c')
-rw-r--r-- | fs/f2fs/file.c | 64 |
1 files changed, 58 insertions, 6 deletions
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index df6a0596eccf..a6f3f6186588 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c | |||
@@ -241,6 +241,8 @@ go_write: | |||
241 | * will be used only for fsynced inodes after checkpoint. | 241 | * will be used only for fsynced inodes after checkpoint. |
242 | */ | 242 | */ |
243 | try_to_fix_pino(inode); | 243 | try_to_fix_pino(inode); |
244 | clear_inode_flag(fi, FI_APPEND_WRITE); | ||
245 | clear_inode_flag(fi, FI_UPDATE_WRITE); | ||
244 | goto out; | 246 | goto out; |
245 | } | 247 | } |
246 | sync_nodes: | 248 | sync_nodes: |
@@ -433,8 +435,12 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count) | |||
433 | continue; | 435 | continue; |
434 | 436 | ||
435 | dn->data_blkaddr = NULL_ADDR; | 437 | dn->data_blkaddr = NULL_ADDR; |
436 | update_extent_cache(dn); | 438 | set_data_blkaddr(dn); |
439 | f2fs_update_extent_cache(dn); | ||
437 | invalidate_blocks(sbi, blkaddr); | 440 | invalidate_blocks(sbi, blkaddr); |
441 | if (dn->ofs_in_node == 0 && IS_INODE(dn->node_page)) | ||
442 | clear_inode_flag(F2FS_I(dn->inode), | ||
443 | FI_FIRST_BLOCK_WRITTEN); | ||
438 | nr_free++; | 444 | nr_free++; |
439 | } | 445 | } |
440 | if (nr_free) { | 446 | if (nr_free) { |
@@ -454,15 +460,16 @@ void truncate_data_blocks(struct dnode_of_data *dn) | |||
454 | truncate_data_blocks_range(dn, ADDRS_PER_BLOCK); | 460 | truncate_data_blocks_range(dn, ADDRS_PER_BLOCK); |
455 | } | 461 | } |
456 | 462 | ||
457 | static int truncate_partial_data_page(struct inode *inode, u64 from) | 463 | static int truncate_partial_data_page(struct inode *inode, u64 from, |
464 | bool force) | ||
458 | { | 465 | { |
459 | unsigned offset = from & (PAGE_CACHE_SIZE - 1); | 466 | unsigned offset = from & (PAGE_CACHE_SIZE - 1); |
460 | struct page *page; | 467 | struct page *page; |
461 | 468 | ||
462 | if (!offset) | 469 | if (!offset && !force) |
463 | return 0; | 470 | return 0; |
464 | 471 | ||
465 | page = find_data_page(inode, from >> PAGE_CACHE_SHIFT, false); | 472 | page = find_data_page(inode, from >> PAGE_CACHE_SHIFT, force); |
466 | if (IS_ERR(page)) | 473 | if (IS_ERR(page)) |
467 | return 0; | 474 | return 0; |
468 | 475 | ||
@@ -473,7 +480,8 @@ static int truncate_partial_data_page(struct inode *inode, u64 from) | |||
473 | 480 | ||
474 | f2fs_wait_on_page_writeback(page, DATA); | 481 | f2fs_wait_on_page_writeback(page, DATA); |
475 | zero_user(page, offset, PAGE_CACHE_SIZE - offset); | 482 | zero_user(page, offset, PAGE_CACHE_SIZE - offset); |
476 | set_page_dirty(page); | 483 | if (!force) |
484 | set_page_dirty(page); | ||
477 | out: | 485 | out: |
478 | f2fs_put_page(page, 1); | 486 | f2fs_put_page(page, 1); |
479 | return 0; | 487 | return 0; |
@@ -487,6 +495,7 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock) | |||
487 | pgoff_t free_from; | 495 | pgoff_t free_from; |
488 | int count = 0, err = 0; | 496 | int count = 0, err = 0; |
489 | struct page *ipage; | 497 | struct page *ipage; |
498 | bool truncate_page = false; | ||
490 | 499 | ||
491 | trace_f2fs_truncate_blocks_enter(inode, from); | 500 | trace_f2fs_truncate_blocks_enter(inode, from); |
492 | 501 | ||
@@ -502,7 +511,10 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock) | |||
502 | } | 511 | } |
503 | 512 | ||
504 | if (f2fs_has_inline_data(inode)) { | 513 | if (f2fs_has_inline_data(inode)) { |
514 | if (truncate_inline_inode(ipage, from)) | ||
515 | set_page_dirty(ipage); | ||
505 | f2fs_put_page(ipage, 1); | 516 | f2fs_put_page(ipage, 1); |
517 | truncate_page = true; | ||
506 | goto out; | 518 | goto out; |
507 | } | 519 | } |
508 | 520 | ||
@@ -533,7 +545,7 @@ out: | |||
533 | 545 | ||
534 | /* lastly zero out the first data page */ | 546 | /* lastly zero out the first data page */ |
535 | if (!err) | 547 | if (!err) |
536 | err = truncate_partial_data_page(inode, from); | 548 | err = truncate_partial_data_page(inode, from, truncate_page); |
537 | 549 | ||
538 | trace_f2fs_truncate_blocks_exit(inode, err); | 550 | trace_f2fs_truncate_blocks_exit(inode, err); |
539 | return err; | 551 | return err; |
@@ -997,6 +1009,9 @@ static int f2fs_ioc_release_volatile_write(struct file *filp) | |||
997 | if (!f2fs_is_volatile_file(inode)) | 1009 | if (!f2fs_is_volatile_file(inode)) |
998 | return 0; | 1010 | return 0; |
999 | 1011 | ||
1012 | if (!f2fs_is_first_block_written(inode)) | ||
1013 | return truncate_partial_data_page(inode, 0, true); | ||
1014 | |||
1000 | punch_hole(inode, 0, F2FS_BLKSIZE); | 1015 | punch_hole(inode, 0, F2FS_BLKSIZE); |
1001 | return 0; | 1016 | return 0; |
1002 | } | 1017 | } |
@@ -1029,6 +1044,41 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp) | |||
1029 | return ret; | 1044 | return ret; |
1030 | } | 1045 | } |
1031 | 1046 | ||
1047 | static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg) | ||
1048 | { | ||
1049 | struct inode *inode = file_inode(filp); | ||
1050 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | ||
1051 | struct super_block *sb = sbi->sb; | ||
1052 | __u32 in; | ||
1053 | |||
1054 | if (!capable(CAP_SYS_ADMIN)) | ||
1055 | return -EPERM; | ||
1056 | |||
1057 | if (get_user(in, (__u32 __user *)arg)) | ||
1058 | return -EFAULT; | ||
1059 | |||
1060 | switch (in) { | ||
1061 | case F2FS_GOING_DOWN_FULLSYNC: | ||
1062 | sb = freeze_bdev(sb->s_bdev); | ||
1063 | if (sb && !IS_ERR(sb)) { | ||
1064 | f2fs_stop_checkpoint(sbi); | ||
1065 | thaw_bdev(sb->s_bdev, sb); | ||
1066 | } | ||
1067 | break; | ||
1068 | case F2FS_GOING_DOWN_METASYNC: | ||
1069 | /* do checkpoint only */ | ||
1070 | f2fs_sync_fs(sb, 1); | ||
1071 | f2fs_stop_checkpoint(sbi); | ||
1072 | break; | ||
1073 | case F2FS_GOING_DOWN_NOSYNC: | ||
1074 | f2fs_stop_checkpoint(sbi); | ||
1075 | break; | ||
1076 | default: | ||
1077 | return -EINVAL; | ||
1078 | } | ||
1079 | return 0; | ||
1080 | } | ||
1081 | |||
1032 | static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg) | 1082 | static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg) |
1033 | { | 1083 | { |
1034 | struct inode *inode = file_inode(filp); | 1084 | struct inode *inode = file_inode(filp); |
@@ -1078,6 +1128,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
1078 | return f2fs_ioc_release_volatile_write(filp); | 1128 | return f2fs_ioc_release_volatile_write(filp); |
1079 | case F2FS_IOC_ABORT_VOLATILE_WRITE: | 1129 | case F2FS_IOC_ABORT_VOLATILE_WRITE: |
1080 | return f2fs_ioc_abort_volatile_write(filp); | 1130 | return f2fs_ioc_abort_volatile_write(filp); |
1131 | case F2FS_IOC_SHUTDOWN: | ||
1132 | return f2fs_ioc_shutdown(filp, arg); | ||
1081 | case FITRIM: | 1133 | case FITRIM: |
1082 | return f2fs_ioc_fitrim(filp, arg); | 1134 | return f2fs_ioc_fitrim(filp, arg); |
1083 | default: | 1135 | default: |